提交 317005f1 编写于 作者: W wetmore

8230977: JEP 244/8051498 - TLS Application-Layer Protocol Negotiation Extension (Java SE 8)

8144093: JEP 244/8051498 - TLS Application-Layer Protocol Negotiation Extension
8170282: Enable ALPN parameters to be supplied during the TLS handshake
8145849: ALPN: getHandshakeApplicationProtocol() always return null
8158978: ALPN not working when values are set directly on a SSLServerSocket
8171443: (spec) An ALPN callback function may also ignore ALPN
Reviewed-by: xuelei, coffeys, rhalade, andrew
上级 39568aea
/*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2020, 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
......@@ -27,6 +27,8 @@ package javax.net.ssl;
import java.nio.ByteBuffer;
import java.nio.ReadOnlyBufferException;
import java.util.List;
import java.util.function.BiFunction;
/**
......@@ -1253,4 +1255,142 @@ public abstract class SSLEngine {
}
}
/**
* Returns the most recent application protocol value negotiated for this
* connection.
* <p>
* If supported by the underlying SSL/TLS/DTLS implementation,
* application name negotiation mechanisms such as <a
* href="http://www.ietf.org/rfc/rfc7301.txt"> RFC 7301 </a>, the
* Application-Layer Protocol Negotiation (ALPN), can negotiate
* application-level values between peers.
*
* @implSpec
* The implementation in this class throws
* {@code UnsupportedOperationException} and performs no other action.
*
* @return null if it has not yet been determined if application
* protocols might be used for this connection, an empty
* {@code String} if application protocols values will not
* be used, or a non-empty application protocol {@code String}
* if a value was successfully negotiated.
* @throws UnsupportedOperationException if the underlying provider
* does not implement the operation.
* @since 8
*/
public String getApplicationProtocol() {
throw new UnsupportedOperationException();
}
/**
* Returns the application protocol value negotiated on a SSL/TLS
* handshake currently in progress.
* <p>
* Like {@link #getHandshakeSession()},
* a connection may be in the middle of a handshake. The
* application protocol may or may not yet be available.
*
* @implSpec
* The implementation in this class throws
* {@code UnsupportedOperationException} and performs no other action.
*
* @return null if it has not yet been determined if application
* protocols might be used for this handshake, an empty
* {@code String} if application protocols values will not
* be used, or a non-empty application protocol {@code String}
* if a value was successfully negotiated.
* @throws UnsupportedOperationException if the underlying provider
* does not implement the operation.
* @since 8
*/
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 supplied 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 an empty {@code String} then application
* protocol indications will not be used.
* 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 8
*/
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 8
*/
public BiFunction<SSLEngine, List<String>, String>
getHandshakeApplicationProtocolSelector() {
throw new UnsupportedOperationException();
}
}
/*
* Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 2020, 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
......@@ -56,6 +56,17 @@ import java.util.LinkedHashMap;
* {@link SSLSocket#setSSLParameters SSLSocket.setSSLParameters()} and
* {@link SSLServerSocket#setSSLParameters SSLServerSocket.setSSLParameters()}
* and {@link SSLEngine#setSSLParameters SSLEngine.setSSLParameters()}.
* <p>
* For example:
*
* <blockquote><pre>
* SSLParameters p = sslSocket.getSSLParameters();
* p.setProtocols(new String[] { "TLSv1.2" });
* p.setCipherSuites(
* new String[] { "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", ... });
* p.setApplicationProtocols(new String[] {"h2", "http/1.1"});
* sslSocket.setSSLParameters(p);
* </pre></blockquote>*
*
* @see SSLSocket
* @see SSLEngine
......@@ -74,6 +85,7 @@ public class SSLParameters {
private Map<Integer, SNIServerName> sniNames = null;
private Map<Integer, SNIMatcher> sniMatchers = null;
private boolean preferLocalCipherSuites;
private String[] applicationProtocols = new String[0];
/**
* Constructs SSLParameters.
......@@ -464,5 +476,74 @@ public class SSLParameters {
public final boolean getUseCipherSuitesOrder() {
return preferLocalCipherSuites;
}
}
/**
* Returns a prioritized array of application-layer protocol names that
* can be negotiated over the SSL/TLS/DTLS protocols.
* <p>
* The array could be empty (zero-length), in which case protocol
* indications will not be used.
* <p>
* This method will return a new array each time it is invoked.
*
* @return a non-null, possibly zero-length array of application protocol
* {@code String}s. The array is ordered based on protocol
* preference, with {@code protocols[0]} being the most preferred.
* @see #setApplicationProtocols
* @since 8
*/
public String[] getApplicationProtocols() {
return applicationProtocols.clone();
}
/**
* Sets the prioritized array of application-layer protocol names that
* can be negotiated over the SSL/TLS/DTLS protocols.
* <p>
* If application-layer protocols are supported by the underlying
* SSL/TLS implementation, this method configures which values can
* be negotiated by protocols such as <a
* href="http://www.ietf.org/rfc/rfc7301.txt"> RFC 7301 </a>, the
* Application Layer Protocol Negotiation (ALPN).
* <p>
* If this end of the connection is expected to offer application protocol
* values, all protocols configured by this method will be sent to the
* peer.
* <p>
* If this end of the connection is expected to select the application
* protocol value, the {@code protocols} configured by this method are
* compared with those sent by the peer. The first matched value becomes
* the negotiated value. If none of the {@code protocols} were actually
* requested by the peer, the underlying protocol will determine what
* action to take. (For example, ALPN will send a
* {@code "no_application_protocol"} alert and terminate the connection.)
*
* @implSpec
* This method will make a copy of the {@code protocols} array.
*
* @param protocols an ordered array of application protocols,
* with {@code protocols[0]} being the most preferred.
* If the array is empty (zero-length), protocol
* indications will not be used.
* @throws IllegalArgumentException if protocols is null, or if
* any element in a non-empty array is null or an
* empty (zero-length) string
* @see #getApplicationProtocols
* @since 8
*/
public void setApplicationProtocols(String[] protocols) {
if (protocols == null) {
throw new IllegalArgumentException("protocols was null");
}
String[] tempProtocols = protocols.clone();
for (String p : tempProtocols) {
if (p == null || p.equals("")) {
throw new IllegalArgumentException(
"An element of protocols was null/empty");
}
}
applicationProtocols = tempProtocols;
}
}
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2020, 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
......@@ -28,6 +28,8 @@ package javax.net.ssl;
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
......@@ -662,4 +664,142 @@ public abstract class SSLSocket extends Socket
}
}
/**
* Returns the most recent application protocol value negotiated for this
* connection.
* <p>
* If supported by the underlying SSL/TLS/DTLS implementation,
* application name negotiation mechanisms such as <a
* href="http://www.ietf.org/rfc/rfc7301.txt"> RFC 7301 </a>, the
* Application-Layer Protocol Negotiation (ALPN), can negotiate
* application-level values between peers.
*
* @implSpec
* The implementation in this class throws
* {@code UnsupportedOperationException} and performs no other action.
*
* @return null if it has not yet been determined if application
* protocols might be used for this connection, an empty
* {@code String} if application protocols values will not
* be used, or a non-empty application protocol {@code String}
* if a value was successfully negotiated.
* @throws UnsupportedOperationException if the underlying provider
* does not implement the operation.
* @since 8
*/
public String getApplicationProtocol() {
throw new UnsupportedOperationException();
}
/**
* Returns the application protocol value negotiated on a SSL/TLS
* handshake currently in progress.
* <p>
* Like {@link #getHandshakeSession()},
* a connection may be in the middle of a handshake. The
* application protocol may or may not yet be available.
*
* @implSpec
* The implementation in this class throws
* {@code UnsupportedOperationException} and performs no other action.
*
* @return null if it has not yet been determined if application
* protocols might be used for this handshake, an empty
* {@code String} if application protocols values will not
* be used, or a non-empty application protocol {@code String}
* if a value was successfully negotiated.
* @throws UnsupportedOperationException if the underlying provider
* does not implement the operation.
* @since 8
*/
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 supplied 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 an empty {@code String} then application
* protocol indications will not be used.
* 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 8
*/
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 8
*/
public BiFunction<SSLSocket, List<String>, String>
getHandshakeApplicationProtocolSelector() {
throw new UnsupportedOperationException();
}
}
/*
* Copyright (c) 2015, 2020, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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;
import java.io.IOException;
import java.nio.charset.*;
import java.util.*;
import javax.net.ssl.*;
/*
* [RFC 7301]
* This TLS extension facilitates the negotiation of application-layer protocols
* within the TLS handshake. Clients MAY include an extension of type
* "application_layer_protocol_negotiation" in the (extended) ClientHello
* message. The "extension_data" field of this extension SHALL contain a
* "ProtocolNameList" value:
*
* enum {
* application_layer_protocol_negotiation(16), (65535)
* } ExtensionType;
*
* opaque ProtocolName<1..2^8-1>;
*
* struct {
* ProtocolName protocol_name_list<2..2^16-1>
* } ProtocolNameList;
*/
final class ALPNExtension extends HelloExtension {
final static int ALPN_HEADER_LENGTH = 1;
final static int MAX_APPLICATION_PROTOCOL_LENGTH = 255;
final static int MAX_APPLICATION_PROTOCOL_LIST_LENGTH = 65535;
private int listLength = 0; // ProtocolNameList length
private List<String> protocolNames = null;
// constructor for ServerHello
ALPNExtension(String protocolName) throws SSLException {
this(new String[]{ protocolName });
}
// constructor for ClientHello
ALPNExtension(String[] protocolNames) throws SSLException {
super(ExtensionType.EXT_ALPN);
if (protocolNames.length == 0) { // never null, never empty
throw new IllegalArgumentException(
"The list of application protocols cannot be empty");
}
this.protocolNames = Arrays.asList(protocolNames);
for (String p : protocolNames) {
int length = p.getBytes(StandardCharsets.UTF_8).length;
if (length == 0) {
throw new SSLProtocolException(
"Application protocol name is empty");
}
if (length <= MAX_APPLICATION_PROTOCOL_LENGTH) {
listLength += length + ALPN_HEADER_LENGTH;
} else {
throw new SSLProtocolException(
"Application protocol name is too long: " + p);
}
if (listLength > MAX_APPLICATION_PROTOCOL_LIST_LENGTH) {
throw new SSLProtocolException(
"Application protocol name list is too long");
}
}
}
// constructor for ServerHello for parsing ALPN extension
ALPNExtension(HandshakeInStream s, int len) throws IOException {
super(ExtensionType.EXT_ALPN);
if (len >= 2) {
listLength = s.getInt16(); // list length
if (listLength < 2 || listLength + 2 != len) {
throw new SSLProtocolException(
"Invalid " + type + " extension: incorrect list length " +
"(length=" + listLength + ")");
}
} else {
throw new SSLProtocolException(
"Invalid " + type + " extension: insufficient data " +
"(length=" + len + ")");
}
int remaining = listLength;
this.protocolNames = new ArrayList<>();
while (remaining > 0) {
// opaque ProtocolName<1..2^8-1>; // RFC 7301
byte[] bytes = s.getBytes8();
if (bytes.length == 0) {
throw new SSLProtocolException("Invalid " + type +
" extension: empty application protocol name");
}
String p =
new String(bytes, StandardCharsets.UTF_8); // app protocol
protocolNames.add(p);
remaining -= bytes.length + ALPN_HEADER_LENGTH;
}
if (remaining != 0) {
throw new SSLProtocolException(
"Invalid " + type + " extension: extra data " +
"(length=" + remaining + ")");
}
}
List<String> getPeerAPs() {
return protocolNames;
}
/*
* Return the length in bytes, including extension type and length fields.
*/
@Override
int length() {
return 6 + listLength;
}
@Override
void send(HandshakeOutStream s) throws IOException {
s.putInt16(type.id);
s.putInt16(listLength + 2); // length of extension_data
s.putInt16(listLength); // length of ProtocolNameList
for (String p : protocolNames) {
s.putBytes8(p.getBytes(StandardCharsets.UTF_8));
}
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
if (protocolNames == null || protocolNames.isEmpty()) {
sb.append("<empty>");
} else {
for (String protocolName : protocolNames) {
sb.append("[" + protocolName + "]");
}
}
return "Extension " + type +
", protocol names: " + sb;
}
}
/*
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2020, 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
......@@ -83,6 +83,9 @@ final class Alerts {
static final byte alert_bad_certificate_status_response = 113;
static final byte alert_bad_certificate_hash_value = 114;
// from RFC 7301 (TLS ALPN Extension)
static final byte alert_no_application_protocol = 120;
static String alertDescription(byte code) {
switch (code) {
......@@ -144,6 +147,8 @@ final class Alerts {
return "bad_certificate_status_response";
case alert_bad_certificate_hash_value:
return "bad_certificate_hash_value";
case alert_no_application_protocol:
return "no_application_protocol";
default:
return "<UNKNOWN ALERT: " + (code & 0x0ff) + ">";
......@@ -189,6 +194,7 @@ final class Alerts {
case alert_unrecognized_name:
case alert_bad_certificate_status_response:
case alert_bad_certificate_hash_value:
case alert_no_application_protocol:
e = new SSLHandshakeException(reason);
break;
......
/*
* Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 2020, 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
......@@ -141,6 +141,9 @@ final class ClientHandshaker extends Handshaker {
private final static boolean allowUnsafeServerCertChange =
Debug.getBooleanProperty("jdk.tls.allowUnsafeServerCertChange", false);
// Whether an ALPN extension was sent in the ClientHello
private boolean alpnActive = false;
private List<SNIServerName> requestedServerNames =
Collections.<SNIServerName>emptyList();
......@@ -689,6 +692,45 @@ final class ClientHandshaker extends Handshaker {
}
}
// check the ALPN extension
ALPNExtension serverHelloALPN =
(ALPNExtension) mesg.extensions.get(ExtensionType.EXT_ALPN);
if (serverHelloALPN != null) {
// Check whether an ALPN extension was sent in ClientHello message
if (!alpnActive) {
fatalSE(Alerts.alert_unsupported_extension,
"Server sent " + ExtensionType.EXT_ALPN +
" extension when not requested by client");
}
List<String> protocols = serverHelloALPN.getPeerAPs();
// Only one application protocol name should be present
String p;
if ((protocols.size() == 1) &&
!((p = protocols.get(0)).isEmpty())) {
int i;
for (i = 0; i < localApl.length; i++) {
if (localApl[i].equals(p)) {
break;
}
}
if (i == localApl.length) {
fatalSE(Alerts.alert_handshake_failure,
"Server has selected an application protocol name " +
"which was not offered by the client: " + p);
}
applicationProtocol = p;
} else {
fatalSE(Alerts.alert_handshake_failure,
"Incorrect data in ServerHello " + ExtensionType.EXT_ALPN +
" message");
}
} else {
applicationProtocol = "";
}
if (resumingSession && session != null) {
setHandshakeSessionSE(session);
// Reserve the handshake state if this is a session-resumption
......@@ -708,6 +750,7 @@ final class ClientHandshaker extends Handshaker {
} else if ((type != ExtensionType.EXT_ELLIPTIC_CURVES)
&& (type != ExtensionType.EXT_EC_POINT_FORMATS)
&& (type != ExtensionType.EXT_SERVER_NAME)
&& (type != ExtensionType.EXT_ALPN)
&& (type != ExtensionType.EXT_RENEGOTIATION_INFO)
&& (type != ExtensionType.EXT_EXTENDED_MASTER_SECRET)){
fatalSE(Alerts.alert_unsupported_extension,
......@@ -1537,6 +1580,12 @@ final class ClientHandshaker extends Handshaker {
}
}
// Add ALPN extension
if (localApl != null && localApl.length > 0) {
clientHelloMessage.addALPNExtension(localApl);
alpnActive = true;
}
// reset the client random cookie
clnt_random = clientHelloMessage.clnt_random;
......
/*
* Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2006, 2020, 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
......@@ -43,7 +43,8 @@ final class ExtensionType {
return name;
}
static List<ExtensionType> knownExtensions = new ArrayList<ExtensionType>(14);
static List<ExtensionType> knownExtensions =
new ArrayList<ExtensionType>(15);
static ExtensionType get(int id) {
for (ExtensionType ext : knownExtensions) {
......@@ -96,6 +97,11 @@ final class ExtensionType {
final static ExtensionType EXT_SIGNATURE_ALGORITHMS =
e(0x000D, "signature_algorithms"); // IANA registry value: 13
// extension defined in RFC 7301 (ALPN)
static final ExtensionType EXT_ALPN =
e(0x0010, "application_layer_protocol_negotiation");
// IANA registry value: 16
// extensions defined in RFC 7627
static final ExtensionType EXT_EXTENDED_MASTER_SECRET =
e(0x0017, "extended_master_secret"); // IANA registry value: 23
......
/*
* Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 2020, 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
......@@ -280,6 +280,11 @@ static final class ClientHello extends HandshakeMessage {
extensions.add(new ExtendedMasterSecretExtension());
}
// add application_layer_protocol_negotiation extension
void addALPNExtension(String[] applicationProtocols) throws SSLException {
extensions.add(new ALPNExtension(applicationProtocols));
}
@Override
int messageType() { return ht_client_hello; }
......
/*
* Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 2020, 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
......@@ -28,6 +28,7 @@ package sun.security.ssl;
import java.io.*;
import java.util.*;
import java.util.function.BiFunction;
import java.security.*;
import javax.crypto.*;
......@@ -109,6 +110,20 @@ abstract class Handshaker {
List<SNIServerName> serverNames = Collections.<SNIServerName>emptyList();
Collection<SNIMatcher> sniMatchers = Collections.<SNIMatcher>emptyList();
// List of local ApplicationProtocols
String[] localApl = null;
// 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;
private boolean isClient;
private boolean needCertVerify;
......@@ -488,6 +503,36 @@ abstract class Handshaker {
this.sniMatchers = sniMatchers;
}
/**
* Sets the Application Protocol list.
*/
void setApplicationProtocols(String[] apl) {
this.localApl = apl;
}
/**
* Gets the "negotiated" ALPN value.
*/
String getHandshakeApplicationProtocol() {
return applicationProtocol;
}
/**
* 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.
*/
......
/*
* Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2006, 2020, 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
......@@ -33,8 +33,8 @@ import javax.net.ssl.*;
/**
* This file contains all the classes relevant to TLS Extensions for the
* ClientHello and ServerHello messages. The extension mechanism and
* several extensions are defined in RFC 3546. Additional extensions are
* defined in the ECC RFC 4492.
* several extensions are defined in RFC 6066. Additional extensions are
* defined in the ECC RFC 4492 and the ALPN extension is defined in RFC 7301.
*
* Currently, only the two ECC extensions are fully supported.
*
......@@ -52,6 +52,7 @@ import javax.net.ssl.*;
* . EllipticCurvesExtension: the ECC supported curves extension.
* . EllipticPointFormatsExtension: the ECC supported point formats
* (compressed/uncompressed) extension.
* . ALPNExtension: the application_layer_protocol_negotiation extension.
*
* @since 1.6
* @author Andreas Sterbenz
......@@ -86,6 +87,8 @@ final class HelloExtensions {
extension = new RenegotiationInfoExtension(s, extlen);
} else if (extType == ExtensionType.EXT_EXTENDED_MASTER_SECRET) {
extension = new ExtendedMasterSecretExtension(s, extlen);
} else if (extType == ExtensionType.EXT_ALPN) {
extension = new ALPNExtension(s, extlen);
} else {
extension = new UnknownExtension(s, extlen, extType);
}
......
/*
* Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2020, 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
......@@ -29,6 +29,7 @@ import java.io.*;
import java.nio.*;
import java.util.*;
import java.security.*;
import java.util.function.BiFunction;
import javax.crypto.BadPaddingException;
......@@ -259,6 +260,19 @@ final public class SSLEngineImpl extends SSLEngine {
Collection<SNIMatcher> sniMatchers =
Collections.<SNIMatcher>emptyList();
// Configured application protocol values
String[] applicationProtocols = new String[0];
// Negotiated application protocol value.
//
// 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;
......@@ -486,6 +500,9 @@ final public class SSLEngineImpl extends SSLEngine {
}
handshaker.setEnabledCipherSuites(enabledCipherSuites);
handshaker.setEnableSessionCreation(enableSessionCreation);
handshaker.setApplicationProtocols(applicationProtocols);
handshaker.setApplicationProtocolSelectorSSLEngine(
applicationProtocolSelector);
}
/*
......@@ -1027,6 +1044,9 @@ final public class SSLEngineImpl extends SSLEngine {
handshaker.isSecureRenegotiation();
clientVerifyData = handshaker.getClientVerifyData();
serverVerifyData = handshaker.getServerVerifyData();
// set connection ALPN value
applicationProtocol =
handshaker.getHandshakeApplicationProtocol();
sess = handshaker.getSession();
handshakeSession = null;
......@@ -2091,6 +2111,7 @@ final public class SSLEngineImpl extends SSLEngine {
params.setSNIMatchers(sniMatchers);
params.setServerNames(serverNames);
params.setUseCipherSuitesOrder(preferLocalCipherSuites);
params.setApplicationProtocols(applicationProtocols);
return params;
}
......@@ -2116,10 +2137,12 @@ final public class SSLEngineImpl extends SSLEngine {
if (matchers != null) {
sniMatchers = matchers;
}
applicationProtocols = params.getApplicationProtocols();
if ((handshaker != null) && !handshaker.started()) {
handshaker.setIdentificationProtocol(identificationProtocol);
handshaker.setAlgorithmConstraints(algorithmConstraints);
applicationProtocols = params.getApplicationProtocols();
if (roleIsServer) {
handshaker.setSNIMatchers(sniMatchers);
handshaker.setUseCipherSuitesOrder(preferLocalCipherSuites);
......@@ -2129,6 +2152,34 @@ final public class SSLEngineImpl extends SSLEngine {
}
}
@Override
public synchronized String getApplicationProtocol() {
return applicationProtocol;
}
@Override
public synchronized String getHandshakeApplicationProtocol() {
if ((handshaker != null) && handshaker.started()) {
return handshaker.getHandshakeApplicationProtocol();
}
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.
*/
......
/*
* Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 2020, 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
......@@ -92,6 +92,9 @@ class SSLServerSocketImpl extends SSLServerSocket
Collection<SNIMatcher> sniMatchers =
Collections.<SNIMatcher>emptyList();
// Configured application protocol values
String[] applicationProtocols = new String[0];
/*
* Whether local cipher suites preference in server side should be
* honored during handshaking?
......@@ -311,7 +314,7 @@ class SSLServerSocketImpl extends SSLServerSocket
params.setAlgorithmConstraints(algorithmConstraints);
params.setSNIMatchers(sniMatchers);
params.setUseCipherSuitesOrder(preferLocalCipherSuites);
params.setApplicationProtocols(applicationProtocols);
return params;
}
......@@ -331,6 +334,7 @@ class SSLServerSocketImpl extends SSLServerSocket
if (matchers != null) {
sniMatchers = params.getSNIMatchers();
}
applicationProtocols = params.getApplicationProtocols();
}
/**
......@@ -343,7 +347,7 @@ class SSLServerSocketImpl extends SSLServerSocket
SSLSocketImpl s = new SSLSocketImpl(sslContext, useServerMode,
enabledCipherSuites, doClientAuth, enableSessionCreation,
enabledProtocols, identificationProtocol, algorithmConstraints,
sniMatchers, preferLocalCipherSuites);
sniMatchers, preferLocalCipherSuites, applicationProtocols);
implAccept(s);
s.doneConnect();
......
/*
* Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 2020, 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
......@@ -36,6 +36,7 @@ import java.security.AlgorithmConstraints;
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.*;
......@@ -220,6 +221,18 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl {
// Is the sniMatchers set to empty with SSLParameters.setSNIMatchers()?
private boolean noSniMatcher = false;
// Configured application protocol values
String[] applicationProtocols = new String[0];
// Negotiated application protocol value.
//
// 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.
......@@ -506,7 +519,8 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl {
String identificationProtocol,
AlgorithmConstraints algorithmConstraints,
Collection<SNIMatcher> sniMatchers,
boolean preferLocalCipherSuites) throws IOException {
boolean preferLocalCipherSuites,
String[] applicationProtocols) throws IOException {
super();
doClientAuth = clientAuth;
......@@ -515,6 +529,7 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl {
this.algorithmConstraints = algorithmConstraints;
this.sniMatchers = sniMatchers;
this.preferLocalCipherSuites = preferLocalCipherSuites;
this.applicationProtocols = applicationProtocols;
init(context, serverMode);
/*
......@@ -1078,6 +1093,9 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl {
handshaker.isSecureRenegotiation();
clientVerifyData = handshaker.getClientVerifyData();
serverVerifyData = handshaker.getServerVerifyData();
// set connection ALPN value
applicationProtocol =
handshaker.getHandshakeApplicationProtocol();
sess = handshaker.getSession();
handshakeSession = null;
......@@ -1329,6 +1347,9 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl {
}
handshaker.setEnabledCipherSuites(enabledCipherSuites);
handshaker.setEnableSessionCreation(enableSessionCreation);
handshaker.setApplicationProtocols(applicationProtocols);
handshaker.setApplicationProtocolSelectorSSLSocket(
applicationProtocolSelector);
}
/**
......@@ -2617,6 +2638,7 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl {
}
params.setUseCipherSuitesOrder(preferLocalCipherSuites);
params.setApplicationProtocols(applicationProtocols);
return params;
}
......@@ -2645,9 +2667,12 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl {
sniMatchers = matchers;
}
applicationProtocols = params.getApplicationProtocols();
if ((handshaker != null) && !handshaker.started()) {
handshaker.setIdentificationProtocol(identificationProtocol);
handshaker.setAlgorithmConstraints(algorithmConstraints);
handshaker.setApplicationProtocols(applicationProtocols);
if (roleIsServer) {
handshaker.setSNIMatchers(sniMatchers);
handshaker.setUseCipherSuitesOrder(preferLocalCipherSuites);
......@@ -2657,6 +2682,34 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl {
}
}
@Override
public synchronized String getApplicationProtocol() {
return applicationProtocol;
}
@Override
public synchronized String getHandshakeApplicationProtocol() {
if ((handshaker != null) && handshaker.started()) {
return handshaker.getHandshakeApplicationProtocol();
}
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
......
/*
* Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 2020, 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
......@@ -33,6 +33,7 @@ import java.security.cert.*;
import java.security.interfaces.*;
import java.security.spec.ECParameterSpec;
import java.math.BigInteger;
import java.util.function.BiFunction;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
......@@ -508,6 +509,44 @@ final class ServerHandshaker extends Handshaker {
}
}
// check the ALPN extension
ALPNExtension clientHelloALPN = (ALPNExtension)
mesg.extensions.get(ExtensionType.EXT_ALPN);
// 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();
// 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"));
}
applicationProtocol = negotiatedValue;
} else {
applicationProtocol = "";
}
} // Otherwise, applicationProtocol will be set by the callback.
/*
* Always make sure this entire record has been digested before we
* start emitting output, to ensure correct digesting order.
......@@ -858,6 +897,39 @@ final class ServerHandshaker extends Handshaker {
m1.extensions.add(new ExtendedMasterSecretExtension());
}
// Prepare the ALPN response
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")) {
m1.print(System.out);
System.out.println("Cipher suite: " + session.getSuite());
......
/*
* Copyright (c) 2016, 2020, 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;
boolean doCheck = true;
MyX509ExtendedKeyManager(X509ExtendedKeyManager akm) {
this.akm = akm;
}
public MyX509ExtendedKeyManager(
X509ExtendedKeyManager akm, String expectedAP, boolean doCheck) {
this.akm = akm;
this.expectedAP = expectedAP;
this.doCheck = doCheck;
}
@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 (!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");
}
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");
}
}
}
/*
* Copyright (c) 2001, 2020, 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.
*/
// SunJSSE does not support dynamic system properties, no way to re-use
// system properties in samevm/agentvm mode.
/*
* @test
* @bug 8051498 8145849 8158978 8170282
* @summary JEP 244: TLS Application-Layer Protocol Negotiation Extension
* @compile MyX509ExtendedKeyManager.java
*
* @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.*;
public class SSLServerSocketAlpnTest {
/*
* =============================================================
* Set the various variables needed for the tests, then
* specify what tests to run on each side.
*/
/*
* Should we run the client or server in a separate thread?
* Both sides can throw exceptions, but do you have a preference
* as to which side should be the main thread.
*/
static boolean separateServerThread = false;
/*
* Where do we find the keystores?
*/
static String pathToStores = "../../../../etc";
static String keyStoreFile = "keystore";
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;
private static boolean hasServerAPs; // whether server APs are present
private static boolean hasCallback; // whether a callback is present
/*
* SSLContext
*/
SSLContext mySSLContext = null;
/*
* Is the server ready to serve?
*/
volatile static boolean serverReady = false;
/*
* Turn on SSL debugging?
*/
static boolean debug = false;
static String[] serverAPs;
static String callbackAP;
static String[] clientAPs;
static String expectedAP;
/*
* 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
* terminate all hung threads after its timeout has expired,
* currently 3 minutes by default, but you might try to be
* smart about it....
*/
/*
* Define the server side of the test.
*
* If the server prematurely exits, serverReady will be set to true
* to avoid infinite hangs.
*/
void doServerSide() throws Exception {
SSLServerSocketFactory sslssf = mySSLContext.getServerSocketFactory();
SSLServerSocket sslServerSocket
= (SSLServerSocket) sslssf.createServerSocket(serverPort);
sslServerSocket.setNeedClientAuth(true);
SSLParameters sslp = sslServerSocket.getSSLParameters();
// for both client/server to call into X509KM
sslp.setNeedClientAuth(true);
/*
* The default ciphersuite ordering from the SSLContext may not
* reflect "h2" ciphersuites as being preferred, additionally the
* client may not send them in an appropriate order. We could resort
* the suite list if so desired.
*/
String[] suites = sslp.getCipherSuites();
sslp.setCipherSuites(suites);
sslp.setUseCipherSuitesOrder(true); // Set server side order
// Set the ALPN selection.
if (serverAPs != null) {
sslp.setApplicationProtocols(serverAPs);
}
sslServerSocket.setSSLParameters(sslp);
serverPort = sslServerSocket.getLocalPort();
/*
* Signal Client, we're ready for his connect.
*/
serverReady = true;
SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
if (sslSocket.getHandshakeApplicationProtocol() != null) {
throw new Exception ("getHandshakeApplicationProtocol() should "
+ "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) {
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");
}
if (expectedAP.equals("NONE")) {
if (!ap.isEmpty()) {
throw new Exception("Expected no ALPN value");
} else {
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");
}
InputStream sslIS = sslSocket.getInputStream();
OutputStream sslOS = sslSocket.getOutputStream();
sslIS.read();
sslOS.write(85);
sslOS.flush();
sslSocket.close();
}
/*
* Define the client side of the test.
*
* If the server prematurely exits, serverReady will be set to true
* to avoid infinite hangs.
*/
void doClientSide() throws Exception {
/*
* Wait for server to get started.
*/
while (!serverReady) {
Thread.sleep(50);
}
SSLSocketFactory sslsf = mySSLContext.getSocketFactory();
SSLSocket sslSocket
= (SSLSocket) sslsf.createSocket("localhost", serverPort);
SSLParameters sslp = sslSocket.getSSLParameters();
/*
* The default ciphersuite ordering from the SSLContext may not
* reflect "h2" ciphersuites as being preferred, additionally the
* client may not send them in an appropriate order. We could resort
* the suite list if so desired.
*/
String[] suites = sslp.getCipherSuites();
sslp.setCipherSuites(suites);
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.
*/
String ap = sslSocket.getApplicationProtocol();
System.out.println("Application Protocol: \"" + ap + "\"");
if (ap == null) {
throw new Exception(
"Handshake was completed but null was received");
}
if (expectedAP.equals("NONE")) {
if (!ap.isEmpty()) {
throw new Exception("Expected no ALPN value");
} else {
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");
}
InputStream sslIS = sslSocket.getInputStream();
OutputStream sslOS = sslSocket.getOutputStream();
sslOS.write(280);
sslOS.flush();
sslIS.read();
sslSocket.close();
}
/*
* =============================================================
* The remainder is just support stuff
*/
// use any free port by default
volatile int serverPort = 0;
volatile Exception serverException = null;
volatile Exception clientException = null;
public static void main(String[] args) throws Exception {
if (debug) {
System.setProperty("javax.net.debug", "all");
}
System.out.println("Test args: " + Arrays.toString(args));
// Validate parameters
if (args.length != 4) {
throw new Exception("Invalid number of test parameters");
}
serverAPs = convert(args[0]);
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.
*/
try {
new SSLServerSocketAlpnTest();
} catch (SSLHandshakeException she) {
if (args[3].equals("ERROR")) {
System.out.println("Caught the expected exception: " + she);
} else {
throw she;
}
}
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,
!hasCallback && hasServerAPs) };
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.
*/
private static String[] convert(String list) {
if (list.equals("UNUSED")) {
return null;
}
if (list.equals("EMPTY")) {
return new String[0];
}
String[] strings;
if (list.indexOf(',') > 0) {
strings = list.split(",");
} else {
strings = new String[]{ list };
}
return strings;
}
Thread clientThread = null;
Thread serverThread = null;
/*
* Primary constructor, used to drive remainder of the test.
*
* Fork off the other side, then do your work.
*/
SSLServerSocketAlpnTest() throws Exception {
Exception startException = null;
mySSLContext = getSSLContext(keyFilename, trustFilename);
try {
if (separateServerThread) {
startServer(true);
startClient(false);
} else {
startClient(true);
startServer(false);
}
} catch (Exception e) {
startException = e;
}
/*
* Wait for other side to close down.
*/
if (separateServerThread) {
if (serverThread != null) {
serverThread.join();
}
} else {
if (clientThread != null) {
clientThread.join();
}
}
/*
* When we get here, the test is pretty much over.
* Which side threw the error?
*/
Exception local;
Exception remote;
if (separateServerThread) {
remote = serverException;
local = clientException;
} else {
remote = clientException;
local = serverException;
}
Exception exception = null;
/*
* Check various exception conditions.
*/
if ((local != null) && (remote != null)) {
// If both failed, return the curthread's exception.
local.initCause(remote);
exception = local;
} else if (local != null) {
exception = local;
} else if (remote != null) {
exception = remote;
} else if (startException != null) {
exception = startException;
}
/*
* If there was an exception *AND* a startException,
* output it.
*/
if (exception != null) {
if (exception != startException && startException != null) {
exception.addSuppressed(startException);
}
throw exception;
}
// Fall-through: no exception to throw!
}
void startServer(boolean newThread) throws Exception {
if (newThread) {
serverThread = new Thread() {
@Override
public void run() {
try {
doServerSide();
} catch (Exception e) {
/*
* Our server thread just died.
*
* Release the client, if not active already...
*/
System.err.println("Server died...");
serverReady = true;
serverException = e;
}
}
};
serverThread.start();
} else {
try {
doServerSide();
} catch (Exception e) {
serverException = e;
} finally {
serverReady = true;
}
}
}
void startClient(boolean newThread) throws Exception {
if (newThread) {
clientThread = new Thread() {
@Override
public void run() {
try {
doClientSide();
} catch (Exception e) {
/*
* Our client thread just died.
*/
System.err.println("Client died...");
clientException = e;
}
}
};
clientThread.start();
} else {
try {
doClientSide();
} catch (Exception e) {
clientException = e;
}
}
}
}
/*
* Copyright (c) 2001, 2020, 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.
*/
// SunJSSE does not support dynamic system properties, no way to re-use
// system properties in samevm/agentvm mode.
/*
* @test
* @bug 8051498 8145849 8170282
* @summary JEP 244: TLS Application-Layer Protocol Negotiation Extension
* @compile MyX509ExtendedKeyManager.java
*
* @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.*;
public class SSLSocketAlpnTest {
/*
* =============================================================
* Set the various variables needed for the tests, then
* specify what tests to run on each side.
*/
/*
* Should we run the client or server in a separate thread?
* Both sides can throw exceptions, but do you have a preference
* as to which side should be the main thread.
*/
static boolean separateServerThread = false;
/*
* Where do we find the keystores?
*/
static String pathToStores = "../../../../etc";
static String keyStoreFile = "keystore";
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;
private static boolean hasServerAPs; // whether server APs are present
private static boolean hasCallback; // whether a callback is present
/*
* SSLContext
*/
SSLContext mySSLContext = null;
/*
* Is the server ready to serve?
*/
volatile static boolean serverReady = false;
/*
* Turn on SSL debugging?
*/
static boolean debug = false;
static String[] serverAPs;
static String callbackAP;
static String[] clientAPs;
static String expectedAP;
/*
* 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
* terminate all hung threads after its timeout has expired,
* currently 3 minutes by default, but you might try to be
* smart about it....
*/
/*
* Define the server side of the test.
*
* If the server prematurely exits, serverReady will be set to true
* to avoid infinite hangs.
*/
void doServerSide() throws Exception {
SSLServerSocketFactory sslssf = mySSLContext.getServerSocketFactory();
SSLServerSocket sslServerSocket
= (SSLServerSocket) sslssf.createServerSocket(serverPort);
// for both client/server to call into X509KM
sslServerSocket.setNeedClientAuth(true);
serverPort = sslServerSocket.getLocalPort();
/*
* Signal Client, we're ready for his connect.
*/
serverReady = true;
SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
SSLParameters sslp = sslSocket.getSSLParameters();
/*
* The default ciphersuite ordering from the SSLContext may not
* reflect "h2" ciphersuites as being preferred, additionally the
* client may not send them in an appropriate order. We could resort
* the suite list if so desired.
*/
String[] suites = sslp.getCipherSuites();
sslp.setCipherSuites(suites);
sslp.setUseCipherSuitesOrder(true); // Set server side order
// Set the ALPN selection.
if (serverAPs != null) {
sslp.setApplicationProtocols(serverAPs);
}
sslSocket.setSSLParameters(sslp);
if (sslSocket.getHandshakeApplicationProtocol() != null) {
throw new Exception ("getHandshakeApplicationProtocol() should "
+ "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) {
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");
}
if (expectedAP.equals("NONE")) {
if (!ap.isEmpty()) {
throw new Exception("Expected no ALPN value");
} else {
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");
}
InputStream sslIS = sslSocket.getInputStream();
OutputStream sslOS = sslSocket.getOutputStream();
sslIS.read();
sslOS.write(85);
sslOS.flush();
sslSocket.close();
}
/*
* Define the client side of the test.
*
* If the server prematurely exits, serverReady will be set to true
* to avoid infinite hangs.
*/
void doClientSide() throws Exception {
/*
* Wait for server to get started.
*/
while (!serverReady) {
Thread.sleep(50);
}
SSLSocketFactory sslsf = mySSLContext.getSocketFactory();
SSLSocket sslSocket
= (SSLSocket) sslsf.createSocket("localhost", serverPort);
SSLParameters sslp = sslSocket.getSSLParameters();
/*
* The default ciphersuite ordering from the SSLContext may not
* reflect "h2" ciphersuites as being preferred, additionally the
* client may not send them in an appropriate order. We could resort
* the suite list if so desired.
*/
String[] suites = sslp.getCipherSuites();
sslp.setCipherSuites(suites);
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.
*/
String ap = sslSocket.getApplicationProtocol();
System.out.println("Application Protocol: \"" + ap + "\"");
if (ap == null) {
throw new Exception(
"Handshake was completed but null was received");
}
if (expectedAP.equals("NONE")) {
if (!ap.isEmpty()) {
throw new Exception("Expected no ALPN value");
} else {
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");
}
InputStream sslIS = sslSocket.getInputStream();
OutputStream sslOS = sslSocket.getOutputStream();
sslOS.write(280);
sslOS.flush();
sslIS.read();
sslSocket.close();
}
/*
* =============================================================
* The remainder is just support stuff
*/
// use any free port by default
volatile int serverPort = 0;
volatile Exception serverException = null;
volatile Exception clientException = null;
public static void main(String[] args) throws Exception {
if (debug) {
System.setProperty("javax.net.debug", "all");
}
System.out.println("Test args: " + Arrays.toString(args));
// Validate parameters
if (args.length != 4) {
throw new Exception("Invalid number of test parameters");
}
serverAPs = convert(args[0]);
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.
*/
try {
new SSLSocketAlpnTest();
} catch (SSLHandshakeException she) {
if (args[3].equals("ERROR")) {
System.out.println("Caught the expected exception: " + she);
} else {
throw she;
}
}
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,
!hasCallback && hasServerAPs) };
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.
*/
private static String[] convert(String list) {
if (list.equals("UNUSED")) {
return null;
}
if (list.equals("EMPTY")) {
return new String[0];
}
String[] strings;
if (list.indexOf(',') > 0) {
strings = list.split(",");
} else {
strings = new String[]{ list };
}
return strings;
}
Thread clientThread = null;
Thread serverThread = null;
/*
* Primary constructor, used to drive remainder of the test.
*
* Fork off the other side, then do your work.
*/
SSLSocketAlpnTest() throws Exception {
Exception startException = null;
mySSLContext = getSSLContext(keyFilename, trustFilename);
try {
if (separateServerThread) {
startServer(true);
startClient(false);
} else {
startClient(true);
startServer(false);
}
} catch (Exception e) {
startException = e;
}
/*
* Wait for other side to close down.
*/
if (separateServerThread) {
if (serverThread != null) {
serverThread.join();
}
} else {
if (clientThread != null) {
clientThread.join();
}
}
/*
* When we get here, the test is pretty much over.
* Which side threw the error?
*/
Exception local;
Exception remote;
if (separateServerThread) {
remote = serverException;
local = clientException;
} else {
remote = clientException;
local = serverException;
}
Exception exception = null;
/*
* Check various exception conditions.
*/
if ((local != null) && (remote != null)) {
// If both failed, return the curthread's exception.
local.initCause(remote);
exception = local;
} else if (local != null) {
exception = local;
} else if (remote != null) {
exception = remote;
} else if (startException != null) {
exception = startException;
}
/*
* If there was an exception *AND* a startException,
* output it.
*/
if (exception != null) {
if (exception != startException && startException != null) {
exception.addSuppressed(startException);
}
throw exception;
}
// Fall-through: no exception to throw!
}
void startServer(boolean newThread) throws Exception {
if (newThread) {
serverThread = new Thread() {
@Override
public void run() {
try {
doServerSide();
} catch (Exception e) {
/*
* Our server thread just died.
*
* Release the client, if not active already...
*/
System.err.println("Server died...");
serverReady = true;
serverException = e;
}
}
};
serverThread.start();
} else {
try {
doServerSide();
} catch (Exception e) {
serverException = e;
} finally {
serverReady = true;
}
}
}
void startClient(boolean newThread) throws Exception {
if (newThread) {
clientThread = new Thread() {
@Override
public void run() {
try {
doClientSide();
} catch (Exception e) {
/*
* Our client thread just died.
*/
System.err.println("Client died...");
clientException = e;
}
}
};
clientThread.start();
} else {
try {
doClientSide();
} catch (Exception e) {
clientException = e;
}
}
}
}
/*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2020, 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
......@@ -78,7 +78,7 @@ public class SSLEngineTemplate {
/*
* Enables logging of the SSLEngine operations.
*/
private static boolean logging = true;
private static final boolean logging = true;
/*
* Enables the JSSE system debugging system property:
......@@ -89,9 +89,9 @@ public class SSLEngineTemplate {
* including specific handshake messages, and might be best examined
* after gaining some familiarity with this application.
*/
private static boolean debug = false;
private static final boolean debug = false;
private SSLContext sslc;
private final SSLContext sslc;
private SSLEngine clientEngine; // client Engine
private ByteBuffer clientOut; // write side of clientEngine
......@@ -112,15 +112,15 @@ public class SSLEngineTemplate {
/*
* The following is to set up the keystores.
*/
private static String pathToStores = "../etc";
private static String keyStoreFile = "keystore";
private static String trustStoreFile = "truststore";
private static String passwd = "passphrase";
private static final String pathToStores = "../etc";
private static final String keyStoreFile = "keystore";
private static final String trustStoreFile = "truststore";
private static final String passwd = "passphrase";
private static String keyFilename =
private static final String keyFilename =
System.getProperty("test.src", ".") + "/" + pathToStores +
"/" + keyStoreFile;
private static String trustFilename =
private static final String trustFilename =
System.getProperty("test.src", ".") + "/" + pathToStores +
"/" + trustStoreFile;
......
/*
* Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2020, 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
......@@ -86,7 +86,7 @@ public class SSLSocketSSLEngineTemplate {
/*
* Enables logging of the SSL/TLS operations.
*/
private static boolean logging = true;
private static final boolean logging = true;
/*
* Enables the JSSE system debugging system property:
......@@ -97,8 +97,8 @@ public class SSLSocketSSLEngineTemplate {
* including specific handshake messages, and might be best examined
* after gaining some familiarity with this application.
*/
private static boolean debug = false;
private SSLContext sslc;
private static final boolean debug = false;
private final SSLContext sslc;
private SSLEngine serverEngine; // server-side SSLEngine
private SSLSocket sslSocket; // client-side socket
private ServerSocket serverSocket; // server-side Socket, generates the...
......@@ -128,10 +128,10 @@ public class SSLSocketSSLEngineTemplate {
private static final String keyStoreFile = "keystore";
private static final String trustStoreFile = "truststore";
private static final String passwd = "passphrase";
private static String keyFilename =
private static final String keyFilename =
System.getProperty("test.src", ".") + "/" + pathToStores
+ "/" + keyStoreFile;
private static String trustFilename =
private static final String trustFilename =
System.getProperty("test.src", ".") + "/" + pathToStores
+ "/" + trustStoreFile;
......@@ -239,7 +239,7 @@ public class SSLSocketSSLEngineTemplate {
byte[] outbound = new byte[8192];
while (!isEngineClosed(serverEngine)) {
int len = 0;
int len;
// Inbound data
log("================");
......@@ -307,7 +307,6 @@ public class SSLSocketSSLEngineTemplate {
serverIn.compact();
}
}
return;
} catch (Exception e) {
serverException = e;
} finally {
......@@ -361,13 +360,12 @@ public class SSLSocketSSLEngineTemplate {
int pos = 0;
int len;
done:
while ((len = is.read(inbound, pos, 2048 - pos)) != -1) {
pos += len;
// Let the client do the closing.
if ((pos == serverMsg.length) && !serverClose) {
sslSocket.close();
break done;
break;
}
}
......
/*
* Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 2020, 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
......@@ -33,7 +33,6 @@
*/
import java.io.*;
import java.net.*;
import javax.net.ssl.*;
public class SSLSocketTemplate {
......@@ -162,8 +161,9 @@ public class SSLSocketTemplate {
System.setProperty("javax.net.ssl.trustStore", trustFilename);
System.setProperty("javax.net.ssl.trustStorePassword", passwd);
if (debug)
if (debug) {
System.setProperty("javax.net.debug", "all");
}
/*
* Start the tests.
......@@ -255,6 +255,7 @@ public class SSLSocketTemplate {
void startServer(boolean newThread) throws Exception {
if (newThread) {
serverThread = new Thread() {
@Override
public void run() {
try {
doServerSide();
......@@ -285,6 +286,7 @@ public class SSLSocketTemplate {
void startClient(boolean newThread) throws Exception {
if (newThread) {
clientThread = new Thread() {
@Override
public void run() {
try {
doClientSide();
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册