8210989: RSASSA-PSS certificate cannot be selected for client auth on TLSv1.2

Reviewed-by: xuelei
This commit is contained in:
Jamil Nimeh 2018-10-16 12:05:57 -07:00
parent a9b4ac9c37
commit a40d0a0ee1
3 changed files with 84 additions and 35 deletions

@ -31,7 +31,9 @@ import java.security.PrivateKey;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
@ -675,45 +677,86 @@ final class CertificateRequest {
chc.peerRequestedSignatureSchemes = sss; chc.peerRequestedSignatureSchemes = sss;
chc.peerRequestedCertSignSchemes = sss; // use the same schemes chc.peerRequestedCertSignSchemes = sss; // use the same schemes
chc.handshakeSession.setPeerSupportedSignatureAlgorithms(sss); chc.handshakeSession.setPeerSupportedSignatureAlgorithms(sss);
chc.peerSupportedAuthorities = crm.getAuthorities();
X509ExtendedKeyManager km = chc.sslContext.getX509KeyManager(); // For TLS 1.2, we no longer use the certificate_types field
String clientAlias = null; // from the CertificateRequest message to directly determine
if (chc.conContext.transport instanceof SSLSocketImpl) { // the SSLPossession. Instead, the choosePossession method
clientAlias = km.chooseClientAlias(crm.getKeyTypes(), // will use the accepted signature schemes in the message to
crm.getAuthorities(), (SSLSocket)chc.conContext.transport); // determine the set of acceptable certificate types to select from.
} else if (chc.conContext.transport instanceof SSLEngineImpl) { SSLPossession pos = choosePossession(chc);
clientAlias = km.chooseEngineClientAlias(crm.getKeyTypes(), if (pos == null) {
crm.getAuthorities(), (SSLEngine)chc.conContext.transport);
}
if (clientAlias == null) {
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
SSLLogger.warning("No available client authentication");
}
return; return;
} }
PrivateKey clientPrivateKey = km.getPrivateKey(clientAlias); chc.handshakePossessions.add(pos);
if (clientPrivateKey == null) {
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
SSLLogger.warning("No available client private key");
}
return;
}
X509Certificate[] clientCerts = km.getCertificateChain(clientAlias);
if ((clientCerts == null) || (clientCerts.length == 0)) {
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
SSLLogger.warning("No available client certificate");
}
return;
}
chc.handshakePossessions.add(
new X509Possession(clientPrivateKey, clientCerts));
chc.handshakeProducers.put(SSLHandshake.CERTIFICATE_VERIFY.id, chc.handshakeProducers.put(SSLHandshake.CERTIFICATE_VERIFY.id,
SSLHandshake.CERTIFICATE_VERIFY); 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 signature and hash algorithms " +
"in CertificateRequest");
}
return null;
}
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;
}
// 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;
}
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
SSLLogger.warning("No available authentication scheme");
}
return null;
}
} }
/** /**

@ -43,6 +43,7 @@ import java.util.Queue;
import javax.crypto.SecretKey; import javax.crypto.SecretKey;
import javax.net.ssl.SNIServerName; import javax.net.ssl.SNIServerName;
import javax.net.ssl.SSLHandshakeException; import javax.net.ssl.SSLHandshakeException;
import javax.security.auth.x500.X500Principal;
import sun.security.ssl.SupportedGroupsExtension.NamedGroup; import sun.security.ssl.SupportedGroupsExtension.NamedGroup;
import sun.security.ssl.SupportedGroupsExtension.NamedGroupType; import sun.security.ssl.SupportedGroupsExtension.NamedGroupType;
import static sun.security.ssl.SupportedGroupsExtension.NamedGroupType.*; import static sun.security.ssl.SupportedGroupsExtension.NamedGroupType.*;
@ -136,6 +137,9 @@ abstract class HandshakeContext implements ConnectionContext {
List<SignatureScheme> peerRequestedSignatureSchemes; List<SignatureScheme> peerRequestedSignatureSchemes;
List<SignatureScheme> peerRequestedCertSignSchemes; List<SignatureScheme> peerRequestedCertSignSchemes;
// Known authorities
X500Principal[] peerSupportedAuthorities = null;
// SupportedGroups // SupportedGroups
List<NamedGroup> clientRequestedNamedGroups; List<NamedGroup> clientRequestedNamedGroups;

@ -170,7 +170,7 @@ enum X509Authentication implements SSLAuthentication {
return null; return null;
} }
// Used by TLS 1.3 only. // Used by TLS 1.2 and TLS 1.3.
private SSLPossession createClientPossession( private SSLPossession createClientPossession(
ClientHandshakeContext chc, String keyType) { ClientHandshakeContext chc, String keyType) {
X509ExtendedKeyManager km = chc.sslContext.getX509KeyManager(); X509ExtendedKeyManager km = chc.sslContext.getX509KeyManager();
@ -178,11 +178,13 @@ enum X509Authentication implements SSLAuthentication {
if (chc.conContext.transport instanceof SSLSocketImpl) { if (chc.conContext.transport instanceof SSLSocketImpl) {
clientAlias = km.chooseClientAlias( clientAlias = km.chooseClientAlias(
new String[] { keyType }, new String[] { keyType },
null, (SSLSocket)chc.conContext.transport); chc.peerSupportedAuthorities,
(SSLSocket)chc.conContext.transport);
} else if (chc.conContext.transport instanceof SSLEngineImpl) { } else if (chc.conContext.transport instanceof SSLEngineImpl) {
clientAlias = km.chooseEngineClientAlias( clientAlias = km.chooseEngineClientAlias(
new String[] { keyType }, new String[] { keyType },
null, (SSLEngine)chc.conContext.transport); chc.peerSupportedAuthorities,
(SSLEngine)chc.conContext.transport);
} }
if (clientAlias == null) { if (clientAlias == null) {