8210989: RSASSA-PSS certificate cannot be selected for client auth on TLSv1.2
Reviewed-by: xuelei
--- a/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java Tue Oct 16 11:47:33 2018 -0700
+++ b/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java Tue Oct 16 12:05:57 2018 -0700
@@ -31,7 +31,9 @@
import java.security.cert.X509Certificate;
import java.text.MessageFormat;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
+import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
@@ -675,44 +677,85 @@
chc.peerRequestedSignatureSchemes = sss;
chc.peerRequestedCertSignSchemes = sss; // use the same schemes
chc.handshakeSession.setPeerSupportedSignatureAlgorithms(sss);
+ chc.peerSupportedAuthorities = crm.getAuthorities();
- X509ExtendedKeyManager km = chc.sslContext.getX509KeyManager();
- String clientAlias = null;
- if (chc.conContext.transport instanceof SSLSocketImpl) {
- clientAlias = km.chooseClientAlias(crm.getKeyTypes(),
- crm.getAuthorities(), (SSLSocket)chc.conContext.transport);
- } else if (chc.conContext.transport instanceof SSLEngineImpl) {
- clientAlias = km.chooseEngineClientAlias(crm.getKeyTypes(),
- crm.getAuthorities(), (SSLEngine)chc.conContext.transport);
- }
-
- if (clientAlias == null) {
- if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
- SSLLogger.warning("No available client authentication");
- }
+ // For TLS 1.2, we no longer use the certificate_types field
+ // from the CertificateRequest message to directly determine
+ // the SSLPossession. Instead, the choosePossession method
+ // will use the accepted signature schemes in the message to
+ // determine the set of acceptable certificate types to select from.
+ SSLPossession pos = choosePossession(chc);
+ if (pos == null) {
return;
}
- PrivateKey clientPrivateKey = km.getPrivateKey(clientAlias);
- if (clientPrivateKey == null) {
+ chc.handshakePossessions.add(pos);
+ chc.handshakeProducers.put(SSLHandshake.CERTIFICATE_VERIFY.id,
+ SSLHandshake.CERTIFICATE_VERIFY);
+ }
+
+ private static SSLPossession choosePossession(HandshakeContext hc)
+ throws IOException {
+ if (hc.peerRequestedCertSignSchemes == null ||
+ hc.peerRequestedCertSignSchemes.isEmpty()) {
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
- SSLLogger.warning("No available client private key");
+ SSLLogger.warning("No signature and hash algorithms " +
+ "in CertificateRequest");
}
- return;
+ return null;
}
- X509Certificate[] clientCerts = km.getCertificateChain(clientAlias);
- if ((clientCerts == null) || (clientCerts.length == 0)) {
- if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
- SSLLogger.warning("No available client certificate");
+ Collection<String> checkedKeyTypes = new HashSet<>();
+ for (SignatureScheme ss : hc.peerRequestedCertSignSchemes) {
+ if (checkedKeyTypes.contains(ss.keyAlgorithm)) {
+ if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
+ SSLLogger.warning(
+ "Unsupported authentication scheme: " + ss.name);
+ }
+ continue;
}
- return;
+
+ // Don't select a signature scheme unless we will be able to
+ // produce a CertificateVerify message later
+ if (SignatureScheme.getPreferableAlgorithm(
+ hc.peerRequestedSignatureSchemes,
+ ss, hc.negotiatedProtocol) == null) {
+
+ if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
+ SSLLogger.warning(
+ "Unable to produce CertificateVerify for " +
+ "signature scheme: " + ss.name);
+ }
+ checkedKeyTypes.add(ss.keyAlgorithm);
+ continue;
+ }
+
+ SSLAuthentication ka = X509Authentication.valueOf(ss);
+ if (ka == null) {
+ if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
+ SSLLogger.warning(
+ "Unsupported authentication scheme: " + ss.name);
+ }
+ checkedKeyTypes.add(ss.keyAlgorithm);
+ continue;
+ }
+
+ SSLPossession pos = ka.createPossession(hc);
+ if (pos == null) {
+ if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
+ SSLLogger.warning(
+ "Unavailable authentication scheme: " + ss.name);
+ }
+ continue;
+ }
+
+ return pos;
}
- chc.handshakePossessions.add(
- new X509Possession(clientPrivateKey, clientCerts));
- chc.handshakeProducers.put(SSLHandshake.CERTIFICATE_VERIFY.id,
- SSLHandshake.CERTIFICATE_VERIFY);
+ if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
+ SSLLogger.warning("No available authentication scheme");
+ }
+ return null;
}
}
--- a/src/java.base/share/classes/sun/security/ssl/HandshakeContext.java Tue Oct 16 11:47:33 2018 -0700
+++ b/src/java.base/share/classes/sun/security/ssl/HandshakeContext.java Tue Oct 16 12:05:57 2018 -0700
@@ -43,6 +43,7 @@
import javax.crypto.SecretKey;
import javax.net.ssl.SNIServerName;
import javax.net.ssl.SSLHandshakeException;
+import javax.security.auth.x500.X500Principal;
import sun.security.ssl.SupportedGroupsExtension.NamedGroup;
import sun.security.ssl.SupportedGroupsExtension.NamedGroupType;
import static sun.security.ssl.SupportedGroupsExtension.NamedGroupType.*;
@@ -136,6 +137,9 @@
List<SignatureScheme> peerRequestedSignatureSchemes;
List<SignatureScheme> peerRequestedCertSignSchemes;
+ // Known authorities
+ X500Principal[] peerSupportedAuthorities = null;
+
// SupportedGroups
List<NamedGroup> clientRequestedNamedGroups;
--- a/src/java.base/share/classes/sun/security/ssl/X509Authentication.java Tue Oct 16 11:47:33 2018 -0700
+++ b/src/java.base/share/classes/sun/security/ssl/X509Authentication.java Tue Oct 16 12:05:57 2018 -0700
@@ -170,7 +170,7 @@
return null;
}
- // Used by TLS 1.3 only.
+ // Used by TLS 1.2 and TLS 1.3.
private SSLPossession createClientPossession(
ClientHandshakeContext chc, String keyType) {
X509ExtendedKeyManager km = chc.sslContext.getX509KeyManager();
@@ -178,11 +178,13 @@
if (chc.conContext.transport instanceof SSLSocketImpl) {
clientAlias = km.chooseClientAlias(
new String[] { keyType },
- null, (SSLSocket)chc.conContext.transport);
+ chc.peerSupportedAuthorities,
+ (SSLSocket)chc.conContext.transport);
} else if (chc.conContext.transport instanceof SSLEngineImpl) {
clientAlias = km.chooseEngineClientAlias(
new String[] { keyType },
- null, (SSLEngine)chc.conContext.transport);
+ chc.peerSupportedAuthorities,
+ (SSLEngine)chc.conContext.transport);
}
if (clientAlias == null) {