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.security.cert.*; 27 import java.util.*; 28 import java.nio.ByteBuffer; 29 import javax.net.ssl.SSLException; 30 import javax.security.auth.x500.X500Principal; 31 import sun.security.provider.certpath.ResponderId; 32 import sun.security.provider.certpath.OCSPNonceExtension; 33 34 /* 35 * Checks that the hash value for a certificate's issuer name is generated 36 * correctly. Requires any certificate that is not self-signed. 37 * 38 * NOTE: this test uses Sun private classes which are subject to change. 39 */ 40 public class CertStatusReqItemV2Tests { 41 42 private static final boolean debug = false; 43 44 private static final byte[] DEF_CSRIV2_OCSP_MULTI_BYTES = { 45 2, 0, 4, 0, 0, 0, 0 46 }; 47 48 private static final byte[] DEF_CSRIV2_OCSP_BYTES = { 49 1, 0, 4, 0, 0, 0, 0 50 }; 51 52 // This is a CSRIV2 (ocsp_multi) that has a single 53 // responder ID and no extensions. 54 private static final byte[] CSRIV2_1RID = { 55 2, 0, 32, 0, 28, 0, 26, -95, 56 24, 48, 22, 49, 20, 48, 18, 6, 57 3, 85, 4, 3, 19, 11, 79, 67, 58 83, 80, 32, 83, 105, 103, 110, 101, 59 114, 0 , 0 60 }; 61 62 // This is a CSRIV2 (ocsp_multi) that has a single 63 // responder ID and no extensions. The request_length 64 // field is too short in this case. 65 private static final byte[] CSRIV2_LENGTH_TOO_SHORT = { 66 2, 0, 27, 0, 28, 0, 26, -95, 67 24, 48, 22, 49, 20, 48, 18, 6, 68 3, 85, 4, 3, 19, 11, 79, 67, 69 83, 80, 32, 83, 105, 103, 110, 101, 70 114, 0 , 0 71 }; 72 73 // This is a CSRIV2 (ocsp_multi) that has a single 74 // responder ID and no extensions. The request_length 75 // field is too long in this case. 76 private static final byte[] CSRIV2_LENGTH_TOO_LONG = { 77 2, 0, 54, 0, 28, 0, 26, -95, 78 24, 48, 22, 49, 20, 48, 18, 6, 79 3, 85, 4, 3, 19, 11, 79, 67, 80 83, 80, 32, 83, 105, 103, 110, 101, 81 114, 0 , 0 82 }; 83 84 // A CSRIV2 (ocsp) with one Responder ID (byName: CN=OCSP Signer) 85 // and a nonce extension (32 bytes). 86 private static final byte[] CSRIV2_OCSP_1RID_1EXT = { 87 1, 0, 83, 0, 28, 0, 26, -95, 88 24, 48, 22, 49, 20, 48, 18, 6, 89 3, 85, 4, 3, 19, 11, 79, 67, 90 83, 80, 32, 83, 105, 103, 110, 101, 91 114, 0, 51, 48, 49, 48, 47, 6, 92 9, 43, 6, 1, 5, 5, 7, 48, 93 1, 2, 4, 34, 4, 32, -34, -83, 94 -66, -17, -34, -83, -66, -17, -34, -83, 95 -66, -17, -34, -83, -66, -17, -34, -83, 96 -66, -17, -34, -83, -66, -17, -34, -83, 97 -66, -17, -34, -83, -66, -17 98 }; 99 100 public static void main(String[] args) throws Exception { 101 Map<String, TestCase> testList = 102 new LinkedHashMap<String, TestCase>() {{ 103 put("CTOR (Default)", testCtorTypeStatReq); 104 put("CTOR (Byte array)", testCtorByteArray); 105 put("CTOR (invalid lengths)", testCtorInvalidLengths); 106 }}; 107 108 TestUtils.runTests(testList); 109 } 110 111 public static final TestCase testCtorTypeStatReq = new TestCase() { 112 @Override 113 public Map.Entry<Boolean, String> runTest() { 114 Boolean pass = Boolean.FALSE; 115 String message = null; 116 try { 117 // Attempt to create CSRIv2 objects using null pointers 118 // for either parameter. In either case NPE should be thrown 119 CertStatusReqItemV2 csriNull; 120 try { 121 csriNull = new CertStatusReqItemV2(null, 122 new OCSPStatusRequest()); 123 throw new RuntimeException("Did not catch expected NPE " + 124 "for null status_type parameter"); 125 } catch (NullPointerException npe) { } 126 127 try { 128 csriNull = new CertStatusReqItemV2(StatusRequestType.OCSP, 129 null); 130 throw new RuntimeException("Did not catch expected NPE " + 131 "for null StatusRequest parameter"); 132 } catch (NullPointerException npe) { } 133 134 // Create an "ocsp_multi" type request using a default 135 // (no Responder IDs, no Extensions) OCSPStatusRequest 136 CertStatusReqItemV2 csriMulti = 137 new CertStatusReqItemV2(StatusRequestType.OCSP_MULTI, 138 new OCSPStatusRequest()); 139 HandshakeOutStream hsout = new HandshakeOutStream(null); 140 csriMulti.send(hsout); 141 TestUtils.valueCheck(DEF_CSRIV2_OCSP_MULTI_BYTES, 142 hsout.toByteArray()); 143 hsout.reset(); 144 145 // Create an "ocsp" type request using a default 146 // (no Responder IDs, no Extensions) OCSPStatusRequest 147 CertStatusReqItemV2 csriSingle = 148 new CertStatusReqItemV2(StatusRequestType.OCSP, 149 new OCSPStatusRequest(new LinkedList<>(), 150 new LinkedList<>())); 151 csriSingle.send(hsout); 152 TestUtils.valueCheck(DEF_CSRIV2_OCSP_BYTES, 153 hsout.toByteArray()); 154 155 // Create the CertStatusRequestItemV2 with a user-defined 156 // StatusRequestType value 157 CertStatusReqItemV2 csriNine = 158 new CertStatusReqItemV2(StatusRequestType.get(9), 159 new OCSPStatusRequest(null, null)); 160 if (csriNine.getType().id != 9) { 161 throw new RuntimeException("Expected status_type = 9, " + 162 "got " + csriNine.getType().id); 163 } else { 164 StatusRequest sr = csriNine.getRequest(); 165 if (!(sr instanceof OCSPStatusRequest)) { 166 throw new RuntimeException("Expected " + 167 "OCSPStatusRequest, got " + 168 sr.getClass().getName()); 169 } 170 } 171 172 // Create the CertStatusRequestItemV2 with a StatusRequest 173 // that does not match the status_type argument. 174 // We expect IllegalArgumentException in this case. 175 try { 176 CertStatusReqItemV2 csriBadSR = new CertStatusReqItemV2( 177 StatusRequestType.OCSP_MULTI, 178 new BogusStatusRequest()); 179 throw new RuntimeException("Constructor accepted a " + 180 "StatusRequest that is inconsistent with " + 181 "the status_type"); 182 } catch (IllegalArgumentException iae) { 183 // The expected result...nothing to do here 184 } 185 186 pass = Boolean.TRUE; 187 } catch (Exception e) { 188 e.printStackTrace(System.out); 189 message = e.getClass().getName(); 190 } 191 192 return new AbstractMap.SimpleEntry<>(pass, message); 193 } 194 }; 195 196 // Test the constructor form that takes the data from a byte array 197 public static final TestCase testCtorByteArray = new TestCase() { 198 @Override 199 public Map.Entry<Boolean, String> runTest() { 200 Boolean pass = Boolean.FALSE; 201 String message = null; 202 try { 203 StatusRequestType sType; 204 StatusRequest sReq; 205 ResponderId checkRid = 206 new ResponderId(new X500Principal("CN=OCSP Signer")); 207 Extension checkExt = new OCSPNonceExtension(32); 208 209 CertStatusReqItemV2 csriv = 210 new CertStatusReqItemV2(CSRIV2_OCSP_1RID_1EXT); 211 sType = csriv.getType(); 212 if (sType != StatusRequestType.OCSP) { 213 throw new RuntimeException("Unexpected StatusRequestType " + 214 sType.getClass().getName()); 215 } 216 217 sReq = csriv.getRequest(); 218 if (sReq instanceof OCSPStatusRequest) { 219 OCSPStatusRequest osr = (OCSPStatusRequest)sReq; 220 List<ResponderId> ridList = osr.getResponderIds(); 221 List<Extension> extList = osr.getExtensions(); 222 223 if (ridList.size() != 1 || !ridList.contains(checkRid)) { 224 throw new RuntimeException("Responder list mismatch"); 225 } else if (extList.size() != 1 || 226 !extList.get(0).getId().equals(checkExt.getId())) { 227 throw new RuntimeException("Extension list mismatch"); 228 } 229 } else { 230 throw new RuntimeException("Expected OCSPStatusRequest " + 231 "from decoded bytes, got " + 232 sReq.getClass().getName()); 233 } 234 235 // Create a CSRIV2 out of random data. A non-OCSP/OCSP_MULTI 236 // type will be forcibly set and the outer length field will 237 // be correct. 238 // The constructor should create a StatusRequestType object 239 // and an UnknownStatusRequest object consisting of the 240 // data segment. 241 byte[] junkData = new byte[48]; 242 Random r = new Random(System.currentTimeMillis()); 243 r.nextBytes(junkData); 244 junkData[0] = 7; // status_type = 7 245 junkData[1] = 0; 246 junkData[2] = 45; // request_length = 45 247 csriv = new CertStatusReqItemV2(junkData); 248 249 sType = csriv.getType(); 250 sReq = csriv.getRequest(); 251 if (sType.id != junkData[0]) { 252 throw new RuntimeException("StatusRequestType mismatch: " + 253 "expected 7, got " + sType.id); 254 } 255 if (sReq instanceof UnknownStatusRequest) { 256 // Verify the underlying StatusRequest bytes have been 257 // preserved correctly. 258 HandshakeOutStream hsout = new HandshakeOutStream(null); 259 sReq.send(hsout); 260 byte[] srDataOut = hsout.toByteArray(); 261 TestUtils.valueCheck(srDataOut, junkData, 0, 3, 262 srDataOut.length); 263 } else { 264 throw new RuntimeException("StatusRequest mismatch: " + 265 "expected UnknownStatusRequest, got " + 266 sReq.getClass().getName()); 267 } 268 269 // Test the parsing of the default OCSP/OCSP_MULTI extensions 270 // and make sure the underlying StatusRequestType and 271 // StatusRequest objects are correct. 272 csriv = new CertStatusReqItemV2(DEF_CSRIV2_OCSP_MULTI_BYTES); 273 sType = csriv.getType(); 274 sReq = csriv.getRequest(); 275 if (sType != StatusRequestType.OCSP_MULTI) { 276 throw new RuntimeException("StatusRequestType mismatch: " + 277 "expected OCSP_MULTI (2), got " + sType.id); 278 } 279 if (!(sReq instanceof OCSPStatusRequest)) { 280 throw new RuntimeException("StatusRequest mismatch: " + 281 "expected OCSPStatusRequest, got " + 282 sReq.getClass().getName()); 283 } 284 285 csriv = new CertStatusReqItemV2(DEF_CSRIV2_OCSP_BYTES); 286 sType = csriv.getType(); 287 sReq = csriv.getRequest(); 288 if (sType != StatusRequestType.OCSP) { 289 throw new RuntimeException("StatusRequestType mismatch: " + 290 "expected OCSP (1), got " + sType.id); 291 } 292 if (!(sReq instanceof OCSPStatusRequest)) { 293 throw new RuntimeException("StatusRequest mismatch: " + 294 "expected OCSPStatusRequest, got " + 295 sReq.getClass().getName()); 296 } 297 298 pass = Boolean.TRUE; 299 } catch (Exception e) { 300 e.printStackTrace(System.out); 301 message = e.getClass().getName(); 302 } 303 304 return new AbstractMap.SimpleEntry<>(pass, message); 305 } 306 }; 307 308 public static final TestCase testCtorInvalidLengths = new TestCase() { 309 @Override 310 public Map.Entry<Boolean, String> runTest() { 311 Boolean pass = Boolean.FALSE; 312 String message = null; 313 try { 314 try { 315 CertStatusReqItemV2 csriTooShort = 316 new CertStatusReqItemV2(CSRIV2_LENGTH_TOO_SHORT); 317 throw new RuntimeException("Expected exception not thrown"); 318 } catch (SSLException ssle) { } 319 320 try { 321 CertStatusReqItemV2 csriTooLong = 322 new CertStatusReqItemV2(CSRIV2_LENGTH_TOO_LONG); 323 throw new RuntimeException("Expected exception not thrown"); 324 } catch (SSLException ssle) { } 325 326 pass = Boolean.TRUE; 327 } catch (Exception e) { 328 e.printStackTrace(System.out); 329 message = e.getClass().getName(); 330 } 331 332 return new AbstractMap.SimpleEntry<>(pass, message); 333 } 334 }; 335 336 // Test the constructor form that takes the data from HandshakeInputStream 337 public static final TestCase testCtorInputStream = new TestCase() { 338 @Override 339 public Map.Entry<Boolean, String> runTest() { 340 Boolean pass = Boolean.FALSE; 341 String message = null; 342 try { 343 StatusRequestType sType; 344 StatusRequest sReq; 345 ResponderId checkRid = 346 new ResponderId(new X500Principal("CN=OCSP Signer")); 347 Extension checkExt = new OCSPNonceExtension(32); 348 349 HandshakeInStream hsis = new HandshakeInStream(); 350 hsis.incomingRecord(ByteBuffer.wrap(CSRIV2_OCSP_1RID_1EXT)); 351 CertStatusReqItemV2 csriv = new CertStatusReqItemV2(hsis); 352 sType = csriv.getType(); 353 if (sType != StatusRequestType.OCSP) { 354 throw new RuntimeException("Unexpected StatusRequestType " + 355 sType.getClass().getName()); 356 } 357 358 sReq = csriv.getRequest(); 359 if (sReq instanceof OCSPStatusRequest) { 360 OCSPStatusRequest osr = (OCSPStatusRequest)sReq; 361 List<ResponderId> ridList = osr.getResponderIds(); 362 List<Extension> extList = osr.getExtensions(); 363 364 if (ridList.size() != 1 || !ridList.contains(checkRid)) { 365 throw new RuntimeException("Responder list mismatch"); 366 } else if (extList.size() != 1 || 367 !extList.get(0).getId().equals(checkExt.getId())) { 368 throw new RuntimeException("Extension list mismatch"); 369 } 370 } else { 371 throw new RuntimeException("Expected OCSPStatusRequest " + 372 "from decoded bytes, got " + 373 sReq.getClass().getName()); 374 } 375 376 // Create a CSRIV2 out of random data. A non-OCSP/OCSP_MULTI 377 // type will be forcibly set and the outer length field will 378 // be correct. 379 // The constructor should create a StatusRequestType object 380 // and an UnknownStatusRequest object consisting of the 381 // data segment. 382 byte[] junkData = new byte[48]; 383 Random r = new Random(System.currentTimeMillis()); 384 r.nextBytes(junkData); 385 junkData[0] = 7; // status_type = 7 386 junkData[1] = 0; 387 junkData[2] = 45; // request_length = 45 388 hsis = new HandshakeInStream(); 389 hsis.incomingRecord(ByteBuffer.wrap(junkData)); 390 csriv = new CertStatusReqItemV2(hsis); 391 392 sType = csriv.getType(); 393 sReq = csriv.getRequest(); 394 if (sType.id != junkData[0]) { 395 throw new RuntimeException("StatusRequestType mismatch: " + 396 "expected 7, got " + sType.id); 397 } 398 if (sReq instanceof UnknownStatusRequest) { 399 // Verify the underlying StatusRequest bytes have been 400 // preserved correctly. 401 HandshakeOutStream hsout = new HandshakeOutStream(null); 402 sReq.send(hsout); 403 byte[] srDataOut = hsout.toByteArray(); 404 TestUtils.valueCheck(srDataOut, junkData, 0, 3, 405 srDataOut.length); 406 } else { 407 throw new RuntimeException("StatusRequest mismatch: " + 408 "expected UnknownStatusRequest, got " + 409 sReq.getClass().getName()); 410 } 411 412 // Test the parsing of the default OCSP/OCSP_MULTI extensions 413 // and make sure the underlying StatusRequestType and 414 // StatusRequest objects are correct. 415 hsis = new HandshakeInStream(); 416 hsis.incomingRecord( 417 ByteBuffer.wrap(DEF_CSRIV2_OCSP_MULTI_BYTES)); 418 csriv = new CertStatusReqItemV2(hsis); 419 sType = csriv.getType(); 420 sReq = csriv.getRequest(); 421 if (sType != StatusRequestType.OCSP_MULTI) { 422 throw new RuntimeException("StatusRequestType mismatch: " + 423 "expected OCSP_MULTI (2), got " + sType.id); 424 } 425 if (!(sReq instanceof OCSPStatusRequest)) { 426 throw new RuntimeException("StatusRequest mismatch: " + 427 "expected OCSPStatusRequest, got " + 428 sReq.getClass().getName()); 429 } 430 431 hsis = new HandshakeInStream(); 432 hsis.incomingRecord(ByteBuffer.wrap(DEF_CSRIV2_OCSP_BYTES)); 433 csriv = new CertStatusReqItemV2(hsis); 434 sType = csriv.getType(); 435 sReq = csriv.getRequest(); 436 if (sType != StatusRequestType.OCSP) { 437 throw new RuntimeException("StatusRequestType mismatch: " + 438 "expected OCSP (1), got " + sType.id); 439 } 440 if (!(sReq instanceof OCSPStatusRequest)) { 441 throw new RuntimeException("StatusRequest mismatch: " + 442 "expected OCSPStatusRequest, got " + 443 sReq.getClass().getName()); 444 } 445 446 pass = Boolean.TRUE; 447 } catch (Exception e) { 448 e.printStackTrace(System.out); 449 message = e.getClass().getName(); 450 } 451 452 return new AbstractMap.SimpleEntry<>(pass, message); 453 } 454 }; 455 }