8196584: TLS 1.3 Implementation

Co-authored-by: Adam Petcher <adam.petcher@oracle.com>
Co-authored-by: Amanda Jiang <amanda.jiang@oracle.com>
Co-authored-by: Anthony Scarpino <anthony.scarpino@oracle.com>
Co-authored-by: Bradford Wetmore <bradford.wetmore@oracle.com>
Co-authored-by: Jamil Nimeh <jamil.j.nimeh@oracle.com>
Co-authored-by: John Jiang <sha.jiang@oracle.com>
Co-authored-by: Rajan Halade <rajan.halade@oracle.com>
Co-authored-by: Sibabrata Sahoo <sibabrata.sahoo@oracle.com>
Co-authored-by: Valerie Peng <valerie.peng@oracle.com>
Co-authored-by: Weijun Wang <weijun.wang@oracle.com>
Reviewed-by: ascarpino, coffeys, dfuchs, jjiang, jnimeh, mullan, rhalade, ssahoo, valeriep, weijun, wetmore, xuelei
This commit is contained in:
Xue-Lei Andrew Fan 2018-06-25 13:41:39 -07:00
parent c7c819cd8b
commit 87c6761704
262 changed files with 44368 additions and 32552 deletions

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 2018, 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
@ -22,36 +22,31 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.ssl;
import java.net.*;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.ArrayList;
import java.math.BigInteger;
import java.net.InetAddress;
import java.security.Principal;
import java.security.PrivateKey;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Queue;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import javax.crypto.SecretKey;
import javax.net.ssl.SSLSessionContext;
import javax.net.ssl.SSLSessionBindingListener;
import javax.net.ssl.SSLSessionBindingEvent;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLPermission;
import javax.net.ssl.ExtendedSSLSession;
import javax.net.ssl.SNIServerName;
import static sun.security.ssl.CipherSuite.KeyExchange.*;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLPermission;
import javax.net.ssl.SSLSessionBindingEvent;
import javax.net.ssl.SSLSessionBindingListener;
import javax.net.ssl.SSLSessionContext;
/**
* Implements the SSL session interface, and exposes the session context
@ -78,9 +73,6 @@ final class SSLSessionImpl extends ExtendedSSLSession {
*/
static final SSLSessionImpl nullSession = new SSLSessionImpl();
// compression methods
private static final byte compression_null = 0;
/*
* The state of a single session, as described in section 7.1
* of the SSLv3 spec.
@ -88,35 +80,37 @@ final class SSLSessionImpl extends ExtendedSSLSession {
private final ProtocolVersion protocolVersion;
private final SessionId sessionId;
private X509Certificate[] peerCerts;
private byte compressionMethod;
private CipherSuite cipherSuite;
private SecretKey masterSecret;
private final boolean useExtendedMasterSecret;
final boolean useExtendedMasterSecret;
/*
* Information not part of the SSLv3 protocol spec, but used
* to support session management policies.
*/
private final long creationTime = System.currentTimeMillis();
private final long creationTime;
private long lastUsedTime = 0;
private final String host;
private final int port;
private SSLSessionContextImpl context;
private int sessionCount;
private boolean invalidated;
private X509Certificate[] localCerts;
private PrivateKey localPrivateKey;
private String[] localSupportedSignAlgs;
private String[] peerSupportedSignAlgs;
private List<SNIServerName> requestedServerNames;
private final String[] localSupportedSignAlgs;
private String[] peerSupportedSignAlgs; // for certificate
private boolean useDefaultPeerSignAlgs = false;
private List<byte[]> statusResponses;
private SecretKey resumptionMasterSecret;
private SecretKey preSharedKey;
private byte[] pskIdentity;
private final long ticketCreationTime = System.currentTimeMillis();
private int ticketAgeAdd;
private int negotiatedMaxFragLen;
private int negotiatedMaxFragLen = -1;
private int maximumPacketSize;
// Principals for non-certificate based cipher suites
private Principal peerPrincipal;
private Principal localPrincipal;
private final Queue<SSLSessionImpl> childSessions =
new ConcurrentLinkedQueue<>();
/*
* Is the session currently re-established with a session-resumption
@ -126,20 +120,17 @@ final class SSLSessionImpl extends ExtendedSSLSession {
*/
private boolean isSessionResumption = false;
/*
* We count session creations, eventually for statistical data but
* also since counters make shorter debugging IDs than the big ones
* we use in the protocol for uniqueness-over-time.
*/
private static volatile int counter;
/*
* Use of session caches is globally enabled/disabled.
*/
private static boolean defaultRejoinable = true;
/* Class and subclass dynamic debugging support */
private static final Debug debug = Debug.getInstance("ssl");
// server name indication
final SNIServerName serverNameIndication;
private final List<SNIServerName> requestedServerNames;
// Counter used to create unique nonces in NewSessionTicket
private BigInteger ticketNonceCounter = BigInteger.ONE;
/*
* Create a new non-rejoinable session, using the default (null)
@ -148,8 +139,16 @@ final class SSLSessionImpl extends ExtendedSSLSession {
* first opened and before handshaking begins.
*/
private SSLSessionImpl() {
this(ProtocolVersion.NONE, CipherSuite.C_NULL, null,
new SessionId(false, null), null, -1, false);
this.protocolVersion = ProtocolVersion.NONE;
this.cipherSuite = CipherSuite.C_NULL;
this.sessionId = new SessionId(false, null);
this.host = null;
this.port = -1;
this.localSupportedSignAlgs = new String[0];
this.serverNameIndication = null;
this.requestedServerNames = Collections.<SNIServerName>emptyList();
this.useExtendedMasterSecret = false;
this.creationTime = System.currentTimeMillis();
}
/*
@ -157,48 +156,81 @@ final class SSLSessionImpl extends ExtendedSSLSession {
* be rejoinable if session caching is enabled; the constructor
* is intended mostly for use by serves.
*/
SSLSessionImpl(ProtocolVersion protocolVersion, CipherSuite cipherSuite,
Collection<SignatureAndHashAlgorithm> algorithms,
SecureRandom generator, String host, int port,
boolean useExtendedMasterSecret) {
this(protocolVersion, cipherSuite, algorithms,
new SessionId(defaultRejoinable, generator), host, port,
useExtendedMasterSecret);
SSLSessionImpl(HandshakeContext hc, CipherSuite cipherSuite) {
this(hc, cipherSuite,
new SessionId(defaultRejoinable, hc.sslContext.getSecureRandom()));
}
/*
* Record a new session, using a given cipher spec and session ID.
*/
SSLSessionImpl(ProtocolVersion protocolVersion, CipherSuite cipherSuite,
Collection<SignatureAndHashAlgorithm> algorithms,
SessionId id, String host, int port,
boolean useExtendedMasterSecret) {
this.protocolVersion = protocolVersion;
sessionId = id;
peerCerts = null;
compressionMethod = compression_null;
this.cipherSuite = cipherSuite;
masterSecret = null;
this.host = host;
this.port = port;
sessionCount = ++counter;
localSupportedSignAlgs =
SignatureAndHashAlgorithm.getAlgorithmNames(algorithms);
negotiatedMaxFragLen = -1;
statusResponses = null;
this.useExtendedMasterSecret = useExtendedMasterSecret;
SSLSessionImpl(HandshakeContext hc, CipherSuite cipherSuite, SessionId id) {
this(hc, cipherSuite, id, System.currentTimeMillis());
}
if (debug != null && Debug.isOn("session")) {
System.out.println("%% Initialized: " + this);
/*
* Record a new session, using a given cipher spec, session ID,
* and creation time
*/
SSLSessionImpl(HandshakeContext hc,
CipherSuite cipherSuite, SessionId id, long creationTime) {
this.protocolVersion = hc.negotiatedProtocol;
this.cipherSuite = cipherSuite;
this.sessionId = id;
this.host = hc.conContext.transport.getPeerHost();
this.port = hc.conContext.transport.getPeerPort();
this.localSupportedSignAlgs =
SignatureScheme.getAlgorithmNames(hc.localSupportedSignAlgs);
this.serverNameIndication = hc.negotiatedServerName;
this.requestedServerNames = Collections.<SNIServerName>unmodifiableList(
hc.getRequestedServerNames());
if (hc.sslConfig.isClientMode) {
this.useExtendedMasterSecret =
(hc.handshakeExtensions.get(
SSLExtension.CH_EXTENDED_MASTER_SECRET) != null) &&
(hc.handshakeExtensions.get(
SSLExtension.SH_EXTENDED_MASTER_SECRET) != null);
} else {
this.useExtendedMasterSecret =
(hc.handshakeExtensions.get(
SSLExtension.CH_EXTENDED_MASTER_SECRET) != null) &&
(!hc.negotiatedProtocol.useTLS13PlusSpec());
}
this.creationTime = creationTime;
if (SSLLogger.isOn && SSLLogger.isOn("session")) {
SSLLogger.finest("Session initialized: " + this);
}
}
void setMasterSecret(SecretKey secret) {
if (masterSecret == null) {
masterSecret = secret;
} else {
throw new RuntimeException("setMasterSecret() error");
}
masterSecret = secret;
}
void setResumptionMasterSecret(SecretKey secret) {
resumptionMasterSecret = secret;
}
void setPreSharedKey(SecretKey key) {
preSharedKey = key;
}
void addChild(SSLSessionImpl session) {
childSessions.add(session);
}
void setTicketAgeAdd(int ticketAgeAdd) {
this.ticketAgeAdd = ticketAgeAdd;
}
void setPskIdentity(byte[] pskIdentity) {
this.pskIdentity = pskIdentity;
}
BigInteger incrTicketNonceCounter() {
BigInteger result = ticketNonceCounter;
ticketNonceCounter = ticketNonceCounter.add(BigInteger.valueOf(1));
return result;
}
/**
@ -208,8 +240,39 @@ final class SSLSessionImpl extends ExtendedSSLSession {
return masterSecret;
}
boolean getUseExtendedMasterSecret() {
return useExtendedMasterSecret;
Optional<SecretKey> getResumptionMasterSecret() {
return Optional.ofNullable(resumptionMasterSecret);
}
synchronized Optional<SecretKey> getPreSharedKey() {
return Optional.ofNullable(preSharedKey);
}
synchronized Optional<SecretKey> consumePreSharedKey() {
Optional<SecretKey> result = Optional.ofNullable(preSharedKey);
preSharedKey = null;
return result;
}
int getTicketAgeAdd() {
return ticketAgeAdd;
}
/*
* Get the PSK identity. Take care not to use it in multiple connections.
*/
synchronized Optional<byte[]> getPskIdentity() {
return Optional.ofNullable(pskIdentity);
}
/* PSK identities created from new_session_ticket messages should only
* be used once. This method will return the identity and then clear it
* so it cannot be used again.
*/
synchronized Optional<byte[]> consumePskIdentity() {
Optional<byte[]> result = Optional.ofNullable(pskIdentity);
pskIdentity = null;
return result;
}
void setPeerCertificates(X509Certificate[] peer) {
@ -227,13 +290,35 @@ final class SSLSessionImpl extends ExtendedSSLSession {
}
void setPeerSupportedSignatureAlgorithms(
Collection<SignatureAndHashAlgorithm> algorithms) {
Collection<SignatureScheme> signatureSchemes) {
peerSupportedSignAlgs =
SignatureAndHashAlgorithm.getAlgorithmNames(algorithms);
SignatureScheme.getAlgorithmNames(signatureSchemes);
}
void setRequestedServerNames(List<SNIServerName> requestedServerNames) {
this.requestedServerNames = new ArrayList<>(requestedServerNames);
// TLS 1.2 only
//
// Per RFC 5246, If the client supports only the default hash
// and signature algorithms, it MAY omit the
// signature_algorithms extension. If the client does not
// support the default algorithms, or supports other hash
// and signature algorithms (and it is willing to use them
// for verifying messages sent by the server, i.e., server
// certificates and server key exchange), it MUST send the
// signature_algorithms extension, listing the algorithms it
// is willing to accept.
void setUseDefaultPeerSignAlgs() {
useDefaultPeerSignAlgs = true;
peerSupportedSignAlgs = new String[] {
"SHA1withRSA", "SHA1withDSA", "SHA1withECDSA"};
}
// Returns the connection session.
SSLSessionImpl finish() {
if (useDefaultPeerSignAlgs) {
this.peerSupportedSignAlgs = new String[0];
}
return this;
}
/**
@ -249,22 +334,6 @@ final class SSLSessionImpl extends ExtendedSSLSession {
}
}
/**
* Set the peer principal.
*/
void setPeerPrincipal(Principal principal) {
if (peerPrincipal == null) {
peerPrincipal = principal;
}
}
/**
* Set the local principal.
*/
void setLocalPrincipal(Principal principal) {
localPrincipal = principal;
}
/**
* Returns true iff this session may be resumed ... sessions are
* usually resumable. Security policies may suggest otherwise,
@ -286,7 +355,7 @@ final class SSLSessionImpl extends ExtendedSSLSession {
* Check if the authentication used when establishing this session
* is still valid. Returns true if no authentication was used
*/
boolean isLocalAuthenticationValid() {
private boolean isLocalAuthenticationValid() {
if (localPrivateKey != null) {
try {
// if the private key is no longer valid, getAlgorithm()
@ -298,6 +367,7 @@ final class SSLSessionImpl extends ExtendedSSLSession {
return false;
}
}
return true;
}
@ -354,8 +424,8 @@ final class SSLSessionImpl extends ExtendedSSLSession {
void setSuite(CipherSuite suite) {
cipherSuite = suite;
if (debug != null && Debug.isOn("session")) {
System.out.println("%% Negotiating: " + this);
if (SSLLogger.isOn && SSLLogger.isOn("session")) {
SSLLogger.finest("Negotiating session: " + this);
}
}
@ -395,13 +465,6 @@ final class SSLSessionImpl extends ExtendedSSLSession {
return getProtocolVersion().name;
}
/**
* Returns the compression technique used in this session
*/
byte getCompression() {
return compressionMethod;
}
/**
* Returns the hashcode for this session
*/
@ -410,7 +473,6 @@ final class SSLSessionImpl extends ExtendedSSLSession {
return sessionId.hashCode();
}
/**
* Returns true if sessions have same ids, false otherwise.
*/
@ -435,8 +497,8 @@ final class SSLSessionImpl extends ExtendedSSLSession {
* Return the cert chain presented by the peer in the
* java.security.cert format.
* Note: This method can be used only when using certificate-based
* cipher suites; using it with non-certificate-based cipher suites,
* such as Kerberos, will throw an SSLPeerUnverifiedException.
* cipher suites; using it with non-certificate-based cipher suites
* will throw an SSLPeerUnverifiedException.
*
* @return array of peer X.509 certs, with the peer's own cert
* first in the chain, and with the "root" CA last.
@ -449,10 +511,6 @@ final class SSLSessionImpl extends ExtendedSSLSession {
// change record of peer identity even by accident, much
// less do it intentionally.
//
if (ClientKeyExchangeService.find(cipherSuite.keyExchange.name) != null) {
throw new SSLPeerUnverifiedException("no certificates expected"
+ " for " + cipherSuite.keyExchange + " cipher suites");
}
if (peerCerts == null) {
throw new SSLPeerUnverifiedException("peer not authenticated");
}
@ -485,8 +543,8 @@ final class SSLSessionImpl extends ExtendedSSLSession {
* Return the cert chain presented by the peer in the
* javax.security.cert format.
* Note: This method can be used only when using certificate-based
* cipher suites; using it with non-certificate-based cipher suites,
* such as Kerberos, will throw an SSLPeerUnverifiedException.
* cipher suites; using it with non-certificate-based cipher suites
* will throw an SSLPeerUnverifiedException.
*
* @return array of peer X.509 certs, with the peer's own cert
* first in the chain, and with the "root" CA last.
@ -504,10 +562,6 @@ final class SSLSessionImpl extends ExtendedSSLSession {
// change record of peer identity even by accident, much
// less do it intentionally.
//
if (ClientKeyExchangeService.find(cipherSuite.keyExchange.name) != null) {
throw new SSLPeerUnverifiedException("no certificates expected"
+ " for " + cipherSuite.keyExchange + " cipher suites");
}
if (peerCerts == null) {
throw new SSLPeerUnverifiedException("peer not authenticated");
}
@ -531,8 +585,8 @@ final class SSLSessionImpl extends ExtendedSSLSession {
/**
* Return the cert chain presented by the peer.
* Note: This method can be used only when using certificate-based
* cipher suites; using it with non-certificate-based cipher suites,
* such as Kerberos, will throw an SSLPeerUnverifiedException.
* cipher suites; using it with non-certificate-based cipher suites
* will throw an SSLPeerUnverifiedException.
*
* @return array of peer X.509 certs, with the peer's own cert
* first in the chain, and with the "root" CA last.
@ -544,10 +598,6 @@ final class SSLSessionImpl extends ExtendedSSLSession {
* change record of peer identity even by accident, much
* less do it intentionally.
*/
if (ClientKeyExchangeService.find(cipherSuite.keyExchange.name) != null) {
throw new SSLPeerUnverifiedException("no certificates expected"
+ " for " + cipherSuite.keyExchange + " cipher suites");
}
if (peerCerts != null) {
return peerCerts.clone();
} else {
@ -584,8 +634,7 @@ final class SSLSessionImpl extends ExtendedSSLSession {
* defining the session.
*
* @return the peer's principal. Returns an X500Principal of the
* end-entity certificate for X509-based cipher suites, and
* Principal for Kerberos cipher suites, etc.
* end-entity certificate for X509-based cipher suites.
*
* @throws SSLPeerUnverifiedException if the peer's identity has not
* been verified
@ -594,13 +643,6 @@ final class SSLSessionImpl extends ExtendedSSLSession {
public Principal getPeerPrincipal()
throws SSLPeerUnverifiedException
{
if (ClientKeyExchangeService.find(cipherSuite.keyExchange.name) != null) {
if (peerPrincipal == null) {
throw new SSLPeerUnverifiedException("peer not authenticated");
} else {
return peerPrincipal;
}
}
if (peerCerts == null) {
throw new SSLPeerUnverifiedException("peer not authenticated");
}
@ -611,20 +653,22 @@ final class SSLSessionImpl extends ExtendedSSLSession {
* Returns the principal that was sent to the peer during handshaking.
*
* @return the principal sent to the peer. Returns an X500Principal
* of the end-entity certificate for X509-based cipher suites, and
* Principal for Kerberos cipher suites, etc. If no principal was
* sent, then null is returned.
* of the end-entity certificate for X509-based cipher suites.
* If no principal was sent, then null is returned.
*/
@Override
public Principal getLocalPrincipal() {
if (ClientKeyExchangeService.find(cipherSuite.keyExchange.name) != null) {
return (localPrincipal == null ? null : localPrincipal);
}
return (localCerts == null ? null :
return ((localCerts == null && localCerts.length != 0) ? null :
localCerts[0].getSubjectX500Principal());
}
/*
* Return the time the ticket for this session was created.
*/
public long getTicketCreationTime() {
return ticketCreationTime;
}
/**
* Returns the time this session was created.
*/
@ -695,14 +739,21 @@ final class SSLSessionImpl extends ExtendedSSLSession {
if (this == nullSession) {
return;
}
invalidated = true;
if (debug != null && Debug.isOn("session")) {
System.out.println("%% Invalidated: " + this);
}
if (context != null) {
context.remove(sessionId);
context = null;
}
if (invalidated) {
return;
}
invalidated = true;
if (SSLLogger.isOn && SSLLogger.isOn("session")) {
SSLLogger.finest("Invalidated session: " + this);
}
for (SSLSessionImpl child : childSessions) {
child.invalidate();
}
}
/*
@ -710,7 +761,8 @@ final class SSLSessionImpl extends ExtendedSSLSession {
* key and the calling security context. This is important since
* sessions can be shared across different protection domains.
*/
private Hashtable<SecureKey, Object> table = new Hashtable<>();
private final ConcurrentHashMap<SecureKey, Object> boundValues =
new ConcurrentHashMap<>();
/**
* Assigns a session value. Session change events are given if
@ -723,7 +775,7 @@ final class SSLSessionImpl extends ExtendedSSLSession {
}
SecureKey secureKey = new SecureKey(key);
Object oldValue = table.put(secureKey, value);
Object oldValue = boundValues.put(secureKey, value);
if (oldValue instanceof SSLSessionBindingListener) {
SSLSessionBindingEvent e;
@ -739,7 +791,6 @@ final class SSLSessionImpl extends ExtendedSSLSession {
}
}
/**
* Returns the specified session value.
*/
@ -750,7 +801,7 @@ final class SSLSessionImpl extends ExtendedSSLSession {
}
SecureKey secureKey = new SecureKey(key);
return table.get(secureKey);
return boundValues.get(secureKey);
}
@ -765,7 +816,7 @@ final class SSLSessionImpl extends ExtendedSSLSession {
}
SecureKey secureKey = new SecureKey(key);
Object value = table.remove(secureKey);
Object value = boundValues.remove(secureKey);
if (value instanceof SSLSessionBindingListener) {
SSLSessionBindingEvent e;
@ -781,22 +832,17 @@ final class SSLSessionImpl extends ExtendedSSLSession {
*/
@Override
public String[] getValueNames() {
Enumeration<SecureKey> e;
Vector<Object> v = new Vector<>();
SecureKey key;
ArrayList<Object> v = new ArrayList<>();
Object securityCtx = SecureKey.getCurrentSecurityContext();
for (e = table.keys(); e.hasMoreElements(); ) {
key = e.nextElement();
for (Enumeration<SecureKey> e = boundValues.keys();
e.hasMoreElements(); ) {
SecureKey key = e.nextElement();
if (securityCtx.equals(key.getSecurityContext())) {
v.addElement(key.getAppKey());
v.add(key.getAppKey());
}
}
String[] names = new String[v.size()];
v.copyInto(names);
return names;
return v.toArray(new String[0]);
}
/**
@ -813,7 +859,8 @@ final class SSLSessionImpl extends ExtendedSSLSession {
* to "true".
*/
private boolean acceptLargeFragments =
Debug.getBooleanProperty("jsse.SSLEngine.acceptLargeFragments", false);
Utilities.getBooleanProperty(
"jsse.SSLEngine.acceptLargeFragments", false);
/**
* Expand the buffer size of both SSL/TLS network packet and
@ -835,7 +882,7 @@ final class SSLSessionImpl extends ExtendedSSLSession {
if (negotiatedMaxFragLen > 0) {
packetSize = cipherSuite.calculatePacketSize(
negotiatedMaxFragLen, protocolVersion,
protocolVersion.isDTLSProtocol());
protocolVersion.isDTLS);
}
if (maximumPacketSize > 0) {
@ -847,7 +894,7 @@ final class SSLSessionImpl extends ExtendedSSLSession {
return packetSize;
}
if (protocolVersion.isDTLSProtocol()) {
if (protocolVersion.isDTLS) {
return DTLSRecord.maxRecordSize;
} else {
return acceptLargeFragments ?
@ -867,7 +914,7 @@ final class SSLSessionImpl extends ExtendedSSLSession {
if (maximumPacketSize > 0) {
fragmentSize = cipherSuite.calculateFragSize(
maximumPacketSize, protocolVersion,
protocolVersion.isDTLSProtocol());
protocolVersion.isDTLS);
}
if (negotiatedMaxFragLen > 0) {
@ -879,7 +926,7 @@ final class SSLSessionImpl extends ExtendedSSLSession {
return fragmentSize;
}
if (protocolVersion.isDTLSProtocol()) {
if (protocolVersion.isDTLS) {
return Record.maxDataSize;
} else {
int maxPacketSize = acceptLargeFragments ?
@ -953,33 +1000,24 @@ final class SSLSessionImpl extends ExtendedSSLSession {
*/
@Override
public List<SNIServerName> getRequestedServerNames() {
if (requestedServerNames != null && !requestedServerNames.isEmpty()) {
return Collections.<SNIServerName>unmodifiableList(
requestedServerNames);
}
return Collections.<SNIServerName>emptyList();
return requestedServerNames;
}
/** Returns a string representation of this SSL session */
@Override
public String toString() {
return "[Session-" + sessionCount
+ ", " + getCipherSuite()
+ "]";
return "Session(" + creationTime + "|" + getCipherSuite() + ")";
}
}
/**
* This "struct" class serves as a Hash Key that combines an
* application-specific key and a security context.
*/
class SecureKey {
private static Object nullObject = new Object();
private Object appKey;
private Object securityCtx;
private static final Object nullObject = new Object();
private final Object appKey;
private final Object securityCtx;
static Object getCurrentSecurityContext() {
SecurityManager sm = System.getSecurityManager();