8268199: Correct certificate requests

Reviewed-by: yan
Backport-of: afeccc7639d3d09041b58cf0f5672eb7310b2cbd
diff --git a/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java b/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java
index 79d92fc..8e8370b 100644
--- a/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java
+++ b/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java
@@ -31,6 +31,7 @@
 import java.security.cert.X509Certificate;
 import java.text.MessageFormat;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashSet;
@@ -44,6 +45,7 @@
 import sun.security.ssl.CipherSuite.KeyExchange;
 import sun.security.ssl.SSLHandshake.HandshakeMessage;
 import sun.security.ssl.X509Authentication.X509Possession;
+import sun.security.ssl.X509Authentication.X509PossessionGenerator;
 
 /**
  * Pack of the CertificateRequest handshake message.
@@ -716,12 +718,11 @@
             chc.handshakeSession.setPeerSupportedSignatureAlgorithms(sss);
             chc.peerSupportedAuthorities = crm.getAuthorities();
 
-            // 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);
+            // For TLS 1.2, we need to use a combination of the CR message's
+            // allowed key types and the signature algorithms in order to
+            // find a certificate chain that has the right key and all certs
+            // using one or more of the allowed cert signature schemes.
+            SSLPossession pos = choosePossession(chc, crm);
             if (pos == null) {
                 return;
             }
@@ -731,8 +732,8 @@
                     SSLHandshake.CERTIFICATE_VERIFY);
         }
 
-        private static SSLPossession choosePossession(HandshakeContext hc)
-                throws IOException {
+        private static SSLPossession choosePossession(HandshakeContext hc,
+                T12CertificateRequestMessage crm) throws IOException {
             if (hc.peerRequestedCertSignSchemes == null ||
                     hc.peerRequestedCertSignSchemes.isEmpty()) {
                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
@@ -742,6 +743,9 @@
                 return null;
             }
 
+            // Put the CR key type into a more friendly format for searching
+            List<String> crKeyTypes = Arrays.asList(crm.getKeyTypes());
+
             Collection<String> checkedKeyTypes = new HashSet<>();
             for (SignatureScheme ss : hc.peerRequestedCertSignSchemes) {
                 if (checkedKeyTypes.contains(ss.keyAlgorithm)) {
@@ -768,7 +772,7 @@
                     continue;
                 }
 
-                SSLAuthentication ka = X509Authentication.valueOf(ss);
+                X509Authentication ka = X509Authentication.valueOf(ss);
                 if (ka == null) {
                     if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
                         SSLLogger.warning(
@@ -776,6 +780,27 @@
                     }
                     checkedKeyTypes.add(ss.keyAlgorithm);
                     continue;
+                } else {
+                    // Any auth object will have a possession generator and
+                    // we need to make sure the key types for that generator
+                    // share at least one common algorithm with the CR's
+                    // allowed key types.
+                    if (ka.possessionGenerator instanceof
+                            X509PossessionGenerator) {
+                        X509PossessionGenerator xpg =
+                            (X509PossessionGenerator) ka.possessionGenerator;
+                        if (Collections.disjoint(crKeyTypes,
+                                Arrays.asList(xpg.keyTypes))) {
+                            if (SSLLogger.isOn &&
+                                    SSLLogger.isOn("ssl,handshake")) {
+                                SSLLogger.warning(
+                                        "Unsupported authentication scheme: " +
+                                                ss.name);
+                            }
+                            checkedKeyTypes.add(ss.keyAlgorithm);
+                            continue;
+                        }
+                    }
                 }
 
                 SSLPossession pos = ka.createPossession(hc);
diff --git a/src/java.base/share/classes/sun/security/ssl/X509Authentication.java b/src/java.base/share/classes/sun/security/ssl/X509Authentication.java
index 5810a7e..32d3b05 100644
--- a/src/java.base/share/classes/sun/security/ssl/X509Authentication.java
+++ b/src/java.base/share/classes/sun/security/ssl/X509Authentication.java
@@ -191,9 +191,9 @@
         }
     }
 
-    private static final
-            class X509PossessionGenerator implements SSLPossessionGenerator {
-        private final String[] keyTypes;
+    static final class X509PossessionGenerator
+                implements SSLPossessionGenerator {
+        final String[] keyTypes;
 
         private X509PossessionGenerator(String[] keyTypes) {
             this.keyTypes = keyTypes;