diff --git a/src/java.base/share/classes/sun/security/ssl/CertSignAlgsExtension.java b/src/java.base/share/classes/sun/security/ssl/CertSignAlgsExtension.java index 2772ecff337..b975290d09d 100644 --- a/src/java.base/share/classes/sun/security/ssl/CertSignAlgsExtension.java +++ b/src/java.base/share/classes/sun/security/ssl/CertSignAlgsExtension.java @@ -99,13 +99,7 @@ public byte[] produce(ConnectionContext context, } // 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 @@ public byte[] produce(ConnectionContext context, } // 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]; diff --git a/src/java.base/share/classes/sun/security/ssl/CertificateMessage.java b/src/java.base/share/classes/sun/security/ssl/CertificateMessage.java index fd9011b59c6..fe711cd7a93 100644 --- a/src/java.base/share/classes/sun/security/ssl/CertificateMessage.java +++ b/src/java.base/share/classes/sun/security/ssl/CertificateMessage.java @@ -693,46 +693,6 @@ private static void checkClientCerts(ServerHandshakeContext shc, } } - /** - * 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; - } - } /** @@ -1330,37 +1290,57 @@ private static X509Certificate[] checkServerCerts( 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; } + } diff --git a/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java b/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java index 062d4d77a58..66b8c048703 100644 --- a/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java +++ b/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java @@ -636,25 +636,11 @@ public byte[] produce(ConnectionContext context, // 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 certReqSignAlgs = new ArrayList<>(shc.localSupportedSignAlgs); certReqSignAlgs.retainAll(shc.localSupportedCertSignAlgs); diff --git a/src/java.base/share/classes/sun/security/ssl/ClientHello.java b/src/java.base/share/classes/sun/security/ssl/ClientHello.java index e75076b11d6..3e43921520d 100644 --- a/src/java.base/share/classes/sun/security/ssl/ClientHello.java +++ b/src/java.base/share/classes/sun/security/ssl/ClientHello.java @@ -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 @@ private void onClientHello(ServerHandshakeContext context, "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()) { diff --git a/src/java.base/share/classes/sun/security/ssl/PreSharedKeyExtension.java b/src/java.base/share/classes/sun/security/ssl/PreSharedKeyExtension.java index 7bf22d7c2d1..8e45f459371 100644 --- a/src/java.base/share/classes/sun/security/ssl/PreSharedKeyExtension.java +++ b/src/java.base/share/classes/sun/security/ssl/PreSharedKeyExtension.java @@ -42,7 +42,6 @@ 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 @@ private static boolean canRejoin(ClientHelloMessage clientHello, // 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 && diff --git a/src/java.base/share/classes/sun/security/ssl/ServerHello.java b/src/java.base/share/classes/sun/security/ssl/ServerHello.java index f19964dd5c7..303095a0722 100644 --- a/src/java.base/share/classes/sun/security/ssl/ServerHello.java +++ b/src/java.base/share/classes/sun/security/ssl/ServerHello.java @@ -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 @@ public byte[] produce(ConnectionContext context, "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 @@ public byte[] produce(ConnectionContext context, "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 @@ private void onHelloRetryRequest(ClientHandshakeContext chc, "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 @@ private void onServerHello(ClientHandshakeContext chc, "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"); diff --git a/src/java.base/share/classes/sun/security/ssl/SessionTicketExtension.java b/src/java.base/share/classes/sun/security/ssl/SessionTicketExtension.java index b3e7ae80d28..86a2ad1c059 100644 --- a/src/java.base/share/classes/sun/security/ssl/SessionTicketExtension.java +++ b/src/java.base/share/classes/sun/security/ssl/SessionTicketExtension.java @@ -40,7 +40,6 @@ 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.action.GetPropertyAction; import sun.security.ssl.SSLExtension.ExtensionConsumer; @@ -355,13 +354,7 @@ public byte[] produce(ConnectionContext context, 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(); } diff --git a/src/java.base/share/classes/sun/security/ssl/SignatureAlgorithmsExtension.java b/src/java.base/share/classes/sun/security/ssl/SignatureAlgorithmsExtension.java index 7cc514cb224..a95b31583bb 100644 --- a/src/java.base/share/classes/sun/security/ssl/SignatureAlgorithmsExtension.java +++ b/src/java.base/share/classes/sun/security/ssl/SignatureAlgorithmsExtension.java @@ -189,13 +189,7 @@ public byte[] produce(ConnectionContext context, } // 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(); @@ -397,18 +391,14 @@ public byte[] produce(ConnectionContext context, } // Produce the extension. - List 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); } diff --git a/src/java.base/share/classes/sun/security/ssl/SignatureScheme.java b/src/java.base/share/classes/sun/security/ssl/SignatureScheme.java index 00b6b0593f5..9e44b656c5c 100644 --- a/src/java.base/share/classes/sun/security/ssl/SignatureScheme.java +++ b/src/java.base/share/classes/sun/security/ssl/SignatureScheme.java @@ -373,9 +373,40 @@ private boolean isPermitted( && (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 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 getSupportedAlgorithms( + private static List getSupportedAlgorithms( SSLConfiguration config, SSLAlgorithmConstraints constraints, List activeProtocols, diff --git a/test/jdk/javax/net/ssl/HttpsURLConnection/CriticalSubjectAltName.java b/test/jdk/javax/net/ssl/HttpsURLConnection/CriticalSubjectAltName.java index d4eca8b5776..cb11b17ebb5 100644 --- a/test/jdk/javax/net/ssl/HttpsURLConnection/CriticalSubjectAltName.java +++ b/test/jdk/javax/net/ssl/HttpsURLConnection/CriticalSubjectAltName.java @@ -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 @@ void doServerSide() throws Exception { (SSLServerSocketFactory) SSLServerSocketFactory.getDefault(); SSLServerSocket sslServerSocket = (SSLServerSocket) sslssf.createServerSocket(serverPort); + sslServerSocket.setEnabledProtocols(new String[]{"TLSv1.2"}); serverPort = sslServerSocket.getLocalPort(); /* diff --git a/test/jdk/javax/net/ssl/templates/SSLSocketTemplate.java b/test/jdk/javax/net/ssl/templates/SSLSocketTemplate.java index b67f8978304..ce1a99a7f1e 100644 --- a/test/jdk/javax/net/ssl/templates/SSLSocketTemplate.java +++ b/test/jdk/javax/net/ssl/templates/SSLSocketTemplate.java @@ -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 @@ protected void doClientSide() throws Exception { // // 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 @@ private void bootup() throws Exception { * 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) { diff --git a/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/DNSIdentities.java b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/DNSIdentities.java index 0d479d60fd2..4b2dece0c75 100644 --- a/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/DNSIdentities.java +++ b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/DNSIdentities.java @@ -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 @@ private static SSLContext getSSLContext(String trusedCertStr, 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"); diff --git a/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/IPAddressIPIdentities.java b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/IPAddressIPIdentities.java index bd6c62c603c..a15093c821e 100644 --- a/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/IPAddressIPIdentities.java +++ b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/IPAddressIPIdentities.java @@ -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 @@ private static SSLContext getSSLContext(String trusedCertStr, 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"); diff --git a/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/IPIdentities.java b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/IPIdentities.java index 91f0020f7d1..6ea62526566 100644 --- a/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/IPIdentities.java +++ b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/IPIdentities.java @@ -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 @@ private static SSLContext getSSLContext(String trusedCertStr, 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"); diff --git a/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/Identities.java b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/Identities.java index 3764b3de688..53960c05895 100644 --- a/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/Identities.java +++ b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/Identities.java @@ -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 @@ private static SSLContext getSSLContext(String trusedCertStr, 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"); diff --git a/test/jdk/sun/security/ssl/SignatureScheme/MD5NotAllowedInTLS13CertificateSignature.java b/test/jdk/sun/security/ssl/SignatureScheme/MD5NotAllowedInTLS13CertificateSignature.java new file mode 100644 index 00000000000..ed61aace3f4 --- /dev/null +++ b/test/jdk/sun/security/ssl/SignatureScheme/MD5NotAllowedInTLS13CertificateSignature.java @@ -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; + } + +}