jdk-24/jdk/test/sun/security/ssl/StatusStapling/OCSPStatusRequestTests.java
Jamil Nimeh e7f31340a0 8046321: OCSP Stapling for TLS
Initial feature commit for OCSP stapling in JSSE

Reviewed-by: xuelei, mullan
2015-08-05 12:19:38 -07:00

341 lines
14 KiB
Java

/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.ssl;
/*
* @test
* @bug 8046321
* @summary OCSP Stapling for TLS (OCSPStatusRequestTests tests)
* @build OCSPStatusRequestTests TestCase TestUtils
* @run main/othervm sun.security.ssl.OCSPStatusRequestTests
*/
import java.security.cert.*;
import java.util.*;
import java.nio.ByteBuffer;
import javax.security.auth.x500.X500Principal;
import sun.security.provider.certpath.ResponderId;
import sun.security.provider.certpath.OCSPNonceExtension;
/*
* Checks that the hash value for a certificate's issuer name is generated
* correctly. Requires any certificate that is not self-signed.
*
* NOTE: this test uses Sun private classes which are subject to change.
*/
public class OCSPStatusRequestTests {
private static final boolean debug = false;
// The default (no Responder IDs or Extensions)
private static final byte[] DEF_OCSPREQ_BYTES = { 0, 0, 0, 0 };
// OCSP Extension with one Responder ID (byName: CN=OCSP Signer) and
// a nonce extension (32 bytes).
private static final byte[] OCSPREQ_1RID_1EXT = {
0, 28, 0, 26, -95, 24, 48, 22,
49, 20, 48, 18, 6, 3, 85, 4,
3, 19, 11, 79, 67, 83, 80, 32,
83, 105, 103, 110, 101, 114, 0, 51,
48, 49, 48, 47, 6, 9, 43, 6,
1, 5, 5, 7, 48, 1, 2, 4,
34, 4, 32, -34, -83, -66, -17, -34,
-83, -66, -17, -34, -83, -66, -17, -34,
-83, -66, -17, -34, -83, -66, -17, -34,
-83, -66, -17, -34, -83, -66, -17, -34,
-83, -66, -17
};
public static void main(String[] args) throws Exception {
Map<String, TestCase> testList =
new LinkedHashMap<String, TestCase>() {{
put("CTOR (default)", testCtorDefault);
put("CTOR (Responder Id and Extension)", testCtorRidsExts);
put("CTOR (HandshakeInStream)", testCtorInStream);
put("CTOR (byte array)", testCtorByteArray);
put("Length tests", testLength);
put("Equals tests", testEquals);
}};
TestUtils.runTests(testList);
}
// Test the default constructor and its encoding
public static final TestCase testCtorDefault = new TestCase() {
@Override
public Map.Entry<Boolean, String> runTest() {
Boolean pass = Boolean.FALSE;
String message = null;
try {
// Create a OCSPStatusRequest with a single ResponderId
// and Extension
OCSPStatusRequest osrDefault = new OCSPStatusRequest();
HandshakeOutStream hsout = new HandshakeOutStream(null);
osrDefault.send(hsout);
System.out.println("Encoded Result:");
TestUtils.dumpBytes(hsout.toByteArray());
TestUtils.valueCheck(DEF_OCSPREQ_BYTES, hsout.toByteArray());
pass = Boolean.TRUE;
} catch (Exception e) {
e.printStackTrace(System.out);
message = e.getClass().getName();
}
return new AbstractMap.SimpleEntry<>(pass, message);
}
};
// Test the constructor form that allows the user to specify zero
// or more ResponderId objects and/or Extensions
public static final TestCase testCtorRidsExts = new TestCase() {
@Override
public Map.Entry<Boolean, String> runTest() {
Boolean pass = Boolean.FALSE;
String message = null;
try {
List<ResponderId> ridList = new LinkedList<ResponderId>() {{
add(new ResponderId(new X500Principal("CN=OCSP Signer")));
}};
List<Extension> extList = new LinkedList<Extension>() {{
add(new OCSPNonceExtension(32));
}};
// Default-style OCSPStatusRequest using both empty Lists and
// null inputs
OCSPStatusRequest osrDef1 =
new OCSPStatusRequest(new LinkedList<ResponderId>(),
null);
OCSPStatusRequest osrDef2 =
new OCSPStatusRequest(null,
new LinkedList<Extension>());
HandshakeOutStream hsout = new HandshakeOutStream(null);
osrDef1.send(hsout);
System.out.println("Encoded Result:");
TestUtils.dumpBytes(hsout.toByteArray());
TestUtils.valueCheck(DEF_OCSPREQ_BYTES, hsout.toByteArray());
hsout.reset();
osrDef2.send(hsout);
System.out.println("Encoded Result:");
TestUtils.dumpBytes(hsout.toByteArray());
TestUtils.valueCheck(DEF_OCSPREQ_BYTES, hsout.toByteArray());
hsout.reset();
OCSPStatusRequest osrWithItems =
new OCSPStatusRequest(ridList, extList);
osrWithItems.send(hsout);
System.out.println("Encoded Result:");
byte[] encodedData = hsout.toByteArray();
TestUtils.dumpBytes(encodedData);
// Check everything except the last 32 bytes (nonce data)
TestUtils.valueCheck(OCSPREQ_1RID_1EXT, encodedData, 0, 0,
encodedData.length - 32);
pass = Boolean.TRUE;
} catch (Exception e) {
e.printStackTrace(System.out);
message = e.getClass().getName();
}
return new AbstractMap.SimpleEntry<>(pass, message);
}
};
// Test the constructor that builds the ob ject using data from
// a HandshakeInStream
public static final TestCase testCtorInStream = new TestCase() {
@Override
public Map.Entry<Boolean, String> runTest() {
Boolean pass = Boolean.FALSE;
String message = null;
try {
ResponderId checkRid =
new ResponderId(new X500Principal("CN=OCSP Signer"));
Extension checkExt = new OCSPNonceExtension(32);
HandshakeInStream hsis = new HandshakeInStream();
hsis.incomingRecord(ByteBuffer.wrap(OCSPREQ_1RID_1EXT));
OCSPStatusRequest osr = new OCSPStatusRequest(hsis);
List<ResponderId> ridList = osr.getResponderIds();
List<Extension> extList = osr.getExtensions();
if (ridList.size() != 1 || !ridList.contains(checkRid)) {
throw new RuntimeException("Responder list mismatch");
} else if (extList.size() != 1 ||
!extList.get(0).getId().equals(checkExt.getId())) {
throw new RuntimeException("Extension list mismatch");
}
pass = Boolean.TRUE;
} catch (Exception e) {
e.printStackTrace(System.out);
message = e.getClass().getName();
}
return new AbstractMap.SimpleEntry<>(pass, message);
}
};
// Test the constructor form that takes the data from a byte array
public static final TestCase testCtorByteArray = new TestCase() {
@Override
public Map.Entry<Boolean, String> runTest() {
Boolean pass = Boolean.FALSE;
String message = null;
try {
ResponderId checkRid =
new ResponderId(new X500Principal("CN=OCSP Signer"));
Extension checkExt = new OCSPNonceExtension(32);
OCSPStatusRequest osr =
new OCSPStatusRequest(OCSPREQ_1RID_1EXT);
List<ResponderId> ridList = osr.getResponderIds();
List<Extension> extList = osr.getExtensions();
if (ridList.size() != 1 || !ridList.contains(checkRid)) {
throw new RuntimeException("Responder list mismatch");
} else if (extList.size() != 1 ||
!extList.get(0).getId().equals(checkExt.getId())) {
throw new RuntimeException("Extension list mismatch");
}
pass = Boolean.TRUE;
} catch (Exception e) {
e.printStackTrace(System.out);
message = e.getClass().getName();
}
return new AbstractMap.SimpleEntry<>(pass, message);
}
};
// Test the length functions for both default and non-default
// OCSPStatusRequest objects
public static final TestCase testLength = new TestCase() {
@Override
public Map.Entry<Boolean, String> runTest() {
Boolean pass = Boolean.FALSE;
String message = null;
try {
HandshakeInStream hsis = new HandshakeInStream();
hsis.incomingRecord(ByteBuffer.wrap(OCSPREQ_1RID_1EXT));
OCSPStatusRequest osr = new OCSPStatusRequest(hsis);
OCSPStatusRequest osrDefault = new OCSPStatusRequest();
if (osrDefault.length() != DEF_OCSPREQ_BYTES.length) {
throw new RuntimeException("Invalid length for default: " +
"Expected" + DEF_OCSPREQ_BYTES.length +
", received " + osrDefault.length());
} else if (osr.length() != OCSPREQ_1RID_1EXT.length) {
throw new RuntimeException("Invalid length for default: " +
"Expected" + OCSPREQ_1RID_1EXT.length +
", received " + osr.length());
}
pass = Boolean.TRUE;
} catch (Exception e) {
e.printStackTrace(System.out);
message = e.getClass().getName();
}
return new AbstractMap.SimpleEntry<>(pass, message);
}
};
// Test the equals method with default and non-default objects
public static final TestCase testEquals = new TestCase() {
@Override
public Map.Entry<Boolean, String> runTest() {
Boolean pass = Boolean.FALSE;
String message = null;
try {
// Make two different lists with the same ResponderId values
// and also make a extension list
List<ResponderId> ridList1 = new LinkedList<ResponderId>() {{
add(new ResponderId(new X500Principal("CN=OCSP Signer")));
}};
List<ResponderId> ridList2 = new LinkedList<ResponderId>() {{
add(new ResponderId(new X500Principal("CN=OCSP Signer")));
}};
List<Extension> extList = new LinkedList<Extension>() {{
add(new OCSPNonceExtension(32));
}};
// We expect two default OCSP objects to be equal
OCSPStatusRequest osrDefault = new OCSPStatusRequest();
if (!osrDefault.equals(new OCSPStatusRequest())) {
throw new RuntimeException("Default OCSPStatusRequest" +
" equality test failed");
}
// null test (expect false return)
if (osrDefault.equals(null)) {
throw new RuntimeException("OCSPStatusRequest matched" +
" unexpectedly");
}
// Self-reference test
OCSPStatusRequest osrSelfRef = osrDefault;
if (!osrDefault.equals(osrSelfRef)) {
throw new RuntimeException("Default OCSPStatusRequest" +
" equality test failed");
}
// Two OCSPStatusRequests with matching ResponderIds should
// be considered equal
OCSPStatusRequest osrByList1 =
new OCSPStatusRequest(ridList1, null);
OCSPStatusRequest osrByList2 = new OCSPStatusRequest(ridList2,
Collections.emptyList());
if (!osrByList1.equals(osrByList2)) {
throw new RuntimeException("Single Responder ID " +
"OCSPStatusRequest equality test failed");
}
// We expect OCSPStatusRequests with different nonces to be
// considered unequal.
HandshakeInStream hsis = new HandshakeInStream();
hsis.incomingRecord(ByteBuffer.wrap(OCSPREQ_1RID_1EXT));
OCSPStatusRequest osrStream = new OCSPStatusRequest(hsis);
OCSPStatusRequest osrRidExt = new OCSPStatusRequest(ridList1,
extList);
if (osrStream.equals(osrRidExt)) {
throw new RuntimeException("OCSPStatusRequest matched" +
" unexpectedly");
}
pass = Boolean.TRUE;
} catch (Exception e) {
e.printStackTrace(System.out);
message = e.getClass().getName();
}
return new AbstractMap.SimpleEntry<>(pass, message);
}
};
}