test/jdk/sun/security/ssl/StatusStapling/java.base/sun/security/ssl/CertStatusReqExtensionTests.java
changeset 50768 68fa3d4026ea
parent 50767 356eaea05bf0
child 50769 1bf8f9840705
equal deleted inserted replaced
50767:356eaea05bf0 50768:68fa3d4026ea
     1 /*
       
     2  * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.
       
     8  *
       
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    12  * version 2 for more details (a copy is included in the LICENSE file that
       
    13  * accompanied this code).
       
    14  *
       
    15  * You should have received a copy of the GNU General Public License version
       
    16  * 2 along with this work; if not, write to the Free Software Foundation,
       
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    18  *
       
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    20  * or visit www.oracle.com if you need additional information or have any
       
    21  * questions.
       
    22  */
       
    23 
       
    24 package sun.security.ssl;
       
    25 
       
    26 import java.io.IOException;
       
    27 import java.util.*;
       
    28 import java.nio.ByteBuffer;
       
    29 
       
    30 /*
       
    31  * Checks that the hash value for a certificate's issuer name is generated
       
    32  * correctly. Requires any certificate that is not self-signed.
       
    33  *
       
    34  * NOTE: this test uses Sun private classes which are subject to change.
       
    35  */
       
    36 public class CertStatusReqExtensionTests {
       
    37 
       
    38     private static final boolean debug = false;
       
    39 
       
    40     // Default status_request extension (type = ocsp, OCSPStatusRequest
       
    41     // with no responder IDs or extensions
       
    42     private static final byte[] CSRE_DEF_OSR = {1, 0, 0, 0, 0};
       
    43 
       
    44     // A status_request extension using a user-defined type (0xFF) and
       
    45     // an underlying no-Responder ID/no-extension OCSPStatusRequest
       
    46     private static final byte[] CSRE_TYPE_FF = {-1, 0, 0, 0, 0};
       
    47 
       
    48     // A CertStatusReqExtension with 5 ResponderIds and 1 Extension
       
    49     private static final byte[] CSRE_REQ_RID_EXTS = {
       
    50            1,    0,  -13,    0,   59,  -95,   57,   48,
       
    51           55,   49,   16,   48,   14,    6,    3,   85,
       
    52            4,   10,   19,    7,   83,  111,  109,  101,
       
    53           73,  110,   99,   49,   16,   48,   14,    6,
       
    54            3,   85,    4,   11,   19,    7,   83,  111,
       
    55          109,  101,   80,   75,   73,   49,   17,   48,
       
    56           15,    6,    3,   85,    4,    3,   19,    8,
       
    57           83,  111,  109,  101,   79,   67,   83,   80,
       
    58            0,   68,  -95,   66,   48,   64,   49,   13,
       
    59           48,   11,    6,    3,   85,    4,   10,   19,
       
    60            4,   79,  104,   77,  121,   49,   14,   48,
       
    61           12,    6,    3,   85,    4,   11,   19,    5,
       
    62           66,  101,   97,  114,  115,   49,   15,   48,
       
    63           13,    6,    3,   85,    4,   11,   19,    6,
       
    64           84,  105,  103,  101,  114,  115,   49,   14,
       
    65           48,   12,    6,    3,   85,    4,    3,   19,
       
    66            5,   76,  105,  111,  110,  115,    0,   58,
       
    67          -95,   56,   48,   54,   49,   16,   48,   14,
       
    68            6,    3,   85,    4,   10,   19,    7,   67,
       
    69          111,  109,  112,   97,  110,  121,   49,   13,
       
    70           48,   11,    6,    3,   85,    4,   11,   19,
       
    71            4,   87,  101,  115,  116,   49,   19,   48,
       
    72           17,    6,    3,   85,    4,    3,   19,   10,
       
    73           82,  101,  115,  112,  111,  110,  100,  101,
       
    74          114,   49,    0,   24,  -94,   22,    4,   20,
       
    75          -67,  -36,  114,  121,   92,  -79,  116,   -1,
       
    76          102, -107,    7,  -21,   18, -113,   64,   76,
       
    77           96,   -7,  -66,  -63,    0,   24,  -94,   22,
       
    78            4,   20,  -51,  -69,  107,  -82,  -39,  -87,
       
    79           45,   25,   41,   28,  -76,  -68,  -11, -110,
       
    80          -94,  -97,   62,   47,   58, -125,    0,   51,
       
    81           48,   49,   48,   47,    6,    9,   43,    6,
       
    82            1,    5,    5,    7,   48,    1,    2,    4,
       
    83           34,    4,   32,  -26,  -81, -120,  -61, -127,
       
    84          -79,    0,  -39,  -54,   49,    3,  -51,  -57,
       
    85          -85,   19, -126,   94,   -2,   21,   26,   98,
       
    86            6,  105,  -35,  -37,  -29,  -73,  101,   53,
       
    87           44,   15,  -19
       
    88     };
       
    89 
       
    90     public static void main(String[] args) throws Exception {
       
    91         Map<String, TestCase> testList =
       
    92                 new LinkedHashMap<String, TestCase>() {{
       
    93             put("CTOR (default)", testCtorDefault);
       
    94             put("CTOR (int, StatusRequest)", testCtorStatReqs);
       
    95             put("CTOR (HandshakeInStream, length, getReqType, getRequest)",
       
    96                     testCtorInStream);
       
    97         }};
       
    98 
       
    99         TestUtils.runTests(testList);
       
   100     }
       
   101 
       
   102     public static final TestCase testCtorDefault = new TestCase() {
       
   103         @Override
       
   104         public Map.Entry<Boolean, String> runTest() {
       
   105             Boolean pass = Boolean.FALSE;
       
   106             String message = null;
       
   107             try {
       
   108                 CertStatusReqExtension csreDef = new CertStatusReqExtension();
       
   109                 HandshakeOutStream hsout =
       
   110                         new HandshakeOutStream(null);
       
   111                 csreDef.send(hsout);
       
   112                 TestUtils.valueCheck(wrapExtData(null), hsout.toByteArray());
       
   113 
       
   114                 // The length should be 4 (2 bytes for the type, 2 for the
       
   115                 // encoding of zero-length
       
   116                 if (csreDef.length() != 4) {
       
   117                     throw new RuntimeException("Incorrect length from " +
       
   118                             "default object.  Expected 4, got " +
       
   119                             csreDef.length());
       
   120                 }
       
   121 
       
   122                 // Since there's no data, there are no status_type or request
       
   123                 // data fields defined.  Both should return null in this case
       
   124                 if (csreDef.getType() != null) {
       
   125                     throw new RuntimeException("Default CSRE returned " +
       
   126                             "non-null status_type");
       
   127                 } else if (csreDef.getRequest() != null) {
       
   128                     throw new RuntimeException("Default CSRE returned " +
       
   129                             "non-null request object");
       
   130                 }
       
   131 
       
   132                 pass = Boolean.TRUE;
       
   133             } catch (Exception e) {
       
   134                 e.printStackTrace(System.out);
       
   135                 message = e.getClass().getName();
       
   136             }
       
   137 
       
   138             return new AbstractMap.SimpleEntry<>(pass, message);
       
   139         }
       
   140     };
       
   141 
       
   142     public static final TestCase testCtorStatReqs = new TestCase() {
       
   143         @Override
       
   144         public Map.Entry<Boolean, String> runTest() {
       
   145             Boolean pass = Boolean.FALSE;
       
   146             String message = null;
       
   147             try {
       
   148                 HandshakeOutStream hsout =
       
   149                         new HandshakeOutStream(null);
       
   150                 StatusRequest basicStatReq = new OCSPStatusRequest();
       
   151 
       
   152                 // Create an extension using a default-style OCSPStatusRequest
       
   153                 // (no responder IDs, no extensions).
       
   154                 CertStatusReqExtension csre1 = new CertStatusReqExtension(
       
   155                         StatusRequestType.OCSP, basicStatReq);
       
   156                 csre1.send(hsout);
       
   157                 TestUtils.valueCheck(wrapExtData(CSRE_DEF_OSR),
       
   158                         hsout.toByteArray());
       
   159                 hsout.reset();
       
   160 
       
   161                 // Create the extension using a StatusRequestType not already
       
   162                 // instantiated as a static StatusRequestType
       
   163                 // (e.g. OCSP/OCSP_MULTI)
       
   164                 CertStatusReqExtension csre2 =
       
   165                         new CertStatusReqExtension(StatusRequestType.get(-1),
       
   166                                 basicStatReq);
       
   167                 csre2.send(hsout);
       
   168                 TestUtils.valueCheck(wrapExtData(CSRE_TYPE_FF),
       
   169                         hsout.toByteArray());
       
   170 
       
   171                 // Create the extension using a StatusRequest that
       
   172                 // does not match the status_type field
       
   173                 // This should throw an IllegalArgumentException
       
   174                 try {
       
   175                     CertStatusReqExtension csreBadRequest =
       
   176                             new CertStatusReqExtension(StatusRequestType.OCSP,
       
   177                                     new BogusStatusRequest());
       
   178                     throw new RuntimeException("Constructor accepted a " +
       
   179                             "StatusRequest that is inconsistent with " +
       
   180                             "the status_type");
       
   181                 } catch (IllegalArgumentException iae) { }
       
   182 
       
   183                 // We don't allow a null value for the StatusRequestType
       
   184                 // parameter in this constructor.
       
   185                 try {
       
   186                     CertStatusReqExtension csreBadRequest =
       
   187                             new CertStatusReqExtension(null, basicStatReq);
       
   188                     throw new RuntimeException("Constructor accepted a " +
       
   189                             "null StatusRequestType");
       
   190                 } catch (NullPointerException npe) { }
       
   191 
       
   192                 // We also don't allow a null value for the StatusRequest
       
   193                 // parameter in this constructor.
       
   194                 try {
       
   195                     CertStatusReqExtension csreBadRequest =
       
   196                             new CertStatusReqExtension(StatusRequestType.OCSP,
       
   197                                     null);
       
   198                     throw new RuntimeException("Constructor accepted a " +
       
   199                             "null StatusRequest");
       
   200                 } catch (NullPointerException npe) { }
       
   201 
       
   202                 pass = Boolean.TRUE;
       
   203             } catch (Exception e) {
       
   204                 e.printStackTrace(System.out);
       
   205                 message = e.getClass().getName();
       
   206             }
       
   207 
       
   208             return new AbstractMap.SimpleEntry<>(pass, message);
       
   209         }
       
   210     };
       
   211 
       
   212     // Test the constructor that builds the ob ject using data from
       
   213     // a HandshakeInStream
       
   214     // This also tests the length, getReqType and getRequest methods
       
   215     public static final TestCase testCtorInStream = new TestCase() {
       
   216         @Override
       
   217         public Map.Entry<Boolean, String> runTest() {
       
   218             Boolean pass = Boolean.FALSE;
       
   219             String message = null;
       
   220             OCSPStatusRequest osr;
       
   221 
       
   222             try {
       
   223                 // To simulate the extension coming in a ServerHello, the
       
   224                 // type and length would already be read by HelloExtensions
       
   225                 // and there is no extension data
       
   226                 HandshakeInStream hsis = new HandshakeInStream();
       
   227                 hsis.incomingRecord(ByteBuffer.wrap(new byte[0]));
       
   228                 CertStatusReqExtension csre =
       
   229                         new CertStatusReqExtension(hsis, hsis.available());
       
   230                 // Verify length/type/request
       
   231                 if (csre.length() != 4) {
       
   232                      throw new RuntimeException("Invalid length: received " +
       
   233                             csre.length() + ", expected 4");
       
   234                 } else if (csre.getType() != null) {
       
   235                     throw new RuntimeException("Non-null type from default " +
       
   236                             "extension");
       
   237                 } else if (csre.getRequest() != null) {
       
   238                     throw new RuntimeException("Non-null request from default " +
       
   239                             "extension");
       
   240                 }
       
   241 
       
   242                 // Try the an extension with a default OCSPStatusRequest
       
   243                 hsis = new HandshakeInStream();
       
   244                 hsis.incomingRecord(ByteBuffer.wrap(CSRE_DEF_OSR));
       
   245                 csre = new CertStatusReqExtension(hsis, hsis.available());
       
   246                 if (csre.length() != (CSRE_DEF_OSR.length + 4)) {
       
   247                     throw new RuntimeException("Invalid length: received " +
       
   248                             csre.length() + ", expected " +
       
   249                             CSRE_DEF_OSR.length + 4);
       
   250                 } else if (!csre.getType().equals(StatusRequestType.OCSP)) {
       
   251                     throw new RuntimeException("Unknown status_type: " +
       
   252                             String.format("0x%02X", csre.getType().id));
       
   253                 } else {
       
   254                     osr = (OCSPStatusRequest)csre.getRequest();
       
   255                     if (!osr.getResponderIds().isEmpty() ||
       
   256                             !osr.getExtensions().isEmpty()) {
       
   257                         throw new RuntimeException("Non-default " +
       
   258                                 "OCSPStatusRequest found in extension");
       
   259                     }
       
   260                 }
       
   261 
       
   262                 // Try with a non-default extension
       
   263                 hsis = new HandshakeInStream();
       
   264                 hsis.incomingRecord(ByteBuffer.wrap(CSRE_REQ_RID_EXTS));
       
   265                 csre = new CertStatusReqExtension(hsis, hsis.available());
       
   266                 if (csre.length() != (CSRE_REQ_RID_EXTS.length + 4)) {
       
   267                     throw new RuntimeException("Invalid length: received " +
       
   268                             csre.length() + ", expected " +
       
   269                             CSRE_REQ_RID_EXTS.length + 4);
       
   270                 } else if (!(csre.getType().equals(StatusRequestType.OCSP))) {
       
   271                     throw new RuntimeException("Unknown status_type: " +
       
   272                             String.format("0x%02X", csre.getType().id));
       
   273                 } else {
       
   274                     osr = (OCSPStatusRequest)csre.getRequest();
       
   275                     if (osr.getResponderIds().size() != 5 ||
       
   276                             osr.getExtensions().size() != 1) {
       
   277                         throw new RuntimeException("Incorrect number of " +
       
   278                                 "ResponderIds or Extensions found in " +
       
   279                                 "OCSPStatusRequest");
       
   280                     }
       
   281                 }
       
   282 
       
   283                 // Create a CSRE that asserts status_request and has the
       
   284                 // proper length, but really is a bunch of random junk inside
       
   285                 // In this case, it will create an UnknownStatusRequest to
       
   286                 // handle the unparseable data.
       
   287                 byte[] junkData = new byte[48];
       
   288                 Random r = new Random(System.currentTimeMillis());
       
   289                 r.nextBytes(junkData);
       
   290                 junkData[0] = 7;        // Ensure it isn't a valid status_type
       
   291                 hsis = new HandshakeInStream();
       
   292                 hsis.incomingRecord(ByteBuffer.wrap(junkData));
       
   293                 csre = new CertStatusReqExtension(hsis, hsis.available());
       
   294                 StatusRequest sr = csre.getRequest();
       
   295                 if (!(sr instanceof UnknownStatusRequest)) {
       
   296                     throw new RuntimeException("Expected returned status " +
       
   297                             "request to be of type UnknownStatusRequest but " +
       
   298                             "received " + sr.getClass().getName());
       
   299                 } else if (csre.length() != (junkData.length + 4)) {
       
   300                     throw new RuntimeException("Invalid length: received " +
       
   301                             csre.length() + ", expected " +
       
   302                             junkData.length + 4);
       
   303                 }
       
   304 
       
   305                 // Set the leading byte to 1 (OCSP type) and run again
       
   306                 // It should pass the argument check and fail trying to parse
       
   307                 // the underlying StatusRequest.
       
   308                 junkData[0] = (byte)StatusRequestType.OCSP.id;
       
   309                 hsis = new HandshakeInStream();
       
   310                 hsis.incomingRecord(ByteBuffer.wrap(junkData));
       
   311                 try {
       
   312                     csre = new CertStatusReqExtension(hsis, hsis.available());
       
   313                     throw new RuntimeException("Expected CTOR exception did " +
       
   314                             "not occur");
       
   315                 } catch (IOException ioe) { }
       
   316 
       
   317                 pass = Boolean.TRUE;
       
   318             } catch (Exception e) {
       
   319                 e.printStackTrace(System.out);
       
   320                 message = e.getClass().getName();
       
   321             }
       
   322 
       
   323             return new AbstractMap.SimpleEntry<>(pass, message);
       
   324         }
       
   325     };
       
   326 
       
   327     // Take CSRE extension data and add extension type and length decorations
       
   328     private static byte[] wrapExtData(byte[] extData) {
       
   329         int bufferLen = (extData != null ? extData.length : 0) + 4;
       
   330         ByteBuffer bb = ByteBuffer.allocate(bufferLen);
       
   331         bb.putShort((short)ExtensionType.EXT_STATUS_REQUEST.id);
       
   332         bb.putShort((short)(extData != null ? extData.length: 0));
       
   333         if (extData != null) {
       
   334             bb.put(extData);
       
   335         }
       
   336         return bb.array();
       
   337     }
       
   338 }