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; |
42 import static java.util.Locale.ENGLISH; |
31 import java.util.concurrent.atomic.AtomicLong; |
43 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.*; |
44 import javax.net.ssl.*; |
40 |
|
41 import sun.security.provider.certpath.AlgorithmChecker; |
45 import sun.security.provider.certpath.AlgorithmChecker; |
42 import sun.security.validator.Validator; |
46 import sun.security.validator.Validator; |
43 |
47 |
44 /** |
48 /** |
45 * The new X509 key manager implementation. The main differences to the |
49 * The new X509 key manager implementation. The main differences to the |
59 * @author Andreas Sterbenz |
63 * @author Andreas Sterbenz |
60 */ |
64 */ |
61 final class X509KeyManagerImpl extends X509ExtendedKeyManager |
65 final class X509KeyManagerImpl extends X509ExtendedKeyManager |
62 implements X509KeyManager { |
66 implements X509KeyManager { |
63 |
67 |
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 |
68 // for unit testing only, set via privileged reflection |
70 private static Date verificationDate; |
69 private static Date verificationDate; |
71 |
70 |
72 // list of the builders |
71 // list of the builders |
73 private final List<Builder> builders; |
72 private final List<Builder> builders; |
187 |
186 |
188 SSLSocket sslSocket = (SSLSocket)socket; |
187 SSLSocket sslSocket = (SSLSocket)socket; |
189 SSLSession session = sslSocket.getHandshakeSession(); |
188 SSLSession session = sslSocket.getHandshakeSession(); |
190 |
189 |
191 if (session != null) { |
190 if (session != null) { |
192 ProtocolVersion protocolVersion = |
191 if (ProtocolVersion.useTLS12PlusSpec(session.getProtocol())) { |
193 ProtocolVersion.valueOf(session.getProtocol()); |
|
194 if (protocolVersion.useTLS12PlusSpec()) { |
|
195 String[] peerSupportedSignAlgs = null; |
192 String[] peerSupportedSignAlgs = null; |
196 |
193 |
197 if (session instanceof ExtendedSSLSession) { |
194 if (session instanceof ExtendedSSLSession) { |
198 ExtendedSSLSession extSession = |
195 ExtendedSSLSession extSession = |
199 (ExtendedSSLSession)session; |
196 (ExtendedSSLSession)session; |
215 // Gets algorithm constraints of the engine. |
212 // Gets algorithm constraints of the engine. |
216 private AlgorithmConstraints getAlgorithmConstraints(SSLEngine engine) { |
213 private AlgorithmConstraints getAlgorithmConstraints(SSLEngine engine) { |
217 if (engine != null) { |
214 if (engine != null) { |
218 SSLSession session = engine.getHandshakeSession(); |
215 SSLSession session = engine.getHandshakeSession(); |
219 if (session != null) { |
216 if (session != null) { |
220 ProtocolVersion protocolVersion = |
217 if (ProtocolVersion.useTLS12PlusSpec(session.getProtocol())) { |
221 ProtocolVersion.valueOf(session.getProtocol()); |
|
222 if (protocolVersion.useTLS12PlusSpec()) { |
|
223 String[] peerSupportedSignAlgs = null; |
218 String[] peerSupportedSignAlgs = null; |
224 |
219 |
225 if (session instanceof ExtendedSSLSession) { |
220 if (session instanceof ExtendedSSLSession) { |
226 ExtendedSSLSession extSession = |
221 ExtendedSSLSession extSession = |
227 (ExtendedSSLSession)session; |
222 (ExtendedSSLSession)session; |
386 // the results will either be a single perfect match |
381 // the results will either be a single perfect match |
387 // or 1 or more imperfect matches |
382 // or 1 or more imperfect matches |
388 // if it's a perfect match, return immediately |
383 // if it's a perfect match, return immediately |
389 EntryStatus status = results.get(0); |
384 EntryStatus status = results.get(0); |
390 if (status.checkResult == CheckResult.OK) { |
385 if (status.checkResult == CheckResult.OK) { |
391 if (useDebug) { |
386 if (SSLLogger.isOn && SSLLogger.isOn("keymanager")) { |
392 debug.println("KeyMgr: choosing key: " + status); |
387 SSLLogger.fine("KeyMgr: choosing key: " + status); |
393 } |
388 } |
394 return makeAlias(status); |
389 return makeAlias(status); |
395 } |
390 } |
396 if (allResults == null) { |
391 if (allResults == null) { |
397 allResults = new ArrayList<EntryStatus>(); |
392 allResults = new ArrayList<EntryStatus>(); |
401 } catch (Exception e) { |
396 } catch (Exception e) { |
402 // ignore |
397 // ignore |
403 } |
398 } |
404 } |
399 } |
405 if (allResults == null) { |
400 if (allResults == null) { |
406 if (useDebug) { |
401 if (SSLLogger.isOn && SSLLogger.isOn("keymanager")) { |
407 debug.println("KeyMgr: no matching key found"); |
402 SSLLogger.fine("KeyMgr: no matching key found"); |
408 } |
403 } |
409 return null; |
404 return null; |
410 } |
405 } |
411 Collections.sort(allResults); |
406 Collections.sort(allResults); |
412 if (useDebug) { |
407 if (SSLLogger.isOn && SSLLogger.isOn("keymanager")) { |
413 debug.println("KeyMgr: no good matching key found, " |
408 SSLLogger.fine( |
414 + "returning best match out of:"); |
409 "KeyMgr: no good matching key found, " |
415 debug.println(allResults.toString()); |
410 + "returning best match out of", allResults); |
416 } |
411 } |
417 return makeAlias(allResults.get(0)); |
412 return makeAlias(allResults.get(0)); |
418 } |
413 } |
419 |
414 |
420 /* |
415 /* |
446 } catch (Exception e) { |
441 } catch (Exception e) { |
447 // ignore |
442 // ignore |
448 } |
443 } |
449 } |
444 } |
450 if (allResults == null || allResults.isEmpty()) { |
445 if (allResults == null || allResults.isEmpty()) { |
451 if (useDebug) { |
446 if (SSLLogger.isOn && SSLLogger.isOn("keymanager")) { |
452 debug.println("KeyMgr: no matching alias found"); |
447 SSLLogger.fine("KeyMgr: no matching alias found"); |
453 } |
448 } |
454 return null; |
449 return null; |
455 } |
450 } |
456 Collections.sort(allResults); |
451 Collections.sort(allResults); |
457 if (useDebug) { |
452 if (SSLLogger.isOn && SSLLogger.isOn("keymanager")) { |
458 debug.println("KeyMgr: getting aliases: " + allResults); |
453 SSLLogger.fine("KeyMgr: getting aliases", allResults); |
459 } |
454 } |
460 return toAliases(allResults); |
455 return toAliases(allResults); |
461 } |
456 } |
462 |
457 |
463 // turn candidate entries into unique aliases we can return to JSSE |
458 // turn candidate entries into unique aliases we can return to JSSE |
574 switch (algorithm) { |
569 switch (algorithm) { |
575 case "RSA": |
570 case "RSA": |
576 // require either signature bit |
571 // require either signature bit |
577 // or if server also allow key encipherment bit |
572 // or if server also allow key encipherment bit |
578 if (kuSignature == false) { |
573 if (kuSignature == false) { |
579 if ((this == CLIENT) || (getBit(ku, 2) == false)) { |
574 if (this == CLIENT || getBit(ku, 2) == false) { |
580 return CheckResult.EXTENSION_MISMATCH; |
575 return CheckResult.EXTENSION_MISMATCH; |
581 } |
576 } |
582 } |
577 } |
583 break; |
578 break; |
584 case "DSA": |
579 case "DSA": |
629 try { |
624 try { |
630 serverName = |
625 serverName = |
631 new SNIHostName(serverName.getEncoded()); |
626 new SNIHostName(serverName.getEncoded()); |
632 } catch (IllegalArgumentException iae) { |
627 } catch (IllegalArgumentException iae) { |
633 // unlikely to happen, just in case ... |
628 // unlikely to happen, just in case ... |
634 if (useDebug) { |
629 if (SSLLogger.isOn && |
635 debug.println( |
630 SSLLogger.isOn("keymanager")) { |
|
631 SSLLogger.fine( |
636 "Illegal server name: " + serverName); |
632 "Illegal server name: " + serverName); |
637 } |
633 } |
638 |
634 |
639 return CheckResult.INSENSITIVE; |
635 return CheckResult.INSENSITIVE; |
640 } |
636 } |
644 |
640 |
645 try { |
641 try { |
646 X509TrustManagerImpl.checkIdentity(hostname, |
642 X509TrustManagerImpl.checkIdentity(hostname, |
647 cert, idAlgorithm); |
643 cert, idAlgorithm); |
648 } catch (CertificateException e) { |
644 } catch (CertificateException e) { |
649 if (useDebug) { |
645 if (SSLLogger.isOn && |
650 debug.println( |
646 SSLLogger.isOn("keymanager")) { |
651 "Certificate identity does not match " + |
647 SSLLogger.fine( |
652 "Server Name Inidication (SNI): " + |
648 "Certificate identity does not match " + |
653 hostname); |
649 "Server Name Inidication (SNI): " + |
|
650 hostname); |
654 } |
651 } |
655 return CheckResult.INSENSITIVE; |
652 return CheckResult.INSENSITIVE; |
656 } |
653 } |
657 |
654 |
658 break; |
655 break; |
722 Date date = verificationDate; |
719 Date date = verificationDate; |
723 boolean preferred = false; |
720 boolean preferred = false; |
724 for (Enumeration<String> e = ks.aliases(); e.hasMoreElements(); ) { |
721 for (Enumeration<String> e = ks.aliases(); e.hasMoreElements(); ) { |
725 String alias = e.nextElement(); |
722 String alias = e.nextElement(); |
726 // check if it is a key entry (private key or secret key) |
723 // check if it is a key entry (private key or secret key) |
727 if (ks.isKeyEntry(alias) == false) { |
724 if (!ks.isKeyEntry(alias)) { |
728 continue; |
725 continue; |
729 } |
726 } |
730 |
727 |
731 Certificate[] chain = ks.getCertificateChain(alias); |
728 Certificate[] chain = ks.getCertificateChain(alias); |
732 if ((chain == null) || (chain.length == 0)) { |
729 if ((chain == null) || (chain.length == 0)) { |
772 found = true; |
769 found = true; |
773 break; |
770 break; |
774 } |
771 } |
775 } |
772 } |
776 if (found == false) { |
773 if (found == false) { |
777 if (useDebug) { |
774 if (SSLLogger.isOn && SSLLogger.isOn("keymanager")) { |
778 debug.println("Ignoring alias " + alias |
775 SSLLogger.fine( |
779 + ": issuers do not match"); |
776 "Ignore alias " + alias |
|
777 + ": issuers do not match"); |
780 } |
778 } |
781 continue; |
779 continue; |
782 } |
780 } |
783 } |
781 } |
784 |
782 |
785 // check the algorithm constraints |
783 // check the algorithm constraints |
786 if (constraints != null && |
784 if (constraints != null && |
787 !conformsToAlgorithmConstraints(constraints, chain, |
785 !conformsToAlgorithmConstraints(constraints, chain, |
788 checkType.getValidator())) { |
786 checkType.getValidator())) { |
789 |
787 |
790 if (useDebug) { |
788 if (SSLLogger.isOn && SSLLogger.isOn("keymanager")) { |
791 debug.println("Ignoring alias " + alias + |
789 SSLLogger.fine("Ignore alias " + alias + |
792 ": certificate list does not conform to " + |
790 ": certificate list does not conform to " + |
793 "algorithm constraints"); |
791 "algorithm constraints"); |
794 } |
792 } |
795 continue; |
793 continue; |
796 } |
794 } |
823 |
821 |
824 private static boolean conformsToAlgorithmConstraints( |
822 private static boolean conformsToAlgorithmConstraints( |
825 AlgorithmConstraints constraints, Certificate[] chain, |
823 AlgorithmConstraints constraints, Certificate[] chain, |
826 String variant) { |
824 String variant) { |
827 |
825 |
828 AlgorithmChecker checker = new AlgorithmChecker(constraints, null, variant); |
826 AlgorithmChecker checker = |
|
827 new AlgorithmChecker(constraints, null, variant); |
829 try { |
828 try { |
830 checker.init(false); |
829 checker.init(false); |
831 } catch (CertPathValidatorException cpve) { |
830 } catch (CertPathValidatorException cpve) { |
832 // unlikely to happen |
831 // unlikely to happen |
833 if (useDebug) { |
832 if (SSLLogger.isOn && SSLLogger.isOn("keymanager")) { |
834 debug.println( |
833 SSLLogger.fine( |
835 "Cannot initialize algorithm constraints checker: " + cpve); |
834 "Cannot initialize algorithm constraints checker", cpve); |
836 } |
835 } |
837 |
836 |
838 return false; |
837 return false; |
839 } |
838 } |
840 |
839 |
843 Certificate cert = chain[i]; |
842 Certificate cert = chain[i]; |
844 try { |
843 try { |
845 // We don't care about the unresolved critical extensions. |
844 // We don't care about the unresolved critical extensions. |
846 checker.check(cert, Collections.<String>emptySet()); |
845 checker.check(cert, Collections.<String>emptySet()); |
847 } catch (CertPathValidatorException cpve) { |
846 } catch (CertPathValidatorException cpve) { |
848 if (useDebug) { |
847 if (SSLLogger.isOn && SSLLogger.isOn("keymanager")) { |
849 debug.println("Certificate (" + cert + |
848 SSLLogger.fine("Certificate does not conform to " + |
850 ") does not conform to algorithm constraints: " + cpve); |
849 "algorithm constraints", cert, cpve); |
851 } |
850 } |
852 |
851 |
853 return false; |
852 return false; |
854 } |
853 } |
855 } |
854 } |
856 |
855 |
857 return true; |
856 return true; |
858 } |
857 } |
859 |
|
860 } |
858 } |