1 /*
   2  * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.security.ssl;
  27 
  28 import java.io.ByteArrayInputStream;
  29 import java.io.IOException;
  30 import java.nio.ByteBuffer;
  31 import java.security.PublicKey;
  32 import java.security.cert.CertPathValidatorException;
  33 import java.security.cert.CertPathValidatorException.BasicReason;
  34 import java.security.cert.CertPathValidatorException.Reason;
  35 import java.security.cert.CertificateEncodingException;
  36 import java.security.cert.CertificateException;
  37 import java.security.cert.CertificateFactory;
  38 import java.security.cert.CertificateParsingException;
  39 import java.security.cert.X509Certificate;
  40 import java.text.MessageFormat;
  41 import java.util.ArrayList;
  42 import java.util.Arrays;
  43 import java.util.Collection;
  44 import java.util.Collections;
  45 import java.util.HashSet;
  46 import java.util.LinkedList;
  47 import java.util.List;
  48 import java.util.Locale;
  49 import javax.net.ssl.SSLEngine;
  50 import javax.net.ssl.SSLException;
  51 import javax.net.ssl.SSLProtocolException;
  52 import javax.net.ssl.SSLSocket;
  53 import javax.net.ssl.X509ExtendedTrustManager;
  54 import javax.net.ssl.X509TrustManager;
  55 import javax.security.auth.x500.X500Principal;
  56 import sun.security.ssl.CertificateMessage.T12CertificateMessage;
  57 import static sun.security.ssl.ClientAuthType.CLIENT_AUTH_REQUIRED;
  58 import sun.security.ssl.ClientHello.ClientHelloMessage;
  59 import sun.security.ssl.SSLHandshake.HandshakeMessage;
  60 import sun.security.ssl.X509Authentication.X509Credentials;
  61 import sun.security.ssl.X509Authentication.X509Possession;
  62 
  63 /**
  64  * Pack of the CertificateMessage handshake message.
  65  */
  66 final class CertificateMessage {
  67     static final SSLConsumer t12HandshakeConsumer =
  68         new T12CertificateConsumer();
  69     static final HandshakeProducer t12HandshakeProducer =
  70         new T12CertificateProducer();
  71 
  72     static final SSLConsumer t13HandshakeConsumer =
  73         new T13CertificateConsumer();
  74     static final HandshakeProducer t13HandshakeProducer =
  75         new T13CertificateProducer();
  76 
  77     /**
  78      * The Certificate handshake message for TLS 1.2 and previous
  79      * SSL/TLS protocol versions.
  80      *
  81      * In server mode, the certificate handshake message is sent whenever the
  82      * agreed-upon key exchange method uses certificates for authentication.
  83      * In client mode, this message is only sent if the server requests a
  84      * certificate for client authentication.
  85      *
  86      *       opaque ASN.1Cert<1..2^24-1>;
  87      *
  88      * SSL 3.0:
  89      *       struct {
  90      *           ASN.1Cert certificate_list<1..2^24-1>;
  91      *       } Certificate;
  92      * Note: For SSL 3.0 client authentication, if no suitable certificate
  93      * is available, the client should send a no_certificate alert instead.
  94      * This alert is only a warning; however, the server may respond with
  95      * a fatal handshake failure alert if client authentication is required.
  96      *
  97      * TLS 1.0/1.1/1.2:
  98      *       struct {
  99      *           ASN.1Cert certificate_list<0..2^24-1>;
 100      *       } Certificate;
 101      */
 102     static final class T12CertificateMessage extends HandshakeMessage {
 103         final List<byte[]> encodedCertChain;
 104 
 105         T12CertificateMessage(HandshakeContext handshakeContext,
 106                 X509Certificate[] certChain) throws SSLException {
 107             super(handshakeContext);
 108 
 109             List<byte[]> encodedCerts = new ArrayList<>(certChain.length);
 110             for (X509Certificate cert : certChain) {
 111                 try {
 112                     encodedCerts.add(cert.getEncoded());
 113                 } catch (CertificateEncodingException cee) {
 114                     // unlikely
 115                     handshakeContext.conContext.fatal(Alert.INTERNAL_ERROR,
 116                             "Could not encode certificate (" +
 117                             cert.getSubjectX500Principal() + ")", cee);
 118                     break;      // make the complier happy
 119                 }
 120             }
 121 
 122             this.encodedCertChain = encodedCerts;
 123         }
 124 
 125         T12CertificateMessage(HandshakeContext handshakeContext,
 126                 ByteBuffer m) throws IOException {
 127             super(handshakeContext);
 128 
 129             int listLen = Record.getInt24(m);
 130             if (listLen > m.remaining()) {
 131                 handshakeContext.conContext.fatal(Alert.ILLEGAL_PARAMETER,
 132                     "Error parsing certificate message:no sufficient data");
 133             }
 134             if (listLen > 0) {
 135                 List<byte[]> encodedCerts = new LinkedList<>();
 136                 while (listLen > 0) {
 137                     byte[] encodedCert = Record.getBytes24(m);
 138                     listLen -= (3 + encodedCert.length);
 139                     encodedCerts.add(encodedCert);
 140                 }
 141                 this.encodedCertChain = encodedCerts;
 142             } else {
 143                 this.encodedCertChain = Collections.emptyList();
 144             }
 145         }
 146 
 147         @Override
 148         public SSLHandshake handshakeType() {
 149             return SSLHandshake.CERTIFICATE;
 150         }
 151 
 152         @Override
 153         public int messageLength() {
 154             int msgLen = 3;
 155             for (byte[] encodedCert : encodedCertChain) {
 156                 msgLen += (encodedCert.length + 3);
 157             }
 158 
 159             return msgLen;
 160         }
 161 
 162         @Override
 163         public void send(HandshakeOutStream hos) throws IOException {
 164             int listLen = 0;
 165             for (byte[] encodedCert : encodedCertChain) {
 166                 listLen += (encodedCert.length + 3);
 167             }
 168 
 169             hos.putInt24(listLen);
 170             for (byte[] encodedCert : encodedCertChain) {
 171                 hos.putBytes24(encodedCert);
 172             }
 173         }
 174 
 175         @Override
 176         public String toString() {
 177             if (encodedCertChain.isEmpty()) {
 178                 return "\"Certificates\": <empty list>";
 179             }
 180 
 181             Object[] x509Certs = new Object[encodedCertChain.size()];
 182             try {
 183                 CertificateFactory cf = CertificateFactory.getInstance("X.509");
 184                 int i = 0;
 185                 for (byte[] encodedCert : encodedCertChain) {
 186                     Object obj;
 187                     try {
 188                         obj = (X509Certificate)cf.generateCertificate(
 189                                     new ByteArrayInputStream(encodedCert));
 190                     } catch (CertificateException ce) {
 191                         obj = encodedCert;
 192                     }
 193                     x509Certs[i++] = obj;
 194                 }
 195             } catch (CertificateException ce) {
 196                 // no X.509 certificate factory service
 197                 int i = 0;
 198                 for (byte[] encodedCert : encodedCertChain) {
 199                     x509Certs[i++] = encodedCert;
 200                 }
 201             }
 202 
 203             MessageFormat messageFormat = new MessageFormat(
 204                     "\"Certificates\": [\n" +
 205                     "{0}\n" +
 206                     "]",
 207                     Locale.ENGLISH);
 208             Object[] messageFields = {
 209                 SSLLogger.toString(x509Certs)
 210             };
 211 
 212             return messageFormat.format(messageFields);
 213         }
 214     }
 215 
 216     /**
 217      * The "Certificate" handshake message producer for TLS 1.2 and
 218      * previous SSL/TLS protocol versions.
 219      */
 220     private static final
 221             class T12CertificateProducer implements HandshakeProducer {
 222         // Prevent instantiation of this class.
 223         private T12CertificateProducer() {
 224             // blank
 225         }
 226 
 227         @Override
 228         public byte[] produce(ConnectionContext context,
 229                 HandshakeMessage message) throws IOException {
 230             // The producing happens in handshake context only.
 231             HandshakeContext hc = (HandshakeContext)context;
 232             if (hc.sslConfig.isClientMode) {
 233                 return onProduceCertificate(
 234                         (ClientHandshakeContext)context, message);
 235             } else {
 236                 return onProduceCertificate(
 237                         (ServerHandshakeContext)context, message);
 238             }
 239         }
 240 
 241         private byte[] onProduceCertificate(ServerHandshakeContext shc,
 242                 SSLHandshake.HandshakeMessage message) throws IOException {
 243             X509Possession x509Possession = null;
 244             for (SSLPossession possession : shc.handshakePossessions) {
 245                 if (possession instanceof X509Possession) {
 246                     x509Possession = (X509Possession)possession;
 247                     break;
 248                 }
 249             }
 250 
 251             if (x509Possession == null) {       // unlikely
 252                 shc.conContext.fatal(Alert.INTERNAL_ERROR,
 253                     "No expected X.509 certificate for server authentication");
 254 
 255                 return null;        // make the compiler happy
 256             }
 257 
 258             shc.handshakeSession.setLocalPrivateKey(
 259                     x509Possession.popPrivateKey);
 260             shc.handshakeSession.setLocalCertificates(x509Possession.popCerts);
 261             T12CertificateMessage cm =
 262                     new T12CertificateMessage(shc, x509Possession.popCerts);
 263             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 264                 SSLLogger.fine(
 265                     "Produced server Certificate handshake message", cm);
 266             }
 267 
 268             // Output the handshake message.
 269             cm.write(shc.handshakeOutput);
 270             shc.handshakeOutput.flush();
 271 
 272             // The handshake message has been delivered.
 273             return null;
 274         }
 275 
 276         private byte[] onProduceCertificate(ClientHandshakeContext chc,
 277                 SSLHandshake.HandshakeMessage message) throws IOException {
 278             X509Possession x509Possession = null;
 279             for (SSLPossession possession : chc.handshakePossessions) {
 280                 if (possession instanceof X509Possession) {
 281                     x509Possession = (X509Possession)possession;
 282                     break;
 283                 }
 284             }
 285 
 286             // Report to the server if no appropriate cert was found.  For
 287             // SSL 3.0, send a no_certificate alert;  TLS 1.0/1.1/1.2 uses
 288             // an empty cert chain instead.
 289             if (x509Possession == null) {
 290                 if (chc.negotiatedProtocol.useTLS10PlusSpec()) {
 291                     if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 292                         SSLLogger.fine(
 293                             "No X.509 certificate for client authentication, " +
 294                             "use empty Certificate message instead");
 295                     }
 296 
 297                     x509Possession =
 298                             new X509Possession(null, new X509Certificate[0]);
 299                 } else {
 300                     if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 301                         SSLLogger.fine(
 302                             "No X.509 certificate for client authentication, " +
 303                             "send a no_certificate alert");
 304                     }
 305 
 306                     chc.conContext.warning(Alert.NO_CERTIFICATE);
 307                     return null;
 308                 }
 309             }
 310 
 311             chc.handshakeSession.setLocalPrivateKey(
 312                     x509Possession.popPrivateKey);
 313             if (x509Possession.popCerts != null &&
 314                     x509Possession.popCerts.length != 0) {
 315                 chc.handshakeSession.setLocalCertificates(
 316                         x509Possession.popCerts);
 317             } else {
 318                 chc.handshakeSession.setLocalCertificates(null);
 319             }
 320             T12CertificateMessage cm =
 321                     new T12CertificateMessage(chc, x509Possession.popCerts);
 322             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 323                 SSLLogger.fine(
 324                     "Produced client Certificate handshake message", cm);
 325             }
 326 
 327             // Output the handshake message.
 328             cm.write(chc.handshakeOutput);
 329             chc.handshakeOutput.flush();
 330 
 331             // The handshake message has been delivered.
 332             return null;
 333         }
 334     }
 335 
 336     /**
 337      * The "Certificate" handshake message consumer for TLS 1.2 and
 338      * previous SSL/TLS protocol versions.
 339      */
 340     static final
 341             class T12CertificateConsumer implements SSLConsumer {
 342         // Prevent instantiation of this class.
 343         private T12CertificateConsumer() {
 344             // blank
 345         }
 346 
 347         @Override
 348         public void consume(ConnectionContext context,
 349                 ByteBuffer message) throws IOException {
 350             // The consuming happens in handshake context only.
 351             HandshakeContext hc = (HandshakeContext)context;
 352 
 353             // clean up this consumer
 354             hc.handshakeConsumers.remove(SSLHandshake.CERTIFICATE.id);
 355 
 356             T12CertificateMessage cm = new T12CertificateMessage(hc, message);
 357             if (hc.sslConfig.isClientMode) {
 358                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 359                     SSLLogger.fine(
 360                         "Consuming server Certificate handshake message", cm);
 361                 }
 362                 onCertificate((ClientHandshakeContext)context, cm);
 363             } else {
 364                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 365                     SSLLogger.fine(
 366                         "Consuming client Certificate handshake message", cm);
 367                 }
 368                 onCertificate((ServerHandshakeContext)context, cm);
 369             }
 370         }
 371 
 372         private void onCertificate(ServerHandshakeContext shc,
 373                 T12CertificateMessage certificateMessage )throws IOException {
 374             List<byte[]> encodedCerts = certificateMessage.encodedCertChain;
 375             if (encodedCerts == null || encodedCerts.isEmpty()) {
 376                 if (shc.sslConfig.clientAuthType !=
 377                         ClientAuthType.CLIENT_AUTH_REQUESTED) {
 378                     // unexpected or require client authentication
 379                     shc.conContext.fatal(Alert.BAD_CERTIFICATE,
 380                         "Empty server certificate chain");
 381                 } else {
 382                     return;
 383                 }
 384             }
 385 
 386             X509Certificate[] x509Certs =
 387                     new X509Certificate[encodedCerts.size()];
 388             try {
 389                 CertificateFactory cf = CertificateFactory.getInstance("X.509");
 390                 int i = 0;
 391                 for (byte[] encodedCert : encodedCerts) {
 392                     x509Certs[i++] = (X509Certificate)cf.generateCertificate(
 393                                     new ByteArrayInputStream(encodedCert));
 394                 }
 395             } catch (CertificateException ce) {
 396                 shc.conContext.fatal(Alert.BAD_CERTIFICATE,
 397                     "Failed to parse server certificates", ce);
 398             }
 399 
 400             checkClientCerts(shc, x509Certs);
 401 
 402             //
 403             // update
 404             //
 405             shc.handshakeCredentials.add(
 406                 new X509Credentials(x509Certs[0].getPublicKey(), x509Certs));
 407             shc.handshakeSession.setPeerCertificates(x509Certs);
 408         }
 409 
 410         private void onCertificate(ClientHandshakeContext chc,
 411                 T12CertificateMessage certificateMessage) throws IOException {
 412             List<byte[]> encodedCerts = certificateMessage.encodedCertChain;
 413             if (encodedCerts == null || encodedCerts.isEmpty()) {
 414                 chc.conContext.fatal(Alert.BAD_CERTIFICATE,
 415                     "Empty server certificate chain");
 416             }
 417 
 418             X509Certificate[] x509Certs =
 419                     new X509Certificate[encodedCerts.size()];
 420             try {
 421                 CertificateFactory cf = CertificateFactory.getInstance("X.509");
 422                 int i = 0;
 423                 for (byte[] encodedCert : encodedCerts) {
 424                     x509Certs[i++] = (X509Certificate)cf.generateCertificate(
 425                                     new ByteArrayInputStream(encodedCert));
 426                 }
 427             } catch (CertificateException ce) {
 428                 chc.conContext.fatal(Alert.BAD_CERTIFICATE,
 429                     "Failed to parse server certificates", ce);
 430             }
 431 
 432             // Allow server certificate change in client side during
 433             // renegotiation after a session-resumption abbreviated
 434             // initial handshake?
 435             //
 436             // DO NOT need to check allowUnsafeServerCertChange here. We only
 437             // reserve server certificates when allowUnsafeServerCertChange is
 438             // flase.
 439             if (chc.reservedServerCerts != null) {
 440                 // It is not necessary to check the certificate update if
 441                 // endpoint identification is enabled.
 442                 String identityAlg = chc.sslConfig.identificationProtocol;
 443                 if ((identityAlg == null || identityAlg.length() == 0) &&
 444                         !isIdentityEquivalent(x509Certs[0],
 445                                 chc.reservedServerCerts[0])) {
 446                     chc.conContext.fatal(Alert.BAD_CERTIFICATE,
 447                             "server certificate change is restricted " +
 448                             "during renegotiation");
 449                 }
 450             }
 451 
 452             // ask the trust manager to verify the chain
 453             if (chc.staplingActive) {
 454                 // Defer the certificate check until after we've received the
 455                 // CertificateStatus message.  If that message doesn't come in
 456                 // immediately following this message we will execute the
 457                 // check from CertificateStatus' absent handler.
 458                 chc.deferredCerts = x509Certs;
 459             } else {
 460                 // We're not doing stapling, so perform the check right now
 461                 checkServerCerts(chc, x509Certs);
 462             }
 463 
 464             //
 465             // update
 466             //
 467             chc.handshakeCredentials.add(
 468                 new X509Credentials(x509Certs[0].getPublicKey(), x509Certs));
 469             chc.handshakeSession.setPeerCertificates(x509Certs);
 470         }
 471 
 472         /*
 473          * Whether the certificates can represent the same identity?
 474          *
 475          * The certificates can be used to represent the same identity:
 476          *     1. If the subject alternative names of IP address are present
 477          *        in both certificates, they should be identical; otherwise,
 478          *     2. if the subject alternative names of DNS name are present in
 479          *        both certificates, they should be identical; otherwise,
 480          *     3. if the subject fields are present in both certificates, the
 481          *        certificate subjects and issuers should be identical.
 482          */
 483         private static boolean isIdentityEquivalent(X509Certificate thisCert,
 484                 X509Certificate prevCert) {
 485             if (thisCert.equals(prevCert)) {
 486                 return true;
 487             }
 488 
 489             // check subject alternative names
 490             Collection<List<?>> thisSubjectAltNames = null;
 491             try {
 492                 thisSubjectAltNames = thisCert.getSubjectAlternativeNames();
 493             } catch (CertificateParsingException cpe) {
 494                 if (SSLLogger.isOn && SSLLogger.isOn("handshake")) {
 495                     SSLLogger.fine(
 496                         "Attempt to obtain subjectAltNames extension failed!");
 497                 }
 498             }
 499 
 500             Collection<List<?>> prevSubjectAltNames = null;
 501             try {
 502                 prevSubjectAltNames = prevCert.getSubjectAlternativeNames();
 503             } catch (CertificateParsingException cpe) {
 504                 if (SSLLogger.isOn && SSLLogger.isOn("handshake")) {
 505                     SSLLogger.fine(
 506                         "Attempt to obtain subjectAltNames extension failed!");
 507                 }
 508             }
 509 
 510             if (thisSubjectAltNames != null && prevSubjectAltNames != null) {
 511                 // check the iPAddress field in subjectAltName extension
 512                 //
 513                 // 7: subject alternative name of type IP.
 514                 Collection<String> thisSubAltIPAddrs =
 515                             getSubjectAltNames(thisSubjectAltNames, 7);
 516                 Collection<String> prevSubAltIPAddrs =
 517                             getSubjectAltNames(prevSubjectAltNames, 7);
 518                 if (thisSubAltIPAddrs != null && prevSubAltIPAddrs != null &&
 519                     isEquivalent(thisSubAltIPAddrs, prevSubAltIPAddrs)) {
 520                     return true;
 521                 }
 522 
 523                 // check the dNSName field in subjectAltName extension
 524                 // 2: subject alternative name of type IP.
 525                 Collection<String> thisSubAltDnsNames =
 526                             getSubjectAltNames(thisSubjectAltNames, 2);
 527                 Collection<String> prevSubAltDnsNames =
 528                             getSubjectAltNames(prevSubjectAltNames, 2);
 529                 if (thisSubAltDnsNames != null && prevSubAltDnsNames != null &&
 530                     isEquivalent(thisSubAltDnsNames, prevSubAltDnsNames)) {
 531                     return true;
 532                 }
 533             }
 534 
 535             // check the certificate subject and issuer
 536             X500Principal thisSubject = thisCert.getSubjectX500Principal();
 537             X500Principal prevSubject = prevCert.getSubjectX500Principal();
 538             X500Principal thisIssuer = thisCert.getIssuerX500Principal();
 539             X500Principal prevIssuer = prevCert.getIssuerX500Principal();
 540 
 541             return (!thisSubject.getName().isEmpty() &&
 542                     !prevSubject.getName().isEmpty() &&
 543                     thisSubject.equals(prevSubject) &&
 544                     thisIssuer.equals(prevIssuer));
 545         }
 546 
 547         /*
 548          * Returns the subject alternative name of the specified type in the
 549          * subjectAltNames extension of a certificate.
 550          *
 551          * Note that only those subjectAltName types that use String data
 552          * should be passed into this function.
 553          */
 554         private static Collection<String> getSubjectAltNames(
 555                 Collection<List<?>> subjectAltNames, int type) {
 556             HashSet<String> subAltDnsNames = null;
 557             for (List<?> subjectAltName : subjectAltNames) {
 558                 int subjectAltNameType = (Integer)subjectAltName.get(0);
 559                 if (subjectAltNameType == type) {
 560                     String subAltDnsName = (String)subjectAltName.get(1);
 561                     if ((subAltDnsName != null) && !subAltDnsName.isEmpty()) {
 562                         if (subAltDnsNames == null) {
 563                             subAltDnsNames =
 564                                     new HashSet<>(subjectAltNames.size());
 565                         }
 566                         subAltDnsNames.add(subAltDnsName);
 567                     }
 568                 }
 569             }
 570 
 571             return subAltDnsNames;
 572         }
 573 
 574         private static boolean isEquivalent(Collection<String> thisSubAltNames,
 575                 Collection<String> prevSubAltNames) {
 576             for (String thisSubAltName : thisSubAltNames) {
 577                 for (String prevSubAltName : prevSubAltNames) {
 578                     // Only allow the exactly match.  No wildcard character
 579                     // checking.
 580                     if (thisSubAltName.equalsIgnoreCase(prevSubAltName)) {
 581                         return true;
 582                     }
 583                 }
 584             }
 585 
 586             return false;
 587         }
 588 
 589         /**
 590          * Perform client-side checking of server certificates.
 591          *
 592          * @param certs an array of {@code X509Certificate} objects presented
 593          *      by the server in the ServerCertificate message.
 594          *
 595          * @throws IOException if a failure occurs during validation or
 596          *      the trust manager associated with the {@code SSLContext} is not
 597          *      an {@code X509ExtendedTrustManager}.
 598          */
 599         static void checkServerCerts(ClientHandshakeContext chc,
 600                 X509Certificate[] certs) throws IOException {
 601 
 602             X509TrustManager tm = chc.sslContext.getX509TrustManager();
 603 
 604             // find out the key exchange algorithm used
 605             // use "RSA" for non-ephemeral "RSA_EXPORT"
 606             String keyExchangeString;
 607             if (chc.negotiatedCipherSuite.keyExchange ==
 608                     CipherSuite.KeyExchange.K_RSA_EXPORT ||
 609                     chc.negotiatedCipherSuite.keyExchange ==
 610                 CipherSuite.KeyExchange.K_DHE_RSA_EXPORT) {
 611                 keyExchangeString = CipherSuite.KeyExchange.K_RSA.name;
 612             } else {
 613                 keyExchangeString = chc.negotiatedCipherSuite.keyExchange.name;
 614             }
 615 
 616             try {
 617                 if (tm instanceof X509ExtendedTrustManager) {
 618                     if (chc.conContext.transport instanceof SSLEngine) {
 619                         SSLEngine engine = (SSLEngine)chc.conContext.transport;
 620                         ((X509ExtendedTrustManager)tm).checkServerTrusted(
 621                             certs.clone(),
 622                             keyExchangeString,
 623                             engine);
 624                     } else {
 625                         SSLSocket socket = (SSLSocket)chc.conContext.transport;
 626                         ((X509ExtendedTrustManager)tm).checkServerTrusted(
 627                             certs.clone(),
 628                             keyExchangeString,
 629                             socket);
 630                     }
 631                 } else {
 632                     // Unlikely to happen, because we have wrapped the old
 633                     // X509TrustManager with the new X509ExtendedTrustManager.
 634                     throw new CertificateException(
 635                             "Improper X509TrustManager implementation");
 636                 }
 637 
 638                 // Once the server certificate chain has been validated, set
 639                 // the certificate chain in the TLS session.
 640                 chc.handshakeSession.setPeerCertificates(certs);
 641             } catch (CertificateException ce) {
 642                 chc.conContext.fatal(getCertificateAlert(chc, ce), ce);
 643             }
 644         }
 645 
 646         private static void checkClientCerts(ServerHandshakeContext shc,
 647                 X509Certificate[] certs) throws IOException {
 648             X509TrustManager tm = shc.sslContext.getX509TrustManager();
 649 
 650             // find out the types of client authentication used
 651             PublicKey key = certs[0].getPublicKey();
 652             String keyAlgorithm = key.getAlgorithm();
 653             String authType;
 654             if (keyAlgorithm.equals("RSA")) {
 655                 authType = "RSA";
 656             } else if (keyAlgorithm.equals("DSA")) {
 657                 authType = "DSA";
 658             } else if (keyAlgorithm.equals("EC")) {
 659                 authType = "EC";
 660             } else {
 661                 // unknown public key type
 662                 authType = "UNKNOWN";
 663             }
 664 
 665             try {
 666                 if (tm instanceof X509ExtendedTrustManager) {
 667                     if (shc.conContext.transport instanceof SSLEngine) {
 668                         SSLEngine engine = (SSLEngine)shc.conContext.transport;
 669                         ((X509ExtendedTrustManager)tm).checkClientTrusted(
 670                             certs.clone(),
 671                             authType,
 672                             engine);
 673                     } else {
 674                         SSLSocket socket = (SSLSocket)shc.conContext.transport;
 675                         ((X509ExtendedTrustManager)tm).checkClientTrusted(
 676                             certs.clone(),
 677                             authType,
 678                             socket);
 679                     }
 680                 } else {
 681                     // Unlikely to happen, because we have wrapped the old
 682                     // X509TrustManager with the new X509ExtendedTrustManager.
 683                     throw new CertificateException(
 684                             "Improper X509TrustManager implementation");
 685                 }
 686             } catch (CertificateException ce) {
 687                 shc.conContext.fatal(Alert.CERTIFICATE_UNKNOWN, ce);
 688             }
 689         }
 690 
 691         /**
 692          * When a failure happens during certificate checking from an
 693          * {@link X509TrustManager}, determine what TLS alert description
 694          * to use.
 695          *
 696          * @param cexc The exception thrown by the {@link X509TrustManager}
 697          *
 698          * @return A byte value corresponding to a TLS alert description number.
 699          */
 700         private static Alert getCertificateAlert(
 701                 ClientHandshakeContext chc, CertificateException cexc) {
 702             // The specific reason for the failure will determine how to
 703             // set the alert description value
 704             Alert alert = Alert.CERTIFICATE_UNKNOWN;
 705 
 706             Throwable baseCause = cexc.getCause();
 707             if (baseCause instanceof CertPathValidatorException) {
 708                 CertPathValidatorException cpve =
 709                         (CertPathValidatorException)baseCause;
 710                 Reason reason = cpve.getReason();
 711                 if (reason == BasicReason.REVOKED) {
 712                     alert = chc.staplingActive ?
 713                             Alert.BAD_CERT_STATUS_RESPONSE :
 714                             Alert.CERTIFICATE_REVOKED;
 715                 } else if (
 716                         reason == BasicReason.UNDETERMINED_REVOCATION_STATUS) {
 717                     alert = chc.staplingActive ?
 718                             Alert.BAD_CERT_STATUS_RESPONSE :
 719                             Alert.CERTIFICATE_UNKNOWN;
 720                 }
 721             }
 722 
 723             return alert;
 724         }
 725 
 726     }
 727 
 728     /**
 729      * The certificate entry used in Certificate handshake message for TLS 1.3.
 730      */
 731     static final class CertificateEntry {
 732         final byte[] encoded;       // encoded cert or public key
 733         private final SSLExtensions extensions;
 734 
 735         CertificateEntry(byte[] encoded, SSLExtensions extensions) {
 736             this.encoded = encoded;
 737             this.extensions = extensions;
 738         }
 739 
 740         private int getEncodedSize() {
 741             int extLen = extensions.length();
 742             if (extLen == 0) {
 743                 extLen = 2;     // empty extensions
 744             }
 745             return 3 + encoded.length + extLen;
 746         }
 747 
 748         @Override
 749         public String toString() {
 750             MessageFormat messageFormat = new MessageFormat(
 751                 "\n'{'\n" +
 752                 "{0}\n" +                       // X.509 certificate
 753                 "  \"extensions\": '{'\n" +
 754                 "{1}\n" +
 755                 "  '}'\n" +
 756                 "'}',", Locale.ENGLISH);
 757 
 758             Object x509Certs;
 759             try {
 760                 // Don't support certificate type extension (RawPublicKey) yet.
 761                 CertificateFactory cf = CertificateFactory.getInstance("X.509");
 762                 x509Certs =
 763                     cf.generateCertificate(new ByteArrayInputStream(encoded));
 764             } catch (CertificateException ce) {
 765                 // no X.509 certificate factory service
 766                 x509Certs = encoded;
 767             }
 768 
 769             Object[] messageFields = {
 770                 SSLLogger.toString(x509Certs),
 771                 Utilities.indent(extensions.toString(), "    ")
 772             };
 773 
 774             return messageFormat.format(messageFields);
 775         }
 776     }
 777 
 778     /**
 779      * The Certificate handshake message for TLS 1.3.
 780      */
 781     static final class T13CertificateMessage extends HandshakeMessage {
 782         private final byte[] requestContext;
 783         private final List<CertificateEntry> certEntries;
 784 
 785         T13CertificateMessage(HandshakeContext context,
 786                 byte[] requestContext, X509Certificate[] certificates)
 787                 throws SSLException, CertificateException  {
 788             super(context);
 789 
 790             this.requestContext = requestContext.clone();
 791             this.certEntries = new LinkedList<>();
 792             for (X509Certificate cert : certificates) {
 793                 // TODO: shall we use the Certificate for the session?
 794                 byte[] encoded = cert.getEncoded();
 795                 SSLExtensions extensions = new SSLExtensions(this);
 796                 certEntries.add(new CertificateEntry(encoded, extensions));
 797             }
 798         }
 799 
 800         T13CertificateMessage(HandshakeContext handshakeContext,
 801                 byte[] requestContext, List<CertificateEntry> certificates) {
 802             super(handshakeContext);
 803 
 804             this.requestContext = requestContext.clone();
 805             this.certEntries = certificates;
 806         }
 807 
 808         T13CertificateMessage(HandshakeContext handshakeContext,
 809                 ByteBuffer m) throws IOException {
 810             super(handshakeContext);
 811 
 812             // struct {
 813             //      opaque certificate_request_context<0..2^8-1>;
 814             //      CertificateEntry certificate_list<0..2^24-1>;
 815             //  } Certificate;
 816             if (m.remaining() < 4) {
 817                 throw new SSLProtocolException(
 818                         "Invalid Certificate message: " +
 819                         "insufficient data (length=" + m.remaining() + ")");
 820             }
 821             this.requestContext = Record.getBytes8(m);
 822 
 823             if (m.remaining() < 3) {
 824                 throw new SSLProtocolException(
 825                         "Invalid Certificate message: " +
 826                         "insufficient certificate entries data (length=" +
 827                         m.remaining() + ")");
 828             }
 829 
 830             int listLen = Record.getInt24(m);
 831             if (listLen != m.remaining()) {
 832                 throw new SSLProtocolException(
 833                     "Invalid Certificate message: " +
 834                     "incorrect list length (length=" + listLen + ")");
 835             }
 836 
 837             SSLExtension[] enabledExtensions =
 838                 handshakeContext.sslConfig.getEnabledExtensions(
 839                         SSLHandshake.CERTIFICATE);
 840             List<CertificateEntry> certList = new LinkedList<>();
 841             while (m.hasRemaining()) {
 842                 // Note: support only X509 CertificateType right now.
 843                 byte[] encodedCert = Record.getBytes24(m);
 844                 if (encodedCert.length == 0) {
 845                     throw new SSLProtocolException(
 846                         "Invalid Certificate message: empty cert_data");
 847                 }
 848 
 849                 SSLExtensions extensions =
 850                         new SSLExtensions(this, m, enabledExtensions);
 851                 certList.add(new CertificateEntry(encodedCert, extensions));
 852             }
 853 
 854             this.certEntries = Collections.unmodifiableList(certList);
 855         }
 856 
 857         @Override
 858         public SSLHandshake handshakeType() {
 859             return SSLHandshake.CERTIFICATE;
 860         }
 861 
 862         @Override
 863         public int messageLength() {
 864             int msgLen = 4 + requestContext.length;
 865             for (CertificateEntry entry : certEntries) {
 866                 msgLen += entry.getEncodedSize();
 867             }
 868 
 869             return msgLen;
 870         }
 871 
 872         @Override
 873         public void send(HandshakeOutStream hos) throws IOException {
 874             int entryListLen = 0;
 875             for (CertificateEntry entry : certEntries) {
 876                 entryListLen += entry.getEncodedSize();
 877             }
 878 
 879             hos.putBytes8(requestContext);
 880             hos.putInt24(entryListLen);
 881             for (CertificateEntry entry : certEntries) {
 882                 hos.putBytes24(entry.encoded);
 883                 // Is it an empty extensions?
 884                 if (entry.extensions.length() == 0) {
 885                     hos.putInt16(0);
 886                 } else {
 887                     entry.extensions.send(hos);
 888                 }
 889             }
 890         }
 891 
 892         @Override
 893         public String toString() {
 894             MessageFormat messageFormat = new MessageFormat(
 895                 "\"Certificate\": '{'\n" +
 896                 "  \"certificate_request_context\": \"{0}\",\n" +
 897                 "  \"certificate_list\": [{1}\n]\n" +
 898                 "'}'",
 899                 Locale.ENGLISH);
 900 
 901             StringBuilder builder = new StringBuilder(512);
 902             for (CertificateEntry entry : certEntries) {
 903                 builder.append(entry.toString());
 904             }
 905 
 906             Object[] messageFields = {
 907                 Utilities.toHexString(requestContext),
 908                 Utilities.indent(builder.toString())
 909             };
 910 
 911             return messageFormat.format(messageFields);
 912         }
 913     }
 914 
 915     /**
 916      * The "Certificate" handshake message producer for TLS 1.3.
 917      */
 918     private static final
 919             class T13CertificateProducer implements HandshakeProducer {
 920         // Prevent instantiation of this class.
 921         private T13CertificateProducer() {
 922             // blank
 923         }
 924 
 925         @Override
 926         public byte[] produce(ConnectionContext context,
 927                 HandshakeMessage message) throws IOException {
 928             // The producing happens in handshake context only.
 929             HandshakeContext hc = (HandshakeContext)context;
 930             if (hc.sslConfig.isClientMode) {
 931                 return onProduceCertificate(
 932                         (ClientHandshakeContext)context, message);
 933             } else {
 934                 return onProduceCertificate(
 935                         (ServerHandshakeContext)context, message);
 936             }
 937         }
 938 
 939         private byte[] onProduceCertificate(ServerHandshakeContext shc,
 940                 HandshakeMessage message) throws IOException {
 941             ClientHelloMessage clientHello = (ClientHelloMessage)message;
 942 
 943             SSLPossession pos = choosePossession(shc, clientHello);
 944             if (pos == null) {
 945                 shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
 946                         "No available authentication scheme");
 947                 return null;    // make the complier happy
 948             }
 949 
 950             if (!(pos instanceof X509Possession)) {
 951                 shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
 952                         "No X.509 certificate for server authentication");
 953             }
 954 
 955             X509Possession x509Possession = (X509Possession)pos;
 956             X509Certificate[] localCerts = x509Possession.popCerts;
 957             if (localCerts == null || localCerts.length == 0) {
 958                 shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
 959                         "No X.509 certificate for server authentication");
 960                 return null;    // make the complier happy
 961             }
 962 
 963             // update the context
 964             shc.handshakePossessions.add(x509Possession);
 965             shc.handshakeSession.setLocalPrivateKey(
 966                     x509Possession.popPrivateKey);
 967             shc.handshakeSession.setLocalCertificates(localCerts);
 968             T13CertificateMessage cm;
 969             try {
 970                 cm = new T13CertificateMessage(shc, (new byte[0]), localCerts);
 971             } catch (SSLException | CertificateException ce) {
 972                 shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
 973                         "Failed to produce server Certificate message", ce);
 974                 return null;    // make the complier happy
 975             }
 976 
 977             // Check the OCSP stapling extensions and attempt
 978             // to get responses.  If the resulting stapleParams is non
 979             // null, it implies that stapling is enabled on the server side.
 980             shc.stapleParams = StatusResponseManager.processStapling(shc);
 981             shc.staplingActive = (shc.stapleParams != null);
 982 
 983             // Process extensions for each CertificateEntry.
 984             // Since there can be multiple CertificateEntries within a
 985             // single CT message, we will pin a specific CertificateEntry
 986             // into the ServerHandshakeContext so individual extension
 987             // producers know which X509Certificate it is processing in
 988             // each call.
 989             SSLExtension[] enabledCTExts = shc.sslConfig.getEnabledExtensions(
 990                     SSLHandshake.CERTIFICATE,
 991                     Arrays.asList(ProtocolVersion.PROTOCOLS_OF_13));
 992             for (CertificateEntry certEnt : cm.certEntries) {
 993                 shc.currentCertEntry = certEnt;
 994                 certEnt.extensions.produce(shc, enabledCTExts);
 995             }
 996 
 997             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 998                 SSLLogger.fine("Produced server Certificate message", cm);
 999             }
1000 
1001             // Output the handshake message.
1002             cm.write(shc.handshakeOutput);
1003             shc.handshakeOutput.flush();
1004 
1005             // The handshake message has been delivered.
1006             return null;
1007         }
1008 
1009         private static SSLPossession choosePossession(
1010                 HandshakeContext hc,
1011                 ClientHelloMessage clientHello) throws IOException {
1012             if (hc.peerRequestedCertSignSchemes == null ||
1013                     hc.peerRequestedCertSignSchemes.isEmpty()) {
1014                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
1015                     SSLLogger.warning(
1016                             "No signature_algorithms(_cert) in ClientHello");
1017                 }
1018                 return null;
1019             }
1020 
1021             Collection<String> checkedKeyTypes = new HashSet<>();
1022             for (SignatureScheme ss : hc.peerRequestedCertSignSchemes) {
1023                 if (checkedKeyTypes.contains(ss.keyAlgorithm)) {
1024                     if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
1025                         SSLLogger.warning(
1026                             "Unsupported authentication scheme: " + ss.name);
1027                     }
1028                     continue;
1029                 }
1030 
1031                 // Don't select a signature scheme unless we will be able to
1032                 // produce a CertificateVerify message later
1033                 if (SignatureScheme.getPreferableAlgorithm(
1034                     hc.peerRequestedSignatureSchemes,
1035                     ss, hc.negotiatedProtocol) == null) {
1036 
1037                     if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
1038                         SSLLogger.warning(
1039                         "Unable to produce CertificateVerify for scheme: " + ss.name);
1040                     }
1041                     checkedKeyTypes.add(ss.keyAlgorithm);
1042                     continue;
1043                 }
1044 
1045                 SSLAuthentication ka =
1046                         X509Authentication.nameOf(ss.keyAlgorithm);
1047                 if (ka == null) {
1048                     if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
1049                         SSLLogger.warning(
1050                             "Unsupported authentication scheme: " + ss.name);
1051                     }
1052                     checkedKeyTypes.add(ss.keyAlgorithm);
1053                     continue;
1054                 }
1055 
1056                 SSLPossession pos = ka.createPossession(hc);
1057                 if (pos == null) {
1058                     if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
1059                         SSLLogger.warning(
1060                             "Unavailable authentication scheme: " + ss.name);
1061                     }
1062                     continue;
1063                 }
1064 
1065                 return pos;
1066             }
1067 
1068             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
1069                 SSLLogger.warning("No available authentication scheme");
1070             }
1071             return null;
1072         }
1073 
1074         private byte[] onProduceCertificate(ClientHandshakeContext chc,
1075                 HandshakeMessage message) throws IOException {
1076             ClientHelloMessage clientHello = (ClientHelloMessage)message;
1077             SSLPossession pos = choosePossession(chc, clientHello);
1078             X509Certificate[] localCerts;
1079             if (pos == null) {
1080                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
1081                     SSLLogger.fine("No available client authentication scheme");
1082                 }
1083                 localCerts = new X509Certificate[0];
1084             } else {
1085                 chc.handshakePossessions.add(pos);
1086                 if (!(pos instanceof X509Possession)) {
1087                     if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
1088                         SSLLogger.fine(
1089                             "No X.509 certificate for client authentication");
1090                     }
1091                     localCerts = new X509Certificate[0];
1092                 } else {
1093                     X509Possession x509Possession = (X509Possession)pos;
1094                     localCerts = x509Possession.popCerts;
1095                     chc.handshakeSession.setLocalPrivateKey(
1096                             x509Possession.popPrivateKey);
1097                 }
1098             }
1099 
1100             if (localCerts != null && localCerts.length != 0) {
1101                 chc.handshakeSession.setLocalCertificates(localCerts);
1102             } else {
1103                 chc.handshakeSession.setLocalCertificates(null);
1104             }
1105 
1106             T13CertificateMessage cm;
1107             try {
1108                 cm = new T13CertificateMessage(
1109                         chc, chc.certRequestContext, localCerts);
1110             } catch (SSLException | CertificateException ce) {
1111                 chc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
1112                         "Failed to produce client Certificate message", ce);
1113                 return null;    // make the complier happy
1114             }
1115             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
1116                 SSLLogger.fine("Produced client Certificate message", cm);
1117             }
1118 
1119             // Output the handshake message.
1120             cm.write(chc.handshakeOutput);
1121             chc.handshakeOutput.flush();
1122 
1123             // The handshake message has been delivered.
1124             return null;
1125         }
1126     }
1127 
1128     /**
1129      * The "Certificate" handshake message consumer for TLS 1.3.
1130      */
1131     private static final class T13CertificateConsumer implements SSLConsumer {
1132         // Prevent instantiation of this class.
1133         private T13CertificateConsumer() {
1134             // blank
1135         }
1136 
1137         @Override
1138         public void consume(ConnectionContext context,
1139                 ByteBuffer message) throws IOException {
1140             // The consuming happens in handshake context only.
1141             HandshakeContext hc = (HandshakeContext)context;
1142 
1143             // clean up this consumer
1144             hc.handshakeConsumers.remove(SSLHandshake.CERTIFICATE.id);
1145             T13CertificateMessage cm = new T13CertificateMessage(hc, message);
1146             if (hc.sslConfig.isClientMode) {
1147                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
1148                     SSLLogger.fine(
1149                         "Consuming server Certificate handshake message", cm);
1150                 }
1151                 onConsumeCertificate((ClientHandshakeContext)context, cm);
1152             } else {
1153                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
1154                     SSLLogger.fine(
1155                         "Consuming client Certificate handshake message", cm);
1156                 }
1157                 onConsumeCertificate((ServerHandshakeContext)context, cm);
1158             }
1159         }
1160 
1161         private void onConsumeCertificate(ServerHandshakeContext shc,
1162                 T13CertificateMessage certificateMessage )throws IOException {
1163             if (certificateMessage.certEntries == null ||
1164                     certificateMessage.certEntries.isEmpty()) {
1165                 if (shc.sslConfig.clientAuthType == CLIENT_AUTH_REQUIRED) {
1166                     shc.conContext.fatal(Alert.BAD_CERTIFICATE,
1167                         "Empty client certificate chain");
1168                 } else {
1169                     // optional client authentication
1170                     return;
1171                 }
1172             }
1173 
1174             // check client certificate entries
1175             X509Certificate[] cliCerts =
1176                     checkClientCerts(shc, certificateMessage.certEntries);
1177 
1178             //
1179             // update
1180             //
1181             shc.handshakeCredentials.add(
1182                 new X509Credentials(cliCerts[0].getPublicKey(), cliCerts));
1183             shc.handshakeSession.setPeerCertificates(cliCerts);
1184         }
1185 
1186         private void onConsumeCertificate(ClientHandshakeContext chc,
1187                 T13CertificateMessage certificateMessage )throws IOException {
1188             if (certificateMessage.certEntries == null ||
1189                     certificateMessage.certEntries.isEmpty()) {
1190                 chc.conContext.fatal(Alert.BAD_CERTIFICATE,
1191                     "Empty server certificate chain");
1192             }
1193 
1194             // Each CertificateEntry will have its own set of extensions
1195             // which must be consumed.
1196             SSLExtension[] enabledExtensions =
1197                 chc.sslConfig.getEnabledExtensions(SSLHandshake.CERTIFICATE);
1198             for (CertificateEntry certEnt : certificateMessage.certEntries) {
1199                 certEnt.extensions.consumeOnLoad(chc, enabledExtensions);
1200             }
1201 
1202             // check server certificate entries
1203             X509Certificate[] srvCerts =
1204                     checkServerCerts(chc, certificateMessage.certEntries);
1205 
1206             //
1207             // update
1208             //
1209             chc.handshakeCredentials.add(
1210                 new X509Credentials(srvCerts[0].getPublicKey(), srvCerts));
1211             chc.handshakeSession.setPeerCertificates(srvCerts);
1212         }
1213 
1214         private static X509Certificate[] checkClientCerts(
1215                 ServerHandshakeContext shc,
1216                 List<CertificateEntry> certEntries) throws IOException {
1217             X509Certificate[] certs =
1218                     new X509Certificate[certEntries.size()];
1219             try {
1220                 CertificateFactory cf = CertificateFactory.getInstance("X.509");
1221                 int i = 0;
1222                 for (CertificateEntry entry : certEntries) {
1223                     certs[i++] = (X509Certificate)cf.generateCertificate(
1224                                     new ByteArrayInputStream(entry.encoded));
1225                     // TODO: check extensions
1226                 }
1227             } catch (CertificateException ce) {
1228                 shc.conContext.fatal(Alert.BAD_CERTIFICATE,
1229                     "Failed to parse server certificates", ce);
1230             }
1231 
1232             // find out the types of client authentication used
1233             String keyAlgorithm = certs[0].getPublicKey().getAlgorithm();
1234             String authType;
1235             switch (keyAlgorithm) {
1236                 case "RSA":
1237                     authType = "RSA";
1238                     break;
1239                 case "DSA":
1240                     authType = "DSA";
1241                     break;
1242                 case "EC":
1243                     authType = "EC";
1244                     break;
1245                 default:
1246                     // unknown public key type
1247                     authType = "UNKNOWN";
1248                     break;
1249             }
1250 
1251             try {
1252                 X509TrustManager tm = shc.sslContext.getX509TrustManager();
1253                 if (tm instanceof X509ExtendedTrustManager) {
1254                     if (shc.conContext.transport instanceof SSLEngine) {
1255                         SSLEngine engine = (SSLEngine)shc.conContext.transport;
1256                         ((X509ExtendedTrustManager)tm).checkClientTrusted(
1257                             certs.clone(),
1258                             authType,
1259                             engine);
1260                     } else {
1261                         SSLSocket socket = (SSLSocket)shc.conContext.transport;
1262                         ((X509ExtendedTrustManager)tm).checkClientTrusted(
1263                             certs.clone(),
1264                             authType,
1265                             socket);
1266                     }
1267                 } else {
1268                     // Unlikely to happen, because we have wrapped the old
1269                     // X509TrustManager with the new X509ExtendedTrustManager.
1270                     throw new CertificateException(
1271                             "Improper X509TrustManager implementation");
1272                 }
1273 
1274                 // Once the client certificate chain has been validated, set
1275                 // the certificate chain in the TLS session.
1276                 shc.handshakeSession.setPeerCertificates(certs);
1277             } catch (CertificateException ce) {
1278                 // TODO: A more precise alert should be used.
1279                 shc.conContext.fatal(Alert.CERTIFICATE_UNKNOWN, ce);
1280             }
1281 
1282             return certs;
1283         }
1284 
1285         private static X509Certificate[] checkServerCerts(
1286                 ClientHandshakeContext chc,
1287                 List<CertificateEntry> certEntries) throws IOException {
1288             X509Certificate[] certs =
1289                     new X509Certificate[certEntries.size()];
1290             try {
1291                 CertificateFactory cf = CertificateFactory.getInstance("X.509");
1292                 int i = 0;
1293                 for (CertificateEntry entry : certEntries) {
1294                     certs[i++] = (X509Certificate)cf.generateCertificate(
1295                                     new ByteArrayInputStream(entry.encoded));
1296                     // TODO: check extensions
1297                 }
1298             } catch (CertificateException ce) {
1299                 chc.conContext.fatal(Alert.BAD_CERTIFICATE,
1300                     "Failed to parse server certificates", ce);
1301             }
1302 
1303             // find out the types of client authentication used
1304             /*
1305             String keyAlgorithm = certs[0].getPublicKey().getAlgorithm();
1306             String authType;
1307             switch (keyAlgorithm) {
1308                 case "RSA":
1309                     authType = "RSA";
1310                     break;
1311                 case "DSA":
1312                     authType = "DSA";
1313                     break;
1314                 case "EC":
1315                     authType = "EC";
1316                     break;
1317                 default:
1318                     // unknown public key type
1319                     authType = "UNKNOWN";
1320                     break;
1321             }
1322             */
1323             String authType = "UNKNOWN";
1324 
1325             try {
1326                 X509TrustManager tm = chc.sslContext.getX509TrustManager();
1327                 if (tm instanceof X509ExtendedTrustManager) {
1328                     if (chc.conContext.transport instanceof SSLEngine) {
1329                         SSLEngine engine = (SSLEngine)chc.conContext.transport;
1330                         ((X509ExtendedTrustManager)tm).checkServerTrusted(
1331                             certs.clone(),
1332                             authType,
1333                             engine);
1334                     } else {
1335                         SSLSocket socket = (SSLSocket)chc.conContext.transport;
1336                         ((X509ExtendedTrustManager)tm).checkServerTrusted(
1337                             certs.clone(),
1338                             authType,
1339                             socket);
1340                     }
1341                 } else {
1342                     // Unlikely to happen, because we have wrapped the old
1343                     // X509TrustManager with the new X509ExtendedTrustManager.
1344                     throw new CertificateException(
1345                             "Improper X509TrustManager implementation");
1346                 }
1347 
1348                 // Once the server certificate chain has been validated, set
1349                 // the certificate chain in the TLS session.
1350                 chc.handshakeSession.setPeerCertificates(certs);
1351             } catch (CertificateException ce) {
1352                 chc.conContext.fatal(getCertificateAlert(chc, ce), ce);
1353             }
1354 
1355             return certs;
1356         }
1357 
1358         /**
1359          * When a failure happens during certificate checking from an
1360          * {@link X509TrustManager}, determine what TLS alert description
1361          * to use.
1362          *
1363          * @param cexc The exception thrown by the {@link X509TrustManager}
1364          *
1365          * @return A byte value corresponding to a TLS alert description number.
1366          */
1367         private static Alert getCertificateAlert(
1368                 ClientHandshakeContext chc, CertificateException cexc) {
1369             // The specific reason for the failure will determine how to
1370             // set the alert description value
1371             Alert alert = Alert.CERTIFICATE_UNKNOWN;
1372 
1373             Throwable baseCause = cexc.getCause();
1374             if (baseCause instanceof CertPathValidatorException) {
1375                 CertPathValidatorException cpve =
1376                         (CertPathValidatorException)baseCause;
1377                 Reason reason = cpve.getReason();
1378                 if (reason == BasicReason.REVOKED) {
1379                     alert = chc.staplingActive ?
1380                             Alert.BAD_CERT_STATUS_RESPONSE :
1381                             Alert.CERTIFICATE_REVOKED;
1382                 } else if (
1383                         reason == BasicReason.UNDETERMINED_REVOCATION_STATUS) {
1384                     alert = chc.staplingActive ?
1385                             Alert.BAD_CERT_STATUS_RESPONSE :
1386                             Alert.CERTIFICATE_UNKNOWN;
1387                 }
1388             }
1389 
1390             return alert;
1391         }
1392     }
1393 }