This commit is contained in:
Henry Jen 2020-04-14 23:11:49 +00:00
commit 0278846eaa
91 changed files with 1073 additions and 416 deletions

View file

@ -265,7 +265,7 @@ enum Alert {
// It's OK to get a no_certificate alert from a client of
// which we requested client authentication. However,
// if we required it, then this is not acceptable.
if (tc.sslConfig.isClientMode ||
if (tc.sslConfig.isClientMode ||
alert != Alert.NO_CERTIFICATE ||
(tc.sslConfig.clientAuthType !=
ClientAuthType.CLIENT_AUTH_REQUESTED)) {
@ -273,8 +273,10 @@ enum Alert {
"received handshake warning: " + alert.description);
} else {
// Otherwise ignore the warning but remove the
// CertificateVerify handshake consumer so the state
// machine doesn't expect it.
// Certificate and CertificateVerify handshake
// consumer so the state machine doesn't expect it.
tc.handshakeContext.handshakeConsumers.remove(
SSLHandshake.CERTIFICATE.id);
tc.handshakeContext.handshakeConsumers.remove(
SSLHandshake.CERTIFICATE_VERIFY.id);
}

View file

@ -406,7 +406,7 @@ final class ClientHello {
ProtocolVersion maxProtocolVersion = chc.maximumActiveProtocol;
// session ID of the ClientHello message
SessionId sessionId = SSLSessionImpl.nullSession.getSessionId();
SessionId sessionId = new SessionId(new byte[0]);
// a list of cipher suites sent by the client
List<CipherSuite> cipherSuites = chc.activeCipherSuites;

View file

@ -90,6 +90,16 @@ final class ClientKeyExchange {
ServerHandshakeContext shc = (ServerHandshakeContext)context;
// clean up this consumer
shc.handshakeConsumers.remove(SSLHandshake.CLIENT_KEY_EXCHANGE.id);
// Check for an unprocessed client Certificate message. If that
// handshake consumer is still present then that expected message
// was not sent.
if (shc.handshakeConsumers.containsKey(
SSLHandshake.CERTIFICATE.id)) {
throw shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
"Unexpected ClientKeyExchange handshake message.");
}
SSLKeyExchange ke = SSLKeyExchange.valueOf(
shc.negotiatedCipherSuite.keyExchange,
shc.negotiatedProtocol);

View file

@ -897,6 +897,8 @@ final class Finished {
// has been received and processed.
if (!chc.isResumption) {
if (chc.handshakeConsumers.containsKey(
SSLHandshake.CERTIFICATE.id) ||
chc.handshakeConsumers.containsKey(
SSLHandshake.CERTIFICATE_VERIFY.id)) {
throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
"Unexpected Finished handshake message");
@ -1029,6 +1031,8 @@ final class Finished {
// has been received and processed.
if (!shc.isResumption) {
if (shc.handshakeConsumers.containsKey(
SSLHandshake.CERTIFICATE.id) ||
shc.handshakeConsumers.containsKey(
SSLHandshake.CERTIFICATE_VERIFY.id)) {
throw shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
"Unexpected Finished handshake message");

View file

@ -164,8 +164,10 @@ abstract class HandshakeContext implements ConnectionContext {
this.conContext = conContext;
this.sslConfig = (SSLConfiguration)conContext.sslConfig.clone();
this.algorithmConstraints = new SSLAlgorithmConstraints(
sslConfig.userSpecifiedAlgorithmConstraints);
this.activeProtocols = getActiveProtocols(sslConfig.enabledProtocols,
sslConfig.enabledCipherSuites, sslConfig.algorithmConstraints);
sslConfig.enabledCipherSuites, algorithmConstraints);
if (activeProtocols.isEmpty()) {
throw new SSLHandshakeException(
"No appropriate protocol (protocol is disabled or " +
@ -181,12 +183,10 @@ abstract class HandshakeContext implements ConnectionContext {
}
this.maximumActiveProtocol = maximumVersion;
this.activeCipherSuites = getActiveCipherSuites(this.activeProtocols,
sslConfig.enabledCipherSuites, sslConfig.algorithmConstraints);
sslConfig.enabledCipherSuites, algorithmConstraints);
if (activeCipherSuites.isEmpty()) {
throw new SSLHandshakeException("No appropriate cipher suite");
}
this.algorithmConstraints =
new SSLAlgorithmConstraints(sslConfig.algorithmConstraints);
this.handshakeConsumers = new LinkedHashMap<>();
this.handshakeProducers = new HashMap<>();
@ -209,7 +209,7 @@ abstract class HandshakeContext implements ConnectionContext {
/**
* Constructor for PostHandshakeContext
*/
HandshakeContext(TransportContext conContext) {
protected HandshakeContext(TransportContext conContext) {
this.sslContext = conContext.sslContext;
this.conContext = conContext;
this.sslConfig = conContext.sslConfig;
@ -219,6 +219,7 @@ abstract class HandshakeContext implements ConnectionContext {
this.handshakeOutput = new HandshakeOutStream(conContext.outputRecord);
this.delegatedActions = new LinkedList<>();
this.handshakeConsumers = new LinkedHashMap<>();
this.handshakeProducers = null;
this.handshakeHash = null;
this.activeProtocols = null;

View file

@ -336,7 +336,7 @@ final class KeyShareExtension {
for (KeyShareEntry entry : spec.clientShares) {
NamedGroup ng = NamedGroup.valueOf(entry.namedGroupId);
if (ng == null || !SupportedGroups.isActivatable(
shc.sslConfig.algorithmConstraints, ng)) {
shc.algorithmConstraints, ng)) {
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
SSLLogger.fine(
"Ignore unsupported named group: " +
@ -620,7 +620,7 @@ final class KeyShareExtension {
KeyShareEntry keyShare = spec.serverShare;
NamedGroup ng = NamedGroup.valueOf(keyShare.namedGroupId);
if (ng == null || !SupportedGroups.isActivatable(
chc.sslConfig.algorithmConstraints, ng)) {
chc.algorithmConstraints, ng)) {
throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
"Unsupported named group: " +
NamedGroup.nameOf(keyShare.namedGroupId));
@ -762,7 +762,7 @@ final class KeyShareExtension {
NamedGroup selectedGroup = null;
for (NamedGroup ng : shc.clientRequestedNamedGroups) {
if (SupportedGroups.isActivatable(
shc.sslConfig.algorithmConstraints, ng)) {
shc.algorithmConstraints, ng)) {
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
SSLLogger.fine(
"HelloRetryRequest selected named group: " +

View file

@ -30,17 +30,11 @@ import java.nio.BufferOverflowException;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* A compact implementation of HandshakeContext for post-handshake messages
*/
final class PostHandshakeContext extends HandshakeContext {
private final static Map<Byte, SSLConsumer> consumers = Map.of(
SSLHandshake.KEY_UPDATE.id, SSLHandshake.KEY_UPDATE,
SSLHandshake.NEW_SESSION_TICKET.id, SSLHandshake.NEW_SESSION_TICKET);
PostHandshakeContext(TransportContext context) throws IOException {
super(context);
@ -49,10 +43,23 @@ final class PostHandshakeContext extends HandshakeContext {
"Post-handshake not supported in " + negotiatedProtocol.name);
}
this.localSupportedSignAlgs = new ArrayList<SignatureScheme>(
this.localSupportedSignAlgs = new ArrayList<>(
context.conSession.getLocalSupportedSignatureSchemes());
handshakeConsumers = new LinkedHashMap<>(consumers);
// Add the potential post-handshake consumers.
if (context.sslConfig.isClientMode) {
handshakeConsumers.putIfAbsent(
SSLHandshake.KEY_UPDATE.id,
SSLHandshake.KEY_UPDATE);
handshakeConsumers.putIfAbsent(
SSLHandshake.NEW_SESSION_TICKET.id,
SSLHandshake.NEW_SESSION_TICKET);
} else {
handshakeConsumers.putIfAbsent(
SSLHandshake.KEY_UPDATE.id,
SSLHandshake.KEY_UPDATE);
}
handshakeFinished = true;
handshakeSession = context.conSession;
}
@ -83,4 +90,21 @@ final class PostHandshakeContext extends HandshakeContext {
SSLHandshake.nameOf(handshakeType), be);
}
}
static boolean isConsumable(TransportContext context, byte handshakeType) {
if (handshakeType == SSLHandshake.KEY_UPDATE.id) {
// The KeyUpdate handshake message does not apply to TLS 1.2 and
// previous protocols.
return context.protocolVersion.useTLS13PlusSpec();
}
if (handshakeType == SSLHandshake.NEW_SESSION_TICKET.id) {
// The new session ticket handshake message could be consumer in
// client side only.
return context.sslConfig.isClientMode;
}
// No more post-handshake message supported currently.
return false;
}
}

View file

@ -71,21 +71,21 @@ final class SSLAlgorithmConstraints implements AlgorithmConstraints {
SSLAlgorithmConstraints(SSLSocket socket,
boolean withDefaultCertPathConstraints) {
this.userSpecifiedConstraints = getConstraints(socket);
this.userSpecifiedConstraints = getUserSpecifiedConstraints(socket);
this.peerSpecifiedConstraints = null;
this.enabledX509DisabledAlgConstraints = withDefaultCertPathConstraints;
}
SSLAlgorithmConstraints(SSLEngine engine,
boolean withDefaultCertPathConstraints) {
this.userSpecifiedConstraints = getConstraints(engine);
this.userSpecifiedConstraints = getUserSpecifiedConstraints(engine);
this.peerSpecifiedConstraints = null;
this.enabledX509DisabledAlgConstraints = withDefaultCertPathConstraints;
}
SSLAlgorithmConstraints(SSLSocket socket, String[] supportedAlgorithms,
boolean withDefaultCertPathConstraints) {
this.userSpecifiedConstraints = getConstraints(socket);
this.userSpecifiedConstraints = getUserSpecifiedConstraints(socket);
this.peerSpecifiedConstraints =
new SupportedSignatureAlgorithmConstraints(supportedAlgorithms);
this.enabledX509DisabledAlgConstraints = withDefaultCertPathConstraints;
@ -93,13 +93,14 @@ final class SSLAlgorithmConstraints implements AlgorithmConstraints {
SSLAlgorithmConstraints(SSLEngine engine, String[] supportedAlgorithms,
boolean withDefaultCertPathConstraints) {
this.userSpecifiedConstraints = getConstraints(engine);
this.userSpecifiedConstraints = getUserSpecifiedConstraints(engine);
this.peerSpecifiedConstraints =
new SupportedSignatureAlgorithmConstraints(supportedAlgorithms);
this.enabledX509DisabledAlgConstraints = withDefaultCertPathConstraints;
}
private static AlgorithmConstraints getConstraints(SSLEngine engine) {
private static AlgorithmConstraints getUserSpecifiedConstraints(
SSLEngine engine) {
if (engine != null) {
// Note that the KeyManager or TrustManager implementation may be
// not implemented in the same provider as SSLSocket/SSLEngine.
@ -108,17 +109,18 @@ final class SSLAlgorithmConstraints implements AlgorithmConstraints {
HandshakeContext hc =
((SSLEngineImpl)engine).conContext.handshakeContext;
if (hc != null) {
return hc.sslConfig.algorithmConstraints;
return hc.sslConfig.userSpecifiedAlgorithmConstraints;
}
} else {
return engine.getSSLParameters().getAlgorithmConstraints();
}
return engine.getSSLParameters().getAlgorithmConstraints();
}
return null;
}
private static AlgorithmConstraints getConstraints(SSLSocket socket) {
private static AlgorithmConstraints getUserSpecifiedConstraints(
SSLSocket socket) {
if (socket != null) {
// Note that the KeyManager or TrustManager implementation may be
// not implemented in the same provider as SSLSocket/SSLEngine.
@ -127,11 +129,11 @@ final class SSLAlgorithmConstraints implements AlgorithmConstraints {
HandshakeContext hc =
((SSLSocketImpl)socket).conContext.handshakeContext;
if (hc != null) {
return hc.sslConfig.algorithmConstraints;
return hc.sslConfig.userSpecifiedAlgorithmConstraints;
}
} else {
return socket.getSSLParameters().getAlgorithmConstraints();
}
return socket.getSSLParameters().getAlgorithmConstraints();
}
return null;

View file

@ -51,7 +51,7 @@ import sun.security.ssl.SSLExtension.ServerExtensions;
*/
final class SSLConfiguration implements Cloneable {
// configurations with SSLParameters
AlgorithmConstraints algorithmConstraints;
AlgorithmConstraints userSpecifiedAlgorithmConstraints;
List<ProtocolVersion> enabledProtocols;
List<CipherSuite> enabledCipherSuites;
ClientAuthType clientAuthType;
@ -116,7 +116,8 @@ final class SSLConfiguration implements Cloneable {
SSLConfiguration(SSLContextImpl sslContext, boolean isClientMode) {
// Configurations with SSLParameters, default values.
this.algorithmConstraints = SSLAlgorithmConstraints.DEFAULT;
this.userSpecifiedAlgorithmConstraints =
SSLAlgorithmConstraints.DEFAULT;
this.enabledProtocols =
sslContext.getDefaultProtocolVersions(!isClientMode);
this.enabledCipherSuites =
@ -153,7 +154,7 @@ final class SSLConfiguration implements Cloneable {
SSLParameters getSSLParameters() {
SSLParameters params = new SSLParameters();
params.setAlgorithmConstraints(this.algorithmConstraints);
params.setAlgorithmConstraints(this.userSpecifiedAlgorithmConstraints);
params.setProtocols(ProtocolVersion.toStringArray(enabledProtocols));
params.setCipherSuites(CipherSuite.namesOf(enabledCipherSuites));
switch (this.clientAuthType) {
@ -193,7 +194,7 @@ final class SSLConfiguration implements Cloneable {
void setSSLParameters(SSLParameters params) {
AlgorithmConstraints ac = params.getAlgorithmConstraints();
if (ac != null) {
this.algorithmConstraints = ac;
this.userSpecifiedAlgorithmConstraints = ac;
} // otherwise, use the default value
String[] sa = params.getCipherSuites();

View file

@ -77,11 +77,6 @@ import javax.net.ssl.SSLSessionContext;
*/
final class SSLSessionImpl extends ExtendedSSLSession {
/*
* we only really need a single null session
*/
static final SSLSessionImpl nullSession = new SSLSessionImpl();
/*
* The state of a single session, as described in section 7.1
* of the SSLv3 spec.
@ -153,7 +148,7 @@ final class SSLSessionImpl extends ExtendedSSLSession {
* be used either by a client or by a server, as a connection is
* first opened and before handshaking begins.
*/
private SSLSessionImpl() {
SSLSessionImpl() {
this.protocolVersion = ProtocolVersion.NONE;
this.cipherSuite = CipherSuite.C_NULL;
this.sessionId = new SessionId(false, null);
@ -1222,15 +1217,6 @@ final class SSLSessionImpl extends ExtendedSSLSession {
public void invalidate() {
sessionLock.lock();
try {
//
// Can't invalidate the NULL session -- this would be
// attempted when we get a handshaking error on a brand
// new connection, with no "real" session yet.
//
if (this == nullSession) {
return;
}
if (context != null) {
context.remove(sessionId);
context = null;

View file

@ -360,7 +360,7 @@ public final class SSLSocketImpl
SSLLogger.severe("handshake failed", ioe);
}
return SSLSessionImpl.nullSession;
return new SSLSessionImpl();
}
return conContext.conSession;

View file

@ -173,12 +173,24 @@ interface SSLTransport {
if (plainText == null) {
plainText = Plaintext.PLAINTEXT_NULL;
} else {
// Fill the destination buffers.
if ((dsts != null) && (dstsLength > 0) &&
(plainText.contentType ==
ContentType.APPLICATION_DATA.id)) {
} else if (plainText.contentType ==
ContentType.APPLICATION_DATA.id) {
// check handshake status
//
// Note that JDK does not support 0-RTT yet. Otherwise, it is
// needed to check early_data.
if (!context.isNegotiated) {
if (SSLLogger.isOn && SSLLogger.isOn("ssl,verbose")) {
SSLLogger.warning("unexpected application data " +
"before handshake completion");
}
throw context.fatal(Alert.UNEXPECTED_MESSAGE,
"Receiving application data before handshake complete");
}
// Fill the destination buffers.
if ((dsts != null) && (dstsLength > 0)) {
ByteBuffer fragment = plainText.fragment;
int remains = fragment.remaining();

View file

@ -130,7 +130,7 @@ final class TransportContext implements ConnectionContext {
this.isUnsureMode = isUnsureMode;
// initial security parameters
this.conSession = SSLSessionImpl.nullSession;
this.conSession = new SSLSessionImpl();
this.protocolVersion = this.sslConfig.maximumProtocolVersion;
this.clientVerifyData = emptyByteArray;
this.serverVerifyData = emptyByteArray;
@ -164,12 +164,13 @@ final class TransportContext implements ConnectionContext {
" message: " +
SSLHandshake.nameOf(type));
}
if (type == SSLHandshake.KEY_UPDATE.id &&
!protocolVersion.useTLS13PlusSpec()) {
if (!PostHandshakeContext.isConsumable(this, type)) {
throw fatal(Alert.UNEXPECTED_MESSAGE,
"Unexpected post-handshake message: " +
SSLHandshake.nameOf(type));
}
handshakeContext = new PostHandshakeContext(this);
} else {
handshakeContext = sslConfig.isClientMode ?