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 static sun.security.ssl.ClientAuthType.CLIENT_AUTH_REQUIRED; 57 import sun.security.ssl.ClientHello.ClientHelloMessage; 58 import sun.security.ssl.SSLHandshake.HandshakeMessage; 59 import sun.security.ssl.X509Authentication.X509Credentials; 60 import sun.security.ssl.X509Authentication.X509Possession; 61 62 /** 63 * Pack of the CertificateMessage handshake message. 64 */ 65 final class CertificateMessage { 66 static final SSLConsumer t12HandshakeConsumer = 67 new T12CertificateConsumer(); 68 static final HandshakeProducer t12HandshakeProducer = 69 new T12CertificateProducer(); 70 71 static final SSLConsumer t13HandshakeConsumer = 72 new T13CertificateConsumer(); 73 static final HandshakeProducer t13HandshakeProducer = 74 new T13CertificateProducer(); 75 76 /** 77 * The Certificate handshake message for TLS 1.2 and previous 78 * SSL/TLS protocol versions. 79 * 80 * In server mode, the certificate handshake message is sent whenever the 81 * agreed-upon key exchange method uses certificates for authentication. 82 * In client mode, this message is only sent if the server requests a 83 * certificate for client authentication. 84 * 85 * opaque ASN.1Cert<1..2^24-1>; 86 * 87 * SSL 3.0: 88 * struct { 89 * ASN.1Cert certificate_list<1..2^24-1>; 90 * } Certificate; 91 * Note: For SSL 3.0 client authentication, if no suitable certificate 92 * is available, the client should send a no_certificate alert instead. 93 * This alert is only a warning; however, the server may respond with 94 * a fatal handshake failure alert if client authentication is required. 95 * 96 * TLS 1.0/1.1/1.2: 97 * struct { 98 * ASN.1Cert certificate_list<0..2^24-1>; 99 * } Certificate; 100 */ 101 static final class T12CertificateMessage extends HandshakeMessage { 102 final List<byte[]> encodedCertChain; 103 104 T12CertificateMessage(HandshakeContext handshakeContext, 105 X509Certificate[] certChain) throws SSLException { 106 super(handshakeContext); 107 108 List<byte[]> encodedCerts = new ArrayList<>(certChain.length); 109 for (X509Certificate cert : certChain) { 110 try { 111 encodedCerts.add(cert.getEncoded()); 112 } catch (CertificateEncodingException cee) { 113 // unlikely 114 handshakeContext.conContext.fatal(Alert.INTERNAL_ERROR, 115 "Could not encode certificate (" + 116 cert.getSubjectX500Principal() + ")", cee); 117 break; 118 } 119 } 120 121 this.encodedCertChain = encodedCerts; 122 } 123 124 T12CertificateMessage(HandshakeContext handshakeContext, 125 ByteBuffer m) throws IOException { 126 super(handshakeContext); 127 128 int listLen = Record.getInt24(m); 129 if (listLen > m.remaining()) { 130 handshakeContext.conContext.fatal(Alert.ILLEGAL_PARAMETER, 131 "Error parsing certificate message:no sufficient data"); 132 } 133 if (listLen > 0) { 134 List<byte[]> encodedCerts = new LinkedList<>(); 135 while (listLen > 0) { 136 byte[] encodedCert = Record.getBytes24(m); 137 listLen -= (3 + encodedCert.length); 138 encodedCerts.add(encodedCert); 139 } 140 this.encodedCertChain = encodedCerts; 141 } else { 142 this.encodedCertChain = Collections.emptyList(); 143 } 144 } 145 146 @Override 147 public SSLHandshake handshakeType() { 148 return SSLHandshake.CERTIFICATE; 149 } 150 151 @Override 152 public int messageLength() { 153 int msgLen = 3; 154 for (byte[] encodedCert : encodedCertChain) { 155 msgLen += (encodedCert.length + 3); 156 } 157 158 return msgLen; 159 } 160 161 @Override 162 public void send(HandshakeOutStream hos) throws IOException { 163 int listLen = 0; 164 for (byte[] encodedCert : encodedCertChain) { 165 listLen += (encodedCert.length + 3); 166 } 167 168 hos.putInt24(listLen); 169 for (byte[] encodedCert : encodedCertChain) { 170 hos.putBytes24(encodedCert); 171 } 172 } 173 174 @Override 175 public String toString() { 176 if (encodedCertChain.isEmpty()) { 177 return "\"Certificates\": <empty list>"; 178 } 179 180 Object[] x509Certs = new Object[encodedCertChain.size()]; 181 try { 182 CertificateFactory cf = CertificateFactory.getInstance("X.509"); 183 int i = 0; 184 for (byte[] encodedCert : encodedCertChain) { 185 Object obj; 186 try { 187 obj = (X509Certificate)cf.generateCertificate( 188 new ByteArrayInputStream(encodedCert)); 189 } catch (CertificateException ce) { 190 obj = encodedCert; 191 } 192 x509Certs[i++] = obj; 193 } 194 } catch (CertificateException ce) { 195 // no X.509 certificate factory service 196 int i = 0; 197 for (byte[] encodedCert : encodedCertChain) { 198 x509Certs[i++] = encodedCert; 199 } 200 } 201 202 MessageFormat messageFormat = new MessageFormat( 203 "\"Certificates\": [\n" + 204 "{0}\n" + 205 "]", 206 Locale.ENGLISH); 207 Object[] messageFields = { 208 SSLLogger.toString(x509Certs) 209 }; 210 211 return messageFormat.format(messageFields); 212 } 213 } 214 215 /** 216 * The "Certificate" handshake message producer for TLS 1.2 and 217 * previous SSL/TLS protocol versions. 218 */ 219 private static final 220 class T12CertificateProducer implements HandshakeProducer { 221 // Prevent instantiation of this class. 222 private T12CertificateProducer() { 223 // blank 224 } 225 226 @Override 227 public byte[] produce(ConnectionContext context, 228 HandshakeMessage message) throws IOException { 229 // The producing happens in handshake context only. 230 HandshakeContext hc = (HandshakeContext)context; 231 if (hc.sslConfig.isClientMode) { 232 return onProduceCertificate( 233 (ClientHandshakeContext)context, message); 234 } else { 235 return onProduceCertificate( 236 (ServerHandshakeContext)context, message); 237 } 238 } 239 240 private byte[] onProduceCertificate(ServerHandshakeContext shc, 241 SSLHandshake.HandshakeMessage message) throws IOException { 242 X509Possession x509Possession = null; 243 for (SSLPossession possession : shc.handshakePossessions) { 244 if (possession instanceof X509Possession) { 245 x509Possession = (X509Possession)possession; 246 break; 247 } 248 } 249 250 if (x509Possession == null) { // unlikely 251 shc.conContext.fatal(Alert.INTERNAL_ERROR, 252 "No expected X.509 certificate for server authentication"); 253 254 return null; // make the compiler happy 255 } 256 257 shc.handshakeSession.setLocalPrivateKey( 258 x509Possession.popPrivateKey); 259 shc.handshakeSession.setLocalCertificates(x509Possession.popCerts); 260 T12CertificateMessage cm = 261 new T12CertificateMessage(shc, x509Possession.popCerts); 262 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { 263 SSLLogger.fine( 264 "Produced server Certificate handshake message", cm); 265 } 266 267 // Output the handshake message. 268 cm.write(shc.handshakeOutput); 269 shc.handshakeOutput.flush(); 270 271 // The handshake message has been delivered. 272 return null; 273 } 274 275 private byte[] onProduceCertificate(ClientHandshakeContext chc, 276 SSLHandshake.HandshakeMessage message) throws IOException { 277 X509Possession x509Possession = null; 278 for (SSLPossession possession : chc.handshakePossessions) { 279 if (possession instanceof X509Possession) { 280 x509Possession = (X509Possession)possession; 281 break; 282 } 283 } 284 285 // Report to the server if no appropriate cert was found. For 286 // SSL 3.0, send a no_certificate alert; TLS 1.0/1.1/1.2 uses 287 // an empty cert chain instead. 288 if (x509Possession == null) { 289 if (chc.negotiatedProtocol.useTLS10PlusSpec()) { 290 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { 291 SSLLogger.fine( 292 "No X.509 certificate for client authentication, " + 293 "use empty Certificate message instead"); 294 } 295 296 x509Possession = 297 new X509Possession(null, new X509Certificate[0]); 298 } else { 299 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { 300 SSLLogger.fine( 301 "No X.509 certificate for client authentication, " + 302 "send a no_certificate alert"); 303 } 304 305 chc.conContext.warning(Alert.NO_CERTIFICATE); 306 return null; 307 } 308 } 309 310 chc.handshakeSession.setLocalPrivateKey( 311 x509Possession.popPrivateKey); 312 if (x509Possession.popCerts != null && 313 x509Possession.popCerts.length != 0) { 314 chc.handshakeSession.setLocalCertificates( 315 x509Possession.popCerts); 316 } else { 317 chc.handshakeSession.setLocalCertificates(null); 318 } 319 T12CertificateMessage cm = 320 new T12CertificateMessage(chc, x509Possession.popCerts); 321 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { 322 SSLLogger.fine( 323 "Produced client Certificate handshake message", cm); 324 } 325 326 // Output the handshake message. 327 cm.write(chc.handshakeOutput); 328 chc.handshakeOutput.flush(); 329 330 // The handshake message has been delivered. 331 return null; 332 } 333 } 334 335 /** 336 * The "Certificate" handshake message consumer for TLS 1.2 and 337 * previous SSL/TLS protocol versions. 338 */ 339 static final 340 class T12CertificateConsumer implements SSLConsumer { 341 // Prevent instantiation of this class. 342 private T12CertificateConsumer() { 343 // blank 344 } 345 346 @Override 347 public void consume(ConnectionContext context, 348 ByteBuffer message) throws IOException { 349 // The consuming happens in handshake context only. 350 HandshakeContext hc = (HandshakeContext)context; 351 352 // clean up this consumer 353 hc.handshakeConsumers.remove(SSLHandshake.CERTIFICATE.id); 354 355 T12CertificateMessage cm = new T12CertificateMessage(hc, message); 356 if (hc.sslConfig.isClientMode) { 357 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { 358 SSLLogger.fine( 359 "Consuming server Certificate handshake message", cm); 360 } 361 onCertificate((ClientHandshakeContext)context, cm); 362 } else { 363 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { 364 SSLLogger.fine( 365 "Consuming client Certificate handshake message", cm); 366 } 367 onCertificate((ServerHandshakeContext)context, cm); 368 } 369 } 370 371 private void onCertificate(ServerHandshakeContext shc, 372 T12CertificateMessage certificateMessage )throws IOException { 373 List<byte[]> encodedCerts = certificateMessage.encodedCertChain; 374 if (encodedCerts == null || encodedCerts.isEmpty()) { 375 if (shc.sslConfig.clientAuthType != 376 ClientAuthType.CLIENT_AUTH_REQUESTED) { 377 // unexpected or require client authentication 378 shc.conContext.fatal(Alert.BAD_CERTIFICATE, 379 "Empty server certificate chain"); 380 } else { 381 return; 382 } 383 } 384 385 X509Certificate[] x509Certs = 386 new X509Certificate[encodedCerts.size()]; 387 try { 388 CertificateFactory cf = CertificateFactory.getInstance("X.509"); 389 int i = 0; 390 for (byte[] encodedCert : encodedCerts) { 391 x509Certs[i++] = (X509Certificate)cf.generateCertificate( 392 new ByteArrayInputStream(encodedCert)); 393 } 394 } catch (CertificateException ce) { 395 shc.conContext.fatal(Alert.BAD_CERTIFICATE, 396 "Failed to parse server certificates", ce); 397 } 398 399 checkClientCerts(shc, x509Certs); 400 401 // 402 // update 403 // 404 shc.handshakeCredentials.add( 405 new X509Credentials(x509Certs[0].getPublicKey(), x509Certs)); 406 shc.handshakeSession.setPeerCertificates(x509Certs); 407 } 408 409 private void onCertificate(ClientHandshakeContext chc, 410 T12CertificateMessage certificateMessage) throws IOException { 411 List<byte[]> encodedCerts = certificateMessage.encodedCertChain; 412 if (encodedCerts == null || encodedCerts.isEmpty()) { 413 chc.conContext.fatal(Alert.BAD_CERTIFICATE, 414 "Empty server certificate chain"); 415 } 416 417 X509Certificate[] x509Certs = 418 new X509Certificate[encodedCerts.size()]; 419 try { 420 CertificateFactory cf = CertificateFactory.getInstance("X.509"); 421 int i = 0; 422 for (byte[] encodedCert : encodedCerts) { 423 x509Certs[i++] = (X509Certificate)cf.generateCertificate( 424 new ByteArrayInputStream(encodedCert)); 425 } 426 } catch (CertificateException ce) { 427 chc.conContext.fatal(Alert.BAD_CERTIFICATE, 428 "Failed to parse server certificates", ce); 429 } 430 431 // Allow server certificate change in client side during 432 // renegotiation after a session-resumption abbreviated 433 // initial handshake? 434 // 435 // DO NOT need to check allowUnsafeServerCertChange here. We only 436 // reserve server certificates when allowUnsafeServerCertChange is 437 // false. 438 if (chc.reservedServerCerts != null && 439 !chc.handshakeSession.useExtendedMasterSecret) { 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 switch (keyAlgorithm) { 655 case "RSA": 656 case "DSA": 657 case "EC": 658 case "RSASSA-PSS": 659 authType = keyAlgorithm; 660 break; 661 default: 662 // unknown public key type 663 authType = "UNKNOWN"; 664 } 665 666 try { 667 if (tm instanceof X509ExtendedTrustManager) { 668 if (shc.conContext.transport instanceof SSLEngine) { 669 SSLEngine engine = (SSLEngine)shc.conContext.transport; 670 ((X509ExtendedTrustManager)tm).checkClientTrusted( 671 certs.clone(), 672 authType, 673 engine); 674 } else { 675 SSLSocket socket = (SSLSocket)shc.conContext.transport; 676 ((X509ExtendedTrustManager)tm).checkClientTrusted( 677 certs.clone(), 678 authType, 679 socket); 680 } 681 } else { 682 // Unlikely to happen, because we have wrapped the old 683 // X509TrustManager with the new X509ExtendedTrustManager. 684 throw new CertificateException( 685 "Improper X509TrustManager implementation"); 686 } 687 } catch (CertificateException ce) { 688 shc.conContext.fatal(Alert.CERTIFICATE_UNKNOWN, ce); 689 } 690 } 691 692 /** 693 * When a failure happens during certificate checking from an 694 * {@link X509TrustManager}, determine what TLS alert description 695 * to use. 696 * 697 * @param cexc The exception thrown by the {@link X509TrustManager} 698 * 699 * @return A byte value corresponding to a TLS alert description number. 700 */ 701 private static Alert getCertificateAlert( 702 ClientHandshakeContext chc, CertificateException cexc) { 703 // The specific reason for the failure will determine how to 704 // set the alert description value 705 Alert alert = Alert.CERTIFICATE_UNKNOWN; 706 707 Throwable baseCause = cexc.getCause(); 708 if (baseCause instanceof CertPathValidatorException) { 709 CertPathValidatorException cpve = 710 (CertPathValidatorException)baseCause; 711 Reason reason = cpve.getReason(); 712 if (reason == BasicReason.REVOKED) { 713 alert = chc.staplingActive ? 714 Alert.BAD_CERT_STATUS_RESPONSE : 715 Alert.CERTIFICATE_REVOKED; 716 } else if ( 717 reason == BasicReason.UNDETERMINED_REVOCATION_STATUS) { 718 alert = chc.staplingActive ? 719 Alert.BAD_CERT_STATUS_RESPONSE : 720 Alert.CERTIFICATE_UNKNOWN; 721 } 722 } 723 724 return alert; 725 } 726 727 } 728 729 /** 730 * The certificate entry used in Certificate handshake message for TLS 1.3. 731 */ 732 static final class CertificateEntry { 733 final byte[] encoded; // encoded cert or public key 734 private final SSLExtensions extensions; 735 736 CertificateEntry(byte[] encoded, SSLExtensions extensions) { 737 this.encoded = encoded; 738 this.extensions = extensions; 739 } 740 741 private int getEncodedSize() { 742 int extLen = extensions.length(); 743 if (extLen == 0) { 744 extLen = 2; // empty extensions 745 } 746 return 3 + encoded.length + extLen; 747 } 748 749 @Override 750 public String toString() { 751 MessageFormat messageFormat = new MessageFormat( 752 "\n'{'\n" + 753 "{0}\n" + // X.509 certificate 754 " \"extensions\": '{'\n" + 755 "{1}\n" + 756 " '}'\n" + 757 "'}',", Locale.ENGLISH); 758 759 Object x509Certs; 760 try { 761 // Don't support certificate type extension (RawPublicKey) yet. 762 CertificateFactory cf = CertificateFactory.getInstance("X.509"); 763 x509Certs = 764 cf.generateCertificate(new ByteArrayInputStream(encoded)); 765 } catch (CertificateException ce) { 766 // no X.509 certificate factory service 767 x509Certs = encoded; 768 } 769 770 Object[] messageFields = { 771 SSLLogger.toString(x509Certs), 772 Utilities.indent(extensions.toString(), " ") 773 }; 774 775 return messageFormat.format(messageFields); 776 } 777 } 778 779 /** 780 * The Certificate handshake message for TLS 1.3. 781 */ 782 static final class T13CertificateMessage extends HandshakeMessage { 783 private final byte[] requestContext; 784 private final List<CertificateEntry> certEntries; 785 786 T13CertificateMessage(HandshakeContext context, 787 byte[] requestContext, X509Certificate[] certificates) 788 throws SSLException, CertificateException { 789 super(context); 790 791 this.requestContext = requestContext.clone(); 792 this.certEntries = new LinkedList<>(); 793 for (X509Certificate cert : certificates) { 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 " + 1040 "signature scheme: " + ss.name); 1041 } 1042 checkedKeyTypes.add(ss.keyAlgorithm); 1043 continue; 1044 } 1045 1046 SSLAuthentication ka = X509Authentication.valueOf(ss); 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; 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 } 1226 } catch (CertificateException ce) { 1227 shc.conContext.fatal(Alert.BAD_CERTIFICATE, 1228 "Failed to parse server certificates", ce); 1229 } 1230 1231 // find out the types of client authentication used 1232 String keyAlgorithm = certs[0].getPublicKey().getAlgorithm(); 1233 String authType; 1234 switch (keyAlgorithm) { 1235 case "RSA": 1236 case "DSA": 1237 case "EC": 1238 case "RSASSA-PSS": 1239 authType = keyAlgorithm; 1240 break; 1241 default: 1242 // unknown public key type 1243 authType = "UNKNOWN"; 1244 } 1245 1246 try { 1247 X509TrustManager tm = shc.sslContext.getX509TrustManager(); 1248 if (tm instanceof X509ExtendedTrustManager) { 1249 if (shc.conContext.transport instanceof SSLEngine) { 1250 SSLEngine engine = (SSLEngine)shc.conContext.transport; 1251 ((X509ExtendedTrustManager)tm).checkClientTrusted( 1252 certs.clone(), 1253 authType, 1254 engine); 1255 } else { 1256 SSLSocket socket = (SSLSocket)shc.conContext.transport; 1257 ((X509ExtendedTrustManager)tm).checkClientTrusted( 1258 certs.clone(), 1259 authType, 1260 socket); 1261 } 1262 } else { 1263 // Unlikely to happen, because we have wrapped the old 1264 // X509TrustManager with the new X509ExtendedTrustManager. 1265 throw new CertificateException( 1266 "Improper X509TrustManager implementation"); 1267 } 1268 1269 // Once the client certificate chain has been validated, set 1270 // the certificate chain in the TLS session. 1271 shc.handshakeSession.setPeerCertificates(certs); 1272 } catch (CertificateException ce) { 1273 shc.conContext.fatal(Alert.CERTIFICATE_UNKNOWN, ce); 1274 } 1275 1276 return certs; 1277 } 1278 1279 private static X509Certificate[] checkServerCerts( 1280 ClientHandshakeContext chc, 1281 List<CertificateEntry> certEntries) throws IOException { 1282 X509Certificate[] certs = 1283 new X509Certificate[certEntries.size()]; 1284 try { 1285 CertificateFactory cf = CertificateFactory.getInstance("X.509"); 1286 int i = 0; 1287 for (CertificateEntry entry : certEntries) { 1288 certs[i++] = (X509Certificate)cf.generateCertificate( 1289 new ByteArrayInputStream(entry.encoded)); 1290 } 1291 } catch (CertificateException ce) { 1292 chc.conContext.fatal(Alert.BAD_CERTIFICATE, 1293 "Failed to parse server certificates", ce); 1294 } 1295 1296 // find out the types of server authentication used 1297 // 1298 // Note that the "UNKNOWN" authentication type is sufficient to 1299 // check the required digitalSignature KeyUsage for TLS 1.3. 1300 String authType = "UNKNOWN"; 1301 1302 try { 1303 X509TrustManager tm = chc.sslContext.getX509TrustManager(); 1304 if (tm instanceof X509ExtendedTrustManager) { 1305 if (chc.conContext.transport instanceof SSLEngine) { 1306 SSLEngine engine = (SSLEngine)chc.conContext.transport; 1307 ((X509ExtendedTrustManager)tm).checkServerTrusted( 1308 certs.clone(), 1309 authType, 1310 engine); 1311 } else { 1312 SSLSocket socket = (SSLSocket)chc.conContext.transport; 1313 ((X509ExtendedTrustManager)tm).checkServerTrusted( 1314 certs.clone(), 1315 authType, 1316 socket); 1317 } 1318 } else { 1319 // Unlikely to happen, because we have wrapped the old 1320 // X509TrustManager with the new X509ExtendedTrustManager. 1321 throw new CertificateException( 1322 "Improper X509TrustManager implementation"); 1323 } 1324 1325 // Once the server certificate chain has been validated, set 1326 // the certificate chain in the TLS session. 1327 chc.handshakeSession.setPeerCertificates(certs); 1328 } catch (CertificateException ce) { 1329 chc.conContext.fatal(getCertificateAlert(chc, ce), ce); 1330 } 1331 1332 return certs; 1333 } 1334 1335 /** 1336 * When a failure happens during certificate checking from an 1337 * {@link X509TrustManager}, determine what TLS alert description 1338 * to use. 1339 * 1340 * @param cexc The exception thrown by the {@link X509TrustManager} 1341 * 1342 * @return A byte value corresponding to a TLS alert description number. 1343 */ 1344 private static Alert getCertificateAlert( 1345 ClientHandshakeContext chc, CertificateException cexc) { 1346 // The specific reason for the failure will determine how to 1347 // set the alert description value 1348 Alert alert = Alert.CERTIFICATE_UNKNOWN; 1349 1350 Throwable baseCause = cexc.getCause(); 1351 if (baseCause instanceof CertPathValidatorException) { 1352 CertPathValidatorException cpve = 1353 (CertPathValidatorException)baseCause; 1354 Reason reason = cpve.getReason(); 1355 if (reason == BasicReason.REVOKED) { 1356 alert = chc.staplingActive ? 1357 Alert.BAD_CERT_STATUS_RESPONSE : 1358 Alert.CERTIFICATE_REVOKED; 1359 } else if ( 1360 reason == BasicReason.UNDETERMINED_REVOCATION_STATUS) { 1361 alert = chc.staplingActive ? 1362 Alert.BAD_CERT_STATUS_RESPONSE : 1363 Alert.CERTIFICATE_UNKNOWN; 1364 } 1365 } 1366 1367 return alert; 1368 } 1369 } 1370 }