diff --git a/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java b/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java index 8df72711dff..a1cc3ee112f 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -31,6 +31,7 @@ import java.security.*; import java.security.cert.*; import java.util.*; import java.util.concurrent.locks.ReentrantLock; +import java.util.stream.Collectors; import javax.net.ssl.*; import sun.security.provider.certpath.AlgorithmChecker; import sun.security.ssl.SSLAlgorithmConstraints.SIGNATURE_CONSTRAINTS_MODE; @@ -366,13 +367,24 @@ public abstract class SSLContextImpl extends SSLContextSpi { Collection allowedCipherSuites, List protocols) { LinkedHashSet suites = new LinkedHashSet<>(); + List disabledSuites = null; + List unAvailableSuites = null; + + if (SSLLogger.isOn() && SSLLogger.isOn(SSLLogger.Opt.SSLCTX)) { + disabledSuites = new ArrayList<>(); + unAvailableSuites = new ArrayList<>(); + } + if (protocols != null && (!protocols.isEmpty())) { for (CipherSuite suite : allowedCipherSuites) { if (!suite.isAvailable()) { + if (SSLLogger.isOn() && + SSLLogger.isOn(SSLLogger.Opt.SSLCTX)) { + unAvailableSuites.add(suite.name); + } continue; } - boolean isSupported = false; for (ProtocolVersion protocol : protocols) { if (!suite.supports(protocol) || !suite.bulkCipher.isAvailable()) { @@ -383,27 +395,43 @@ public abstract class SSLContextImpl extends SSLContextSpi { EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), suite.name, null)) { suites.add(suite); - isSupported = true; } else if (SSLLogger.isOn() && - SSLLogger.isOn(SSLLogger.Opt.HANDSHAKE)) { - SSLLogger.fine( - "Ignore disabled cipher suite: " + suite.name); + SSLLogger.isOn(SSLLogger.Opt.SSLCTX)) { + disabledSuites.add(suite.name); } break; } - - if (!isSupported && SSLLogger.isOn() && - SSLLogger.isOn(SSLLogger.Opt.HANDSHAKE)) { - SSLLogger.finest( - "Ignore unsupported cipher suite: " + suite); - } } } + if(SSLLogger.isOn() && SSLLogger.isOn(SSLLogger.Opt.SSLCTX)) { + logSuites("Ignore disabled cipher suites for protocols: ", + protocols, disabledSuites); + logSuites("Ignore unavailable cipher suites for protocols: ", + protocols, unAvailableSuites); + logSuites("Available cipher suites for protocols: ", + protocols, suites); + + } return new ArrayList<>(suites); } + private static void logSuites(String message, + List protocols, + Collection suites) { + if (suites.isEmpty()) { + return; + } + String protocolStr = protocols.stream() + .map(pv -> pv.name) + .collect(Collectors.joining(", ", "[", "]")); + String suiteStr = String.join(", ", + suites.stream().map(Object::toString).collect(Collectors.toList())); + SSLLogger.finest(message + protocolStr + System.lineSeparator() + + Utilities.wrapText("[" + suiteStr + "]", 140)); + } + /* * Get the customized cipher suites specified by the given system property. */ @@ -459,10 +487,14 @@ public abstract class SSLContextImpl extends SSLContextSpi { } } } - + if (cipherSuites.isEmpty() && SSLLogger.isOn() + && SSLLogger.isOn(SSLLogger.Opt.SSLCTX)) { + SSLLogger.fine( + "No cipher suites satisfy property: " + propertyName + + ". Returning empty list"); + } return cipherSuites; } - return Collections.emptyList(); } @@ -530,9 +562,6 @@ public abstract class SSLContextImpl extends SSLContextSpi { private static final List supportedProtocols; private static final List serverDefaultProtocols; - private static final List supportedCipherSuites; - private static final List serverDefaultCipherSuites; - static { supportedProtocols = Arrays.asList( ProtocolVersion.TLS13, @@ -550,13 +579,15 @@ public abstract class SSLContextImpl extends SSLContextSpi { ProtocolVersion.TLS11, ProtocolVersion.TLS10 }); - - supportedCipherSuites = getApplicableSupportedCipherSuites( - supportedProtocols); - serverDefaultCipherSuites = getApplicableEnabledCipherSuites( - serverDefaultProtocols, false); } + private static final LazyConstant> + supportedCipherSuites = LazyConstant.of(() -> + getApplicableSupportedCipherSuites(supportedProtocols)); + private static final LazyConstant> + serverDefaultCipherSuites = LazyConstant.of(() -> + getApplicableEnabledCipherSuites(serverDefaultProtocols, false)); + @Override List getSupportedProtocolVersions() { return supportedProtocols; @@ -564,7 +595,7 @@ public abstract class SSLContextImpl extends SSLContextSpi { @Override List getSupportedCipherSuites() { - return supportedCipherSuites; + return supportedCipherSuites.get(); } @Override @@ -574,7 +605,7 @@ public abstract class SSLContextImpl extends SSLContextSpi { @Override List getServerDefaultCipherSuites() { - return serverDefaultCipherSuites; + return serverDefaultCipherSuites.get(); } @Override @@ -814,10 +845,18 @@ public abstract class SSLContextImpl extends SSLContextSpi { clientDefaultCipherSuites = getApplicableEnabledCipherSuites( clientDefaultProtocols, true); - serverDefaultCipherSuites = - getApplicableEnabledCipherSuites( - serverDefaultProtocols, false); - + // getApplicableEnabledCipherSuites returns same CS List if + // no customized CS in use and protocols are same. Can avoid + // the getApplicableEnabledCipherSuites call + if (clientCustomizedCipherSuites.isEmpty() && + serverCustomizedCipherSuites.isEmpty() && + clientDefaultProtocols.equals(serverDefaultProtocols)) { + serverDefaultCipherSuites = clientDefaultCipherSuites; + } else { + serverDefaultCipherSuites = + getApplicableEnabledCipherSuites( + serverDefaultProtocols, false); + } } else { // unlikely to be used clientDefaultProtocols = null; diff --git a/src/java.base/share/classes/sun/security/ssl/Utilities.java b/src/java.base/share/classes/sun/security/ssl/Utilities.java index e289a9e1bd6..cfd39aecac2 100644 --- a/src/java.base/share/classes/sun/security/ssl/Utilities.java +++ b/src/java.base/share/classes/sun/security/ssl/Utilities.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -168,6 +168,35 @@ final class Utilities { return builder.toString(); } + static String wrapText(String text, int maxWidth) { + if (text == null || text.isEmpty() || maxWidth <= 0) { + return ""; + } + StringBuilder result = new StringBuilder(); + String[] values = text.split(",\\s*"); + StringBuilder line = new StringBuilder(); + + for (int i = 0; i < values.length; i++) { + String value = values[i]; + // If adding this value would exceed maxWidth + if (line.length() > 0) { + // +1 for the comma + if (line.length() + 1 + value.length() > maxWidth) { + result.append(line).append(LINE_SEP); + line.setLength(0); + } else { + line.append(","); + } + } + line.append(value); + } + // Append any remaining line + if (line.length() > 0) { + result.append(line); + } + return result.toString(); + } + static String byte16HexString(int id) { return "0x" + HEX_FORMATTER.toHexDigits((short)id); } diff --git a/test/jdk/sun/security/ssl/SSLLogger/DebugPropertyValuesTest.java b/test/jdk/sun/security/ssl/SSLLogger/DebugPropertyValuesTest.java index 77f585d6d55..59becf3b664 100644 --- a/test/jdk/sun/security/ssl/SSLLogger/DebugPropertyValuesTest.java +++ b/test/jdk/sun/security/ssl/SSLLogger/DebugPropertyValuesTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 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 @@ -23,7 +23,7 @@ /** * @test - * @bug 8350582 8340312 8369995 8044609 8372004 + * @bug 8350582 8340312 8369995 8044609 8372004 8371333 * @library /test/lib /javax/net/ssl/templates * @summary Correct the parsing of the ssl value in javax.net.debug * @run junit DebugPropertyValuesTest @@ -60,8 +60,8 @@ public class DebugPropertyValuesTest extends SSLSocketTemplate { "supported_versions")); debugMessages.put("handshake-expand", List.of("\"logger\".*: \"javax.net.ssl\",", - "\"specifics\" : \\[", - "\"message\".*: \"Produced ClientHello handshake message")); + "\"specifics\" : \\[", + "\"message\".*: \"Produced ClientHello handshake message")); debugMessages.put("keymanager", List.of("Choosing key:")); debugMessages.put("packet", List.of("Raw write")); debugMessages.put("plaintext", @@ -73,11 +73,13 @@ public class DebugPropertyValuesTest extends SSLSocketTemplate { debugMessages.put("session", List.of("Session initialized:")); debugMessages.put("ssl", List.of("jdk.tls.keyLimits:")); debugMessages.put("sslctx", - List.of("trigger seeding of SecureRandom")); + List.of("trigger seeding of SecureRandom", + // Available list should finish with this style + "TLS_EMPTY_RENEGOTIATION_INFO_SCSV]", + "Ignore disabled cipher suites for protocols: " + + "\\[TLSv1.3, TLSv1.2\\]")); debugMessages.put("trustmanager", List.of("adding as trusted certificates")); - debugMessages.put("verbose", - List.of("Ignore unsupported cipher suite:")); debugMessages.put("help", List.of("print this help message and exit", "verbose handshake message printing")); @@ -110,17 +112,16 @@ public class DebugPropertyValuesTest extends SSLSocketTemplate { Arguments.of(List.of("-Djavax.net.debug=all"), List.of("handshake", "keymanager", "packet", "plaintext", "record", "session", "ssl", - "sslctx", "trustmanager", "verbose")), + "sslctx", "trustmanager")), // ssl should print most details except verbose details Arguments.of(List.of("-Djavax.net.debug=ssl"), List.of("handshake", "keymanager", "record", "session", "ssl", - "sslctx", "trustmanager", "verbose")), + "sslctx", "trustmanager")), // allow expand option for more verbose output Arguments.of( List.of("-Djavax.net.debug=ssl,handshake,expand"), - List.of("handshake", "handshake-expand", - "ssl", "verbose")), + List.of("handshake", "handshake-expand", "ssl")), // filtering on record option, with expand Arguments.of(List.of("-Djavax.net.debug=ssl:record,expand"), List.of("record", "record-expand", "ssl")), @@ -142,12 +143,12 @@ public class DebugPropertyValuesTest extends SSLSocketTemplate { Arguments.of(List.of("-Djavax.net.debug=ssl,typo"), List.of("handshake", "keymanager", "record", "session", "ssl", - "sslctx", "trustmanager", "verbose")), + "sslctx", "trustmanager")), // ssltypo contains "ssl". Treat like "ssl" Arguments.of(List.of("-Djavax.net.debug=ssltypo"), List.of("handshake", "keymanager", "record", "session", "ssl", - "sslctx", "trustmanager", "verbose")), + "sslctx", "trustmanager")), // plaintext is valid for record option Arguments.of(List.of("-Djavax.net.debug=ssl:record:plaintext"), List.of("plaintext", "record", "ssl")), @@ -168,7 +169,7 @@ public class DebugPropertyValuesTest extends SSLSocketTemplate { List.of("handshake", "javax.net.debug.logger", "keymanager", "packet", "plaintext", "record", "session", "ssl", - "sslctx", "trustmanager", "verbose")) + "sslctx", "trustmanager")) ); }