8280494: (D)TLS signature schemes

Reviewed-by: mullan
This commit is contained in:
Xue-Lei Andrew Fan 2022-03-09 16:11:07 +00:00
parent 5df2a05770
commit 6d8d156c97
6 changed files with 509 additions and 59 deletions

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2022, 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
@ -29,11 +29,7 @@ import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.AlgorithmConstraints;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.*;
import java.util.function.BiFunction;
import javax.crypto.KeyGenerator;
import javax.net.ssl.HandshakeCompletedListener;
@ -66,7 +62,7 @@ final class SSLConfiguration implements Cloneable {
// The configured signature schemes for "signature_algorithms" and
// "signature_algorithms_cert" extensions
List<SignatureScheme> signatureSchemes;
String[] signatureSchemes;
// the maximum protocol version of enabled protocols
ProtocolVersion maximumProtocolVersion;
@ -204,6 +200,7 @@ final class SSLConfiguration implements Cloneable {
params.setUseCipherSuitesOrder(this.preferLocalCipherSuites);
params.setEnableRetransmissions(this.enableRetransmissions);
params.setMaximumPacketSize(this.maximumPacketSize);
params.setSignatureSchemes(this.signatureSchemes);
return params;
}
@ -261,6 +258,13 @@ final class SSLConfiguration implements Cloneable {
this.applicationProtocols = sa;
} // otherwise, use the default values
String[] ss = params.getSignatureSchemes();
if (ss != null) {
// Note if 'ss' is empty, then no signature schemes should be
// specified over the connections.
this.signatureSchemes = ss;
} // Otherwise, use the default values
this.preferLocalCipherSuites = params.getUseCipherSuitesOrder();
this.enableRetransmissions = params.getEnableRetransmissions();
this.maximumPacketSize = params.getMaximumPacketSize();
@ -403,10 +407,15 @@ final class SSLConfiguration implements Cloneable {
void toggleClientMode() {
this.isClientMode ^= true;
// reset the signature schemes
this.signatureSchemes = isClientMode ?
CustomizedClientSignatureSchemes.signatureSchemes :
CustomizedServerSignatureSchemes.signatureSchemes;
// Reset the signature schemes, if it was configured with SSLParameters.
if (Arrays.equals(signatureSchemes,
CustomizedClientSignatureSchemes.signatureSchemes) ||
Arrays.equals(signatureSchemes,
CustomizedServerSignatureSchemes.signatureSchemes)) {
this.signatureSchemes = isClientMode ?
CustomizedClientSignatureSchemes.signatureSchemes :
CustomizedServerSignatureSchemes.signatureSchemes;
}
}
@Override
@ -434,7 +443,7 @@ final class SSLConfiguration implements Cloneable {
//
// See Effective Java Second Edition: Item 71.
private static final class CustomizedClientSignatureSchemes {
private static final List<SignatureScheme> signatureSchemes =
private static final String[] signatureSchemes =
getCustomizedSignatureScheme("jdk.tls.client.SignatureSchemes");
}
@ -442,7 +451,7 @@ final class SSLConfiguration implements Cloneable {
//
// See Effective Java Second Edition: Item 71.
private static final class CustomizedServerSignatureSchemes {
private static final List<SignatureScheme> signatureSchemes =
private static final String[] signatureSchemes =
getCustomizedSignatureScheme("jdk.tls.server.SignatureSchemes");
}
@ -450,14 +459,12 @@ final class SSLConfiguration implements Cloneable {
* Get the customized signature schemes specified by the given
* system property.
*/
private static List<SignatureScheme> getCustomizedSignatureScheme(
String propertyName) {
private static String[] getCustomizedSignatureScheme(String propertyName) {
String property = GetPropertyAction.privilegedGetProperty(propertyName);
if (SSLLogger.isOn && SSLLogger.isOn("ssl,sslctx")) {
SSLLogger.fine(
"System property " + propertyName + " is set to '" +
property + "'");
property + "'");
}
if (property != null && !property.isEmpty()) {
// remove double quote marks from beginning/end of the property
@ -469,31 +476,34 @@ final class SSLConfiguration implements Cloneable {
if (property != null && !property.isEmpty()) {
String[] signatureSchemeNames = property.split(",");
List<SignatureScheme> signatureSchemes =
new ArrayList<>(signatureSchemeNames.length);
for (int i = 0; i < signatureSchemeNames.length; i++) {
signatureSchemeNames[i] = signatureSchemeNames[i].trim();
if (signatureSchemeNames[i].isEmpty()) {
List<String> signatureSchemes =
new ArrayList<>(signatureSchemeNames.length);
for (String schemeName : signatureSchemeNames) {
schemeName = schemeName.trim();
if (schemeName.isEmpty()) {
continue;
}
SignatureScheme scheme =
SignatureScheme.nameOf(signatureSchemeNames[i]);
// Check the availability
SignatureScheme scheme = SignatureScheme.nameOf(schemeName);
if (scheme != null && scheme.isAvailable) {
signatureSchemes.add(scheme);
signatureSchemes.add(schemeName);
} else {
if (SSLLogger.isOn && SSLLogger.isOn("ssl,sslctx")) {
SSLLogger.fine(
"The current installed providers do not " +
"support signature scheme: " +
signatureSchemeNames[i]);
"The current installed providers do not " +
"support signature scheme: " + schemeName);
}
}
}
return signatureSchemes;
if (!signatureSchemes.isEmpty()) {
return signatureSchemes.toArray(new String[0]);
}
}
return Collections.emptyList();
// Note that if the System Property value is not defined (JDK
// default value) or empty, the provider-specific default is used.
return null;
}
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2022, 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
@ -181,7 +181,7 @@ enum SignatureScheme {
"anonymous", "rsa", "dsa", "ecdsa",
};
static enum SigAlgParamSpec { // support RSASSA-PSS only now
enum SigAlgParamSpec { // support RSASSA-PSS only now
RSA_PSS_SHA256 ("SHA-256", 32),
RSA_PSS_SHA384 ("SHA-384", 48),
RSA_PSS_SHA512 ("SHA-512", 64);
@ -224,13 +224,13 @@ enum SignatureScheme {
Collections.unmodifiableSet(EnumSet.of(CryptoPrimitive.SIGNATURE));
private SignatureScheme(int id, String name,
SignatureScheme(int id, String name,
String algorithm, String keyAlgorithm,
ProtocolVersion[] supportedProtocols) {
this(id, name, algorithm, keyAlgorithm, -1, supportedProtocols);
}
private SignatureScheme(int id, String name,
SignatureScheme(int id, String name,
String algorithm, String keyAlgorithm,
int minimalKeySize,
ProtocolVersion[] supportedProtocols) {
@ -238,7 +238,7 @@ enum SignatureScheme {
null, minimalKeySize, supportedProtocols);
}
private SignatureScheme(int id, String name,
SignatureScheme(int id, String name,
String algorithm, String keyAlgorithm,
SigAlgParamSpec signAlgParamSpec, int minimalKeySize,
ProtocolVersion[] supportedProtocols) {
@ -247,7 +247,7 @@ enum SignatureScheme {
supportedProtocols, supportedProtocols);
}
private SignatureScheme(int id, String name,
SignatureScheme(int id, String name,
String algorithm, String keyAlgorithm,
NamedGroup namedGroup,
ProtocolVersion[] supportedProtocols) {
@ -256,7 +256,7 @@ enum SignatureScheme {
supportedProtocols, supportedProtocols);
}
private SignatureScheme(int id, String name,
SignatureScheme(int id, String name,
String algorithm, String keyAlgorithm,
SigAlgParamSpec signAlgParams,
NamedGroup namedGroup, int minimalKeySize,
@ -376,15 +376,10 @@ enum SignatureScheme {
List<ProtocolVersion> activeProtocols) {
List<SignatureScheme> supported = new LinkedList<>();
// If config.signatureSchemes is non-empty then it means that
// it was defined by a System property. Per
// SSLConfiguration.getCustomizedSignatureScheme() the list will
// only contain schemes that are in the enum.
// Otherwise, use the enum constants (converted to a List).
List<SignatureScheme> schemesToCheck =
config.signatureSchemes.isEmpty() ?
config.signatureSchemes == null ?
Arrays.asList(SignatureScheme.values()) :
config.signatureSchemes;
namesOfAvailable(config.signatureSchemes);
for (SignatureScheme ss: schemesToCheck) {
if (!ss.isAvailable) {
@ -437,8 +432,8 @@ enum SignatureScheme {
}
} else if (ss.isAvailable &&
ss.supportedProtocols.contains(protocolVersion) &&
(config.signatureSchemes.isEmpty() ||
config.signatureSchemes.contains(ss)) &&
(config.signatureSchemes == null ||
Utilities.contains(config.signatureSchemes, ss.name)) &&
ss.isPermitted(constraints)) {
supported.add(ss);
} else {
@ -563,6 +558,33 @@ enum SignatureScheme {
return new String[0];
}
private static List<SignatureScheme> namesOfAvailable(
String[] signatureSchemes) {
if (signatureSchemes == null || signatureSchemes.length == 0) {
return Collections.emptyList();
}
List<SignatureScheme> sss = new ArrayList<>(signatureSchemes.length);
for (String ss : signatureSchemes) {
SignatureScheme scheme = SignatureScheme.nameOf(ss);
if (scheme == null || !scheme.isAvailable) {
if (SSLLogger.isOn &&
SSLLogger.isOn("ssl,handshake,verbose")) {
SSLLogger.finest(
"Ignore the signature algorithm (" + ss
+ "), unsupported or unavailable");
}
continue;
}
sss.add(scheme);
}
return sss;
}
// This method is used to get the signature instance of this signature
// scheme for the specific public key. Unlike getSigner(), the exception
// is bubbled up. If the public key does not support this signature

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2022, 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
@ -229,6 +229,16 @@ final class Utilities {
}
}
static <T> boolean contains(T[] array, T item) {
for (T t : array) {
if (item.equals(t)) {
return true;
}
}
return false;
}
private static void swap(byte[] arr, int i, int j) {
byte tmp = arr[i];
arr[i] = arr[j];