From 695a62b1d0526f8f2e82ac9a37be388b0ce898e5 Mon Sep 17 00:00:00 2001 From: Severin Gehwolf Date: Mon, 8 Jun 2026 16:52:33 +0200 Subject: [PATCH 1/3] Backport 257efa5af5d962ef9b10af7123a0db916fd4ef06 8349583: Add mechanism to disable signature schemes based on their TLS scope Since 'JDK-8226374: Restrict TLS signature schemes and named groups' is not in 8u, take minimal parts from it to update SignatureScheme: - use 'SigAlgParamSpec signAlgParams' over 'AlgorithmParameterSpec signAlgParameter' field. - Update usages of 'getPreferableAlgorithm()' and 'getSignerOfPreferableAlgorithm()' in: CertificateVerify, DHServerKeyExchange, ECDHServerKeyExchange, CertificateRequest and CertificateMessage passing in SSLAlgorithmConstraints as an extra parameter. - Add 'isPermitted()' without the extra bit added by JDK-8226374. - Update 'SignatureUtil.initVerifyWithParam()' with the change of the 'signAlgParams' field. The change to java.security-* is duplicated to all versions. Since '8341964: Add mechanism to disable different parts of TLS cipher suite' is not a dependency only include the relevant parts for JDK-8349583. Various test changes to adapt to 8u library code: - /test/lib => /lib/testlibrary - Utils.java is in jdk.testlibrary.Utils package in 8u. - Remove DTLS 1.2 test which isn't supported in 8u TLS 1.3 - Change usage of Map.ofEntries() which is only JDK 11+ API - Change usage of List.of() which is only in JDK 11+ API Other changes: - Set.of(x) => Collections.unmodifiableSet(EnumSet.of(x)) --- .../security/ssl/CertSignAlgsExtension.java | 47 ++-- .../sun/security/ssl/CertificateMessage.java | 1 + .../sun/security/ssl/CertificateRequest.java | 59 ++-- .../sun/security/ssl/CertificateVerify.java | 2 + .../sun/security/ssl/DHServerKeyExchange.java | 1 + .../security/ssl/ECDHServerKeyExchange.java | 1 + .../sun/security/ssl/HandshakeContext.java | 5 +- .../security/ssl/PostHandshakeContext.java | 4 +- .../security/ssl/PreSharedKeyExtension.java | 22 +- .../security/ssl/SSLAlgorithmConstraints.java | 34 +-- .../classes/sun/security/ssl/SSLScope.java | 55 ++++ .../sun/security/ssl/SSLSessionImpl.java | 6 +- .../classes/sun/security/ssl/ServerHello.java | 27 +- .../ssl/SignatureAlgorithmsExtension.java | 18 +- .../sun/security/ssl/SignatureScheme.java | 100 ++++--- .../util/DisabledAlgorithmConstraints.java | 61 ++++- jdk/src/share/lib/security/java.security-aix | 17 ++ .../share/lib/security/java.security-linux | 17 ++ .../share/lib/security/java.security-macosx | 17 ++ .../share/lib/security/java.security-solaris | 17 ++ .../share/lib/security/java.security-windows | 17 ++ .../javax/net/ssl/ALPN/SSLEngineAlpnTest.java | 3 + .../net/ssl/TLSv13/EngineOutOfSeqCCS.java | 4 +- .../net/ssl/templates/SSLEngineTemplate.java | 79 +++++- .../testlibrary/jdk/testlibrary/Utils.java | 25 +- .../AbstractCheckSignatureSchemes.java | 251 ++++++++++++++++++ .../DisableSignatureSchemePerScopeTLS12.java | 150 +++++++++++ .../DisableSignatureSchemePerScopeTLS13.java | 108 ++++++++ .../MixingTLSUsageConstraintsWithNonTLS.java | 56 ++++ .../SigAlgosExtTestWithTLS12.java | 19 +- 30 files changed, 1098 insertions(+), 125 deletions(-) create mode 100644 jdk/src/share/classes/sun/security/ssl/SSLScope.java create mode 100644 jdk/test/sun/security/ssl/SignatureScheme/AbstractCheckSignatureSchemes.java create mode 100644 jdk/test/sun/security/ssl/SignatureScheme/DisableSignatureSchemePerScopeTLS12.java create mode 100644 jdk/test/sun/security/ssl/SignatureScheme/DisableSignatureSchemePerScopeTLS13.java create mode 100644 jdk/test/sun/security/ssl/SignatureScheme/MixingTLSUsageConstraintsWithNonTLS.java diff --git a/jdk/src/share/classes/sun/security/ssl/CertSignAlgsExtension.java b/jdk/src/share/classes/sun/security/ssl/CertSignAlgsExtension.java index fd899c273c3..8e1e8fd24f1 100644 --- a/jdk/src/share/classes/sun/security/ssl/CertSignAlgsExtension.java +++ b/jdk/src/share/classes/sun/security/ssl/CertSignAlgsExtension.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 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 @@ -25,6 +25,8 @@ package sun.security.ssl; +import static sun.security.ssl.SignatureScheme.CERTIFICATE_SCOPE; + import java.io.IOException; import java.nio.ByteBuffer; import java.util.Arrays; @@ -98,26 +100,27 @@ public byte[] produce(ConnectionContext context, } // Produce the extension. - if (chc.localSupportedSignAlgs == null) { - chc.localSupportedSignAlgs = - SignatureScheme.getSupportedAlgorithms( - chc.sslConfig, - chc.algorithmConstraints, chc.activeProtocols); + if (chc.localSupportedCertSignAlgs == null) { + chc.localSupportedCertSignAlgs = + SignatureScheme.getSupportedAlgorithms( + chc.sslConfig, + chc.algorithmConstraints, chc.activeProtocols, + CERTIFICATE_SCOPE); } int vectorLen = SignatureScheme.sizeInRecord() * - chc.localSupportedSignAlgs.size(); + chc.localSupportedCertSignAlgs.size(); byte[] extData = new byte[vectorLen + 2]; ByteBuffer m = ByteBuffer.wrap(extData); Record.putInt16(m, vectorLen); - for (SignatureScheme ss : chc.localSupportedSignAlgs) { + for (SignatureScheme ss : chc.localSupportedCertSignAlgs) { Record.putInt16(m, ss.id); } // Update the context. chc.handshakeExtensions.put( SSLExtension.CH_SIGNATURE_ALGORITHMS_CERT, - new SignatureSchemesSpec(chc.localSupportedSignAlgs)); + new SignatureSchemesSpec(chc.localSupportedCertSignAlgs)); return extData; } @@ -197,7 +200,9 @@ public void consume(ConnectionContext context, SignatureScheme.getSupportedAlgorithms( shc.sslConfig, shc.algorithmConstraints, shc.negotiatedProtocol, - spec.signatureSchemes); + spec.signatureSchemes, + CERTIFICATE_SCOPE); + shc.peerRequestedCertSignSchemes = schemes; shc.handshakeSession.setPeerSupportedSignatureAlgorithms(schemes); @@ -246,26 +251,30 @@ public byte[] produce(ConnectionContext context, } // Produce the extension. - List protocols = Arrays.asList(shc.negotiatedProtocol); - protocols = Collections.unmodifiableList(protocols); - List sigAlgs = + if (shc.localSupportedCertSignAlgs == null) { + List protocols = Arrays.asList(shc.negotiatedProtocol); + protocols = Collections.unmodifiableList(protocols); + shc.localSupportedCertSignAlgs = SignatureScheme.getSupportedAlgorithms( shc.sslConfig, shc.algorithmConstraints, - protocols); + protocols, + CERTIFICATE_SCOPE); + } - int vectorLen = SignatureScheme.sizeInRecord() * sigAlgs.size(); + int vectorLen = SignatureScheme.sizeInRecord() + * shc.localSupportedCertSignAlgs.size(); byte[] extData = new byte[vectorLen + 2]; ByteBuffer m = ByteBuffer.wrap(extData); Record.putInt16(m, vectorLen); - for (SignatureScheme ss : sigAlgs) { + for (SignatureScheme ss : shc.localSupportedCertSignAlgs) { Record.putInt16(m, ss.id); } // Update the context. shc.handshakeExtensions.put( SSLExtension.CR_SIGNATURE_ALGORITHMS_CERT, - new SignatureSchemesSpec(shc.localSupportedSignAlgs)); + new SignatureSchemesSpec(shc.localSupportedCertSignAlgs)); return extData; } @@ -344,7 +353,9 @@ public void consume(ConnectionContext context, SignatureScheme.getSupportedAlgorithms( chc.sslConfig, chc.algorithmConstraints, chc.negotiatedProtocol, - spec.signatureSchemes); + spec.signatureSchemes, + CERTIFICATE_SCOPE); + chc.peerRequestedCertSignSchemes = schemes; chc.handshakeSession.setPeerSupportedSignatureAlgorithms(schemes); } diff --git a/jdk/src/share/classes/sun/security/ssl/CertificateMessage.java b/jdk/src/share/classes/sun/security/ssl/CertificateMessage.java index 36948d18fd0..ddfe205f6ad 100644 --- a/jdk/src/share/classes/sun/security/ssl/CertificateMessage.java +++ b/jdk/src/share/classes/sun/security/ssl/CertificateMessage.java @@ -1055,6 +1055,7 @@ private static SSLPossession choosePossession( // Don't select a signature scheme unless we will be able to // produce a CertificateVerify message later if (SignatureScheme.getPreferableAlgorithm( + hc.algorithmConstraints, hc.peerRequestedSignatureSchemes, ss, hc.negotiatedProtocol) == null) { diff --git a/jdk/src/share/classes/sun/security/ssl/CertificateRequest.java b/jdk/src/share/classes/sun/security/ssl/CertificateRequest.java index 85c7716d691..2647672c1a5 100644 --- a/jdk/src/share/classes/sun/security/ssl/CertificateRequest.java +++ b/jdk/src/share/classes/sun/security/ssl/CertificateRequest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021, 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 @@ -25,6 +25,9 @@ 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.PrivateKey; @@ -380,7 +383,6 @@ public void consume(ConnectionContext context, crm.getAuthorities(), (SSLEngine)chc.conContext.transport); } - if (clientAlias == null) { if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { SSLLogger.warning("No available client authentication"); @@ -607,16 +609,33 @@ private T12CertificateRequestProducer() { public byte[] produce(ConnectionContext context, HandshakeMessage message) throws IOException { // The producing happens in server side only. - ServerHandshakeContext shc = (ServerHandshakeContext)context; + ServerHandshakeContext shc = (ServerHandshakeContext) context; + if (shc.localSupportedSignAlgs == null) { shc.localSupportedSignAlgs = - SignatureScheme.getSupportedAlgorithms( - shc.sslConfig, - shc.algorithmConstraints, shc.activeProtocols); + 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); } - if (shc.localSupportedSignAlgs == null || - shc.localSupportedSignAlgs.isEmpty()) { + // According to TLSv1.2 RFC, CertificateRequest message must + // contain signature schemes supported for both: + // handshake signatures and certificate signatures. + List certReqSignAlgs = + new ArrayList<>(shc.localSupportedSignAlgs); + certReqSignAlgs.retainAll(shc.localSupportedCertSignAlgs); + + if (certReqSignAlgs == null || + certReqSignAlgs.isEmpty()) { throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE, "No supported signature algorithm"); } @@ -625,7 +644,7 @@ public byte[] produce(ConnectionContext context, shc.sslContext.getX509TrustManager().getAcceptedIssuers(); T12CertificateRequestMessage crm = new T12CertificateRequestMessage( shc, caCerts, shc.negotiatedCipherSuite.keyExchange, - shc.localSupportedSignAlgs); + certReqSignAlgs); if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Produced CertificateRequest handshake message", crm); @@ -706,19 +725,28 @@ public void consume(ConnectionContext context, chc.handshakeProducers.put(SSLHandshake.CERTIFICATE.id, SSLHandshake.CERTIFICATE); - List sss = + List signAlgs = + SignatureScheme.getSupportedAlgorithms( + chc.sslConfig, + chc.algorithmConstraints, chc.negotiatedProtocol, + crm.algorithmIds, + HANDSHAKE_SCOPE); + + List signCertAlgs = SignatureScheme.getSupportedAlgorithms( chc.sslConfig, chc.algorithmConstraints, chc.negotiatedProtocol, - crm.algorithmIds); - if (sss == null || sss.isEmpty()) { + crm.algorithmIds, + CERTIFICATE_SCOPE); + + if (signAlgs == null || signAlgs.isEmpty() || signCertAlgs.isEmpty()) { throw chc.conContext.fatal(Alert.HANDSHAKE_FAILURE, "No supported signature algorithm"); } - chc.peerRequestedSignatureSchemes = sss; - chc.peerRequestedCertSignSchemes = sss; // use the same schemes - chc.handshakeSession.setPeerSupportedSignatureAlgorithms(sss); + chc.peerRequestedSignatureSchemes = signAlgs; + chc.peerRequestedCertSignSchemes = signCertAlgs; + chc.handshakeSession.setPeerSupportedSignatureAlgorithms(signCertAlgs); chc.peerSupportedAuthorities = crm.getAuthorities(); // For TLS 1.2, we need to use a combination of the CR message's @@ -762,6 +790,7 @@ private static SSLPossession choosePossession(HandshakeContext hc, // Don't select a signature scheme unless we will be able to // produce a CertificateVerify message later if (SignatureScheme.getPreferableAlgorithm( + hc.algorithmConstraints, hc.peerRequestedSignatureSchemes, ss, hc.negotiatedProtocol) == null) { diff --git a/jdk/src/share/classes/sun/security/ssl/CertificateVerify.java b/jdk/src/share/classes/sun/security/ssl/CertificateVerify.java index 8f3d86c4237..2abd1e19000 100644 --- a/jdk/src/share/classes/sun/security/ssl/CertificateVerify.java +++ b/jdk/src/share/classes/sun/security/ssl/CertificateVerify.java @@ -588,6 +588,7 @@ static final class T12CertificateVerifyMessage extends HandshakeMessage { ClientHandshakeContext chc = (ClientHandshakeContext)context; Map.Entry schemeAndSigner = SignatureScheme.getSignerOfPreferableAlgorithm( + chc.algorithmConstraints, chc.peerRequestedSignatureSchemes, x509Possession, chc.negotiatedProtocol); @@ -897,6 +898,7 @@ static final class T13CertificateVerifyMessage extends HandshakeMessage { Map.Entry schemeAndSigner = SignatureScheme.getSignerOfPreferableAlgorithm( + context.algorithmConstraints, context.peerRequestedSignatureSchemes, x509Possession, context.negotiatedProtocol); diff --git a/jdk/src/share/classes/sun/security/ssl/DHServerKeyExchange.java b/jdk/src/share/classes/sun/security/ssl/DHServerKeyExchange.java index 3245482d79f..2fe580c95bd 100644 --- a/jdk/src/share/classes/sun/security/ssl/DHServerKeyExchange.java +++ b/jdk/src/share/classes/sun/security/ssl/DHServerKeyExchange.java @@ -128,6 +128,7 @@ class DHServerKeyExchangeMessage extends HandshakeMessage { if (useExplicitSigAlgorithm) { Map.Entry schemeAndSigner = SignatureScheme.getSignerOfPreferableAlgorithm( + shc.algorithmConstraints, shc.peerRequestedSignatureSchemes, x509Possession, shc.negotiatedProtocol); diff --git a/jdk/src/share/classes/sun/security/ssl/ECDHServerKeyExchange.java b/jdk/src/share/classes/sun/security/ssl/ECDHServerKeyExchange.java index 29fc0808489..d8a4a3745dd 100644 --- a/jdk/src/share/classes/sun/security/ssl/ECDHServerKeyExchange.java +++ b/jdk/src/share/classes/sun/security/ssl/ECDHServerKeyExchange.java @@ -142,6 +142,7 @@ class ECDHServerKeyExchangeMessage extends HandshakeMessage { if (useExplicitSigAlgorithm) { Map.Entry schemeAndSigner = SignatureScheme.getSignerOfPreferableAlgorithm( + shc.algorithmConstraints, shc.peerRequestedSignatureSchemes, x509Possession, shc.negotiatedProtocol); diff --git a/jdk/src/share/classes/sun/security/ssl/HandshakeContext.java b/jdk/src/share/classes/sun/security/ssl/HandshakeContext.java index 9980f2bbcf7..ff07fdee234 100644 --- a/jdk/src/share/classes/sun/security/ssl/HandshakeContext.java +++ b/jdk/src/share/classes/sun/security/ssl/HandshakeContext.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 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 @@ -83,7 +83,7 @@ abstract class HandshakeContext implements ConnectionContext { // consolidated parameters final List activeProtocols; final List activeCipherSuites; - final AlgorithmConstraints algorithmConstraints; + final SSLAlgorithmConstraints algorithmConstraints; final ProtocolVersion maximumActiveProtocol; // output stream @@ -136,6 +136,7 @@ abstract class HandshakeContext implements ConnectionContext { // SignatureScheme List localSupportedSignAlgs; + List localSupportedCertSignAlgs; List peerRequestedSignatureSchemes; List peerRequestedCertSignSchemes; diff --git a/jdk/src/share/classes/sun/security/ssl/PostHandshakeContext.java b/jdk/src/share/classes/sun/security/ssl/PostHandshakeContext.java index 692fd74ba10..a5f9c8c5491 100644 --- a/jdk/src/share/classes/sun/security/ssl/PostHandshakeContext.java +++ b/jdk/src/share/classes/sun/security/ssl/PostHandshakeContext.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 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 @@ -43,7 +43,7 @@ final class PostHandshakeContext extends HandshakeContext { "Post-handshake not supported in " + negotiatedProtocol.name); } - this.localSupportedSignAlgs = new ArrayList<>( + this.localSupportedCertSignAlgs = new ArrayList<>( context.conSession.getLocalSupportedSignatureSchemes()); // Add the potential post-handshake consumers. diff --git a/jdk/src/share/classes/sun/security/ssl/PreSharedKeyExtension.java b/jdk/src/share/classes/sun/security/ssl/PreSharedKeyExtension.java index 8084aae0d4a..2b812eff7f9 100644 --- a/jdk/src/share/classes/sun/security/ssl/PreSharedKeyExtension.java +++ b/jdk/src/share/classes/sun/security/ssl/PreSharedKeyExtension.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2019, 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 @@ -42,6 +42,7 @@ import sun.security.ssl.SSLExtension.SSLExtensionSpec; import sun.security.ssl.SSLHandshake.HandshakeMessage; import static sun.security.ssl.SSLExtension.*; +import static sun.security.ssl.SignatureScheme.CERTIFICATE_SCOPE; /** * Pack of the "pre_shared_key" extension. @@ -412,15 +413,16 @@ private static boolean canRejoin(ClientHelloMessage clientHello, result = false; } - // Make sure that the server handshake context's localSupportedSignAlgs - // field is populated. This is particularly important when - // client authentication was used in an initial session and it is - // now being resumed. - if (shc.localSupportedSignAlgs == null) { - shc.localSupportedSignAlgs = + // Make sure that the server handshake context's + // 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); + shc.algorithmConstraints, shc.activeProtocols, + CERTIFICATE_SCOPE); } // Validate the required client authentication. @@ -442,7 +444,7 @@ private static boolean canRejoin(ClientHelloMessage clientHello, Collection sessionSigAlgs = s.getLocalSupportedSignatureSchemes(); if (result && - !shc.localSupportedSignAlgs.containsAll(sessionSigAlgs)) { + !shc.localSupportedCertSignAlgs.containsAll(sessionSigAlgs)) { if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("Can't resume. Session uses different " + @@ -636,7 +638,7 @@ public byte[] produce(ConnectionContext context, // Make sure the list of supported signature algorithms matches Collection sessionSigAlgs = chc.resumingSession.getLocalSupportedSignatureSchemes(); - if (!chc.localSupportedSignAlgs.containsAll(sessionSigAlgs)) { + if (!chc.localSupportedCertSignAlgs.containsAll(sessionSigAlgs)) { if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("Existing session uses different " + "signature algorithms"); diff --git a/jdk/src/share/classes/sun/security/ssl/SSLAlgorithmConstraints.java b/jdk/src/share/classes/sun/security/ssl/SSLAlgorithmConstraints.java index 59662ab8fd2..171026f1a93 100644 --- a/jdk/src/share/classes/sun/security/ssl/SSLAlgorithmConstraints.java +++ b/jdk/src/share/classes/sun/security/ssl/SSLAlgorithmConstraints.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2022, 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 @@ -42,11 +42,11 @@ */ final class SSLAlgorithmConstraints implements AlgorithmConstraints { - private static final AlgorithmConstraints tlsDisabledAlgConstraints = + private static final DisabledAlgorithmConstraints tlsDisabledAlgConstraints = new DisabledAlgorithmConstraints(PROPERTY_TLS_DISABLED_ALGS, new SSLAlgorithmDecomposer()); - private static final AlgorithmConstraints x509DisabledAlgConstraints = + private static final DisabledAlgorithmConstraints x509DisabledAlgConstraints = new DisabledAlgorithmConstraints(PROPERTY_CERTPATH_DISABLED_ALGS, new SSLAlgorithmDecomposer(true)); @@ -56,11 +56,11 @@ final class SSLAlgorithmConstraints implements AlgorithmConstraints { private final boolean enabledX509DisabledAlgConstraints; // the default algorithm constraints - static final AlgorithmConstraints DEFAULT = + static final SSLAlgorithmConstraints DEFAULT = new SSLAlgorithmConstraints(null, true); // the default SSL only algorithm constraints - static final AlgorithmConstraints DEFAULT_SSL_ONLY = + static final SSLAlgorithmConstraints DEFAULT_SSL_ONLY = new SSLAlgorithmConstraints(null, false); private SSLAlgorithmConstraints(AlgorithmConstraints userSpecifiedConstraints, @@ -84,11 +84,11 @@ private SSLAlgorithmConstraints( * @param userSpecifiedConstraints additional constraints to check * @return a SSLAlgorithmConstraints instance */ - static AlgorithmConstraints wrap(AlgorithmConstraints userSpecifiedConstraints) { + static SSLAlgorithmConstraints wrap(AlgorithmConstraints userSpecifiedConstraints) { return wrap(userSpecifiedConstraints, true); } - private static AlgorithmConstraints wrap( + private static SSLAlgorithmConstraints wrap( AlgorithmConstraints userSpecifiedConstraints, boolean withDefaultCertPathConstraints) { if (nullIfDefault(userSpecifiedConstraints) == null) { @@ -199,22 +199,22 @@ public boolean permits(Set primitives, if (peerSpecifiedConstraints != null) { permitted = peerSpecifiedConstraints.permits( - primitives, algorithm, parameters); + primitives, algorithm, parameters); } if (permitted && userSpecifiedConstraints != null) { permitted = userSpecifiedConstraints.permits( - primitives, algorithm, parameters); + primitives, algorithm, parameters); } if (permitted) { permitted = tlsDisabledAlgConstraints.permits( - primitives, algorithm, parameters); + primitives, algorithm, parameters); } if (permitted && enabledX509DisabledAlgConstraints) { permitted = x509DisabledAlgConstraints.permits( - primitives, algorithm, parameters); + primitives, algorithm, parameters); } return permitted; @@ -252,27 +252,31 @@ public boolean permits(Set primitives, if (peerSpecifiedConstraints != null) { permitted = peerSpecifiedConstraints.permits( - primitives, algorithm, key, parameters); + primitives, algorithm, key, parameters); } if (permitted && userSpecifiedConstraints != null) { permitted = userSpecifiedConstraints.permits( - primitives, algorithm, key, parameters); + primitives, algorithm, key, parameters); } if (permitted) { permitted = tlsDisabledAlgConstraints.permits( - primitives, algorithm, key, parameters); + primitives, algorithm, key, parameters); } if (permitted && enabledX509DisabledAlgConstraints) { permitted = x509DisabledAlgConstraints.permits( - primitives, algorithm, key, parameters); + primitives, algorithm, key, parameters); } return permitted; } + // Checks if algorithm is disabled for the given TLS scopes. + boolean permits(String algorithm, Set scopes) { + return tlsDisabledAlgConstraints.permits(algorithm, scopes); + } private static class SupportedSignatureAlgorithmConstraints implements AlgorithmConstraints { diff --git a/jdk/src/share/classes/sun/security/ssl/SSLScope.java b/jdk/src/share/classes/sun/security/ssl/SSLScope.java new file mode 100644 index 00000000000..d2f4dfc14a3 --- /dev/null +++ b/jdk/src/share/classes/sun/security/ssl/SSLScope.java @@ -0,0 +1,55 @@ +/* + * 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package sun.security.ssl; + +/* + * Scopes defining different parts of TLS protocol. + */ + +public enum SSLScope { + // Handshake signature scope as in signature_algorithms extension. + HANDSHAKE_SIGNATURE("HandshakeSignature"), + + // Certificate signature scope as in signature_algorithms_cert extension. + CERTIFICATE_SIGNATURE("CertificateSignature"); + + private final String name; + + SSLScope(String name) { + this.name = name; + } + + // Note: the SSLScope name is case-insensitive. + public static SSLScope nameOf(String scopeName) { + for (SSLScope scope : SSLScope.values()) { + if (scope.name.equalsIgnoreCase(scopeName)) { + return scope; + } + } + + return null; + } +} diff --git a/jdk/src/share/classes/sun/security/ssl/SSLSessionImpl.java b/jdk/src/share/classes/sun/security/ssl/SSLSessionImpl.java index 4954e7b4a3a..a71f5b87ec6 100644 --- a/jdk/src/share/classes/sun/security/ssl/SSLSessionImpl.java +++ b/jdk/src/share/classes/sun/security/ssl/SSLSessionImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2020, Azul Systems, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -189,10 +189,10 @@ final class SSLSessionImpl extends ExtendedSSLSession { this.sessionId = id; this.host = hc.conContext.transport.getPeerHost(); this.port = hc.conContext.transport.getPeerPort(); - this.localSupportedSignAlgs = hc.localSupportedSignAlgs == null ? + this.localSupportedSignAlgs = hc.localSupportedCertSignAlgs == null ? Collections.emptySet() : Collections.unmodifiableCollection( - new ArrayList<>(hc.localSupportedSignAlgs)); + new ArrayList<>(hc.localSupportedCertSignAlgs)); this.serverNameIndication = hc.negotiatedServerName; this.requestedServerNames = Collections.unmodifiableList( new ArrayList<>(hc.getRequestedServerNames())); diff --git a/jdk/src/share/classes/sun/security/ssl/ServerHello.java b/jdk/src/share/classes/sun/security/ssl/ServerHello.java index 9e888eb964d..3a5b9621cb2 100644 --- a/jdk/src/share/classes/sun/security/ssl/ServerHello.java +++ b/jdk/src/share/classes/sun/security/ssl/ServerHello.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. * Copyright (c) 2020, Azul Systems, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -26,6 +26,9 @@ 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.AccessController; @@ -277,7 +280,16 @@ public byte[] produce(ConnectionContext context, shc.localSupportedSignAlgs = SignatureScheme.getSupportedAlgorithms( shc.sslConfig, - shc.algorithmConstraints, shc.activeProtocols); + shc.algorithmConstraints, shc.activeProtocols, + HANDSHAKE_SCOPE); + } + + if (shc.localSupportedCertSignAlgs == null) { + shc.localSupportedCertSignAlgs = + SignatureScheme.getSupportedAlgorithms( + shc.sslConfig, + shc.algorithmConstraints, shc.activeProtocols, + CERTIFICATE_SCOPE); } SSLSessionImpl session = @@ -506,7 +518,16 @@ public byte[] produce(ConnectionContext context, shc.localSupportedSignAlgs = SignatureScheme.getSupportedAlgorithms( shc.sslConfig, - shc.algorithmConstraints, shc.activeProtocols); + shc.algorithmConstraints, shc.activeProtocols, + HANDSHAKE_SCOPE); + } + + if (shc.localSupportedCertSignAlgs == null) { + shc.localSupportedCertSignAlgs = + SignatureScheme.getSupportedAlgorithms( + shc.sslConfig, + shc.algorithmConstraints, shc.activeProtocols, + CERTIFICATE_SCOPE); } SSLSessionImpl session = diff --git a/jdk/src/share/classes/sun/security/ssl/SignatureAlgorithmsExtension.java b/jdk/src/share/classes/sun/security/ssl/SignatureAlgorithmsExtension.java index b0184ccd76e..3a9225b4a77 100644 --- a/jdk/src/share/classes/sun/security/ssl/SignatureAlgorithmsExtension.java +++ b/jdk/src/share/classes/sun/security/ssl/SignatureAlgorithmsExtension.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, 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 @@ -25,6 +25,8 @@ package sun.security.ssl; +import static sun.security.ssl.SignatureScheme.HANDSHAKE_SCOPE; + import java.io.IOException; import java.nio.ByteBuffer; import java.text.MessageFormat; @@ -187,7 +189,8 @@ public byte[] produce(ConnectionContext context, chc.localSupportedSignAlgs = SignatureScheme.getSupportedAlgorithms( chc.sslConfig, - chc.algorithmConstraints, chc.activeProtocols); + chc.algorithmConstraints, chc.activeProtocols, + HANDSHAKE_SCOPE); } int vectorLen = SignatureScheme.sizeInRecord() * @@ -281,7 +284,9 @@ public void consume(ConnectionContext context, SignatureScheme.getSupportedAlgorithms( shc.sslConfig, shc.algorithmConstraints, shc.negotiatedProtocol, - spec.signatureSchemes); + spec.signatureSchemes, + HANDSHAKE_SCOPE); + if (sss == null || sss.isEmpty()) { throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE, "No supported signature algorithm"); @@ -421,7 +426,8 @@ public byte[] produce(ConnectionContext context, SignatureScheme.getSupportedAlgorithms( shc.sslConfig, shc.algorithmConstraints, - protocols); + protocols, + HANDSHAKE_SCOPE); int vectorLen = SignatureScheme.sizeInRecord() * sigAlgs.size(); byte[] extData = new byte[vectorLen + 2]; @@ -522,7 +528,9 @@ public void consume(ConnectionContext context, SignatureScheme.getSupportedAlgorithms( chc.sslConfig, chc.algorithmConstraints, chc.negotiatedProtocol, - spec.signatureSchemes); + spec.signatureSchemes, + HANDSHAKE_SCOPE); + if (sss == null || sss.isEmpty()) { throw chc.conContext.fatal(Alert.HANDSHAKE_FAILURE, "No supported signature algorithm"); diff --git a/jdk/src/share/classes/sun/security/ssl/SignatureScheme.java b/jdk/src/share/classes/sun/security/ssl/SignatureScheme.java index 75cde10f334..3058faefd1b 100644 --- a/jdk/src/share/classes/sun/security/ssl/SignatureScheme.java +++ b/jdk/src/share/classes/sun/security/ssl/SignatureScheme.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, 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 @@ -153,7 +153,7 @@ enum SignatureScheme { final String name; // literal name private final String algorithm; // signature algorithm final String keyAlgorithm; // signature key algorithm - private final AlgorithmParameterSpec signAlgParameter; + private final SigAlgParamSpec signAlgParams; private final NamedGroup namedGroup; // associated named group // The minimal required key size in bits. @@ -189,6 +189,7 @@ static enum SigAlgParamSpec { // support RSASSA-PSS only now RSA_PSS_SHA512 ("SHA-512", 64); final private AlgorithmParameterSpec parameterSpec; + final private AlgorithmParameters parameters; final boolean isAvailable; SigAlgParamSpec(String hash, int saltLength) { @@ -196,11 +197,13 @@ static enum SigAlgParamSpec { // support RSASSA-PSS only now PSSParameterSpec pssParamSpec = new PSSParameterSpec(hash, "MGF1", new MGF1ParameterSpec(hash), saltLength, 1); + AlgorithmParameters pssParams = null; boolean mediator = true; try { Signature signer = JsseJce.getSignature("RSASSA-PSS"); signer.setParameter(pssParamSpec); + pssParams = signer.getParameters(); } catch (InvalidAlgorithmParameterException | NoSuchAlgorithmException exp) { mediator = false; @@ -213,6 +216,7 @@ static enum SigAlgParamSpec { // support RSASSA-PSS only now this.isAvailable = mediator; this.parameterSpec = mediator ? pssParamSpec : null; + this.parameters = mediator ? pssParams : null; } AlgorithmParameterSpec getParameterSpec() { @@ -220,10 +224,17 @@ AlgorithmParameterSpec getParameterSpec() { } } - // performance optimization - private static final Set SIGNATURE_PRIMITIVE_SET = - Collections.unmodifiableSet(EnumSet.of(CryptoPrimitive.SIGNATURE)); + // Handshake signature scope. + static final Set HANDSHAKE_SCOPE = + Collections.unmodifiableSet(EnumSet.of(SSLScope.HANDSHAKE_SIGNATURE)); + + // Certificate signature scope. + static final Set CERTIFICATE_SCOPE = + Collections.unmodifiableSet(EnumSet.of(SSLScope.CERTIFICATE_SIGNATURE)); + // Non-TLS specific SIGNATURE CryptoPrimitive. + private static final Set SIGNATURE_PRIMITIVE_SET = + Collections.unmodifiableSet(EnumSet.of(CryptoPrimitive.SIGNATURE)); private SignatureScheme(int id, String name, String algorithm, String keyAlgorithm, @@ -267,8 +278,7 @@ private SignatureScheme(int id, String name, this.name = name; this.algorithm = algorithm; this.keyAlgorithm = keyAlgorithm; - this.signAlgParameter = - signAlgParamSpec != null ? signAlgParamSpec.parameterSpec : null; + this.signAlgParams = signAlgParamSpec; this.namedGroup = namedGroup; this.minimalKeySize = minimalKeySize; this.supportedProtocols = Arrays.asList(supportedProtocols); @@ -357,12 +367,24 @@ static int sizeInRecord() { return 2; } + private boolean isPermitted( + SSLAlgorithmConstraints constraints, Set scopes) { + return constraints.permits(this.name, scopes) + && constraints.permits(this.keyAlgorithm, scopes) + && constraints.permits(this.algorithm, scopes) + && constraints.permits(SIGNATURE_PRIMITIVE_SET, this.name, null) + && constraints.permits(SIGNATURE_PRIMITIVE_SET, this.keyAlgorithm, null) + && constraints.permits(SIGNATURE_PRIMITIVE_SET, this.algorithm, + (signAlgParams != null ? signAlgParams.parameters : null)); + } + // Get local supported algorithm collection complying to algorithm - // constraints. + // constraints and SSL scopes. static List getSupportedAlgorithms( SSLConfiguration config, - AlgorithmConstraints constraints, - List activeProtocols) { + SSLAlgorithmConstraints constraints, + List activeProtocols, + Set scopes) { List supported = new LinkedList<>(); for (SignatureScheme ss: SignatureScheme.values()) { if (!ss.isAvailable || @@ -378,15 +400,14 @@ static List getSupportedAlgorithms( boolean isMatch = false; for (ProtocolVersion pv : activeProtocols) { - if (ss.supportedProtocols.contains(pv)) { + if (ss.isSupportedProtocol(pv, scopes)) { isMatch = true; break; } } if (isMatch) { - if (constraints.permits( - SIGNATURE_PRIMITIVE_SET, ss.algorithm, null)) { + if (ss.isPermitted(constraints, scopes)) { supported.add(ss); } else if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake,verbose")) { @@ -405,8 +426,10 @@ static List getSupportedAlgorithms( static List getSupportedAlgorithms( SSLConfiguration config, - AlgorithmConstraints constraints, - ProtocolVersion protocolVersion, int[] algorithmIds) { + SSLAlgorithmConstraints constraints, + ProtocolVersion protocolVersion, + int[] algorithmIds, + Set scopes) { List supported = new LinkedList<>(); for (int ssid : algorithmIds) { SignatureScheme ss = SignatureScheme.valueOf(ssid); @@ -416,12 +439,9 @@ static List getSupportedAlgorithms( "Unsupported signature scheme: " + SignatureScheme.nameOf(ssid)); } - } else if (ss.isAvailable && - ss.supportedProtocols.contains(protocolVersion) && - (config.signatureSchemes.isEmpty() || - config.signatureSchemes.contains(ss)) && - constraints.permits(SIGNATURE_PRIMITIVE_SET, - ss.algorithm, null)) { + } else if ((config.signatureSchemes.isEmpty() + || config.signatureSchemes.contains(ss)) + && ss.isAllowed(constraints, protocolVersion, scopes)) { supported.add(ss); } else { if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { @@ -435,15 +455,14 @@ static List getSupportedAlgorithms( } static SignatureScheme getPreferableAlgorithm( + SSLAlgorithmConstraints constraints, List schemes, SignatureScheme certScheme, ProtocolVersion version) { for (SignatureScheme ss : schemes) { - if (ss.isAvailable && - ss.handshakeSupportedProtocols.contains(version) && - certScheme.keyAlgorithm.equalsIgnoreCase(ss.keyAlgorithm)) { - + if (certScheme.keyAlgorithm.equalsIgnoreCase(ss.keyAlgorithm) + && ss.isAllowed(constraints, version, HANDSHAKE_SCOPE)) { return ss; } } @@ -452,6 +471,7 @@ static SignatureScheme getPreferableAlgorithm( } static Map.Entry getSignerOfPreferableAlgorithm( + SSLAlgorithmConstraints constraints, List schemes, X509Possession x509Possession, ProtocolVersion version) { @@ -467,9 +487,9 @@ static Map.Entry getSignerOfPreferableAlgorithm( keySize = Integer.MAX_VALUE; } for (SignatureScheme ss : schemes) { - if (ss.isAvailable && (keySize >= ss.minimalKeySize) && - ss.handshakeSupportedProtocols.contains(version) && - keyAlgorithm.equalsIgnoreCase(ss.keyAlgorithm)) { + if (keySize >= ss.minimalKeySize && + keyAlgorithm.equalsIgnoreCase(ss.keyAlgorithm) && + ss.isAllowed(constraints, version, HANDSHAKE_SCOPE)) { if (ss.namedGroup != null && ss.namedGroup.type == NamedGroupType.NAMED_GROUP_ECDHE) { ECParameterSpec params = @@ -529,6 +549,26 @@ static Map.Entry getSignerOfPreferableAlgorithm( return null; } + // Returns true if this signature scheme is supported for the given + // protocol version and SSL scopes. + private boolean isSupportedProtocol( + ProtocolVersion version, Set scopes) { + if (scopes != null && scopes.equals(HANDSHAKE_SCOPE)) { + return this.handshakeSupportedProtocols.contains(version); + } else { + return this.supportedProtocols.contains(version); + } + } + + // Returns true if this signature scheme is available, supported and + // permitted for the given constraints, protocol version and SSL scopes. + private boolean isAllowed(SSLAlgorithmConstraints constraints, + ProtocolVersion version, Set scopes) { + return isAvailable + && isSupportedProtocol(version, scopes) + && isPermitted(constraints, scopes); + } + static String[] getAlgorithmNames(Collection schemes) { if (schemes != null) { ArrayList names = new ArrayList<>(schemes.size()); @@ -554,7 +594,7 @@ Signature getVerifier(PublicKey publicKey) throws NoSuchAlgorithmException, } Signature verifier = Signature.getInstance(algorithm); - SignatureUtil.initVerifyWithParam(verifier, publicKey, signAlgParameter); + SignatureUtil.initVerifyWithParam(verifier, publicKey, (signAlgParams != null ? signAlgParams.parameterSpec : null)); return verifier; } @@ -571,7 +611,7 @@ private Signature getSigner(PrivateKey privateKey) { try { Signature signer = Signature.getInstance(algorithm); SignatureUtil.initSignWithParam(signer, privateKey, - signAlgParameter, + (signAlgParams != null ? signAlgParams.parameterSpec : null), null); return signer; } catch (NoSuchAlgorithmException | InvalidKeyException | diff --git a/jdk/src/share/classes/sun/security/util/DisabledAlgorithmConstraints.java b/jdk/src/share/classes/sun/security/util/DisabledAlgorithmConstraints.java index ce3c97120ce..7e118e2cd61 100644 --- a/jdk/src/share/classes/sun/security/util/DisabledAlgorithmConstraints.java +++ b/jdk/src/share/classes/sun/security/util/DisabledAlgorithmConstraints.java @@ -25,6 +25,7 @@ package sun.security.util; +import sun.security.ssl.SSLScope; import sun.security.validator.Validator; import java.lang.ref.SoftReference; @@ -176,6 +177,12 @@ public final boolean permits(Set primitives, return true; } + // Checks if algorithm is disabled for the given TLS scopes. + public boolean permits(String algorithm, Set scopes) { + List list = algorithmConstraints.getConstraints(algorithm); + return list == null || list.stream().allMatch(c -> c.permits(scopes)); + } + /* * Checks if the key algorithm has been disabled or constraints have been * placed on the key. @@ -425,7 +432,7 @@ public Constraints(String propertyName, List constraintArray) { denyAfterLimit = true; } else if (entry.startsWith("usage")) { String s[] = (entry.substring(5)).trim().split(" "); - c = new UsageConstraint(algorithm, s); + c = new UsageConstraint(algorithm, s, propertyName); if (debug != null) { debug.println("Constraints usage length is " + s.length); } @@ -596,6 +603,17 @@ public boolean permits(AlgorithmParameters parameters) { return true; } + /** + * Check if the algorithm constraint permits the given TLS scopes. + * + * @param scopes TLS scopes + * @return 'true' if TLS scopes are allowed, + * 'false' otherwise. + */ + public boolean permits(Set scopes) { + return true; + } + /** * Check if an algorithm constraint is permitted with a given * ConstraintsParameters. @@ -773,14 +791,49 @@ public boolean permits(Key key) { /* * The usage constraint is for the "usage" keyword. It checks against the - * variant value in ConstraintsParameters. + * variant value in ConstraintsParameters and against TLS scopes. */ private static class UsageConstraint extends Constraint { String[] usages; + Set scopes; - UsageConstraint(String algorithm, String[] usages) { + UsageConstraint( + String algorithm, String[] usages, String propertyName) { this.algorithm = algorithm; - this.usages = usages; + + // Support TLS scopes only for jdk.tls.disabledAlgorithms property. + if (PROPERTY_TLS_DISABLED_ALGS.equals(propertyName)) { + for (String usage : usages) { + SSLScope scope = SSLScope.nameOf(usage); + + if (scope != null) { + if (this.scopes == null) { + this.scopes = new HashSet<>(usages.length); + } + this.scopes.add(scope); + } else { + this.usages = usages; + } + } + + if (this.scopes != null && this.usages != null) { + throw new IllegalArgumentException( + "Can't mix TLS protocol specific constraints" + + " with other usage constraints"); + } + + } else { + this.usages = usages; + } + } + + @Override + public boolean permits(Set scopes) { + if (this.scopes == null || scopes == null) { + return true; + } + + return Collections.disjoint(this.scopes, scopes); } @Override diff --git a/jdk/src/share/lib/security/java.security-aix b/jdk/src/share/lib/security/java.security-aix index 2736882f3d3..8da8d62e562 100644 --- a/jdk/src/share/lib/security/java.security-aix +++ b/jdk/src/share/lib/security/java.security-aix @@ -694,6 +694,23 @@ jdk.jar.disabledAlgorithms=MD2, MD5, RSA keySize < 1024, \ # See the specification of "jdk.certpath.disabledAlgorithms" for the # syntax of the disabled algorithm string. # +# Additional TLS-specific syntax supported by this property: +# - TLS protocol specific usage constraints are supported by this property: +# +# UsageConstraint: +# usage UsageType { UsageType } +# +# UsageType: +# HandshakeSignature | CertificateSignature +# +# HandshakeSignature restricts the use of the algorithm in TLS handshake +# signatures. CertificateSignature restricts the use of the algorithm in +# certificate signatures. An algorithm with this constraint cannot include +# other usage types defined in the jdk.certpath.disabledAlgorithms +# property. The usage type follows the keyword and more than one usage type +# can be specified with a whitespace delimiter. +# Example: "rsa_pkcs1_sha1 usage HandshakeSignature" +# # Note: The algorithm restrictions do not apply to trust anchors or # self-signed certificates. # diff --git a/jdk/src/share/lib/security/java.security-linux b/jdk/src/share/lib/security/java.security-linux index 816302e2db2..fb016e141bf 100644 --- a/jdk/src/share/lib/security/java.security-linux +++ b/jdk/src/share/lib/security/java.security-linux @@ -694,6 +694,23 @@ jdk.jar.disabledAlgorithms=MD2, MD5, RSA keySize < 1024, \ # See the specification of "jdk.certpath.disabledAlgorithms" for the # syntax of the disabled algorithm string. # +# Additional TLS-specific syntax supported by this property: +# - TLS protocol specific usage constraints are supported by this property: +# +# UsageConstraint: +# usage UsageType { UsageType } +# +# UsageType: +# HandshakeSignature | CertificateSignature +# +# HandshakeSignature restricts the use of the algorithm in TLS handshake +# signatures. CertificateSignature restricts the use of the algorithm in +# certificate signatures. An algorithm with this constraint cannot include +# other usage types defined in the jdk.certpath.disabledAlgorithms +# property. The usage type follows the keyword and more than one usage type +# can be specified with a whitespace delimiter. +# Example: "rsa_pkcs1_sha1 usage HandshakeSignature" +# # Note: The algorithm restrictions do not apply to trust anchors or # self-signed certificates. # diff --git a/jdk/src/share/lib/security/java.security-macosx b/jdk/src/share/lib/security/java.security-macosx index 18a01e4fafd..6c12001f3e1 100644 --- a/jdk/src/share/lib/security/java.security-macosx +++ b/jdk/src/share/lib/security/java.security-macosx @@ -697,6 +697,23 @@ jdk.jar.disabledAlgorithms=MD2, MD5, RSA keySize < 1024, \ # See the specification of "jdk.certpath.disabledAlgorithms" for the # syntax of the disabled algorithm string. # +# Additional TLS-specific syntax supported by this property: +# - TLS protocol specific usage constraints are supported by this property: +# +# UsageConstraint: +# usage UsageType { UsageType } +# +# UsageType: +# HandshakeSignature | CertificateSignature +# +# HandshakeSignature restricts the use of the algorithm in TLS handshake +# signatures. CertificateSignature restricts the use of the algorithm in +# certificate signatures. An algorithm with this constraint cannot include +# other usage types defined in the jdk.certpath.disabledAlgorithms +# property. The usage type follows the keyword and more than one usage type +# can be specified with a whitespace delimiter. +# Example: "rsa_pkcs1_sha1 usage HandshakeSignature" +# # Note: The algorithm restrictions do not apply to trust anchors or # self-signed certificates. # diff --git a/jdk/src/share/lib/security/java.security-solaris b/jdk/src/share/lib/security/java.security-solaris index 9ca53122ce7..7cfd3be06f5 100644 --- a/jdk/src/share/lib/security/java.security-solaris +++ b/jdk/src/share/lib/security/java.security-solaris @@ -695,6 +695,23 @@ jdk.jar.disabledAlgorithms=MD2, MD5, RSA keySize < 1024, \ # See the specification of "jdk.certpath.disabledAlgorithms" for the # syntax of the disabled algorithm string. # +# Additional TLS-specific syntax supported by this property: +# - TLS protocol specific usage constraints are supported by this property: +# +# UsageConstraint: +# usage UsageType { UsageType } +# +# UsageType: +# HandshakeSignature | CertificateSignature +# +# HandshakeSignature restricts the use of the algorithm in TLS handshake +# signatures. CertificateSignature restricts the use of the algorithm in +# certificate signatures. An algorithm with this constraint cannot include +# other usage types defined in the jdk.certpath.disabledAlgorithms +# property. The usage type follows the keyword and more than one usage type +# can be specified with a whitespace delimiter. +# Example: "rsa_pkcs1_sha1 usage HandshakeSignature" +# # Note: The algorithm restrictions do not apply to trust anchors or # self-signed certificates. # diff --git a/jdk/src/share/lib/security/java.security-windows b/jdk/src/share/lib/security/java.security-windows index fdc05f30914..36cec5d1a9c 100644 --- a/jdk/src/share/lib/security/java.security-windows +++ b/jdk/src/share/lib/security/java.security-windows @@ -697,6 +697,23 @@ jdk.jar.disabledAlgorithms=MD2, MD5, RSA keySize < 1024, \ # See the specification of "jdk.certpath.disabledAlgorithms" for the # syntax of the disabled algorithm string. # +# Additional TLS-specific syntax supported by this property: +# - TLS protocol specific usage constraints are supported by this property: +# +# UsageConstraint: +# usage UsageType { UsageType } +# +# UsageType: +# HandshakeSignature | CertificateSignature +# +# HandshakeSignature restricts the use of the algorithm in TLS handshake +# signatures. CertificateSignature restricts the use of the algorithm in +# certificate signatures. An algorithm with this constraint cannot include +# other usage types defined in the jdk.certpath.disabledAlgorithms +# property. The usage type follows the keyword and more than one usage type +# can be specified with a whitespace delimiter. +# Example: "rsa_pkcs1_sha1 usage HandshakeSignature" +# # Note: The algorithm restrictions do not apply to trust anchors or # self-signed certificates. # diff --git a/jdk/test/javax/net/ssl/ALPN/SSLEngineAlpnTest.java b/jdk/test/javax/net/ssl/ALPN/SSLEngineAlpnTest.java index ca4af2740a0..155cae24206 100644 --- a/jdk/test/javax/net/ssl/ALPN/SSLEngineAlpnTest.java +++ b/jdk/test/javax/net/ssl/ALPN/SSLEngineAlpnTest.java @@ -28,6 +28,8 @@ * @test * @bug 8051498 8145849 8170282 * @summary JEP 244: TLS Application-Layer Protocol Negotiation Extension + * @library /lib/testlibrary + * @build jdk.testlibrary.Utils * * @run main/othervm SSLEngineAlpnTest h2 UNUSED h2 h2 * @run main/othervm SSLEngineAlpnTest h2 UNUSED h2,http/1.1 h2 @@ -128,6 +130,7 @@ import java.security.*; import java.nio.*; import java.util.Arrays; +import jdk.testlibrary.Utils; public class SSLEngineAlpnTest { diff --git a/jdk/test/javax/net/ssl/TLSv13/EngineOutOfSeqCCS.java b/jdk/test/javax/net/ssl/TLSv13/EngineOutOfSeqCCS.java index 94a2c0fe311..cb2421d89cd 100644 --- a/jdk/test/javax/net/ssl/TLSv13/EngineOutOfSeqCCS.java +++ b/jdk/test/javax/net/ssl/TLSv13/EngineOutOfSeqCCS.java @@ -25,7 +25,8 @@ * @test * @bug 8326643 * @summary Test for out-of-sequence change_cipher_spec in TLSv1.3 - * @library /javax/net/ssl/templates + * @library /javax/net/ssl/templates /lib/testlibrary + * @build jdk.testlibrary.Utils * @run main/othervm EngineOutOfSeqCCS */ @@ -34,6 +35,7 @@ import javax.net.ssl.SSLEngineResult.HandshakeStatus; import javax.net.ssl.SSLException; import javax.net.ssl.SSLParameters; +import jdk.testlibrary.Utils; public class EngineOutOfSeqCCS extends SSLEngineTemplate { diff --git a/jdk/test/javax/net/ssl/templates/SSLEngineTemplate.java b/jdk/test/javax/net/ssl/templates/SSLEngineTemplate.java index 9c044f32ebf..bea8856d4a7 100644 --- a/jdk/test/javax/net/ssl/templates/SSLEngineTemplate.java +++ b/jdk/test/javax/net/ssl/templates/SSLEngineTemplate.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -28,12 +28,16 @@ * @test * @bug 8250839 * @summary Improve test template SSLEngineTemplate with SSLContextTemplate - * @build SSLContextTemplate + * @library /lib/testlibrary + * @build SSLContextTemplate jdk.testlibrary.Utils * @run main/othervm SSLEngineTemplate */ + +import java.util.Objects; import javax.net.ssl.*; import javax.net.ssl.SSLEngineResult.HandshakeStatus; import java.nio.ByteBuffer; +import jdk.testlibrary.Utils; /** * A SSLEngine usage example which simplifies the presentation @@ -264,4 +268,75 @@ static void checkTransfer(ByteBuffer a, ByteBuffer b) a.limit(a.capacity()); b.limit(b.capacity()); } + + /** + * Given a TLS record containing one or more handshake messages, return + * the specific handshake message as a ByteBuffer (a slice of the record) + * + * @param tlsRecord A ByteBuffer containing a TLS record. It is + * assumed that the position of the ByteBuffer is on the + * first byte of the TLS record header. + * @param hsMsgId The message identifier for the handshake message + * being sought. + * + * Message Identifiers + * + * @param isDtls Indicates whether DTLS protocol being used. + * @return a ByteBuffer containing the TLS handshake message. + * The position of the returned ByteBuffer will be on the + * first byte of the TLS handshake message data, + * immediately following the handshake header. + * If the message is not found, null will be returned. + * @throws SSLException if the incoming ByteBuffer does not contain + * a well-formed TLS message. + */ + protected static ByteBuffer extractHandshakeMsg( + ByteBuffer tlsRecord, int hsMsgId, boolean isDtls) + throws SSLException { + Objects.requireNonNull(tlsRecord); + tlsRecord.mark(); + + // Process the TLS record header + int type = Byte.toUnsignedInt(tlsRecord.get()); + int ver_major = Byte.toUnsignedInt(tlsRecord.get()); + int ver_minor = Byte.toUnsignedInt(tlsRecord.get()); + // Skip DTLS-specific bytes + if (isDtls) { + tlsRecord.position(tlsRecord.position() + 8); + } + int recLen = Short.toUnsignedInt(tlsRecord.getShort()); + + if (recLen > tlsRecord.remaining()) { + throw new SSLException("Incomplete record in buffer: " + + "Record length = " + recLen + + ", Remaining = " + + tlsRecord.remaining()); + } + + while (tlsRecord.hasRemaining()) { + // Grab the handshake message header. + int msgHdr = tlsRecord.getInt(); + int msgType = (msgHdr >> 24) & 0x000000FF; + int msgLen = msgHdr & 0x00FFFFFF; + // Skip DTLS-specific bytes + if (isDtls) { + tlsRecord.position(tlsRecord.position() + 8); + } + + if (msgType == hsMsgId) { + // Slice the buffer such that it contains the entire + // handshake message (less the handshake header). + ByteBuffer buf = Utils.slice(tlsRecord, tlsRecord.position(), msgLen); + tlsRecord.reset(); + return buf; + } else { + // Skip to the next handshake message, if there is one + tlsRecord.position(tlsRecord.position() + msgLen); + } + } + + tlsRecord.reset(); + return null; + } } diff --git a/jdk/test/lib/testlibrary/jdk/testlibrary/Utils.java b/jdk/test/lib/testlibrary/jdk/testlibrary/Utils.java index 8a315537927..cb0e13837d2 100644 --- a/jdk/test/lib/testlibrary/jdk/testlibrary/Utils.java +++ b/jdk/test/lib/testlibrary/jdk/testlibrary/Utils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2026, 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 @@ -43,6 +43,7 @@ import java.util.LinkedList; import java.util.Objects; import java.util.Set; +import java.nio.ByteBuffer; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -1191,4 +1192,26 @@ public static Set setOf(E... elements) { return Collections.unmodifiableSet(s); } } + + /** + * Implementation of ByteBuffer.slice(int, int) for JDK11. + * @param buffer The ByteBuffer to operate with (read only). + * @param index The position in this buffer at which the content of the + * new buffer will start; must be non-negative and no + * larger than buffer.limit() + * @param length The number of elements the new buffer will contain; must + * be non-negative and no larger than buffer.limit() - index + * @return The new ByteBuffer. + */ + public static ByteBuffer slice(ByteBuffer buffer, int index, int length) { + final int limit = buffer.limit(); + final int position = buffer.position(); + buffer.position(index); + buffer.limit(index + length); + ByteBuffer slice = buffer.slice(); + buffer.limit(limit); + buffer.position(position); + return slice; + } + } diff --git a/jdk/test/sun/security/ssl/SignatureScheme/AbstractCheckSignatureSchemes.java b/jdk/test/sun/security/ssl/SignatureScheme/AbstractCheckSignatureSchemes.java new file mode 100644 index 00000000000..4cbfb057f3a --- /dev/null +++ b/jdk/test/sun/security/ssl/SignatureScheme/AbstractCheckSignatureSchemes.java @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2021, 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. + */ + +import java.nio.ByteBuffer; +import java.util.Collections; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLException; + +/** + * This is not a test. Actual tests are implemented by concrete subclasses. + * The abstract class AbstractCheckSignatureSchemes provides a base framework + * for checking TLS signature schemes. + */ + +public abstract class AbstractCheckSignatureSchemes extends SSLEngineTemplate { + + // Helper map to correlate integral SignatureScheme identifiers to + // their IANA string name counterparts. + protected static final Map sigSchemeMap; + static { + Map temp = new HashMap<>(); + temp.put(0x0401, "rsa_pkcs1_sha256"); + temp.put(0x0501, "rsa_pkcs1_sha384"); + temp.put(0x0601, "rsa_pkcs1_sha512"); + temp.put(0x0403, "ecdsa_secp256r1_sha256"); + temp.put(0x0503, "ecdsa_secp384r1_sha384"); + temp.put(0x0603, "ecdsa_secp521r1_sha512"); + temp.put(0x0804, "rsa_pss_rsae_sha256"); + temp.put(0x0805, "rsa_pss_rsae_sha384"); + temp.put(0x0806, "rsa_pss_rsae_sha512"); + temp.put(0x0807, "ed25519"); + temp.put(0x0808, "ed448"); + temp.put(0x0809, "rsa_pss_pss_sha256"); + temp.put(0x080a, "rsa_pss_pss_sha384"); + temp.put(0x080b, "rsa_pss_pss_sha512"); + temp.put(0x0101, "rsa_md5"); + temp.put(0x0201, "rsa_pkcs1_sha1"); + temp.put(0x0202, "dsa_sha1"); + temp.put(0x0203, "ecdsa_sha1"); + temp.put(0x0301, "rsa_sha224"); + temp.put(0x0302, "dsa_sha224"); + temp.put(0x0303, "ecdsa_sha224"); + temp.put(0x0402, "rsa_pkcs1_sha256"); + sigSchemeMap = Collections.unmodifiableMap(temp); + } + + // Other useful TLS definitions for these tests + protected static final int TLS_HS_CLI_HELLO = 1; + protected static final int TLS_HS_CERT_REQ = 13; + protected static final int SIG_ALGS_EXT = 13; + protected static final int SIG_ALGS_CERT_EXT = 50; + + protected AbstractCheckSignatureSchemes() throws Exception { + super(); + } + + // Returns the protocol for test to use. + abstract String getProtocol(); + + protected boolean isDtls() { + return getProtocol().startsWith("DTLS"); + } + + @Override + protected SSLEngine configureClientEngine(SSLEngine clientEngine) { + clientEngine.setUseClientMode(true); + clientEngine.setEnabledProtocols(new String[]{getProtocol()}); + return clientEngine; + } + + @Override + protected SSLEngine configureServerEngine(SSLEngine serverEngine) { + serverEngine.setUseClientMode(false); + serverEngine.setWantClientAuth(true); + serverEngine.setEnabledProtocols(new String[]{getProtocol()}); + return serverEngine; + } + + @Override + protected ContextParameters getServerContextParameters() { + return new ContextParameters(getProtocol(), "PKIX", "NewSunX509"); + } + + @Override + protected ContextParameters getClientContextParameters() { + return new ContextParameters(getProtocol(), "PKIX", "NewSunX509"); + } + + protected ByteBuffer extractHandshakeMsg(ByteBuffer tlsRecord, int hsMsgId) + throws SSLException { + return extractHandshakeMsg(tlsRecord, hsMsgId, isDtls()); + } + + /** + * Parses the ClientHello message and extracts from it a list of + * SignatureScheme values in string form. It is assumed that the provided + * ByteBuffer has its position set at the first byte of the ClientHello + * message body (AFTER the handshake header) and contains the entire + * hello message. Upon successful completion of this method the ByteBuffer + * will have its position reset to the initial offset in the buffer. + * If an exception is thrown the position at the time of the exception + * will be preserved. + * + * @param data The ByteBuffer containing the ClientHello bytes. + * @param extCode Code of the TLS extension from which to extract + * signature schemes. + * @return A List of the signature schemes in string form. + */ + protected List getSigSchemesCliHello( + ByteBuffer data, int extCode) { + Objects.requireNonNull(data); + data.mark(); + + // Skip over the protocol version and client random + data.position(data.position() + 34); + + // Jump past the session ID (if there is one) + int sessLen = Byte.toUnsignedInt(data.get()); + if (sessLen != 0) { + data.position(data.position() + sessLen); + } + + // Skip DTLS-specific opaque cookie if any + if (isDtls()) { + int cookieLen = Byte.toUnsignedInt(data.get()); + if (cookieLen != 0) { + data.position(data.position() + cookieLen); + } + } + + // Jump past the cipher suites + int csLen = Short.toUnsignedInt(data.getShort()); + if (csLen != 0) { + data.position(data.position() + csLen); + } + + // ...and the compression + int compLen = Byte.toUnsignedInt(data.get()); + if (compLen != 0) { + data.position(data.position() + compLen); + } + + // Now for the fun part. Go through the extensions and look + // for the two status request exts. + List extSigAlgs = getSigSchemesFromExt(data, extCode); + + // We should be at the end of the ClientHello + data.reset(); + return extSigAlgs; + } + + /** + * Parses the CertificateRequest message and extracts from it a list of + * SignatureScheme values in string form. It is assumed that the provided + * ByteBuffer has its position set at the first byte of the + * CertificateRequest message body (AFTER the handshake header) and + * contains the entire CR message. Upon successful completion of this + * method the ByteBuffer will have its position reset to the initial + * offset in the buffer. + * If an exception is thrown the position at the time of the exception + * will be preserved. + * + * @param data The ByteBuffer containing the CertificateRequest bytes + * + * @return A List of the signature schemes in string form. If no + * signature_algorithms extension is present in the CertificateRequest + * then an empty list will be returned. + */ + protected List getSigSchemesCertReq(ByteBuffer data) { + Objects.requireNonNull(data); + data.mark(); + + // Jump past the certificate types + int certTypeLen = Byte.toUnsignedInt(data.get()); + if (certTypeLen != 0) { + data.position(data.position() + certTypeLen); + } + + // Collect the SignatureAndHashAlgorithms + List extSigAlgs = new ArrayList(); + int sigSchemeLen = Short.toUnsignedInt(data.getShort()); + for (int ssOff = 0; ssOff < sigSchemeLen; ssOff += 2) { + String schemeName = sigSchemeMap.get( + Short.toUnsignedInt(data.getShort())); + if (schemeName != null) { + extSigAlgs.add(schemeName); + } + } + + data.reset(); + return extSigAlgs; + } + + /** + * Gets signatures schemes from the given TLS extension. + * The buffer should be positioned at the start of the extension. + */ + protected List getSigSchemesFromExt( + ByteBuffer data, int extCode) { + + List extSigAlgs = new ArrayList<>(); + data.getShort(); // read length + + while (data.hasRemaining()) { + int extType = Short.toUnsignedInt(data.getShort()); + int extLen = Short.toUnsignedInt(data.getShort()); + if (extType == extCode) { + // Start processing signature algorithms + int sigSchemeLen = Short.toUnsignedInt(data.getShort()); + for (int ssOff = 0; ssOff < sigSchemeLen; ssOff += 2) { + String schemeName = sigSchemeMap.get( + Short.toUnsignedInt(data.getShort())); + if (schemeName != null) { + extSigAlgs.add(schemeName); + } + } + } else { + // Not the extension we're looking for. Skip past the + // extension data + data.position(data.position() + extLen); + } + } + + return extSigAlgs; + } +} diff --git a/jdk/test/sun/security/ssl/SignatureScheme/DisableSignatureSchemePerScopeTLS12.java b/jdk/test/sun/security/ssl/SignatureScheme/DisableSignatureSchemePerScopeTLS12.java new file mode 100644 index 00000000000..6c98f5d4d51 --- /dev/null +++ b/jdk/test/sun/security/ssl/SignatureScheme/DisableSignatureSchemePerScopeTLS12.java @@ -0,0 +1,150 @@ +/* + * 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 8349583 + * @summary Add mechanism to disable signature schemes based on their TLS scope. + * This test only covers TLS 1.2. + * @library /javax/net/ssl/templates /lib/testlibrary /test/lib + * @build jdk.testlibrary.Utils + * @run main/othervm DisableSignatureSchemePerScopeTLS12 + */ + +import static jdk.test.lib.Asserts.assertFalse; +import static jdk.test.lib.Asserts.assertTrue; +import jdk.testlibrary.Utils; + +import java.security.Security; +import java.util.List; + +public class DisableSignatureSchemePerScopeTLS12 extends + AbstractCheckSignatureSchemes { + + // Disabled for Handshake scope. + protected static final String HANDSHAKE_DISABLED_SIG = "rsa_pss_rsae_sha384"; + + // Disabled for Certificate scope. + protected static final String CERTIFICATE_DISABLED_SIG = "ecdsa_secp384r1_sha384"; + + // jdk.tls.disabledAlgorithms value + // We differ from "HandshakeSignature" and "CertificateSignature" specified + // in java.security to check case-insensitive matching. + protected static final String DISABLED_CONSTRAINTS = + HANDSHAKE_DISABLED_SIG + " usage HandShakesignature, " + + CERTIFICATE_DISABLED_SIG + " usage certificateSignature"; + + protected DisableSignatureSchemePerScopeTLS12() throws Exception { + super(); + } + + public static void main(String[] args) throws Exception { + Security.setProperty( + "jdk.tls.disabledAlgorithms", DISABLED_CONSTRAINTS); + new DisableSignatureSchemePerScopeTLS12().run(); + } + + protected String getProtocol() { + return "TLSv1.2"; + } + + // Run things in TLS handshake order. + protected void run() throws Exception { + + // Produce client_hello + clientEngine.wrap(clientOut, cTOs); + cTOs.flip(); + + checkClientHello(); + + // Consume client_hello. + serverEngine.unwrap(cTOs, serverIn); + runDelegatedTasks(serverEngine); + + // Produce server_hello. + serverEngine.wrap(serverOut, sTOc); + sTOc.flip(); + + checkCertificateRequest(); + } + + protected void checkClientHello() throws Exception { + // --- Check signature_algorithms extension --- + + // Get signature_algorithms extension signature schemes. + List sigAlgsSS = getSigSchemesCliHello( + extractHandshakeMsg(cTOs, TLS_HS_CLI_HELLO), + SIG_ALGS_EXT); + + // signature_algorithms extension MUST NOT contain disabled + // handshake signature scheme. + assertFalse(sigAlgsSS.contains(HANDSHAKE_DISABLED_SIG), + "Signature Scheme " + HANDSHAKE_DISABLED_SIG + + " present in ClientHello's signature_algorithms extension"); + + // signature_algorithms extension MUST contain disabled + // certificate signature scheme. + assertTrue(sigAlgsSS.contains(CERTIFICATE_DISABLED_SIG), + "Signature Scheme " + CERTIFICATE_DISABLED_SIG + + " isn't present in ClientHello's" + + " signature_algorithms extension"); + + // --- Check signature_algorithms_cert extension --- + + // Get signature_algorithms_cert extension signature schemes. + List sigAlgsCertSS = getSigSchemesCliHello( + extractHandshakeMsg(cTOs, TLS_HS_CLI_HELLO), + SIG_ALGS_CERT_EXT); + + // signature_algorithms_cert extension MUST contain disabled + // handshake signature scheme. + assertTrue(sigAlgsCertSS.contains(HANDSHAKE_DISABLED_SIG), + "Signature Scheme " + HANDSHAKE_DISABLED_SIG + + " isn't present in ClientHello's" + + " signature_algorithms extension"); + + // signature_algorithms_cert extension MUST NOT contain disabled + // certificate signature scheme. + assertFalse(sigAlgsCertSS.contains(CERTIFICATE_DISABLED_SIG), + "Signature Scheme " + CERTIFICATE_DISABLED_SIG + + " present in ClientHello's signature_algorithms extension"); + } + + protected void checkCertificateRequest() throws Exception { + // Get CertificateRequest message signature schemes. + List sigAlgsCertSS = getSigSchemesCertReq( + extractHandshakeMsg(sTOc, TLS_HS_CERT_REQ)); + + // TLSv1.2 CertificateRequest message MUST NOT contain both: + // disabled handshake signature scheme and disabled + // certificate signature scheme + + assertFalse(sigAlgsCertSS.contains(HANDSHAKE_DISABLED_SIG), + "Signature Scheme " + HANDSHAKE_DISABLED_SIG + + " present in CertificateRequest"); + + assertFalse(sigAlgsCertSS.contains(CERTIFICATE_DISABLED_SIG), + "Signature Scheme " + CERTIFICATE_DISABLED_SIG + + " present in CertificateRequest"); + } +} diff --git a/jdk/test/sun/security/ssl/SignatureScheme/DisableSignatureSchemePerScopeTLS13.java b/jdk/test/sun/security/ssl/SignatureScheme/DisableSignatureSchemePerScopeTLS13.java new file mode 100644 index 00000000000..02dc7f84595 --- /dev/null +++ b/jdk/test/sun/security/ssl/SignatureScheme/DisableSignatureSchemePerScopeTLS13.java @@ -0,0 +1,108 @@ +/* + * 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 8349583 + * @summary Add mechanism to disable signature schemes based on their TLS scope. + * This test only covers TLS 1.3. + * @library /javax/net/ssl/templates /lib/testlibrary /test/lib + * @build jdk.testlibrary.Utils + * @run main/othervm DisableSignatureSchemePerScopeTLS13 + */ + + +import static jdk.test.lib.Asserts.assertFalse; +import static jdk.test.lib.Asserts.assertTrue; + +import java.security.Security; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class DisableSignatureSchemePerScopeTLS13 + extends DisableSignatureSchemePerScopeTLS12 { + + // Signature schemes not supported in TLSv1.3 only for the handshake. + // This is regardless of jdk.tls.disabledAlgorithms configuration. + static final List NOT_SUPPORTED_FOR_HANDSHAKE; + static { + List temp = new ArrayList<>(); + temp.add("rsa_pkcs1_sha1"); + temp.add("rsa_pkcs1_sha256"); + temp.add("rsa_pkcs1_sha384"); + temp.add("rsa_pkcs1_sha512"); + NOT_SUPPORTED_FOR_HANDSHAKE = Collections.unmodifiableList(temp); + } + + protected DisableSignatureSchemePerScopeTLS13() throws Exception { + super(); + } + + public static void main(String[] args) throws Exception { + Security.setProperty( + "jdk.tls.disabledAlgorithms", DISABLED_CONSTRAINTS); + new DisableSignatureSchemePerScopeTLS13().run(); + } + + @Override + protected String getProtocol() { + return "TLSv1.3"; + } + + @Override + protected void checkClientHello() throws Exception { + super.checkClientHello(); + + // Get signature_algorithms extension signature schemes. + List sigAlgsSS = getSigSchemesCliHello( + extractHandshakeMsg(cTOs, TLS_HS_CLI_HELLO), + SIG_ALGS_EXT); + + // Should not be present in signature_algorithms extension. + NOT_SUPPORTED_FOR_HANDSHAKE.forEach(ss -> + assertFalse(sigAlgsSS.contains(ss), + "Signature Scheme " + ss + + " present in ClientHello's signature_algorithms extension")); + + // Get signature_algorithms_cert extension signature schemes. + List sigAlgsCertSS = getSigSchemesCliHello( + extractHandshakeMsg(cTOs, TLS_HS_CLI_HELLO), + SIG_ALGS_CERT_EXT); + + // Should be present in signature_algorithms_cert extension. + NOT_SUPPORTED_FOR_HANDSHAKE.forEach(ss -> + assertTrue(sigAlgsCertSS.contains(ss), + "Signature Scheme " + ss + + " isn't present in ClientHello's" + + " signature_algorithms extension")); + } + + // TLSv1.3 sends CertificateRequest signature schemes in + // signature_algorithms and signature_algorithms_cert extensions. Same as + // ClientHello, but they are encrypted. So we skip CertificateRequest + // signature schemes verification for TLSv1.3. + @Override + protected void checkCertificateRequest() { + } +} diff --git a/jdk/test/sun/security/ssl/SignatureScheme/MixingTLSUsageConstraintsWithNonTLS.java b/jdk/test/sun/security/ssl/SignatureScheme/MixingTLSUsageConstraintsWithNonTLS.java new file mode 100644 index 00000000000..3dc811ca66c --- /dev/null +++ b/jdk/test/sun/security/ssl/SignatureScheme/MixingTLSUsageConstraintsWithNonTLS.java @@ -0,0 +1,56 @@ +/* + * 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 8349583 + * @summary Add mechanism to disable signature schemes based on their TLS scope + * @library /javax/net/ssl/templates + * /test/lib + * @run main/othervm MixingTLSUsageConstraintsWithNonTLS + */ + +import static jdk.test.lib.Asserts.assertEquals; +import static jdk.test.lib.Asserts.assertTrue; +import static jdk.test.lib.Utils.runAndCheckException; + +import java.security.Security; + +public class MixingTLSUsageConstraintsWithNonTLS extends SSLSocketTemplate { + + public static void main(String[] args) throws Exception { + Security.setProperty("jdk.tls.disabledAlgorithms", + "rsa_pkcs1_sha1 usage handshakeSignature certificateSignature TLSServer"); + + runAndCheckException( + () -> new MixingTLSUsageConstraintsWithNonTLS().run(), + e -> { + assertTrue(e instanceof ExceptionInInitializerError); + assertTrue( + e.getCause() instanceof IllegalArgumentException); + assertEquals(e.getCause().getMessage(), + "Can't mix TLS protocol specific constraints" + + " with other usage constraints"); + }); + } +} diff --git a/jdk/test/sun/security/ssl/SignatureScheme/SigAlgosExtTestWithTLS12.java b/jdk/test/sun/security/ssl/SignatureScheme/SigAlgosExtTestWithTLS12.java index b2571f46a86..11deea47fc5 100644 --- a/jdk/test/sun/security/ssl/SignatureScheme/SigAlgosExtTestWithTLS12.java +++ b/jdk/test/sun/security/ssl/SignatureScheme/SigAlgosExtTestWithTLS12.java @@ -27,9 +27,11 @@ * the connection should fail fast with "No supported signature algorithm". * This test only covers TLS 1.2. * - * @library /test/lib + * @library /lib/testlibrary * /javax/net/ssl/templates * + * @build jdk.testlibrary.Utils + * * @run main/othervm * -Djdk.tls.server.SignatureSchemes=ecdsa_secp384r1_sha384 * -Djdk.tls.client.SignatureSchemes=ecdsa_secp256r1_sha256,ecdsa_secp384r1_sha384 @@ -53,6 +55,7 @@ import javax.net.ssl.*; import java.nio.ByteBuffer; import java.util.*; +import jdk.testlibrary.Utils; public class SigAlgosExtTestWithTLS12 extends SSLEngineTemplate { @@ -214,7 +217,7 @@ private static void twistCertReqMsg( // Slice the buffer such that it contains the entire // handshake message (less the handshake header). int bufPos = tlsRecord.position(); - ByteBuffer buf = slice(tlsRecord, bufPos, msgLen); + ByteBuffer buf = Utils.slice(tlsRecord, bufPos, msgLen); // Replace the signature scheme with an unknown value twistSigSchemesCertReq(buf, (short) 0x0000); @@ -232,18 +235,6 @@ private static void twistCertReqMsg( tlsRecord.reset(); } - /* Implementation of ByteBuffer.slice(int, int) for JDK11 */ - private static final ByteBuffer slice(ByteBuffer buffer, int index, int length) { - final int limit = buffer.limit(); - final int position = buffer.position(); - buffer.position(index); - buffer.limit(index + length); - ByteBuffer slice = buffer.slice(); - buffer.limit(limit); - buffer.position(position); - return slice; - } - /** * Replace the signature schemes in CertificateRequest message with an * alternative value. It is assumed that the provided ByteBuffer has its From fb271a00eb2b223d79bc88a8f8d9be900bcf9f60 Mon Sep 17 00:00:00 2001 From: Severin Gehwolf Date: Tue, 9 Jun 2026 17:54:25 +0200 Subject: [PATCH 2/3] Fix JDK build when generating the symbols file When ct.sym is being generated by the CreateSymbols annotation processor, generation fails when trying to process DisabledAlgorithmConstraints class since SSLScope doesn't exist in the boot JDK (it's introduced in this patch). Fix the issue by adding a minimal extra boot class path for the boot JDK with just the added class. This will no longer be needed once an 8u512 build has been released with the class included in rt.jar --- common/autoconf/spec.gmk.in | 3 +++ jdk/make/CopyFiles.gmk | 11 +++++++++++ jdk/make/CreateJars.gmk | 2 +- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/common/autoconf/spec.gmk.in b/common/autoconf/spec.gmk.in index ea4ec8e1251..311bb22b5af 100644 --- a/common/autoconf/spec.gmk.in +++ b/common/autoconf/spec.gmk.in @@ -500,8 +500,11 @@ JARSIGNER=@FIXPATH@ $(BOOT_JDK)/bin/jarsigner # You run the new javac using the boot jdk with $(BOOT_JDK)/bin/java $(NEW_JAVAC) ... BOOTSTRAP_JAVAC_JAR:=$(LANGTOOLS_OUTPUTDIR)/dist/bootstrap/lib/javac.jar +BOOTSTRAP_CLASSES_CREATE_SYMBOLS:=$(BUILD_OUTPUT)/jdk/createSymbolsBP BOOTSTRAP_JAVAC_ARGS:="-Xbootclasspath/p:$(BOOTSTRAP_JAVAC_JAR)" -cp $(BOOTSTRAP_JAVAC_JAR) +BOOTSTRAP_JAVAC_ARGS_EXTRA:="-Xbootclasspath/p:$(BOOTSTRAP_JAVAC_JAR)$(PATH_SEP)$(BOOTSTRAP_CLASSES_CREATE_SYMBOLS)" -cp $(BOOTSTRAP_JAVAC_JAR) NEW_JAVAC = $(BOOTSTRAP_JAVAC_ARGS) com.sun.tools.javac.Main +NEW_JAVAC_CREATESYMBOLS = $(BOOTSTRAP_JAVAC_ARGS_EXTRA) com.sun.tools.javac.Main NEW_JAVADOC = $(BOOTSTRAP_JAVAC_ARGS) com.sun.tools.javadoc.Main # Base flags for RC diff --git a/jdk/make/CopyFiles.gmk b/jdk/make/CopyFiles.gmk index 8d6dfa30865..67b64754316 100644 --- a/jdk/make/CopyFiles.gmk +++ b/jdk/make/CopyFiles.gmk @@ -261,6 +261,17 @@ COPY_FILES += $(LIBDIR)/jvm.hprof.txt ########################################################################################## +# +# Bootstrap classpath for CreateSymbols. Add needed files not in the boot JDK +# here. Currently only SSLScope.class since it's needed for DisabledAlgorithmConstraints +# processing. +# +$(eval $(call SetupCopyFiles,COPY_CREATE_SYMBOLS, \ + SRC := $(JDK_OUTPUTDIR)/classes, \ + DEST := $(BOOTSTRAP_CLASSES_CREATE_SYMBOLS), \ + FILES := sun/security/ssl/SSLScope.class)) +COPY_FILES += $(COPY_CREATE_SYMBOLS) + # # How to install jvm.cfg. # diff --git a/jdk/make/CreateJars.gmk b/jdk/make/CreateJars.gmk index 6e484369008..a238d571962 100644 --- a/jdk/make/CreateJars.gmk +++ b/jdk/make/CreateJars.gmk @@ -560,7 +560,7 @@ EXPORTED_PRIVATE_PKGS = com.oracle.net \ $(IMAGES_OUTPUTDIR)/symbols/_the.symbols: $(IMAGES_OUTPUTDIR)/lib/rt.jar $(RM) -r $(IMAGES_OUTPUTDIR)/symbols/META-INF/sym $(MKDIR) -p $(IMAGES_OUTPUTDIR)/symbols/META-INF/sym - $(JAVA) $(NEW_JAVAC) \ + $(JAVA) $(NEW_JAVAC_CREATESYMBOLS) \ -bootclasspath $(JDK_OUTPUTDIR)/classes \ -XDprocess.packages -proc:only \ -processor com.sun.tools.javac.sym.CreateSymbols \ From 91fcc834127df5f6bdca8dd36ada9178a94aa438 Mon Sep 17 00:00:00 2001 From: Severin Gehwolf Date: Mon, 15 Jun 2026 16:28:10 +0200 Subject: [PATCH 3/3] Correct jcheck errors --- .../DisableSignatureSchemePerScopeTLS13.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/jdk/test/sun/security/ssl/SignatureScheme/DisableSignatureSchemePerScopeTLS13.java b/jdk/test/sun/security/ssl/SignatureScheme/DisableSignatureSchemePerScopeTLS13.java index 02dc7f84595..f9de83ac563 100644 --- a/jdk/test/sun/security/ssl/SignatureScheme/DisableSignatureSchemePerScopeTLS13.java +++ b/jdk/test/sun/security/ssl/SignatureScheme/DisableSignatureSchemePerScopeTLS13.java @@ -48,11 +48,11 @@ public class DisableSignatureSchemePerScopeTLS13 static final List NOT_SUPPORTED_FOR_HANDSHAKE; static { List temp = new ArrayList<>(); - temp.add("rsa_pkcs1_sha1"); - temp.add("rsa_pkcs1_sha256"); - temp.add("rsa_pkcs1_sha384"); - temp.add("rsa_pkcs1_sha512"); - NOT_SUPPORTED_FOR_HANDSHAKE = Collections.unmodifiableList(temp); + temp.add("rsa_pkcs1_sha1"); + temp.add("rsa_pkcs1_sha256"); + temp.add("rsa_pkcs1_sha384"); + temp.add("rsa_pkcs1_sha512"); + NOT_SUPPORTED_FOR_HANDSHAKE = Collections.unmodifiableList(temp); } protected DisableSignatureSchemePerScopeTLS13() throws Exception {