8170282: Enable ALPN parameters to be supplied during the TLS handshake
Reviewed-by: wetmore, xuelei
--- a/jdk/src/java.base/share/classes/javax/net/ssl/SSLEngine.java Fri Dec 16 19:50:35 2016 +0800
+++ b/jdk/src/java.base/share/classes/javax/net/ssl/SSLEngine.java Fri Dec 16 14:32:51 2016 +0000
@@ -27,6 +27,8 @@
import java.nio.ByteBuffer;
import java.nio.ReadOnlyBufferException;
+import java.util.List;
+import java.util.function.BiFunction;
/**
@@ -1332,4 +1334,89 @@
public String getHandshakeApplicationProtocol() {
throw new UnsupportedOperationException();
}
+
+ /**
+ * Registers a callback function that selects an application protocol
+ * value for a SSL/TLS/DTLS handshake.
+ * The function overrides any values set using
+ * {@link SSLParameters#setApplicationProtocols
+ * SSLParameters.setApplicationProtocols} and it supports the following
+ * type parameters:
+ * <blockquote>
+ * <dl>
+ * <dt> {@code SSLEngine}
+ * <dd> The function's first argument allows the current {@code SSLEngine}
+ * to be inspected, including the handshake session and configuration
+ * settings.
+ * <dt> {@code List<String>}
+ * <dd> The function's second argument lists the application protocol names
+ * advertised by the TLS peer.
+ * <dt> {@code String}
+ * <dd> The function's result is an application protocol name, or null to
+ * indicate that none of the advertised names are acceptable.
+ * If the return value is null (no value chosen) or is a value that
+ * was not advertised by the peer, the underlying protocol will
+ * determine what action to take. (For example, ALPN will send a
+ * "no_application_protocol" alert and terminate the connection.)
+ * </dl>
+ * </blockquote>
+ *
+ * For example, the following call registers a callback function that
+ * examines the TLS handshake parameters and selects an application protocol
+ * name:
+ * <pre>{@code
+ * serverEngine.setHandshakeApplicationProtocolSelector(
+ * (serverEngine, clientProtocols) -> {
+ * SSLSession session = serverEngine.getHandshakeSession();
+ * return chooseApplicationProtocol(
+ * serverEngine,
+ * clientProtocols,
+ * session.getProtocol(),
+ * session.getCipherSuite());
+ * });
+ * }</pre>
+ *
+ * @apiNote
+ * This method should be called by TLS server applications before the TLS
+ * handshake begins. Also, this {@code SSLEngine} should be configured with
+ * parameters that are compatible with the application protocol selected by
+ * the callback function. For example, enabling a poor choice of cipher
+ * suites could result in no suitable application protocol.
+ * See {@link SSLParameters}.
+ *
+ * @implSpec
+ * The implementation in this class throws
+ * {@code UnsupportedOperationException} and performs no other action.
+ *
+ * @param selector the callback function, or null to disable the callback
+ * functionality.
+ * @throws UnsupportedOperationException if the underlying provider
+ * does not implement the operation.
+ * @since 9
+ */
+ public void setHandshakeApplicationProtocolSelector(
+ BiFunction<SSLEngine, List<String>, String> selector) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Retrieves the callback function that selects an application protocol
+ * value during a SSL/TLS/DTLS handshake.
+ * See {@link #setHandshakeApplicationProtocolSelector
+ * setHandshakeApplicationProtocolSelector}
+ * for the function's type parameters.
+ *
+ * @implSpec
+ * The implementation in this class throws
+ * {@code UnsupportedOperationException} and performs no other action.
+ *
+ * @return the callback function, or null if none has been set.
+ * @throws UnsupportedOperationException if the underlying provider
+ * does not implement the operation.
+ * @since 9
+ */
+ public BiFunction<SSLEngine, List<String>, String>
+ getHandshakeApplicationProtocolSelector() {
+ throw new UnsupportedOperationException();
+ }
}
--- a/jdk/src/java.base/share/classes/javax/net/ssl/SSLSocket.java Fri Dec 16 19:50:35 2016 +0800
+++ b/jdk/src/java.base/share/classes/javax/net/ssl/SSLSocket.java Fri Dec 16 14:32:51 2016 +0000
@@ -28,6 +28,8 @@
import java.io.IOException;
import java.net.*;
+import java.util.List;
+import java.util.function.BiFunction;
/**
* This class extends <code>Socket</code>s and provides secure
@@ -742,4 +744,89 @@
public String getHandshakeApplicationProtocol() {
throw new UnsupportedOperationException();
}
+
+
+ /**
+ * Registers a callback function that selects an application protocol
+ * value for a SSL/TLS/DTLS handshake.
+ * The function overrides any values set using
+ * {@link SSLParameters#setApplicationProtocols
+ * SSLParameters.setApplicationProtocols} and it supports the following
+ * type parameters:
+ * <blockquote>
+ * <dl>
+ * <dt> {@code SSLSocket}
+ * <dd> The function's first argument allows the current {@code SSLSocket}
+ * to be inspected, including the handshake session and configuration
+ * settings.
+ * <dt> {@code List<String>}
+ * <dd> The function's second argument lists the application protocol names
+ * advertised by the TLS peer.
+ * <dt> {@code String}
+ * <dd> The function's result is an application protocol name, or null to
+ * indicate that none of the advertised names are acceptable.
+ * If the return value is null (no value chosen) or is a value that
+ * was not advertised by the peer, the underlying protocol will
+ * determine what action to take. (For example, ALPN will send a
+ * "no_application_protocol" alert and terminate the connection.)
+ * </dl>
+ * </blockquote>
+ *
+ * For example, the following call registers a callback function that
+ * examines the TLS handshake parameters and selects an application protocol
+ * name:
+ * <pre>{@code
+ * serverSocket.setHandshakeApplicationProtocolSelector(
+ * (serverSocket, clientProtocols) -> {
+ * SSLSession session = serverSocket.getHandshakeSession();
+ * return chooseApplicationProtocol(
+ * serverSocket,
+ * clientProtocols,
+ * session.getProtocol(),
+ * session.getCipherSuite());
+ * });
+ * }</pre>
+ *
+ * @apiNote
+ * This method should be called by TLS server applications before the TLS
+ * handshake begins. Also, this {@code SSLSocket} should be configured with
+ * parameters that are compatible with the application protocol selected by
+ * the callback function. For example, enabling a poor choice of cipher
+ * suites could result in no suitable application protocol.
+ * See {@link SSLParameters}.
+ *
+ * @implSpec
+ * The implementation in this class throws
+ * {@code UnsupportedOperationException} and performs no other action.
+ *
+ * @param selector the callback function, or null to de-register.
+ * @throws UnsupportedOperationException if the underlying provider
+ * does not implement the operation.
+ * @since 9
+ */
+ public void setHandshakeApplicationProtocolSelector(
+ BiFunction<SSLSocket, List<String>, String> selector) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Retrieves the callback function that selects an application protocol
+ * value during a SSL/TLS/DTLS handshake.
+ * See {@link #setHandshakeApplicationProtocolSelector
+ * setHandshakeApplicationProtocolSelector}
+ * for the function's type parameters.
+ *
+ * @implSpec
+ * The implementation in this class throws
+ * {@code UnsupportedOperationException} and performs no other action.
+ *
+ * @return the callback function, or null if none has been set.
+ * @throws UnsupportedOperationException if the underlying provider
+ * does not implement the operation.
+ * @since 9
+ */
+ public BiFunction<SSLSocket, List<String>, String>
+ getHandshakeApplicationProtocolSelector() {
+ throw new UnsupportedOperationException();
+ }
}
--- a/jdk/src/java.base/share/classes/sun/security/ssl/Handshaker.java Fri Dec 16 19:50:35 2016 +0800
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/Handshaker.java Fri Dec 16 14:32:51 2016 +0000
@@ -36,6 +36,7 @@
import java.security.AccessControlContext;
import java.security.PrivilegedExceptionAction;
import java.security.PrivilegedActionException;
+import java.util.function.BiFunction;
import javax.crypto.*;
import javax.crypto.spec.*;
@@ -122,6 +123,14 @@
// Negotiated ALPN value
String applicationProtocol = null;
+ // Application protocol callback function (for SSLEngine)
+ BiFunction<SSLEngine,List<String>,String>
+ appProtocolSelectorSSLEngine = null;
+
+ // Application protocol callback function (for SSLSocket)
+ BiFunction<SSLSocket,List<String>,String>
+ appProtocolSelectorSSLSocket = null;
+
// The maximum expected network packet size for SSL/TLS/DTLS records.
int maximumPacketSize = 0;
@@ -501,6 +510,22 @@
}
/**
+ * Sets the Application Protocol selector function for SSLEngine.
+ */
+ void setApplicationProtocolSelectorSSLEngine(
+ BiFunction<SSLEngine,List<String>,String> selector) {
+ this.appProtocolSelectorSSLEngine = selector;
+ }
+
+ /**
+ * Sets the Application Protocol selector function for SSLSocket.
+ */
+ void setApplicationProtocolSelectorSSLSocket(
+ BiFunction<SSLSocket,List<String>,String> selector) {
+ this.appProtocolSelectorSSLSocket = selector;
+ }
+
+ /**
* Sets the cipher suites preference.
*/
void setUseCipherSuitesOrder(boolean on) {
--- a/jdk/src/java.base/share/classes/sun/security/ssl/SSLEngineImpl.java Fri Dec 16 19:50:35 2016 +0800
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/SSLEngineImpl.java Fri Dec 16 14:32:51 2016 +0000
@@ -27,8 +27,9 @@
import java.io.*;
import java.nio.*;
+import java.security.*;
import java.util.*;
-import java.security.*;
+import java.util.function.BiFunction;
import javax.crypto.BadPaddingException;
@@ -206,6 +207,10 @@
// The value under negotiation will be obtained from handshaker.
String applicationProtocol = null;
+ // Callback function that selects the application protocol value during
+ // the SSL/TLS handshake.
+ BiFunction<SSLEngine, List<String>, String> applicationProtocolSelector;
+
// Have we been told whether we're client or server?
private boolean serverModeSet = false;
private boolean roleIsServer;
@@ -442,6 +447,8 @@
handshaker.setEnabledCipherSuites(enabledCipherSuites);
handshaker.setEnableSessionCreation(enableSessionCreation);
handshaker.setApplicationProtocols(applicationProtocols);
+ handshaker.setApplicationProtocolSelectorSSLEngine(
+ applicationProtocolSelector);
outputRecord.initHandshaker();
}
@@ -2264,6 +2271,21 @@
return null;
}
+ @Override
+ public synchronized void setHandshakeApplicationProtocolSelector(
+ BiFunction<SSLEngine, List<String>, String> selector) {
+ applicationProtocolSelector = selector;
+ if ((handshaker != null) && !handshaker.activated()) {
+ handshaker.setApplicationProtocolSelectorSSLEngine(selector);
+ }
+ }
+
+ @Override
+ public synchronized BiFunction<SSLEngine, List<String>, String>
+ getHandshakeApplicationProtocolSelector() {
+ return this.applicationProtocolSelector;
+ }
+
/**
* Returns a printable representation of this end of the connection.
*/
--- a/jdk/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java Fri Dec 16 19:50:35 2016 +0800
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java Fri Dec 16 14:32:51 2016 +0000
@@ -37,6 +37,7 @@
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
+import java.util.function.BiFunction;
import javax.crypto.BadPaddingException;
import javax.net.ssl.*;
@@ -223,6 +224,10 @@
// The value under negotiation will be obtained from handshaker.
String applicationProtocol = null;
+ // Callback function that selects the application protocol value during
+ // the SSL/TLS handshake.
+ BiFunction<SSLSocket, List<String>, String> applicationProtocolSelector;
+
/*
* READ ME * READ ME * READ ME * READ ME * READ ME * READ ME *
* IMPORTANT STUFF TO UNDERSTANDING THE SYNCHRONIZATION ISSUES.
@@ -1370,6 +1375,8 @@
handshaker.setEnabledCipherSuites(enabledCipherSuites);
handshaker.setEnableSessionCreation(enableSessionCreation);
handshaker.setApplicationProtocols(applicationProtocols);
+ handshaker.setApplicationProtocolSelectorSSLSocket(
+ applicationProtocolSelector);
}
/**
@@ -2658,6 +2665,21 @@
return null;
}
+ @Override
+ public synchronized void setHandshakeApplicationProtocolSelector(
+ BiFunction<SSLSocket, List<String>, String> selector) {
+ applicationProtocolSelector = selector;
+ if ((handshaker != null) && !handshaker.activated()) {
+ handshaker.setApplicationProtocolSelectorSSLSocket(selector);
+ }
+ }
+
+ @Override
+ public synchronized BiFunction<SSLSocket, List<String>, String>
+ getHandshakeApplicationProtocolSelector() {
+ return this.applicationProtocolSelector;
+ }
+
//
// We allocate a separate thread to deliver handshake completion
// events. This ensures that the notifications don't block the
--- a/jdk/src/java.base/share/classes/sun/security/ssl/ServerHandshaker.java Fri Dec 16 19:50:35 2016 +0800
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/ServerHandshaker.java Fri Dec 16 14:32:51 2016 +0000
@@ -34,6 +34,7 @@
import java.security.interfaces.*;
import java.security.spec.ECParameterSpec;
import java.math.BigInteger;
+import java.util.function.BiFunction;
import javax.crypto.SecretKey;
import javax.net.ssl.*;
@@ -532,31 +533,39 @@
ALPNExtension clientHelloALPN = (ALPNExtension)
mesg.extensions.get(ExtensionType.EXT_ALPN);
- if ((clientHelloALPN != null) && (localApl.length > 0)) {
+ // Use the application protocol callback when provided.
+ // Otherwise use the local list of application protocols.
+ boolean hasAPCallback =
+ ((engine != null && appProtocolSelectorSSLEngine != null) ||
+ (conn != null && appProtocolSelectorSSLSocket != null));
+
+ if (!hasAPCallback) {
+ if ((clientHelloALPN != null) && (localApl.length > 0)) {
- // Intersect the requested and the locally supported,
- // and save for later.
- String negotiatedValue = null;
- List<String> protocols = clientHelloALPN.getPeerAPs();
+ // Intersect the requested and the locally supported,
+ // and save for later.
+ String negotiatedValue = null;
+ List<String> protocols = clientHelloALPN.getPeerAPs();
- // Use server preference order
- for (String ap : localApl) {
- if (protocols.contains(ap)) {
- negotiatedValue = ap;
- break;
+ // Use server preference order
+ for (String ap : localApl) {
+ if (protocols.contains(ap)) {
+ negotiatedValue = ap;
+ break;
+ }
}
- }
- if (negotiatedValue == null) {
- fatalSE(Alerts.alert_no_application_protocol,
- new SSLHandshakeException(
- "No matching ALPN values"));
+ if (negotiatedValue == null) {
+ fatalSE(Alerts.alert_no_application_protocol,
+ new SSLHandshakeException(
+ "No matching ALPN values"));
+ }
+ applicationProtocol = negotiatedValue;
+
+ } else {
+ applicationProtocol = "";
}
- applicationProtocol = negotiatedValue;
-
- } else {
- applicationProtocol = "";
- }
+ } // Otherwise, applicationProtocol will be set by the callback.
session = null; // forget about the current session
//
@@ -892,8 +901,36 @@
}
// Prepare the ALPN response
- if (applicationProtocol != null && !applicationProtocol.isEmpty()) {
- m1.extensions.add(new ALPNExtension(applicationProtocol));
+ if (clientHelloALPN != null) {
+ List<String> peerAPs = clientHelloALPN.getPeerAPs();
+
+ // check for a callback function
+ if (hasAPCallback) {
+ if (conn != null) {
+ applicationProtocol =
+ appProtocolSelectorSSLSocket.apply(conn, peerAPs);
+ } else {
+ applicationProtocol =
+ appProtocolSelectorSSLEngine.apply(engine, peerAPs);
+ }
+ }
+
+ // check for no-match and that the selected name was also proposed
+ // by the TLS peer
+ if (applicationProtocol == null ||
+ (!applicationProtocol.isEmpty() &&
+ !peerAPs.contains(applicationProtocol))) {
+
+ fatalSE(Alerts.alert_no_application_protocol,
+ new SSLHandshakeException(
+ "No matching ALPN values"));
+
+ } else if (!applicationProtocol.isEmpty()) {
+ m1.extensions.add(new ALPNExtension(applicationProtocol));
+ }
+ } else {
+ // Nothing was negotiated, returned at end of the handshake
+ applicationProtocol = "";
}
if (debug != null && Debug.isOn("handshake")) {
--- a/jdk/test/javax/net/ssl/ALPN/MyX509ExtendedKeyManager.java Fri Dec 16 19:50:35 2016 +0800
+++ b/jdk/test/javax/net/ssl/ALPN/MyX509ExtendedKeyManager.java Fri Dec 16 14:32:51 2016 +0000
@@ -34,15 +34,17 @@
static final String ERROR = "ERROR";
X509ExtendedKeyManager akm;
String expectedAP;
+ boolean doCheck = true;
MyX509ExtendedKeyManager(X509ExtendedKeyManager akm) {
this.akm = akm;
}
public MyX509ExtendedKeyManager(
- X509ExtendedKeyManager akm, String expectedAP) {
+ X509ExtendedKeyManager akm, String expectedAP, boolean doCheck) {
this.akm = akm;
this.expectedAP = expectedAP;
+ this.doCheck = doCheck;
}
@@ -104,6 +106,12 @@
private void checkALPN(String ap) {
+ if (!doCheck) {
+ System.out.println("Skipping KeyManager checks " +
+ "because a callback has been registered");
+ return;
+ }
+
if (ERROR.equals(expectedAP)) {
throw new RuntimeException("Should not reach here");
}
--- a/jdk/test/javax/net/ssl/ALPN/SSLEngineAlpnTest.java Fri Dec 16 19:50:35 2016 +0800
+++ b/jdk/test/javax/net/ssl/ALPN/SSLEngineAlpnTest.java Fri Dec 16 14:32:51 2016 +0000
@@ -26,23 +26,53 @@
/*
* @test
- * @bug 8051498 8145849
+ * @bug 8051498 8145849 8170282
* @summary JEP 244: TLS Application-Layer Protocol Negotiation Extension
* @compile MyX509ExtendedKeyManager.java
- * @run main/othervm SSLEngineAlpnTest h2 h2 h2
- * @run main/othervm SSLEngineAlpnTest h2 h2,http/1.1 h2
- * @run main/othervm SSLEngineAlpnTest h2,http/1.1 h2,http/1.1 h2
- * @run main/othervm SSLEngineAlpnTest http/1.1,h2 h2,http/1.1 http/1.1
- * @run main/othervm SSLEngineAlpnTest h4,h3,h2 h1,h2 h2
- * @run main/othervm SSLEngineAlpnTest EMPTY h2,http/1.1 NONE
- * @run main/othervm SSLEngineAlpnTest h2 EMPTY NONE
- * @run main/othervm SSLEngineAlpnTest H2 h2 ERROR
- * @run main/othervm SSLEngineAlpnTest h2 http/1.1 ERROR
+ *
+ * @run main/othervm SSLEngineAlpnTest h2 UNUSED h2 h2
+ * @run main/othervm SSLEngineAlpnTest h2 UNUSED h2,http/1.1 h2
+ * @run main/othervm SSLEngineAlpnTest h2,http/1.1 UNUSED h2,http/1.1 h2
+ * @run main/othervm SSLEngineAlpnTest http/1.1,h2 UNUSED h2,http/1.1 http/1.1
+ * @run main/othervm SSLEngineAlpnTest h4,h3,h2 UNUSED h1,h2 h2
+ * @run main/othervm SSLEngineAlpnTest EMPTY UNUSED h2,http/1.1 NONE
+ * @run main/othervm SSLEngineAlpnTest h2 UNUSED EMPTY NONE
+ * @run main/othervm SSLEngineAlpnTest H2 UNUSED h2 ERROR
+ * @run main/othervm SSLEngineAlpnTest h2 UNUSED http/1.1 ERROR
+ *
+ * @run main/othervm SSLEngineAlpnTest UNUSED h2 h2 h2
+ * @run main/othervm SSLEngineAlpnTest UNUSED h2 h2,http/1.1 h2
+ * @run main/othervm SSLEngineAlpnTest UNUSED h2 http/1.1,h2 h2
+ * @run main/othervm SSLEngineAlpnTest UNUSED http/1.1 h2,http/1.1 http/1.1
+ * @run main/othervm SSLEngineAlpnTest UNUSED EMPTY h2,http/1.1 NONE
+ * @run main/othervm SSLEngineAlpnTest UNUSED h2 EMPTY NONE
+ * @run main/othervm SSLEngineAlpnTest UNUSED H2 h2 ERROR
+ * @run main/othervm SSLEngineAlpnTest UNUSED h2 http/1.1 ERROR
+ *
+ * @run main/othervm SSLEngineAlpnTest h2 h2 h2 h2
+ * @run main/othervm SSLEngineAlpnTest H2 h2 h2,http/1.1 h2
+ * @run main/othervm SSLEngineAlpnTest h2,http/1.1 http/1.1 h2,http/1.1 http/1.1
+ * @run main/othervm SSLEngineAlpnTest http/1.1,h2 h2 h2,http/1.1 h2
+ * @run main/othervm SSLEngineAlpnTest EMPTY h2 h2 h2
+ * @run main/othervm SSLEngineAlpnTest h2,http/1.1 EMPTY http/1.1 NONE
+ * @run main/othervm SSLEngineAlpnTest h2,http/1.1 h2 EMPTY NONE
+ * @run main/othervm SSLEngineAlpnTest UNUSED UNUSED http/1.1,h2 NONE
+ * @run main/othervm SSLEngineAlpnTest h2 h2 http/1.1 ERROR
+ * @run main/othervm SSLEngineAlpnTest h2,http/1.1 H2 http/1.1 ERROR
*/
/**
* A simple SSLEngine-based client/server that demonstrates the proposed API
* changes for JEP 244 in support of the TLS ALPN extension (RFC 7301).
*
+ * Usage:
+ * java SSLEngineAlpnTest <server-APs> <callback-AP> <client-APs> <result>
+ *
+ * where:
+ * EMPTY indicates that ALPN is disabled
+ * UNUSED indicates that no ALPN values are supplied (server-side only)
+ * ERROR indicates that an exception is expected
+ * NONE indicates that no ALPN is expected
+ *
* This example is based on our standard SSLEngineTemplate.
*
* The immediate consumer of ALPN will be HTTP/2 (RFC 7540), aka H2. The H2 IETF
@@ -98,6 +128,7 @@
import java.io.*;
import java.security.*;
import java.nio.*;
+import java.util.Arrays;
public class SSLEngineAlpnTest {
@@ -117,6 +148,9 @@
*/
private static final boolean debug = false;
+ private static boolean hasServerAPs; // whether server APs are present
+ private static boolean hasCallback; // whether a callback is present
+
private final SSLContext sslc;
private SSLEngine clientEngine; // client Engine
@@ -157,17 +191,21 @@
if (debug) {
System.setProperty("javax.net.debug", "all");
}
+ System.out.println("Test args: " + Arrays.toString(args));
// Validate parameters
- if (args.length != 3) {
+ if (args.length != 4) {
throw new Exception("Invalid number of test parameters");
}
- SSLEngineAlpnTest test = new SSLEngineAlpnTest(args[2]);
+ hasServerAPs = !args[0].equals("UNUSED"); // are server APs being used?
+ hasCallback = !args[1].equals("UNUSED"); // is callback being used?
+
+ SSLEngineAlpnTest test = new SSLEngineAlpnTest(args[3]);
try {
- test.runTest(convert(args[0]), convert(args[1]), args[2]);
+ test.runTest(convert(args[0]), args[1], convert(args[2]), args[3]);
} catch (SSLHandshakeException she) {
- if (args[2].equals("ERROR")) {
+ if (args[3].equals("ERROR")) {
System.out.println("Caught the expected exception: " + she);
} else {
throw she;
@@ -199,7 +237,8 @@
}
kms = new KeyManager[] { new MyX509ExtendedKeyManager(
- (X509ExtendedKeyManager) kms[0], expectedAP) };
+ (X509ExtendedKeyManager) kms[0], expectedAP,
+ !hasCallback && hasServerAPs) };
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(ts);
@@ -215,12 +254,15 @@
* Convert a comma-separated list into an array of strings.
*/
private static String[] convert(String list) {
- String[] strings = null;
+ if (list.equals("UNUSED")) {
+ return null;
+ }
if (list.equals("EMPTY")) {
return new String[0];
}
+ String[] strings;
if (list.indexOf(',') > 0) {
strings = list.split(",");
} else {
@@ -247,12 +289,12 @@
* One could easily separate these phases into separate
* sections of code.
*/
- private void runTest(String[] serverAPs, String[] clientAPs,
- String expectedAP) throws Exception {
+ private void runTest(String[] serverAPs, String callbackAP,
+ String[] clientAPs, String expectedAP) throws Exception {
boolean dataDone = false;
- createSSLEngines(serverAPs, clientAPs);
+ createSSLEngines(serverAPs, callbackAP, clientAPs);
createBuffers();
SSLEngineResult clientResult; // results from client's last operation
@@ -364,8 +406,8 @@
* Using the SSLContext created during object creation,
* create/configure the SSLEngines we'll use for this test.
*/
- private void createSSLEngines(String[] serverAPs, String[] clientAPs)
- throws Exception {
+ private void createSSLEngines(String[] serverAPs, String callbackAP,
+ String[] clientAPs) throws Exception {
/*
* Configure the serverEngine to act as a server in the SSL/TLS
* handshake. Also, require SSL client authentication.
@@ -385,18 +427,42 @@
*/
String[] suites = sslp.getCipherSuites();
sslp.setCipherSuites(suites);
- sslp.setApplicationProtocols(serverAPs);
+ if (serverAPs != null) {
+ sslp.setApplicationProtocols(serverAPs);
+ }
sslp.setUseCipherSuitesOrder(true); // Set server side order
serverEngine.setSSLParameters(sslp);
+ // check that no callback has been registered
+ if (serverEngine.getHandshakeApplicationProtocolSelector() != null) {
+ throw new Exception("getHandshakeApplicationProtocolSelector() " +
+ "should return null");
+ }
+
+ if (hasCallback) {
+ serverEngine.setHandshakeApplicationProtocolSelector(
+ (sslEngine, clientProtocols) -> {
+ return callbackAP.equals("EMPTY") ? "" : callbackAP;
+ });
+
+ // check that the callback can be retrieved
+ if (serverEngine.getHandshakeApplicationProtocolSelector()
+ == null) {
+ throw new Exception("getHandshakeApplicationProtocolSelector()"
+ + " should return non-null");
+ }
+ }
+
/*
* Similar to above, but using client mode instead.
*/
clientEngine = sslc.createSSLEngine("client", 80);
clientEngine.setUseClientMode(true);
sslp = clientEngine.getSSLParameters();
- sslp.setApplicationProtocols(clientAPs);
+ if (clientAPs != null) {
+ sslp.setApplicationProtocols(clientAPs);
+ }
clientEngine.setSSLParameters(sslp);
if ((clientEngine.getHandshakeApplicationProtocol() != null) ||
--- a/jdk/test/javax/net/ssl/ALPN/SSLServerSocketAlpnTest.java Fri Dec 16 19:50:35 2016 +0800
+++ b/jdk/test/javax/net/ssl/ALPN/SSLServerSocketAlpnTest.java Fri Dec 16 14:32:51 2016 +0000
@@ -26,22 +26,61 @@
/*
* @test
- * @bug 8051498 8145849 8158978
+ * @bug 8051498 8145849 8158978 8170282
* @summary JEP 244: TLS Application-Layer Protocol Negotiation Extension
* @compile MyX509ExtendedKeyManager.java
- * @run main/othervm SSLServerSocketAlpnTest h2 h2 h2
- * @run main/othervm SSLServerSocketAlpnTest h2 h2,http/1.1 h2
- * @run main/othervm SSLServerSocketAlpnTest h2,http/1.1 h2,http/1.1 h2
- * @run main/othervm SSLServerSocketAlpnTest http/1.1,h2 h2,http/1.1 http/1.1
- * @run main/othervm SSLServerSocketAlpnTest h4,h3,h2 h1,h2 h2
- * @run main/othervm SSLServerSocketAlpnTest EMPTY h2,http/1.1 NONE
- * @run main/othervm SSLServerSocketAlpnTest h2 EMPTY NONE
- * @run main/othervm SSLServerSocketAlpnTest H2 h2 ERROR
- * @run main/othervm SSLServerSocketAlpnTest h2 http/1.1 ERROR
+ *
+ * @run main/othervm SSLServerSocketAlpnTest h2 UNUSED h2 h2
+ * @run main/othervm SSLServerSocketAlpnTest h2 UNUSED h2,http/1.1 h2
+ * @run main/othervm SSLServerSocketAlpnTest h2,http/1.1 UNUSED h2,http/1.1 h2
+ * @run main/othervm SSLServerSocketAlpnTest http/1.1,h2 UNUSED h2,http/1.1 http/1.1
+ * @run main/othervm SSLServerSocketAlpnTest h4,h3,h2 UNUSED h1,h2 h2
+ * @run main/othervm SSLServerSocketAlpnTest EMPTY UNUSED h2,http/1.1 NONE
+ * @run main/othervm SSLServerSocketAlpnTest h2 UNUSED EMPTY NONE
+ * @run main/othervm SSLServerSocketAlpnTest H2 UNUSED h2 ERROR
+ * @run main/othervm SSLServerSocketAlpnTest h2 UNUSED http/1.1 ERROR
+ *
+ * @run main/othervm SSLServerSocketAlpnTest UNUSED h2 h2 h2
+ * @run main/othervm SSLServerSocketAlpnTest UNUSED h2 h2,http/1.1 h2
+ * @run main/othervm SSLServerSocketAlpnTest UNUSED h2 http/1.1,h2 h2
+ * @run main/othervm SSLServerSocketAlpnTest UNUSED http/1.1 h2,http/1.1 http/1.1
+ * @run main/othervm SSLServerSocketAlpnTest UNUSED EMPTY h2,http/1.1 NONE
+ * @run main/othervm SSLServerSocketAlpnTest UNUSED h2 EMPTY NONE
+ * @run main/othervm SSLServerSocketAlpnTest UNUSED H2 h2 ERROR
+ * @run main/othervm SSLServerSocketAlpnTest UNUSED h2 http/1.1 ERROR
+ *
+ * @run main/othervm SSLServerSocketAlpnTest h2 h2 h2 h2
+ * @run main/othervm SSLServerSocketAlpnTest H2 h2 h2,http/1.1 h2
+ * @run main/othervm SSLServerSocketAlpnTest h2,http/1.1 http/1.1 h2,http/1.1 http/1.1
+ * @run main/othervm SSLServerSocketAlpnTest http/1.1,h2 h2 h2,http/1.1 h2
+ * @run main/othervm SSLServerSocketAlpnTest EMPTY h2 h2 h2
+ * @run main/othervm SSLServerSocketAlpnTest h2,http/1.1 EMPTY http/1.1 NONE
+ * @run main/othervm SSLServerSocketAlpnTest h2,http/1.1 h2 EMPTY NONE
+ * @run main/othervm SSLServerSocketAlpnTest UNUSED UNUSED http/1.1,h2 NONE
+ * @run main/othervm SSLServerSocketAlpnTest h2 h2 http/1.1 ERROR
+ * @run main/othervm SSLServerSocketAlpnTest h2,http/1.1 H2 http/1.1 ERROR
+ *
* @author Brad Wetmore
*/
+/**
+ * A simple SSLSocket-based client/server that demonstrates the proposed API
+ * changes for JEP 244 in support of the TLS ALPN extension (RFC 7301).
+ *
+ * Usage:
+ * java SSLServerSocketAlpnTest
+ * <server-APs> <callback-AP> <client-APs> <result>
+ *
+ * where:
+ * EMPTY indicates that ALPN is disabled
+ * UNUSED indicates that no ALPN values are supplied (server-side only)
+ * ERROR indicates that an exception is expected
+ * NONE indicates that no ALPN is expected
+ *
+ * This example is based on our standard SSLSocketTemplate.
+ */
import java.io.*;
import java.security.KeyStore;
+import java.util.Arrays;
import javax.net.ssl.*;
@@ -73,6 +112,9 @@
static String trustFilename = System.getProperty("test.src", ".") + "/"
+ pathToStores + "/" + trustStoreFile;
+ private static boolean hasServerAPs; // whether server APs are present
+ private static boolean hasCallback; // whether a callback is present
+
/*
* SSLContext
*/
@@ -89,6 +131,7 @@
static boolean debug = false;
static String[] serverAPs;
+ static String callbackAP;
static String[] clientAPs;
static String expectedAP;
@@ -129,7 +172,9 @@
sslp.setUseCipherSuitesOrder(true); // Set server side order
// Set the ALPN selection.
- sslp.setApplicationProtocols(serverAPs);
+ if (serverAPs != null) {
+ sslp.setApplicationProtocols(serverAPs);
+ }
sslServerSocket.setSSLParameters(sslp);
serverPort = sslServerSocket.getLocalPort();
@@ -146,6 +191,25 @@
+ "return null before the handshake starts");
}
+ // check that no callback has been registered
+ if (sslSocket.getHandshakeApplicationProtocolSelector() != null) {
+ throw new Exception("getHandshakeApplicationProtocolSelector() " +
+ "should return null");
+ }
+
+ if (hasCallback) {
+ sslSocket.setHandshakeApplicationProtocolSelector(
+ (serverSocket, clientProtocols) -> {
+ return callbackAP.equals("EMPTY") ? "" : callbackAP;
+ });
+
+ // check that the callback can be retrieved
+ if (sslSocket.getHandshakeApplicationProtocolSelector() == null) {
+ throw new Exception("getHandshakeApplicationProtocolSelector()"
+ + " should return non-null");
+ }
+ }
+
sslSocket.startHandshake();
if (sslSocket.getHandshakeApplicationProtocol() != null) {
@@ -276,14 +340,19 @@
if (debug) {
System.setProperty("javax.net.debug", "all");
}
+ System.out.println("Test args: " + Arrays.toString(args));
// Validate parameters
- if (args.length != 3) {
+ if (args.length != 4) {
throw new Exception("Invalid number of test parameters");
}
serverAPs = convert(args[0]);
- clientAPs = convert(args[1]);
- expectedAP = args[2];
+ callbackAP = args[1];
+ clientAPs = convert(args[2]);
+ expectedAP = args[3];
+
+ hasServerAPs = !args[0].equals("UNUSED"); // are server APs being used?
+ hasCallback = !callbackAP.equals("UNUSED"); // is callback being used?
/*
* Start the tests.
@@ -291,7 +360,7 @@
try {
new SSLServerSocketAlpnTest();
} catch (SSLHandshakeException she) {
- if (args[2].equals("ERROR")) {
+ if (args[3].equals("ERROR")) {
System.out.println("Caught the expected exception: " + she);
} else {
throw she;
@@ -322,7 +391,8 @@
}
kms = new KeyManager[] { new MyX509ExtendedKeyManager(
- (X509ExtendedKeyManager) kms[0], expectedAP) };
+ (X509ExtendedKeyManager) kms[0], expectedAP,
+ !hasCallback && hasServerAPs) };
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(trustKS);
@@ -338,12 +408,15 @@
* Convert a comma-separated list into an array of strings.
*/
private static String[] convert(String list) {
- String[] strings;
+ if (list.equals("UNUSED")) {
+ return null;
+ }
if (list.equals("EMPTY")) {
return new String[0];
}
+ String[] strings;
if (list.indexOf(',') > 0) {
strings = list.split(",");
} else {
--- a/jdk/test/javax/net/ssl/ALPN/SSLSocketAlpnTest.java Fri Dec 16 19:50:35 2016 +0800
+++ b/jdk/test/javax/net/ssl/ALPN/SSLSocketAlpnTest.java Fri Dec 16 14:32:51 2016 +0000
@@ -26,22 +26,60 @@
/*
* @test
- * @bug 8051498 8145849
+ * @bug 8051498 8145849 8170282
* @summary JEP 244: TLS Application-Layer Protocol Negotiation Extension
* @compile MyX509ExtendedKeyManager.java
- * @run main/othervm SSLSocketAlpnTest h2 h2 h2
- * @run main/othervm SSLSocketAlpnTest h2 h2,http/1.1 h2
- * @run main/othervm SSLSocketAlpnTest h2,http/1.1 h2,http/1.1 h2
- * @run main/othervm SSLSocketAlpnTest http/1.1,h2 h2,http/1.1 http/1.1
- * @run main/othervm SSLSocketAlpnTest h4,h3,h2 h1,h2 h2
- * @run main/othervm SSLSocketAlpnTest EMPTY h2,http/1.1 NONE
- * @run main/othervm SSLSocketAlpnTest h2 EMPTY NONE
- * @run main/othervm SSLSocketAlpnTest H2 h2 ERROR
- * @run main/othervm SSLSocketAlpnTest h2 http/1.1 ERROR
+ *
+ * @run main/othervm SSLSocketAlpnTest h2 UNUSED h2 h2
+ * @run main/othervm SSLSocketAlpnTest h2 UNUSED h2,http/1.1 h2
+ * @run main/othervm SSLSocketAlpnTest h2,http/1.1 UNUSED h2,http/1.1 h2
+ * @run main/othervm SSLSocketAlpnTest http/1.1,h2 UNUSED h2,http/1.1 http/1.1
+ * @run main/othervm SSLSocketAlpnTest h4,h3,h2 UNUSED h1,h2 h2
+ * @run main/othervm SSLSocketAlpnTest EMPTY UNUSED h2,http/1.1 NONE
+ * @run main/othervm SSLSocketAlpnTest h2 UNUSED EMPTY NONE
+ * @run main/othervm SSLSocketAlpnTest H2 UNUSED h2 ERROR
+ * @run main/othervm SSLSocketAlpnTest h2 UNUSED http/1.1 ERROR
+ *
+ * @run main/othervm SSLSocketAlpnTest UNUSED h2 h2 h2
+ * @run main/othervm SSLSocketAlpnTest UNUSED h2 h2,http/1.1 h2
+ * @run main/othervm SSLSocketAlpnTest UNUSED h2 http/1.1,h2 h2
+ * @run main/othervm SSLSocketAlpnTest UNUSED http/1.1 h2,http/1.1 http/1.1
+ * @run main/othervm SSLSocketAlpnTest UNUSED EMPTY h2,http/1.1 NONE
+ * @run main/othervm SSLSocketAlpnTest UNUSED h2 EMPTY NONE
+ * @run main/othervm SSLSocketAlpnTest UNUSED H2 h2 ERROR
+ * @run main/othervm SSLSocketAlpnTest UNUSED h2 http/1.1 ERROR
+ *
+ * @run main/othervm SSLSocketAlpnTest h2 h2 h2 h2
+ * @run main/othervm SSLSocketAlpnTest H2 h2 h2,http/1.1 h2
+ * @run main/othervm SSLSocketAlpnTest h2,http/1.1 http/1.1 h2,http/1.1 http/1.1
+ * @run main/othervm SSLSocketAlpnTest http/1.1,h2 h2 h2,http/1.1 h2
+ * @run main/othervm SSLSocketAlpnTest EMPTY h2 h2 h2
+ * @run main/othervm SSLSocketAlpnTest h2,http/1.1 EMPTY http/1.1 NONE
+ * @run main/othervm SSLSocketAlpnTest h2,http/1.1 h2 EMPTY NONE
+ * @run main/othervm SSLSocketAlpnTest UNUSED UNUSED http/1.1,h2 NONE
+ * @run main/othervm SSLSocketAlpnTest h2 h2 http/1.1 ERROR
+ * @run main/othervm SSLSocketAlpnTest h2,http/1.1 H2 http/1.1 ERROR
+ *
* @author Brad Wetmore
*/
+/**
+ * A simple SSLSocket-based client/server that demonstrates the proposed API
+ * changes for JEP 244 in support of the TLS ALPN extension (RFC 7301).
+ *
+ * Usage:
+ * java SSLSocketAlpnTest <server-APs> <callback-AP> <client-APs> <result>
+ *
+ * where:
+ * EMPTY indicates that ALPN is disabled
+ * UNUSED indicates that no ALPN values are supplied (server-side only)
+ * ERROR indicates that an exception is expected
+ * NONE indicates that no ALPN is expected
+ *
+ * This example is based on our standard SSLSocketTemplate.
+ */
import java.io.*;
import java.security.KeyStore;
+import java.util.Arrays;
import javax.net.ssl.*;
@@ -73,6 +111,9 @@
static String trustFilename = System.getProperty("test.src", ".") + "/"
+ pathToStores + "/" + trustStoreFile;
+ private static boolean hasServerAPs; // whether server APs are present
+ private static boolean hasCallback; // whether a callback is present
+
/*
* SSLContext
*/
@@ -89,6 +130,7 @@
static boolean debug = false;
static String[] serverAPs;
+ static String callbackAP;
static String[] clientAPs;
static String expectedAP;
@@ -136,7 +178,9 @@
sslp.setUseCipherSuitesOrder(true); // Set server side order
// Set the ALPN selection.
- sslp.setApplicationProtocols(serverAPs);
+ if (serverAPs != null) {
+ sslp.setApplicationProtocols(serverAPs);
+ }
sslSocket.setSSLParameters(sslp);
if (sslSocket.getHandshakeApplicationProtocol() != null) {
@@ -144,6 +188,24 @@
+ "return null before the handshake starts");
}
+ // check that no callback has been registered
+ if (sslSocket.getHandshakeApplicationProtocolSelector() != null) {
+ throw new Exception("getHandshakeApplicationProtocolSelector() " +
+ "should return null");
+ }
+
+ if (hasCallback) {
+ sslSocket.setHandshakeApplicationProtocolSelector(
+ (serverSocket, clientProtocols) -> {
+ return callbackAP.equals("EMPTY") ? "" : callbackAP;
+ });
+
+ // check that the callback can be retrieved
+ if (sslSocket.getHandshakeApplicationProtocolSelector() == null) {
+ throw new Exception("getHandshakeApplicationProtocolSelector()" + " should return non-null");
+ }
+ }
+
sslSocket.startHandshake();
if (sslSocket.getHandshakeApplicationProtocol() != null) {
@@ -274,14 +336,19 @@
if (debug) {
System.setProperty("javax.net.debug", "all");
}
+ System.out.println("Test args: " + Arrays.toString(args));
// Validate parameters
- if (args.length != 3) {
+ if (args.length != 4) {
throw new Exception("Invalid number of test parameters");
}
serverAPs = convert(args[0]);
- clientAPs = convert(args[1]);
- expectedAP = args[2];
+ callbackAP = args[1];
+ clientAPs = convert(args[2]);
+ expectedAP = args[3];
+
+ hasServerAPs = !args[0].equals("UNUSED"); // are server APs being used?
+ hasCallback = !callbackAP.equals("UNUSED"); // is callback being used?
/*
* Start the tests.
@@ -289,7 +356,7 @@
try {
new SSLSocketAlpnTest();
} catch (SSLHandshakeException she) {
- if (args[2].equals("ERROR")) {
+ if (args[3].equals("ERROR")) {
System.out.println("Caught the expected exception: " + she);
} else {
throw she;
@@ -320,7 +387,8 @@
}
kms = new KeyManager[] { new MyX509ExtendedKeyManager(
- (X509ExtendedKeyManager) kms[0], expectedAP) };
+ (X509ExtendedKeyManager) kms[0], expectedAP,
+ !hasCallback && hasServerAPs) };
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(trustKS);
@@ -336,12 +404,15 @@
* Convert a comma-separated list into an array of strings.
*/
private static String[] convert(String list) {
- String[] strings;
+ if (list.equals("UNUSED")) {
+ return null;
+ }
if (list.equals("EMPTY")) {
return new String[0];
}
+ String[] strings;
if (list.indexOf(',') > 0) {
strings = list.split(",");
} else {