mirror of
https://github.com/openjdk/jdk.git
synced 2026-07-19 07:29:08 +00:00
8350807: Certificates using MD5 algorithm that are disabled by default are incorrectly allowed in TLSv1.3 when re-enabled
Reviewed-by: mullan
This commit is contained in:
parent
dda4b5a4ad
commit
abb23828f9
@ -99,13 +99,7 @@ final class CertSignAlgsExtension {
|
||||
}
|
||||
|
||||
// Produce the extension.
|
||||
if (chc.localSupportedCertSignAlgs == null) {
|
||||
chc.localSupportedCertSignAlgs =
|
||||
SignatureScheme.getSupportedAlgorithms(
|
||||
chc.sslConfig,
|
||||
chc.algorithmConstraints, chc.activeProtocols,
|
||||
CERTIFICATE_SCOPE);
|
||||
}
|
||||
SignatureScheme.updateHandshakeLocalSupportedAlgs(chc);
|
||||
|
||||
int vectorLen = SignatureScheme.sizeInRecord() *
|
||||
chc.localSupportedCertSignAlgs.size();
|
||||
@ -245,15 +239,8 @@ final class CertSignAlgsExtension {
|
||||
}
|
||||
|
||||
// Produce the extension.
|
||||
if (shc.localSupportedCertSignAlgs == null) {
|
||||
shc.localSupportedCertSignAlgs =
|
||||
SignatureScheme.getSupportedAlgorithms(
|
||||
shc.sslConfig,
|
||||
shc.algorithmConstraints,
|
||||
List.of(shc.negotiatedProtocol),
|
||||
CERTIFICATE_SCOPE);
|
||||
}
|
||||
|
||||
// localSupportedCertSignAlgs has been already updated when we set
|
||||
// the negotiated protocol.
|
||||
int vectorLen = SignatureScheme.sizeInRecord()
|
||||
* shc.localSupportedCertSignAlgs.size();
|
||||
byte[] extData = new byte[vectorLen + 2];
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2025, 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
|
||||
@ -697,46 +697,6 @@ final class CertificateMessage {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When a failure happens during certificate checking from an
|
||||
* {@link X509TrustManager}, determine what TLS alert description
|
||||
* to use.
|
||||
*
|
||||
* @param cexc The exception thrown by the {@link X509TrustManager}
|
||||
*
|
||||
* @return A byte value corresponding to a TLS alert description number.
|
||||
*/
|
||||
private static Alert getCertificateAlert(
|
||||
ClientHandshakeContext chc, CertificateException cexc) {
|
||||
// The specific reason for the failure will determine how to
|
||||
// set the alert description value
|
||||
Alert alert = Alert.CERTIFICATE_UNKNOWN;
|
||||
|
||||
Throwable baseCause = cexc.getCause();
|
||||
if (baseCause instanceof CertPathValidatorException cpve) {
|
||||
Reason reason = cpve.getReason();
|
||||
if (reason == BasicReason.REVOKED) {
|
||||
alert = chc.staplingActive ?
|
||||
Alert.BAD_CERT_STATUS_RESPONSE :
|
||||
Alert.CERTIFICATE_REVOKED;
|
||||
} else if (
|
||||
reason == BasicReason.UNDETERMINED_REVOCATION_STATUS) {
|
||||
alert = chc.staplingActive ?
|
||||
Alert.BAD_CERT_STATUS_RESPONSE :
|
||||
Alert.CERTIFICATE_UNKNOWN;
|
||||
} else if (reason == BasicReason.ALGORITHM_CONSTRAINED) {
|
||||
alert = Alert.UNSUPPORTED_CERTIFICATE;
|
||||
} else if (reason == BasicReason.EXPIRED) {
|
||||
alert = Alert.CERTIFICATE_EXPIRED;
|
||||
} else if (reason == BasicReason.INVALID_SIGNATURE ||
|
||||
reason == BasicReason.NOT_YET_VALID) {
|
||||
alert = Alert.BAD_CERTIFICATE;
|
||||
}
|
||||
}
|
||||
|
||||
return alert;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1329,37 +1289,57 @@ final class CertificateMessage {
|
||||
return certs;
|
||||
}
|
||||
|
||||
/**
|
||||
* When a failure happens during certificate checking from an
|
||||
* {@link X509TrustManager}, determine what TLS alert description
|
||||
* to use.
|
||||
*
|
||||
* @param cexc The exception thrown by the {@link X509TrustManager}
|
||||
*
|
||||
* @return A byte value corresponding to a TLS alert description number.
|
||||
*/
|
||||
private static Alert getCertificateAlert(
|
||||
ClientHandshakeContext chc, CertificateException cexc) {
|
||||
// The specific reason for the failure will determine how to
|
||||
// set the alert description value
|
||||
Alert alert = Alert.CERTIFICATE_UNKNOWN;
|
||||
}
|
||||
|
||||
Throwable baseCause = cexc.getCause();
|
||||
if (baseCause instanceof CertPathValidatorException cpve) {
|
||||
Reason reason = cpve.getReason();
|
||||
if (reason == BasicReason.REVOKED) {
|
||||
alert = chc.staplingActive ?
|
||||
Alert.BAD_CERT_STATUS_RESPONSE :
|
||||
Alert.CERTIFICATE_REVOKED;
|
||||
} else if (
|
||||
reason == BasicReason.UNDETERMINED_REVOCATION_STATUS) {
|
||||
alert = chc.staplingActive ?
|
||||
Alert.BAD_CERT_STATUS_RESPONSE :
|
||||
Alert.CERTIFICATE_UNKNOWN;
|
||||
/**
|
||||
* When a failure happens during certificate checking from an
|
||||
* {@link X509TrustManager}, determine what TLS alert description
|
||||
* to use.
|
||||
*
|
||||
* @param cexc The exception thrown by the {@link X509TrustManager}
|
||||
* @return A byte value corresponding to a TLS alert description number.
|
||||
*/
|
||||
private static Alert getCertificateAlert(
|
||||
ClientHandshakeContext chc, CertificateException cexc) {
|
||||
// The specific reason for the failure will determine how to
|
||||
// set the alert description value
|
||||
Alert alert = Alert.CERTIFICATE_UNKNOWN;
|
||||
|
||||
Throwable baseCause = cexc.getCause();
|
||||
if (baseCause instanceof CertPathValidatorException cpve) {
|
||||
Reason reason = cpve.getReason();
|
||||
if (reason == BasicReason.REVOKED) {
|
||||
alert = chc.staplingActive ?
|
||||
Alert.BAD_CERT_STATUS_RESPONSE :
|
||||
Alert.CERTIFICATE_REVOKED;
|
||||
} else if (reason == BasicReason.UNDETERMINED_REVOCATION_STATUS) {
|
||||
alert = chc.staplingActive ?
|
||||
Alert.BAD_CERT_STATUS_RESPONSE :
|
||||
Alert.CERTIFICATE_UNKNOWN;
|
||||
} else if (reason == BasicReason.EXPIRED) {
|
||||
alert = Alert.CERTIFICATE_EXPIRED;
|
||||
} else if (reason == BasicReason.INVALID_SIGNATURE
|
||||
|| reason == BasicReason.NOT_YET_VALID) {
|
||||
alert = Alert.BAD_CERTIFICATE;
|
||||
} else if (reason == BasicReason.ALGORITHM_CONSTRAINED) {
|
||||
alert = Alert.UNSUPPORTED_CERTIFICATE;
|
||||
|
||||
// Per TLSv1.3 RFC we MUST abort the handshake with a
|
||||
// "bad_certificate" alert if we reject certificate
|
||||
// because of the signature using MD5 or SHA1 algorithm.
|
||||
if (chc.negotiatedProtocol != null
|
||||
&& chc.negotiatedProtocol.useTLS13PlusSpec()) {
|
||||
final String exMsg = cexc.getMessage().toUpperCase();
|
||||
|
||||
if (exMsg.contains("MD5WITH")
|
||||
|| exMsg.contains("SHA1WITH")) {
|
||||
alert = Alert.BAD_CERTIFICATE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return alert;
|
||||
}
|
||||
|
||||
return alert;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -636,25 +636,11 @@ final class CertificateRequest {
|
||||
// The producing happens in server side only.
|
||||
ServerHandshakeContext shc = (ServerHandshakeContext) context;
|
||||
|
||||
if (shc.localSupportedSignAlgs == null) {
|
||||
shc.localSupportedSignAlgs =
|
||||
SignatureScheme.getSupportedAlgorithms(
|
||||
shc.sslConfig,
|
||||
shc.algorithmConstraints, shc.activeProtocols,
|
||||
HANDSHAKE_SCOPE);
|
||||
}
|
||||
|
||||
if (shc.localSupportedCertSignAlgs == null) {
|
||||
shc.localSupportedCertSignAlgs =
|
||||
SignatureScheme.getSupportedAlgorithms(
|
||||
shc.sslConfig,
|
||||
shc.algorithmConstraints, shc.activeProtocols,
|
||||
CERTIFICATE_SCOPE);
|
||||
}
|
||||
|
||||
// According to TLSv1.2 RFC, CertificateRequest message must
|
||||
// contain signature schemes supported for both:
|
||||
// handshake signatures and certificate signatures.
|
||||
// localSupportedSignAlgs and localSupportedCertSignAlgs have been
|
||||
// already updated when we set the negotiated protocol.
|
||||
List<SignatureScheme> certReqSignAlgs =
|
||||
new ArrayList<>(shc.localSupportedSignAlgs);
|
||||
certReqSignAlgs.retainAll(shc.localSupportedCertSignAlgs);
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2025, 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
|
||||
@ -825,6 +825,10 @@ final class ClientHello {
|
||||
"Negotiated protocol version: " + negotiatedProtocol.name);
|
||||
}
|
||||
|
||||
// Protocol version is negotiated, update locally supported
|
||||
// signature schemes according to the protocol being used.
|
||||
SignatureScheme.updateHandshakeLocalSupportedAlgs(context);
|
||||
|
||||
// Consume the handshake message for the specific protocol version.
|
||||
if (negotiatedProtocol.isDTLS) {
|
||||
if (negotiatedProtocol.useTLS13PlusSpec()) {
|
||||
|
||||
@ -42,7 +42,6 @@ import sun.security.ssl.SessionTicketExtension.SessionTicketSpec;
|
||||
import sun.security.util.HexDumpEncoder;
|
||||
|
||||
import static sun.security.ssl.SSLExtension.*;
|
||||
import static sun.security.ssl.SignatureScheme.CERTIFICATE_SCOPE;
|
||||
|
||||
/**
|
||||
* Pack of the "pre_shared_key" extension.
|
||||
@ -445,13 +444,7 @@ final class PreSharedKeyExtension {
|
||||
// localSupportedCertSignAlgs field is populated. This is particularly
|
||||
// important when client authentication was used in an initial session,
|
||||
// and it is now being resumed.
|
||||
if (shc.localSupportedCertSignAlgs == null) {
|
||||
shc.localSupportedCertSignAlgs =
|
||||
SignatureScheme.getSupportedAlgorithms(
|
||||
shc.sslConfig,
|
||||
shc.algorithmConstraints, shc.activeProtocols,
|
||||
CERTIFICATE_SCOPE);
|
||||
}
|
||||
SignatureScheme.updateHandshakeLocalSupportedAlgs(shc);
|
||||
|
||||
// Validate the required client authentication.
|
||||
if (result &&
|
||||
|
||||
@ -25,9 +25,6 @@
|
||||
|
||||
package sun.security.ssl;
|
||||
|
||||
import static sun.security.ssl.SignatureScheme.CERTIFICATE_SCOPE;
|
||||
import static sun.security.ssl.SignatureScheme.HANDSHAKE_SCOPE;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.security.AlgorithmConstraints;
|
||||
@ -272,22 +269,6 @@ final class ServerHello {
|
||||
"Not resumption, and no new session is allowed");
|
||||
}
|
||||
|
||||
if (shc.localSupportedSignAlgs == null) {
|
||||
shc.localSupportedSignAlgs =
|
||||
SignatureScheme.getSupportedAlgorithms(
|
||||
shc.sslConfig,
|
||||
shc.algorithmConstraints, shc.activeProtocols,
|
||||
HANDSHAKE_SCOPE);
|
||||
}
|
||||
|
||||
if (shc.localSupportedCertSignAlgs == null) {
|
||||
shc.localSupportedCertSignAlgs =
|
||||
SignatureScheme.getSupportedAlgorithms(
|
||||
shc.sslConfig,
|
||||
shc.algorithmConstraints, shc.activeProtocols,
|
||||
CERTIFICATE_SCOPE);
|
||||
}
|
||||
|
||||
SSLSessionImpl session =
|
||||
new SSLSessionImpl(shc, CipherSuite.C_NULL);
|
||||
session.setMaximumPacketSize(shc.sslConfig.maximumPacketSize);
|
||||
@ -522,22 +503,6 @@ final class ServerHello {
|
||||
"Not resumption, and no new session is allowed");
|
||||
}
|
||||
|
||||
if (shc.localSupportedSignAlgs == null) {
|
||||
shc.localSupportedSignAlgs =
|
||||
SignatureScheme.getSupportedAlgorithms(
|
||||
shc.sslConfig,
|
||||
shc.algorithmConstraints, shc.activeProtocols,
|
||||
HANDSHAKE_SCOPE);
|
||||
}
|
||||
|
||||
if (shc.localSupportedCertSignAlgs == null) {
|
||||
shc.localSupportedCertSignAlgs =
|
||||
SignatureScheme.getSupportedAlgorithms(
|
||||
shc.sslConfig,
|
||||
shc.algorithmConstraints, shc.activeProtocols,
|
||||
CERTIFICATE_SCOPE);
|
||||
}
|
||||
|
||||
SSLSessionImpl session =
|
||||
new SSLSessionImpl(shc, CipherSuite.C_NULL);
|
||||
session.setMaximumPacketSize(shc.sslConfig.maximumPacketSize);
|
||||
@ -959,6 +924,10 @@ final class ServerHello {
|
||||
"Negotiated protocol version: " + serverVersion.name);
|
||||
}
|
||||
|
||||
// Protocol version is negotiated, update locally supported
|
||||
// signature schemes according to the protocol being used.
|
||||
SignatureScheme.updateHandshakeLocalSupportedAlgs(chc);
|
||||
|
||||
// TLS 1.3 key share extension may have produced client
|
||||
// possessions for TLS 1.3 key exchanges.
|
||||
//
|
||||
@ -1010,6 +979,10 @@ final class ServerHello {
|
||||
"Negotiated protocol version: " + serverVersion.name);
|
||||
}
|
||||
|
||||
// Protocol version is negotiated, update locally supported
|
||||
// signature schemes according to the protocol being used.
|
||||
SignatureScheme.updateHandshakeLocalSupportedAlgs(chc);
|
||||
|
||||
if (serverHello.serverRandom.isVersionDowngrade(chc)) {
|
||||
throw chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
|
||||
"A potential protocol version downgrade attack");
|
||||
|
||||
@ -40,7 +40,6 @@ import javax.net.ssl.SSLSessionContext;
|
||||
|
||||
import static sun.security.ssl.SSLExtension.CH_SESSION_TICKET;
|
||||
import static sun.security.ssl.SSLExtension.SH_SESSION_TICKET;
|
||||
import static sun.security.ssl.SignatureScheme.CERTIFICATE_SCOPE;
|
||||
|
||||
import sun.security.ssl.SSLExtension.ExtensionConsumer;
|
||||
import sun.security.ssl.SSLExtension.SSLExtensionSpec;
|
||||
@ -353,13 +352,7 @@ final class SessionTicketExtension {
|
||||
return new byte[0];
|
||||
}
|
||||
|
||||
if (chc.localSupportedCertSignAlgs == null) {
|
||||
chc.localSupportedCertSignAlgs =
|
||||
SignatureScheme.getSupportedAlgorithms(
|
||||
chc.sslConfig,
|
||||
chc.algorithmConstraints, chc.activeProtocols,
|
||||
CERTIFICATE_SCOPE);
|
||||
}
|
||||
SignatureScheme.updateHandshakeLocalSupportedAlgs(chc);
|
||||
|
||||
return chc.resumingSession.getPskIdentity();
|
||||
}
|
||||
|
||||
@ -187,13 +187,7 @@ final class SignatureAlgorithmsExtension {
|
||||
}
|
||||
|
||||
// Produce the extension.
|
||||
if (chc.localSupportedSignAlgs == null) {
|
||||
chc.localSupportedSignAlgs =
|
||||
SignatureScheme.getSupportedAlgorithms(
|
||||
chc.sslConfig,
|
||||
chc.algorithmConstraints, chc.activeProtocols,
|
||||
HANDSHAKE_SCOPE);
|
||||
}
|
||||
SignatureScheme.updateHandshakeLocalSupportedAlgs(chc);
|
||||
|
||||
int vectorLen = SignatureScheme.sizeInRecord() *
|
||||
chc.localSupportedSignAlgs.size();
|
||||
@ -417,18 +411,14 @@ final class SignatureAlgorithmsExtension {
|
||||
}
|
||||
|
||||
// Produce the extension.
|
||||
List<SignatureScheme> sigAlgs =
|
||||
SignatureScheme.getSupportedAlgorithms(
|
||||
shc.sslConfig,
|
||||
shc.algorithmConstraints,
|
||||
List.of(shc.negotiatedProtocol),
|
||||
HANDSHAKE_SCOPE);
|
||||
|
||||
int vectorLen = SignatureScheme.sizeInRecord() * sigAlgs.size();
|
||||
// localSupportedSignAlgs has been already updated when we
|
||||
// set the negotiated protocol.
|
||||
int vectorLen = SignatureScheme.sizeInRecord()
|
||||
* shc.localSupportedSignAlgs.size();
|
||||
byte[] extData = new byte[vectorLen + 2];
|
||||
ByteBuffer m = ByteBuffer.wrap(extData);
|
||||
Record.putInt16(m, vectorLen);
|
||||
for (SignatureScheme ss : sigAlgs) {
|
||||
for (SignatureScheme ss : shc.localSupportedSignAlgs) {
|
||||
Record.putInt16(m, ss.id);
|
||||
}
|
||||
|
||||
|
||||
@ -374,9 +374,40 @@ enum SignatureScheme {
|
||||
&& (namedGroup == null || namedGroup.isPermitted(constraints));
|
||||
}
|
||||
|
||||
// Helper method to update all locally supported signature schemes for
|
||||
// a given HandshakeContext.
|
||||
static void updateHandshakeLocalSupportedAlgs(HandshakeContext hc) {
|
||||
// To improve performance we only update when necessary.
|
||||
// No need to do anything if we already computed the local supported
|
||||
// algorithms and either there is no negotiated protocol yet or the
|
||||
// only active protocol ends up to be the negotiated protocol.
|
||||
if (hc.localSupportedSignAlgs != null
|
||||
&& hc.localSupportedCertSignAlgs != null
|
||||
&& (hc.negotiatedProtocol == null
|
||||
|| hc.activeProtocols.size() == 1)) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<ProtocolVersion> protocols = hc.negotiatedProtocol != null ?
|
||||
List.of(hc.negotiatedProtocol) :
|
||||
hc.activeProtocols;
|
||||
|
||||
hc.localSupportedSignAlgs = getSupportedAlgorithms(
|
||||
hc.sslConfig,
|
||||
hc.algorithmConstraints,
|
||||
protocols,
|
||||
HANDSHAKE_SCOPE);
|
||||
|
||||
hc.localSupportedCertSignAlgs = getSupportedAlgorithms(
|
||||
hc.sslConfig,
|
||||
hc.algorithmConstraints,
|
||||
protocols,
|
||||
CERTIFICATE_SCOPE);
|
||||
}
|
||||
|
||||
// Get local supported algorithm collection complying to algorithm
|
||||
// constraints and SSL scopes.
|
||||
static List<SignatureScheme> getSupportedAlgorithms(
|
||||
private static List<SignatureScheme> getSupportedAlgorithms(
|
||||
SSLConfiguration config,
|
||||
SSLAlgorithmConstraints constraints,
|
||||
List<ProtocolVersion> activeProtocols,
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2001, 2025, 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
|
||||
@ -105,6 +105,7 @@ public class CriticalSubjectAltName implements HostnameVerifier {
|
||||
(SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
|
||||
SSLServerSocket sslServerSocket =
|
||||
(SSLServerSocket) sslssf.createServerSocket(serverPort);
|
||||
sslServerSocket.setEnabledProtocols(new String[]{"TLSv1.2"});
|
||||
serverPort = sslServerSocket.getLocalPort();
|
||||
|
||||
/*
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2025, 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
|
||||
@ -245,7 +245,7 @@ public class SSLSocketTemplate extends SSLContextTemplate {
|
||||
//
|
||||
// The server side takes care of the issue if the server cannot
|
||||
// get started in 90 seconds. The client side would just ignore
|
||||
// the test case if the serer is not ready.
|
||||
// the test case if the server is not ready.
|
||||
boolean serverIsReady =
|
||||
serverCondition.await(90L, TimeUnit.SECONDS);
|
||||
if (!serverIsReady) {
|
||||
@ -378,7 +378,7 @@ public class SSLSocketTemplate extends SSLContextTemplate {
|
||||
* Check various exception conditions.
|
||||
*/
|
||||
if ((local != null) && (remote != null)) {
|
||||
// If both failed, return the curthread's exception.
|
||||
// If both failed, return the current thread's exception.
|
||||
local.addSuppressed(remote);
|
||||
exception = local;
|
||||
} else if (local != null) {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2010, 2025, 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
|
||||
@ -893,7 +893,7 @@ public class DNSIdentities {
|
||||
TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
|
||||
tmf.init(ks);
|
||||
|
||||
SSLContext ctx = SSLContext.getInstance("TLS");
|
||||
SSLContext ctx = SSLContext.getInstance("TLSv1.2");
|
||||
|
||||
if (keyCertStr != null) {
|
||||
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2010, 2025, 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
|
||||
@ -901,7 +901,7 @@ public class IPAddressIPIdentities {
|
||||
TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
|
||||
tmf.init(ks);
|
||||
|
||||
SSLContext ctx = SSLContext.getInstance("TLS");
|
||||
SSLContext ctx = SSLContext.getInstance("TLSv1.2");
|
||||
|
||||
if (keyCertStr != null) {
|
||||
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2010, 2025, 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
|
||||
@ -900,7 +900,7 @@ public class IPIdentities {
|
||||
TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
|
||||
tmf.init(ks);
|
||||
|
||||
SSLContext ctx = SSLContext.getInstance("TLS");
|
||||
SSLContext ctx = SSLContext.getInstance("TLSv1.2");
|
||||
|
||||
if (keyCertStr != null) {
|
||||
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2010, 2025, 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
|
||||
@ -893,7 +893,7 @@ public class Identities {
|
||||
TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
|
||||
tmf.init(ks);
|
||||
|
||||
SSLContext ctx = SSLContext.getInstance("TLS");
|
||||
SSLContext ctx = SSLContext.getInstance("TLSv1.2");
|
||||
|
||||
if (keyCertStr != null) {
|
||||
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
|
||||
|
||||
@ -0,0 +1,231 @@
|
||||
/*
|
||||
* Copyright (c) 2025, 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8350807
|
||||
* @summary Certificates using MD5 algorithm that are disabled by default are
|
||||
* incorrectly allowed in TLSv1.3 when re-enabled.
|
||||
* @modules java.base/sun.security.x509
|
||||
* java.base/sun.security.util
|
||||
* @library /javax/net/ssl/templates
|
||||
* /test/lib
|
||||
* @run main/othervm MD5NotAllowedInTLS13CertificateSignature
|
||||
*/
|
||||
|
||||
import static jdk.test.lib.Asserts.assertEquals;
|
||||
import static jdk.test.lib.Asserts.assertTrue;
|
||||
import static jdk.test.lib.Utils.runAndCheckException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.security.KeyPair;
|
||||
import java.security.KeyPairGenerator;
|
||||
import java.security.KeyStore;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import javax.net.ssl.KeyManagerFactory;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLHandshakeException;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
import jdk.test.lib.security.CertificateBuilder;
|
||||
import jdk.test.lib.security.SecurityUtils;
|
||||
import sun.security.x509.AuthorityKeyIdentifierExtension;
|
||||
import sun.security.x509.GeneralName;
|
||||
import sun.security.x509.GeneralNames;
|
||||
import sun.security.x509.KeyIdentifier;
|
||||
import sun.security.x509.SerialNumber;
|
||||
import sun.security.x509.X500Name;
|
||||
|
||||
public class MD5NotAllowedInTLS13CertificateSignature extends
|
||||
SSLSocketTemplate {
|
||||
|
||||
private final String protocol;
|
||||
private X509Certificate trustedCert;
|
||||
private X509Certificate serverCert;
|
||||
private X509Certificate clientCert;
|
||||
private KeyPair serverKeys;
|
||||
private KeyPair clientKeys;
|
||||
|
||||
protected MD5NotAllowedInTLS13CertificateSignature(String protocol)
|
||||
throws Exception {
|
||||
super();
|
||||
this.protocol = protocol;
|
||||
setupCertificates();
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
// MD5 is disabled by default in java.security config file,
|
||||
// re-enable it for our test.
|
||||
SecurityUtils.removeFromDisabledAlgs(
|
||||
"jdk.certpath.disabledAlgorithms", List.of("MD5"));
|
||||
SecurityUtils.removeFromDisabledAlgs(
|
||||
"jdk.tls.disabledAlgorithms", List.of("MD5withRSA"));
|
||||
|
||||
// Should fail on TLSv1.3 and up.
|
||||
runAndCheckException(
|
||||
// The conditions to reproduce the bug being fixed only met when
|
||||
// 'TLS' is specified, i.e. when older versions of protocol are
|
||||
// supported besides TLSv1.3.
|
||||
() -> new MD5NotAllowedInTLS13CertificateSignature("TLS").run(),
|
||||
serverEx -> {
|
||||
Throwable clientEx = serverEx.getSuppressed()[0];
|
||||
assertTrue(clientEx instanceof SSLHandshakeException);
|
||||
assertEquals(clientEx.getMessage(), "(bad_certificate) "
|
||||
+ "PKIX path validation failed: "
|
||||
+ "java.security.cert.CertPathValidatorException: "
|
||||
+ "Algorithm constraints check failed on signature"
|
||||
+ " algorithm: MD5withRSA");
|
||||
});
|
||||
|
||||
// Should run fine on TLSv1.2.
|
||||
new MD5NotAllowedInTLS13CertificateSignature("TLSv1.2").run();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SSLContext createServerSSLContext() throws Exception {
|
||||
return getSSLContext(
|
||||
trustedCert, serverCert, serverKeys.getPrivate(), protocol);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SSLContext createClientSSLContext() throws Exception {
|
||||
return getSSLContext(
|
||||
trustedCert, clientCert, clientKeys.getPrivate(), protocol);
|
||||
}
|
||||
|
||||
private static SSLContext getSSLContext(
|
||||
X509Certificate trustedCertificate, X509Certificate keyCertificate,
|
||||
PrivateKey privateKey, String protocol)
|
||||
throws Exception {
|
||||
|
||||
// create a key store
|
||||
KeyStore ks = KeyStore.getInstance("PKCS12");
|
||||
ks.load(null, null);
|
||||
|
||||
// import the trusted cert
|
||||
ks.setCertificateEntry("TLS Signer", trustedCertificate);
|
||||
|
||||
// generate certificate chain
|
||||
Certificate[] chain = new Certificate[2];
|
||||
chain[0] = keyCertificate;
|
||||
chain[1] = trustedCertificate;
|
||||
|
||||
// import the key entry.
|
||||
final char[] passphrase = "passphrase".toCharArray();
|
||||
ks.setKeyEntry("Whatever", privateKey, passphrase, chain);
|
||||
|
||||
// Using PKIX TrustManager - this is where MD5 signature check is done.
|
||||
TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
|
||||
tmf.init(ks);
|
||||
|
||||
// create SSL context
|
||||
SSLContext ctx = SSLContext.getInstance(protocol);
|
||||
|
||||
// Using "SunX509" which doesn't check peer supported signature
|
||||
// algorithms, so we check against local supported signature
|
||||
// algorithms which constitutes the fix being tested.
|
||||
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
|
||||
kmf.init(ks, passphrase);
|
||||
|
||||
ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
// Certificate-building helper methods.
|
||||
// Certificates are signed with signature using MD5WithRSA algorithm.
|
||||
|
||||
private void setupCertificates() throws Exception {
|
||||
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
|
||||
kpg.initialize(1024);
|
||||
KeyPair caKeys = kpg.generateKeyPair();
|
||||
this.serverKeys = kpg.generateKeyPair();
|
||||
this.clientKeys = kpg.generateKeyPair();
|
||||
|
||||
this.trustedCert = createTrustedCert(caKeys);
|
||||
|
||||
this.serverCert = customCertificateBuilder(
|
||||
"O=Some-Org, L=Some-City, ST=Some-State, C=US",
|
||||
serverKeys.getPublic(), caKeys.getPublic())
|
||||
.addBasicConstraintsExt(false, false, -1)
|
||||
.build(trustedCert, caKeys.getPrivate(), "MD5WithRSA");
|
||||
|
||||
this.clientCert = customCertificateBuilder(
|
||||
"CN=localhost, OU=SSL-Client, O=Some-Org, L=Some-City, ST=Some-State, C=US",
|
||||
clientKeys.getPublic(), caKeys.getPublic())
|
||||
.addBasicConstraintsExt(false, false, -1)
|
||||
.build(trustedCert, caKeys.getPrivate(), "MD5WithRSA");
|
||||
}
|
||||
|
||||
private static X509Certificate createTrustedCert(KeyPair caKeys)
|
||||
throws Exception {
|
||||
SecureRandom random = new SecureRandom();
|
||||
|
||||
KeyIdentifier kid = new KeyIdentifier(caKeys.getPublic());
|
||||
GeneralNames gns = new GeneralNames();
|
||||
GeneralName name = new GeneralName(new X500Name(
|
||||
"O=Some-Org, L=Some-City, ST=Some-State, C=US"));
|
||||
gns.add(name);
|
||||
BigInteger serialNumber = BigInteger.valueOf(
|
||||
random.nextLong(1000000) + 1);
|
||||
return customCertificateBuilder(
|
||||
"O=Some-Org, L=Some-City, ST=Some-State, C=US",
|
||||
caKeys.getPublic(), caKeys.getPublic())
|
||||
.setSerialNumber(serialNumber)
|
||||
.addExtension(new AuthorityKeyIdentifierExtension(kid, gns,
|
||||
new SerialNumber(serialNumber)))
|
||||
.addBasicConstraintsExt(true, true, -1)
|
||||
.build(null, caKeys.getPrivate(), "MD5WithRSA");
|
||||
}
|
||||
|
||||
private static CertificateBuilder customCertificateBuilder(
|
||||
String subjectName, PublicKey publicKey, PublicKey caKey)
|
||||
throws CertificateException, IOException {
|
||||
SecureRandom random = new SecureRandom();
|
||||
|
||||
CertificateBuilder builder = new CertificateBuilder()
|
||||
.setSubjectName(subjectName)
|
||||
.setPublicKey(publicKey)
|
||||
.setNotAfter(
|
||||
Date.from(Instant.now().minus(1, ChronoUnit.HOURS)))
|
||||
.setNotAfter(Date.from(Instant.now().plus(1, ChronoUnit.HOURS)))
|
||||
.setSerialNumber(
|
||||
BigInteger.valueOf(random.nextLong(1000000) + 1))
|
||||
.addSubjectKeyIdExt(publicKey)
|
||||
.addAuthorityKeyIdExt(caKey);
|
||||
builder.addKeyUsageExt(
|
||||
new boolean[]{true, true, true, true, true, true});
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user