mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 06:45:07 +02:00
8206929: Check session context for TLS 1.3 session resumption
Additional checks to prevent TLS 1.3 sessions from being resumed when they shouldn't Reviewed-by: xuelei
This commit is contained in:
parent
2c82c9e1bd
commit
108461949f
5 changed files with 676 additions and 18 deletions
|
@ -27,6 +27,7 @@ package sun.security.ssl;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -46,6 +47,9 @@ final class PostHandshakeContext extends HandshakeContext {
|
|||
"Post-handshake not supported in " + negotiatedProtocol.name);
|
||||
}
|
||||
|
||||
this.localSupportedSignAlgs = new ArrayList<SignatureScheme>(
|
||||
context.conSession.getLocalSupportedSignatureSchemes());
|
||||
|
||||
handshakeConsumers = new LinkedHashMap<>(consumers);
|
||||
handshakeFinished = true;
|
||||
}
|
||||
|
|
|
@ -33,8 +33,11 @@ import java.util.ArrayList;
|
|||
import java.util.Locale;
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
import java.util.Collection;
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.net.ssl.SSLPeerUnverifiedException;
|
||||
import static sun.security.ssl.ClientAuthType.CLIENT_AUTH_REQUIRED;
|
||||
import sun.security.ssl.ClientHello.ClientHelloMessage;
|
||||
import sun.security.ssl.SSLExtension.ExtensionConsumer;
|
||||
import sun.security.ssl.SSLExtension.SSLExtensionSpec;
|
||||
|
@ -167,7 +170,7 @@ final class PreSharedKeyExtension {
|
|||
|
||||
int getIdsEncodedLength() {
|
||||
int idEncodedLength = 0;
|
||||
for(PskIdentity curId : identities) {
|
||||
for (PskIdentity curId : identities) {
|
||||
idEncodedLength += curId.getEncodedLength();
|
||||
}
|
||||
|
||||
|
@ -190,7 +193,7 @@ final class PreSharedKeyExtension {
|
|||
byte[] buffer = new byte[encodedLength];
|
||||
ByteBuffer m = ByteBuffer.wrap(buffer);
|
||||
Record.putInt16(m, idsEncodedLength);
|
||||
for(PskIdentity curId : identities) {
|
||||
for (PskIdentity curId : identities) {
|
||||
curId.writeEncoded(m);
|
||||
}
|
||||
Record.putInt16(m, bindersEncodedLength);
|
||||
|
@ -220,7 +223,7 @@ final class PreSharedKeyExtension {
|
|||
|
||||
String identitiesString() {
|
||||
StringBuilder result = new StringBuilder();
|
||||
for(PskIdentity curId : identities) {
|
||||
for (PskIdentity curId : identities) {
|
||||
result.append(curId.toString() + "\n");
|
||||
}
|
||||
|
||||
|
@ -229,7 +232,7 @@ final class PreSharedKeyExtension {
|
|||
|
||||
String bindersString() {
|
||||
StringBuilder result = new StringBuilder();
|
||||
for(byte[] curBinder : binders) {
|
||||
for (byte[] curBinder : binders) {
|
||||
result.append("{" + Utilities.toHexString(curBinder) + "}\n");
|
||||
}
|
||||
|
||||
|
@ -328,6 +331,7 @@ final class PreSharedKeyExtension {
|
|||
public void consume(ConnectionContext context,
|
||||
HandshakeMessage message,
|
||||
ByteBuffer buffer) throws IOException {
|
||||
ClientHelloMessage clientHello = (ClientHelloMessage) message;
|
||||
ServerHandshakeContext shc = (ServerHandshakeContext)context;
|
||||
// Is it a supported and enabled extension?
|
||||
if (!shc.sslConfig.isAvailable(SSLExtension.CH_PRE_SHARED_KEY)) {
|
||||
|
@ -367,8 +371,7 @@ final class PreSharedKeyExtension {
|
|||
int idIndex = 0;
|
||||
for (PskIdentity requestedId : pskSpec.identities) {
|
||||
SSLSessionImpl s = sessionCache.get(requestedId.identity);
|
||||
if (s != null && s.isRejoinable() &&
|
||||
s.getPreSharedKey().isPresent()) {
|
||||
if (s != null && canRejoin(clientHello, shc, s)) {
|
||||
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
|
||||
SSLLogger.fine("Resuming session: ", s);
|
||||
}
|
||||
|
@ -392,10 +395,68 @@ final class PreSharedKeyExtension {
|
|||
|
||||
// update the context
|
||||
shc.handshakeExtensions.put(
|
||||
SSLExtension.CH_PRE_SHARED_KEY, pskSpec);
|
||||
SSLExtension.CH_PRE_SHARED_KEY, pskSpec);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean canRejoin(ClientHelloMessage clientHello,
|
||||
ServerHandshakeContext shc, SSLSessionImpl s) {
|
||||
|
||||
boolean result = s.isRejoinable() && s.getPreSharedKey().isPresent();
|
||||
|
||||
// Check protocol version
|
||||
if (result && s.getProtocolVersion() != shc.negotiatedProtocol) {
|
||||
if (SSLLogger.isOn &&
|
||||
SSLLogger.isOn("ssl,handshake,verbose")) {
|
||||
|
||||
SSLLogger.finest("Can't resume, incorrect protocol version");
|
||||
}
|
||||
result = false;
|
||||
}
|
||||
|
||||
// Validate the required client authentication.
|
||||
if (result &&
|
||||
(shc.sslConfig.clientAuthType == CLIENT_AUTH_REQUIRED)) {
|
||||
try {
|
||||
s.getPeerPrincipal();
|
||||
} catch (SSLPeerUnverifiedException e) {
|
||||
if (SSLLogger.isOn &&
|
||||
SSLLogger.isOn("ssl,handshake,verbose")) {
|
||||
SSLLogger.finest(
|
||||
"Can't resume, " +
|
||||
"client authentication is required");
|
||||
}
|
||||
result = false;
|
||||
}
|
||||
|
||||
// Make sure the list of supported signature algorithms matches
|
||||
Collection<SignatureScheme> sessionSigAlgs =
|
||||
s.getLocalSupportedSignatureSchemes();
|
||||
if (result &&
|
||||
!shc.localSupportedSignAlgs.containsAll(sessionSigAlgs)) {
|
||||
|
||||
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
|
||||
SSLLogger.fine("Can't resume. Session uses different " +
|
||||
"signature algorithms");
|
||||
}
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure cipher suite can be negotiated
|
||||
if (result && (!shc.isNegotiable(s.getSuite()) ||
|
||||
!clientHello.cipherSuites.contains(s.getSuite()))) {
|
||||
if (SSLLogger.isOn &&
|
||||
SSLLogger.isOn("ssl,handshake,verbose")) {
|
||||
SSLLogger.finest(
|
||||
"Can't resume, unavailable session cipher suite");
|
||||
}
|
||||
result = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static final
|
||||
class CHPreSharedKeyUpdate implements HandshakeConsumer {
|
||||
// Prevent instantiation of this class.
|
||||
|
@ -547,6 +608,18 @@ final class PreSharedKeyExtension {
|
|||
return null;
|
||||
}
|
||||
|
||||
// Make sure the list of supported signature algorithms matches
|
||||
Collection<SignatureScheme> sessionSigAlgs =
|
||||
chc.resumingSession.getLocalSupportedSignatureSchemes();
|
||||
if (!chc.localSupportedSignAlgs.containsAll(sessionSigAlgs)) {
|
||||
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
|
||||
SSLLogger.fine("Existing session uses different " +
|
||||
"signature algorithms");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// The session must have a pre-shared key
|
||||
Optional<SecretKey> pskOpt = chc.resumingSession.getPreSharedKey();
|
||||
if (!pskOpt.isPresent()) {
|
||||
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
|
||||
|
@ -658,7 +731,7 @@ final class PreSharedKeyExtension {
|
|||
} catch (NoSuchAlgorithmException | InvalidKeyException ex) {
|
||||
throw new IOException(ex);
|
||||
}
|
||||
} catch(GeneralSecurityException ex) {
|
||||
} catch (GeneralSecurityException ex) {
|
||||
throw new IOException(ex);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -96,7 +96,7 @@ final class SSLSessionImpl extends ExtendedSSLSession {
|
|||
private boolean invalidated;
|
||||
private X509Certificate[] localCerts;
|
||||
private PrivateKey localPrivateKey;
|
||||
private final String[] localSupportedSignAlgs;
|
||||
private final Collection<SignatureScheme> localSupportedSignAlgs;
|
||||
private String[] peerSupportedSignAlgs; // for certificate
|
||||
private boolean useDefaultPeerSignAlgs = false;
|
||||
private List<byte[]> statusResponses;
|
||||
|
@ -144,7 +144,7 @@ final class SSLSessionImpl extends ExtendedSSLSession {
|
|||
this.sessionId = new SessionId(false, null);
|
||||
this.host = null;
|
||||
this.port = -1;
|
||||
this.localSupportedSignAlgs = new String[0];
|
||||
this.localSupportedSignAlgs = Collections.emptySet();
|
||||
this.serverNameIndication = null;
|
||||
this.requestedServerNames = Collections.<SNIServerName>emptyList();
|
||||
this.useExtendedMasterSecret = false;
|
||||
|
@ -179,8 +179,9 @@ final class SSLSessionImpl extends ExtendedSSLSession {
|
|||
this.sessionId = id;
|
||||
this.host = hc.conContext.transport.getPeerHost();
|
||||
this.port = hc.conContext.transport.getPeerPort();
|
||||
this.localSupportedSignAlgs =
|
||||
SignatureScheme.getAlgorithmNames(hc.localSupportedSignAlgs);
|
||||
this.localSupportedSignAlgs = hc.localSupportedSignAlgs == null ?
|
||||
Collections.emptySet() :
|
||||
Collections.unmodifiableCollection(hc.localSupportedSignAlgs);
|
||||
this.serverNameIndication = hc.negotiatedServerName;
|
||||
this.requestedServerNames = Collections.<SNIServerName>unmodifiableList(
|
||||
hc.getRequestedServerNames());
|
||||
|
@ -969,16 +970,20 @@ final class SSLSessionImpl extends ExtendedSSLSession {
|
|||
}
|
||||
|
||||
/**
|
||||
* Gets an array of supported signature algorithms that the local side is
|
||||
* willing to verify.
|
||||
* Gets an array of supported signature algorithm names that the local
|
||||
* side is willing to verify.
|
||||
*/
|
||||
@Override
|
||||
public String[] getLocalSupportedSignatureAlgorithms() {
|
||||
if (localSupportedSignAlgs != null) {
|
||||
return localSupportedSignAlgs.clone();
|
||||
}
|
||||
return SignatureScheme.getAlgorithmNames(localSupportedSignAlgs);
|
||||
}
|
||||
|
||||
return new String[0];
|
||||
/**
|
||||
* Gets an array of supported signature schemes that the local side is
|
||||
* willing to verify.
|
||||
*/
|
||||
public Collection<SignatureScheme> getLocalSupportedSignatureSchemes() {
|
||||
return localSupportedSignAlgs;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue