8145849: ALPN: getHandshakeApplicationProtocol() always return null

Reviewed-by: wetmore, vinnie
This commit is contained in:
Amanda Jiang 2016-01-13 17:36:01 -08:00 committed by Bradford Wetmore
parent 717c4699a8
commit 751dd7f031
5 changed files with 239 additions and 36 deletions

View File

@ -2211,7 +2211,7 @@ public final class SSLEngineImpl extends SSLEngine {
@Override
public synchronized String getHandshakeApplicationProtocol() {
if ((handshaker != null) && !handshaker.started()) {
if ((handshaker != null) && handshaker.started()) {
return handshaker.getHandshakeApplicationProtocol();
}
return null;

View File

@ -2598,7 +2598,7 @@ public final class SSLSocketImpl extends BaseSSLSocketImpl {
@Override
public synchronized String getHandshakeApplicationProtocol() {
if ((handshaker != null) && !handshaker.started()) {
if ((handshaker != null) && handshaker.started()) {
return handshaker.getHandshakeApplicationProtocol();
}
return null;

View File

@ -0,0 +1,130 @@
/*
* Copyright (c) 2016, 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.
*/
import java.net.Socket;
import java.security.Principal;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.X509ExtendedKeyManager;
public class MyX509ExtendedKeyManager extends X509ExtendedKeyManager {
static final String ERROR = "ERROR";
X509ExtendedKeyManager akm;
String expectedAP;
MyX509ExtendedKeyManager(X509ExtendedKeyManager akm) {
this.akm = akm;
}
public MyX509ExtendedKeyManager(
X509ExtendedKeyManager akm, String expectedAP) {
this.akm = akm;
this.expectedAP = expectedAP;
}
@Override
public String[] getClientAliases(String keyType, Principal[] issuers) {
return akm.getClientAliases(keyType, issuers);
}
@Override
public String chooseClientAlias(String[] keyType, Principal[] issuers,
Socket socket) {
String nap = ((SSLSocket) socket).getHandshakeApplicationProtocol();
checkALPN(nap);
return akm.chooseClientAlias(keyType, issuers, socket);
}
@Override
public String[] getServerAliases(String keyType, Principal[] issuers) {
return akm.getServerAliases(keyType, issuers);
}
@Override
public String chooseServerAlias(String keyType, Principal[] issuers,
Socket socket) {
String nap = ((SSLSocket) socket).getHandshakeApplicationProtocol();
checkALPN(nap);
return akm.chooseServerAlias(keyType, issuers, socket);
}
@Override
public X509Certificate[] getCertificateChain(String alias) {
return akm.getCertificateChain(alias);
}
@Override
public PrivateKey getPrivateKey(String alias) {
return akm.getPrivateKey(alias);
}
@Override
public String chooseEngineClientAlias(String[] keyType, Principal[] issuers,
SSLEngine engine) {
String nap = engine.getHandshakeApplicationProtocol();
checkALPN(nap);
return akm.chooseEngineClientAlias(keyType, issuers, engine);
}
@Override
public String chooseEngineServerAlias(String keyType, Principal[] issuers,
SSLEngine engine) {
String nap = engine.getHandshakeApplicationProtocol();
checkALPN(nap);
return akm.chooseEngineServerAlias(keyType, issuers, engine);
}
private void checkALPN(String ap) {
if (ERROR.equals(expectedAP)) {
throw new RuntimeException("Should not reach here");
}
System.out.println("Expected ALPN value: " + expectedAP
+ " Got: " + ap);
if (ap == null) {
throw new RuntimeException(
"ALPN should be negotiated, but null was received");
}
if (expectedAP.equals("NONE")) {
if (!ap.isEmpty()) {
throw new RuntimeException("Expected no ALPN value");
} else {
System.out.println("No ALPN value negotiated, as expected");
}
} else if (!expectedAP.equals(ap)) {
throw new RuntimeException(expectedAP
+ " ALPN value not available on negotiated connection");
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2016, 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
@ -26,8 +26,9 @@
/*
* @test
* @bug 8051498
* @bug 8051498 8145849
* @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
@ -162,7 +163,7 @@ public class SSLEngineAlpnTest {
throw new Exception("Invalid number of test parameters");
}
SSLEngineAlpnTest test = new SSLEngineAlpnTest();
SSLEngineAlpnTest test = new SSLEngineAlpnTest(args[2]);
try {
test.runTest(convert(args[0]), convert(args[1]), args[2]);
} catch (SSLHandshakeException she) {
@ -179,7 +180,7 @@ public class SSLEngineAlpnTest {
/*
* Create an initialized SSLContext to use for these tests.
*/
public SSLEngineAlpnTest() throws Exception {
public SSLEngineAlpnTest(String expectedAP) throws Exception {
KeyStore ks = KeyStore.getInstance("JKS");
KeyStore ts = KeyStore.getInstance("JKS");
@ -192,12 +193,20 @@ public class SSLEngineAlpnTest {
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, passphrase);
KeyManager [] kms = kmf.getKeyManagers();
if (!(kms[0] instanceof X509ExtendedKeyManager)) {
throw new Exception("kms[0] not X509ExtendedKeyManager");
}
kms = new KeyManager[] { new MyX509ExtendedKeyManager(
(X509ExtendedKeyManager) kms[0], expectedAP) };
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(ts);
SSLContext sslCtx = SSLContext.getInstance("TLS");
sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
sslCtx.init(kms, tmf.getTrustManagers(), null);
sslc = sslCtx;
}
@ -327,6 +336,11 @@ public class SSLEngineAlpnTest {
return;
}
if (engine.getHandshakeApplicationProtocol() != null) {
throw new Exception ("getHandshakeApplicationProtocol() should "
+ "return null after the handshake is completed");
}
String ap = engine.getApplicationProtocol();
System.out.println("Application Protocol: \"" + ap + "\"");
@ -384,6 +398,12 @@ public class SSLEngineAlpnTest {
sslp = clientEngine.getSSLParameters();
sslp.setApplicationProtocols(clientAPs);
clientEngine.setSSLParameters(sslp);
if ((clientEngine.getHandshakeApplicationProtocol() != null) ||
(serverEngine.getHandshakeApplicationProtocol() != null)) {
throw new Exception ("getHandshakeApplicationProtocol() should "
+ "return null before the handshake starts");
}
}
/*

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 2016, 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
@ -26,8 +26,9 @@
/*
* @test
* @bug 8051498
* @bug 8051498 8145849
* @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
@ -40,6 +41,8 @@
* @author Brad Wetmore
*/
import java.io.*;
import java.security.KeyStore;
import javax.net.ssl.*;
public class SSLSocketAlpnTest {
@ -65,6 +68,16 @@ public class SSLSocketAlpnTest {
static String trustStoreFile = "truststore";
static String passwd = "passphrase";
static String keyFilename = System.getProperty("test.src", ".") + "/"
+ pathToStores + "/" + keyStoreFile;
static String trustFilename = System.getProperty("test.src", ".") + "/"
+ pathToStores + "/" + trustStoreFile;
/*
* SSLContext
*/
SSLContext mySSLContext = null;
/*
* Is the server ready to serve?
*/
@ -82,7 +95,7 @@ public class SSLSocketAlpnTest {
/*
* If the client or server is doing some kind of object creation
* that the other side depends on, and that thread prematurely
* exits, you may experience a hang. The test harness will
* exits, you may experience a hang. The test harness will
* terminate all hung threads after its timeout has expired,
* currently 3 minutes by default, but you might try to be
* smart about it....
@ -95,10 +108,11 @@ public class SSLSocketAlpnTest {
* to avoid infinite hangs.
*/
void doServerSide() throws Exception {
SSLServerSocketFactory sslssf
= (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
SSLServerSocketFactory sslssf = mySSLContext.getServerSocketFactory();
SSLServerSocket sslServerSocket
= (SSLServerSocket) sslssf.createServerSocket(serverPort);
// for both client/server to call into X509KM
sslServerSocket.setNeedClientAuth(true);
serverPort = sslServerSocket.getLocalPort();
@ -119,20 +133,30 @@ public class SSLSocketAlpnTest {
*/
String[] suites = sslp.getCipherSuites();
sslp.setCipherSuites(suites);
sslp.setUseCipherSuitesOrder(true); // Set server side order
sslp.setUseCipherSuitesOrder(true); // Set server side order
// Set the ALPN selection.
sslp.setApplicationProtocols(serverAPs);
sslSocket.setSSLParameters(sslp);
if (sslSocket.getHandshakeApplicationProtocol() != null) {
throw new Exception ("getHandshakeApplicationProtocol() should "
+ "return null before the handshake starts");
}
sslSocket.startHandshake();
if (sslSocket.getHandshakeApplicationProtocol() != null) {
throw new Exception ("getHandshakeApplicationProtocol() should "
+ "return null after the handshake is completed");
}
String ap = sslSocket.getApplicationProtocol();
System.out.println("Application Protocol: \"" + ap + "\"");
if (ap == null) {
throw new Exception(
"Handshake was completed but null was received");
"Handshake was completed but null was received");
}
if (expectedAP.equals("NONE")) {
if (!ap.isEmpty()) {
@ -141,8 +165,8 @@ public class SSLSocketAlpnTest {
System.out.println("No ALPN value negotiated, as expected");
}
} else if (!expectedAP.equals(ap)) {
throw new Exception(expectedAP +
" ALPN value not available on negotiated connection");
throw new Exception(expectedAP
+ " ALPN value not available on negotiated connection");
}
InputStream sslIS = sslSocket.getInputStream();
@ -170,8 +194,7 @@ public class SSLSocketAlpnTest {
Thread.sleep(50);
}
SSLSocketFactory sslsf
= (SSLSocketFactory) SSLSocketFactory.getDefault();
SSLSocketFactory sslsf = mySSLContext.getSocketFactory();
SSLSocket sslSocket
= (SSLSocket) sslsf.createSocket("localhost", serverPort);
@ -185,28 +208,35 @@ public class SSLSocketAlpnTest {
*/
String[] suites = sslp.getCipherSuites();
sslp.setCipherSuites(suites);
sslp.setUseCipherSuitesOrder(true); // Set server side order
sslp.setUseCipherSuitesOrder(true); // Set server side order
// Set the ALPN selection.
sslp.setApplicationProtocols(clientAPs);
sslSocket.setSSLParameters(sslp);
if (sslSocket.getHandshakeApplicationProtocol() != null) {
throw new Exception ("getHandshakeApplicationProtocol() should "
+ "return null before the handshake starts");
}
sslSocket.startHandshake();
if (sslSocket.getHandshakeApplicationProtocol() != null) {
throw new Exception ("getHandshakeApplicationProtocol() should "
+ "return null after the handshake is completed");
}
/*
* Check that the resulting connection meets our defined ALPN
* criteria. If we were connecting to a non-JSSE implementation,
* the server might have negotiated something we shouldn't accept.
*
* We were expecting H2 from server, let's make sure the
* conditions match.
*/
String ap = sslSocket.getApplicationProtocol();
System.out.println("Application Protocol: \"" + ap + "\"");
if (ap == null) {
throw new Exception(
"Handshake was completed but null was received");
"Handshake was completed but null was received");
}
if (expectedAP.equals("NONE")) {
if (!ap.isEmpty()) {
@ -215,8 +245,8 @@ public class SSLSocketAlpnTest {
System.out.println("No ALPN value negotiated, as expected");
}
} else if (!expectedAP.equals(ap)) {
throw new Exception(expectedAP +
" ALPN value not available on negotiated connection");
throw new Exception(expectedAP
+ " ALPN value not available on negotiated connection");
}
InputStream sslIS = sslSocket.getInputStream();
@ -240,17 +270,6 @@ public class SSLSocketAlpnTest {
volatile Exception clientException = null;
public static void main(String[] args) throws Exception {
String keyFilename
= System.getProperty("test.src", ".") + "/" + pathToStores
+ "/" + keyStoreFile;
String trustFilename
= System.getProperty("test.src", ".") + "/" + pathToStores
+ "/" + trustStoreFile;
System.setProperty("javax.net.ssl.keyStore", keyFilename);
System.setProperty("javax.net.ssl.keyStorePassword", passwd);
System.setProperty("javax.net.ssl.trustStore", trustFilename);
System.setProperty("javax.net.ssl.trustStorePassword", passwd);
if (debug) {
System.setProperty("javax.net.debug", "all");
@ -280,6 +299,39 @@ public class SSLSocketAlpnTest {
System.out.println("Test Passed.");
}
SSLContext getSSLContext(String keyFilename, String trustFilename)
throws Exception {
SSLContext ctx = SSLContext.getInstance("TLS");
// Keystores
KeyStore keyKS = KeyStore.getInstance("JKS");
keyKS.load(new FileInputStream(keyFilename), passwd.toCharArray());
KeyStore trustKS = KeyStore.getInstance("JKS");
trustKS.load(new FileInputStream(trustFilename), passwd.toCharArray());
// Generate KeyManager and TrustManager
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(keyKS, passwd.toCharArray());
KeyManager[] kms = kmf.getKeyManagers();
if (!(kms[0] instanceof X509ExtendedKeyManager)) {
throw new Exception("kms[0] not X509ExtendedKeyManager");
}
kms = new KeyManager[] { new MyX509ExtendedKeyManager(
(X509ExtendedKeyManager) kms[0], expectedAP) };
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(trustKS);
TrustManager[] tms = tmf.getTrustManagers();
// initial SSLContext
ctx.init(kms, tms, null);
return ctx;
}
/*
* Convert a comma-separated list into an array of strings.
*/
@ -309,6 +361,7 @@ public class SSLSocketAlpnTest {
*/
SSLSocketAlpnTest() throws Exception {
Exception startException = null;
mySSLContext = getSSLContext(keyFilename, trustFilename);
try {
if (separateServerThread) {
startServer(true);