8371333: Optimize static initialization of SSLContextImpl classes and improve logging

Reviewed-by: hchao, jnimeh
This commit is contained in:
Sean Coffey 2026-02-25 12:57:30 +00:00
parent ce6ccd385f
commit 93fe49abef
3 changed files with 112 additions and 43 deletions

View File

@ -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<CipherSuite> allowedCipherSuites,
List<ProtocolVersion> protocols) {
LinkedHashSet<CipherSuite> suites = new LinkedHashSet<>();
List<String> disabledSuites = null;
List<String> 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<ProtocolVersion> 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<ProtocolVersion> supportedProtocols;
private static final List<ProtocolVersion> serverDefaultProtocols;
private static final List<CipherSuite> supportedCipherSuites;
private static final List<CipherSuite> 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<List<CipherSuite>>
supportedCipherSuites = LazyConstant.of(() ->
getApplicableSupportedCipherSuites(supportedProtocols));
private static final LazyConstant<List<CipherSuite>>
serverDefaultCipherSuites = LazyConstant.of(() ->
getApplicableEnabledCipherSuites(serverDefaultProtocols, false));
@Override
List<ProtocolVersion> getSupportedProtocolVersions() {
return supportedProtocols;
@ -564,7 +595,7 @@ public abstract class SSLContextImpl extends SSLContextSpi {
@Override
List<CipherSuite> getSupportedCipherSuites() {
return supportedCipherSuites;
return supportedCipherSuites.get();
}
@Override
@ -574,7 +605,7 @@ public abstract class SSLContextImpl extends SSLContextSpi {
@Override
List<CipherSuite> 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;

View File

@ -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);
}

View File

@ -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"))
);
}