1 /* |
1 /* |
2 * Copyright (c) 2004, 2017, Oracle and/or its affiliates. All rights reserved. |
2 * Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * |
4 * |
5 * This code is free software; you can redistribute it and/or modify it |
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 |
6 * under the terms of the GNU General Public License version 2 only, as |
7 * published by the Free Software Foundation. Oracle designates this |
7 * published by the Free Software Foundation. Oracle designates this |
24 */ |
24 */ |
25 |
25 |
26 package sun.security.ssl; |
26 package sun.security.ssl; |
27 |
27 |
28 import java.lang.ref.*; |
28 import java.lang.ref.*; |
|
29 import java.net.Socket; |
|
30 import java.security.AlgorithmConstraints; |
|
31 import java.security.KeyStore; |
|
32 import java.security.KeyStore.Builder; |
|
33 import java.security.KeyStore.Entry; |
|
34 import java.security.KeyStore.PrivateKeyEntry; |
|
35 import java.security.Principal; |
|
36 import java.security.PrivateKey; |
|
37 import java.security.cert.CertPathValidatorException; |
|
38 import java.security.cert.Certificate; |
|
39 import java.security.cert.CertificateException; |
|
40 import java.security.cert.X509Certificate; |
29 import java.util.*; |
41 import java.util.*; |
30 import static java.util.Locale.ENGLISH; |
|
31 import java.util.concurrent.atomic.AtomicLong; |
42 import java.util.concurrent.atomic.AtomicLong; |
32 import java.net.Socket; |
|
33 |
|
34 import java.security.*; |
|
35 import java.security.KeyStore.*; |
|
36 import java.security.cert.*; |
|
37 import java.security.cert.Certificate; |
|
38 |
|
39 import javax.net.ssl.*; |
43 import javax.net.ssl.*; |
40 |
|
41 import sun.security.provider.certpath.AlgorithmChecker; |
44 import sun.security.provider.certpath.AlgorithmChecker; |
42 import sun.security.validator.Validator; |
45 import sun.security.validator.Validator; |
43 |
46 |
44 /** |
47 /** |
45 * The new X509 key manager implementation. The main differences to the |
48 * The new X509 key manager implementation. The main differences to the |
59 * @author Andreas Sterbenz |
62 * @author Andreas Sterbenz |
60 */ |
63 */ |
61 final class X509KeyManagerImpl extends X509ExtendedKeyManager |
64 final class X509KeyManagerImpl extends X509ExtendedKeyManager |
62 implements X509KeyManager { |
65 implements X509KeyManager { |
63 |
66 |
64 private static final Debug debug = Debug.getInstance("ssl"); |
|
65 |
|
66 private static final boolean useDebug = |
|
67 (debug != null) && Debug.isOn("keymanager"); |
|
68 |
|
69 // for unit testing only, set via privileged reflection |
67 // for unit testing only, set via privileged reflection |
70 private static Date verificationDate; |
68 private static Date verificationDate; |
71 |
69 |
72 // list of the builders |
70 // list of the builders |
73 private final List<Builder> builders; |
71 private final List<Builder> builders; |
187 |
185 |
188 SSLSocket sslSocket = (SSLSocket)socket; |
186 SSLSocket sslSocket = (SSLSocket)socket; |
189 SSLSession session = sslSocket.getHandshakeSession(); |
187 SSLSession session = sslSocket.getHandshakeSession(); |
190 |
188 |
191 if (session != null) { |
189 if (session != null) { |
192 ProtocolVersion protocolVersion = |
190 if (ProtocolVersion.useTLS12PlusSpec(session.getProtocol())) { |
193 ProtocolVersion.valueOf(session.getProtocol()); |
|
194 if (protocolVersion.useTLS12PlusSpec()) { |
|
195 String[] peerSupportedSignAlgs = null; |
191 String[] peerSupportedSignAlgs = null; |
196 |
192 |
197 if (session instanceof ExtendedSSLSession) { |
193 if (session instanceof ExtendedSSLSession) { |
198 ExtendedSSLSession extSession = |
194 ExtendedSSLSession extSession = |
199 (ExtendedSSLSession)session; |
195 (ExtendedSSLSession)session; |
215 // Gets algorithm constraints of the engine. |
211 // Gets algorithm constraints of the engine. |
216 private AlgorithmConstraints getAlgorithmConstraints(SSLEngine engine) { |
212 private AlgorithmConstraints getAlgorithmConstraints(SSLEngine engine) { |
217 if (engine != null) { |
213 if (engine != null) { |
218 SSLSession session = engine.getHandshakeSession(); |
214 SSLSession session = engine.getHandshakeSession(); |
219 if (session != null) { |
215 if (session != null) { |
220 ProtocolVersion protocolVersion = |
216 if (ProtocolVersion.useTLS12PlusSpec(session.getProtocol())) { |
221 ProtocolVersion.valueOf(session.getProtocol()); |
|
222 if (protocolVersion.useTLS12PlusSpec()) { |
|
223 String[] peerSupportedSignAlgs = null; |
217 String[] peerSupportedSignAlgs = null; |
224 |
218 |
225 if (session instanceof ExtendedSSLSession) { |
219 if (session instanceof ExtendedSSLSession) { |
226 ExtendedSSLSession extSession = |
220 ExtendedSSLSession extSession = |
227 (ExtendedSSLSession)session; |
221 (ExtendedSSLSession)session; |
295 final String keyAlgorithm; |
289 final String keyAlgorithm; |
296 |
290 |
297 // In TLS 1.2, the signature algorithm has been obsoleted by the |
291 // In TLS 1.2, the signature algorithm has been obsoleted by the |
298 // supported_signature_algorithms, and the certificate type no longer |
292 // supported_signature_algorithms, and the certificate type no longer |
299 // restricts the algorithm used to sign the certificate. |
293 // restricts the algorithm used to sign the certificate. |
|
294 // |
300 // However, because we don't support certificate type checking other |
295 // However, because we don't support certificate type checking other |
301 // than rsa_sign, dss_sign and ecdsa_sign, we don't have to check the |
296 // than rsa_sign, dss_sign and ecdsa_sign, we don't have to check the |
302 // protocol version here. |
297 // protocol version here. |
303 final String sigKeyAlgorithm; |
298 final String sigKeyAlgorithm; |
304 |
299 |
326 chain[1].getPublicKey().getAlgorithm()); |
321 chain[1].getPublicKey().getAlgorithm()); |
327 } else { |
322 } else { |
328 // Check the signature algorithm of the certificate itself. |
323 // Check the signature algorithm of the certificate itself. |
329 // Look for the "withRSA" in "SHA1withRSA", etc. |
324 // Look for the "withRSA" in "SHA1withRSA", etc. |
330 X509Certificate issuer = (X509Certificate)chain[0]; |
325 X509Certificate issuer = (X509Certificate)chain[0]; |
331 String sigAlgName = issuer.getSigAlgName().toUpperCase(ENGLISH); |
326 String sigAlgName = |
332 String pattern = "WITH" + sigKeyAlgorithm.toUpperCase(ENGLISH); |
327 issuer.getSigAlgName().toUpperCase(Locale.ENGLISH); |
|
328 String pattern = |
|
329 "WITH" + sigKeyAlgorithm.toUpperCase(Locale.ENGLISH); |
333 return sigAlgName.contains(pattern); |
330 return sigAlgName.contains(pattern); |
334 } |
331 } |
335 } |
332 } |
336 } |
333 } |
337 |
334 |
386 // the results will either be a single perfect match |
383 // the results will either be a single perfect match |
387 // or 1 or more imperfect matches |
384 // or 1 or more imperfect matches |
388 // if it's a perfect match, return immediately |
385 // if it's a perfect match, return immediately |
389 EntryStatus status = results.get(0); |
386 EntryStatus status = results.get(0); |
390 if (status.checkResult == CheckResult.OK) { |
387 if (status.checkResult == CheckResult.OK) { |
391 if (useDebug) { |
388 if (SSLLogger.isOn && SSLLogger.isOn("keymanager")) { |
392 debug.println("KeyMgr: choosing key: " + status); |
389 SSLLogger.fine("KeyMgr: choosing key: " + status); |
393 } |
390 } |
394 return makeAlias(status); |
391 return makeAlias(status); |
395 } |
392 } |
396 if (allResults == null) { |
393 if (allResults == null) { |
397 allResults = new ArrayList<EntryStatus>(); |
394 allResults = new ArrayList<EntryStatus>(); |
401 } catch (Exception e) { |
398 } catch (Exception e) { |
402 // ignore |
399 // ignore |
403 } |
400 } |
404 } |
401 } |
405 if (allResults == null) { |
402 if (allResults == null) { |
406 if (useDebug) { |
403 if (SSLLogger.isOn && SSLLogger.isOn("keymanager")) { |
407 debug.println("KeyMgr: no matching key found"); |
404 SSLLogger.fine("KeyMgr: no matching key found"); |
408 } |
405 } |
409 return null; |
406 return null; |
410 } |
407 } |
411 Collections.sort(allResults); |
408 Collections.sort(allResults); |
412 if (useDebug) { |
409 if (SSLLogger.isOn && SSLLogger.isOn("keymanager")) { |
413 debug.println("KeyMgr: no good matching key found, " |
410 SSLLogger.fine( |
414 + "returning best match out of:"); |
411 "KeyMgr: no good matching key found, " |
415 debug.println(allResults.toString()); |
412 + "returning best match out of", allResults); |
416 } |
413 } |
417 return makeAlias(allResults.get(0)); |
414 return makeAlias(allResults.get(0)); |
418 } |
415 } |
419 |
416 |
420 /* |
417 /* |
437 List<EntryStatus> results = getAliases(i, keyTypeList, |
434 List<EntryStatus> results = getAliases(i, keyTypeList, |
438 issuerSet, true, checkType, constraints, |
435 issuerSet, true, checkType, constraints, |
439 null, null); |
436 null, null); |
440 if (results != null) { |
437 if (results != null) { |
441 if (allResults == null) { |
438 if (allResults == null) { |
442 allResults = new ArrayList<EntryStatus>(); |
439 allResults = new ArrayList<>(); |
443 } |
440 } |
444 allResults.addAll(results); |
441 allResults.addAll(results); |
445 } |
442 } |
446 } catch (Exception e) { |
443 } catch (Exception e) { |
447 // ignore |
444 // ignore |
448 } |
445 } |
449 } |
446 } |
450 if (allResults == null || allResults.isEmpty()) { |
447 if (allResults == null || allResults.isEmpty()) { |
451 if (useDebug) { |
448 if (SSLLogger.isOn && SSLLogger.isOn("keymanager")) { |
452 debug.println("KeyMgr: no matching alias found"); |
449 SSLLogger.fine("KeyMgr: no matching alias found"); |
453 } |
450 } |
454 return null; |
451 return null; |
455 } |
452 } |
456 Collections.sort(allResults); |
453 Collections.sort(allResults); |
457 if (useDebug) { |
454 if (SSLLogger.isOn && SSLLogger.isOn("keymanager")) { |
458 debug.println("KeyMgr: getting aliases: " + allResults); |
455 SSLLogger.fine("KeyMgr: getting aliases", allResults); |
459 } |
456 } |
460 return toAliases(allResults); |
457 return toAliases(allResults); |
461 } |
458 } |
462 |
459 |
463 // turn candidate entries into unique aliases we can return to JSSE |
460 // turn candidate entries into unique aliases we can return to JSSE |
542 |
539 |
543 private static boolean getBit(boolean[] keyUsage, int bit) { |
540 private static boolean getBit(boolean[] keyUsage, int bit) { |
544 return (bit < keyUsage.length) && keyUsage[bit]; |
541 return (bit < keyUsage.length) && keyUsage[bit]; |
545 } |
542 } |
546 |
543 |
547 // check if this certificate is appropriate for this type of use |
544 // Check if this certificate is appropriate for this type of use |
548 // first check extensions, if they match, check expiration |
545 // first check extensions, if they match, check expiration. |
549 // note: we may want to move this code into the sun.security.validator |
546 // |
|
547 // Note: we may want to move this code into the sun.security.validator |
550 // package |
548 // package |
551 CheckResult check(X509Certificate cert, Date date, |
549 CheckResult check(X509Certificate cert, Date date, |
552 List<SNIServerName> serverNames, String idAlgorithm) { |
550 List<SNIServerName> serverNames, String idAlgorithm) { |
553 |
551 |
554 if (this == NONE) { |
552 if (this == NONE) { |
568 |
566 |
569 // check key usage |
567 // check key usage |
570 boolean[] ku = cert.getKeyUsage(); |
568 boolean[] ku = cert.getKeyUsage(); |
571 if (ku != null) { |
569 if (ku != null) { |
572 String algorithm = cert.getPublicKey().getAlgorithm(); |
570 String algorithm = cert.getPublicKey().getAlgorithm(); |
573 boolean kuSignature = getBit(ku, 0); |
571 boolean supportsDigitalSignature = getBit(ku, 0); |
574 switch (algorithm) { |
572 switch (algorithm) { |
575 case "RSA": |
573 case "RSA": |
576 // require either signature bit |
574 // require either signature bit |
577 // or if server also allow key encipherment bit |
575 // or if server also allow key encipherment bit |
578 if (kuSignature == false) { |
576 if (!supportsDigitalSignature) { |
579 if ((this == CLIENT) || (getBit(ku, 2) == false)) { |
577 if (this == CLIENT || getBit(ku, 2) == false) { |
580 return CheckResult.EXTENSION_MISMATCH; |
578 return CheckResult.EXTENSION_MISMATCH; |
581 } |
579 } |
582 } |
580 } |
583 break; |
581 break; |
|
582 case "RSASSA-PSS": |
|
583 if (!supportsDigitalSignature && (this == SERVER)) { |
|
584 return CheckResult.EXTENSION_MISMATCH; |
|
585 } |
|
586 break; |
584 case "DSA": |
587 case "DSA": |
585 // require signature bit |
588 // require signature bit |
586 if (kuSignature == false) { |
589 if (!supportsDigitalSignature) { |
587 return CheckResult.EXTENSION_MISMATCH; |
590 return CheckResult.EXTENSION_MISMATCH; |
588 } |
591 } |
589 break; |
592 break; |
590 case "DH": |
593 case "DH": |
591 // require keyagreement bit |
594 // require keyagreement bit |
593 return CheckResult.EXTENSION_MISMATCH; |
596 return CheckResult.EXTENSION_MISMATCH; |
594 } |
597 } |
595 break; |
598 break; |
596 case "EC": |
599 case "EC": |
597 // require signature bit |
600 // require signature bit |
598 if (kuSignature == false) { |
601 if (!supportsDigitalSignature) { |
599 return CheckResult.EXTENSION_MISMATCH; |
602 return CheckResult.EXTENSION_MISMATCH; |
600 } |
603 } |
601 // For servers, also require key agreement. |
604 // For servers, also require key agreement. |
602 // This is not totally accurate as the keyAgreement |
605 // This is not totally accurate as the keyAgreement |
603 // bit is only necessary for static ECDH key |
606 // bit is only necessary for static ECDH key |
629 try { |
632 try { |
630 serverName = |
633 serverName = |
631 new SNIHostName(serverName.getEncoded()); |
634 new SNIHostName(serverName.getEncoded()); |
632 } catch (IllegalArgumentException iae) { |
635 } catch (IllegalArgumentException iae) { |
633 // unlikely to happen, just in case ... |
636 // unlikely to happen, just in case ... |
634 if (useDebug) { |
637 if (SSLLogger.isOn && |
635 debug.println( |
638 SSLLogger.isOn("keymanager")) { |
|
639 SSLLogger.fine( |
636 "Illegal server name: " + serverName); |
640 "Illegal server name: " + serverName); |
637 } |
641 } |
638 |
642 |
639 return CheckResult.INSENSITIVE; |
643 return CheckResult.INSENSITIVE; |
640 } |
644 } |
644 |
648 |
645 try { |
649 try { |
646 X509TrustManagerImpl.checkIdentity(hostname, |
650 X509TrustManagerImpl.checkIdentity(hostname, |
647 cert, idAlgorithm); |
651 cert, idAlgorithm); |
648 } catch (CertificateException e) { |
652 } catch (CertificateException e) { |
649 if (useDebug) { |
653 if (SSLLogger.isOn && |
650 debug.println( |
654 SSLLogger.isOn("keymanager")) { |
651 "Certificate identity does not match " + |
655 SSLLogger.fine( |
652 "Server Name Inidication (SNI): " + |
656 "Certificate identity does not match " + |
653 hostname); |
657 "Server Name Inidication (SNI): " + |
|
658 hostname); |
654 } |
659 } |
655 return CheckResult.INSENSITIVE; |
660 return CheckResult.INSENSITIVE; |
656 } |
661 } |
657 |
662 |
658 break; |
663 break; |
722 Date date = verificationDate; |
727 Date date = verificationDate; |
723 boolean preferred = false; |
728 boolean preferred = false; |
724 for (Enumeration<String> e = ks.aliases(); e.hasMoreElements(); ) { |
729 for (Enumeration<String> e = ks.aliases(); e.hasMoreElements(); ) { |
725 String alias = e.nextElement(); |
730 String alias = e.nextElement(); |
726 // check if it is a key entry (private key or secret key) |
731 // check if it is a key entry (private key or secret key) |
727 if (ks.isKeyEntry(alias) == false) { |
732 if (!ks.isKeyEntry(alias)) { |
728 continue; |
733 continue; |
729 } |
734 } |
730 |
735 |
731 Certificate[] chain = ks.getCertificateChain(alias); |
736 Certificate[] chain = ks.getCertificateChain(alias); |
732 if ((chain == null) || (chain.length == 0)) { |
737 if ((chain == null) || (chain.length == 0)) { |
772 found = true; |
777 found = true; |
773 break; |
778 break; |
774 } |
779 } |
775 } |
780 } |
776 if (found == false) { |
781 if (found == false) { |
777 if (useDebug) { |
782 if (SSLLogger.isOn && SSLLogger.isOn("keymanager")) { |
778 debug.println("Ignoring alias " + alias |
783 SSLLogger.fine( |
779 + ": issuers do not match"); |
784 "Ignore alias " + alias |
|
785 + ": issuers do not match"); |
780 } |
786 } |
781 continue; |
787 continue; |
782 } |
788 } |
783 } |
789 } |
784 |
790 |
785 // check the algorithm constraints |
791 // check the algorithm constraints |
786 if (constraints != null && |
792 if (constraints != null && |
787 !conformsToAlgorithmConstraints(constraints, chain, |
793 !conformsToAlgorithmConstraints(constraints, chain, |
788 checkType.getValidator())) { |
794 checkType.getValidator())) { |
789 |
795 |
790 if (useDebug) { |
796 if (SSLLogger.isOn && SSLLogger.isOn("keymanager")) { |
791 debug.println("Ignoring alias " + alias + |
797 SSLLogger.fine("Ignore alias " + alias + |
792 ": certificate list does not conform to " + |
798 ": certificate list does not conform to " + |
793 "algorithm constraints"); |
799 "algorithm constraints"); |
794 } |
800 } |
795 continue; |
801 continue; |
796 } |
802 } |
811 // if we have a good match and do not need all matches, |
817 // if we have a good match and do not need all matches, |
812 // return immediately |
818 // return immediately |
813 return Collections.singletonList(status); |
819 return Collections.singletonList(status); |
814 } else { |
820 } else { |
815 if (results == null) { |
821 if (results == null) { |
816 results = new ArrayList<EntryStatus>(); |
822 results = new ArrayList<>(); |
817 } |
823 } |
818 results.add(status); |
824 results.add(status); |
819 } |
825 } |
820 } |
826 } |
821 return results; |
827 return results; |
823 |
829 |
824 private static boolean conformsToAlgorithmConstraints( |
830 private static boolean conformsToAlgorithmConstraints( |
825 AlgorithmConstraints constraints, Certificate[] chain, |
831 AlgorithmConstraints constraints, Certificate[] chain, |
826 String variant) { |
832 String variant) { |
827 |
833 |
828 AlgorithmChecker checker = new AlgorithmChecker(constraints, null, variant); |
834 AlgorithmChecker checker = |
|
835 new AlgorithmChecker(constraints, null, variant); |
829 try { |
836 try { |
830 checker.init(false); |
837 checker.init(false); |
831 } catch (CertPathValidatorException cpve) { |
838 } catch (CertPathValidatorException cpve) { |
832 // unlikely to happen |
839 // unlikely to happen |
833 if (useDebug) { |
840 if (SSLLogger.isOn && SSLLogger.isOn("keymanager")) { |
834 debug.println( |
841 SSLLogger.fine( |
835 "Cannot initialize algorithm constraints checker: " + cpve); |
842 "Cannot initialize algorithm constraints checker", cpve); |
836 } |
843 } |
837 |
844 |
838 return false; |
845 return false; |
839 } |
846 } |
840 |
847 |
843 Certificate cert = chain[i]; |
850 Certificate cert = chain[i]; |
844 try { |
851 try { |
845 // We don't care about the unresolved critical extensions. |
852 // We don't care about the unresolved critical extensions. |
846 checker.check(cert, Collections.<String>emptySet()); |
853 checker.check(cert, Collections.<String>emptySet()); |
847 } catch (CertPathValidatorException cpve) { |
854 } catch (CertPathValidatorException cpve) { |
848 if (useDebug) { |
855 if (SSLLogger.isOn && SSLLogger.isOn("keymanager")) { |
849 debug.println("Certificate (" + cert + |
856 SSLLogger.fine("Certificate does not conform to " + |
850 ") does not conform to algorithm constraints: " + cpve); |
857 "algorithm constraints", cert, cpve); |
851 } |
858 } |
852 |
859 |
853 return false; |
860 return false; |
854 } |
861 } |
855 } |
862 } |
856 |
863 |
857 return true; |
864 return true; |
858 } |
865 } |
859 |
|
860 } |
866 } |