History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/sun/security/ssl/X509KeyManagerImpl.java (1 of 18352 files). Show all

Unified · Split

java/pkg/sun/security/ssl/X509KeyManagerImpl.java+741−0
@@ -0,0 +1,741 @@
1/*
2 * Copyright (c) 2004, 2011, 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
26package sun.security.ssl;
27
28import java.lang.ref.*;
29import java.util.*;
30import static java.util.Locale.ENGLISH;
31import java.util.concurrent.atomic.AtomicLong;
32import java.net.Socket;
33
34import java.security.*;
35import java.security.KeyStore.*;
36import java.security.cert.*;
37import java.security.cert.Certificate;
38
39import javax.net.ssl.*;
40
41import sun.security.provider.certpath.AlgorithmChecker;
42
43/**
44 * The new X509 key manager implementation. The main differences to the
45 * old SunX509 key manager are:
46 * . it is based around the KeyStore.Builder API. This allows it to use
47 * other forms of KeyStore protection or password input (e.g. a
48 * CallbackHandler) or to have keys within one KeyStore protected by
49 * different keys.
50 * . it can use multiple KeyStores at the same time.
51 * . it is explicitly designed to accomodate KeyStores that change over
52 * the lifetime of the process.
53 * . it makes an effort to choose the key that matches best, i.e. one that
54 * is not expired and has the appropriate certificate extensions.
55 *
56 * Note that this code is not explicitly performance optimzied yet.
57 *
58 * @author Andreas Sterbenz
59 */
60final class X509KeyManagerImpl extends X509ExtendedKeyManager
61 implements X509KeyManager {
62
63 private static final Debug debug = Debug.getInstance("ssl");
64
65 private final static boolean useDebug =
66 (debug != null) && Debug.isOn("keymanager");
67
68 // for unit testing only, set via privileged reflection
69 private static Date verificationDate;
70
71 // list of the builders
72 private final List<Builder> builders;
73
74 // counter to generate unique ids for the aliases
75 private final AtomicLong uidCounter;
76
77 // cached entries
78 private final Map<String,Reference<PrivateKeyEntry>> entryCacheMap;
79
80 X509KeyManagerImpl(Builder builder) {
81 this(Collections.singletonList(builder));
82 }
83
84 X509KeyManagerImpl(List<Builder> builders) {
85 this.builders = builders;
86 uidCounter = new AtomicLong();
87 entryCacheMap = Collections.synchronizedMap
88 (new SizedMap<String,Reference<PrivateKeyEntry>>());
89 }
90
91 // LinkedHashMap with a max size of 10
92 // see LinkedHashMap JavaDocs
93 private static class SizedMap<K,V> extends LinkedHashMap<K,V> {
94 @Override protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
95 return size() > 10;
96 }
97 }
98
99 //
100 // public methods
101 //
102
103 public X509Certificate[] getCertificateChain(String alias) {
104 PrivateKeyEntry entry = getEntry(alias);
105 return entry == null ? null :
106 (X509Certificate[])entry.getCertificateChain();
107 }
108
109 public PrivateKey getPrivateKey(String alias) {
110 PrivateKeyEntry entry = getEntry(alias);
111 return entry == null ? null : entry.getPrivateKey();
112 }
113
114 public String chooseClientAlias(String[] keyTypes, Principal[] issuers,
115 Socket socket) {
116 return chooseAlias(getKeyTypes(keyTypes), issuers, CheckType.CLIENT,
117 getAlgorithmConstraints(socket));
118 }
119
120 public String chooseEngineClientAlias(String[] keyTypes,
121 Principal[] issuers, SSLEngine engine) {
122 return chooseAlias(getKeyTypes(keyTypes), issuers, CheckType.CLIENT,
123 getAlgorithmConstraints(engine));
124 }
125
126 public String chooseServerAlias(String keyType,
127 Principal[] issuers, Socket socket) {
128 return chooseAlias(getKeyTypes(keyType), issuers, CheckType.SERVER,
129 getAlgorithmConstraints(socket));
130 }
131
132 public String chooseEngineServerAlias(String keyType,
133 Principal[] issuers, SSLEngine engine) {
134 return chooseAlias(getKeyTypes(keyType), issuers, CheckType.SERVER,
135 getAlgorithmConstraints(engine));
136 }
137
138 public String[] getClientAliases(String keyType, Principal[] issuers) {
139 return getAliases(keyType, issuers, CheckType.CLIENT, null);
140 }
141
142 public String[] getServerAliases(String keyType, Principal[] issuers) {
143 return getAliases(keyType, issuers, CheckType.SERVER, null);
144 }
145
146 //
147 // implementation private methods
148 //
149
150 // Gets algorithm constraints of the socket.
151 private AlgorithmConstraints getAlgorithmConstraints(Socket socket) {
152 if (socket != null && socket.isConnected() &&
153 socket instanceof SSLSocket) {
154
155 SSLSocket sslSocket = (SSLSocket)socket;
156 SSLSession session = sslSocket.getHandshakeSession();
157
158 if (session != null) {
159 ProtocolVersion protocolVersion =
160 ProtocolVersion.valueOf(session.getProtocol());
161 if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
162 String[] peerSupportedSignAlgs = null;
163
164 if (session instanceof ExtendedSSLSession) {
165 ExtendedSSLSession extSession =
166 (ExtendedSSLSession)session;
167 peerSupportedSignAlgs =
168 extSession.getPeerSupportedSignatureAlgorithms();
169 }
170
171 return new SSLAlgorithmConstraints(
172 sslSocket, peerSupportedSignAlgs, true);
173 }
174 }
175
176 return new SSLAlgorithmConstraints(sslSocket, true);
177 }
178
179 return new SSLAlgorithmConstraints((SSLSocket)null, true);
180 }
181
182 // Gets algorithm constraints of the engine.
183 private AlgorithmConstraints getAlgorithmConstraints(SSLEngine engine) {
184 if (engine != null) {
185 SSLSession session = engine.getHandshakeSession();
186 if (session != null) {
187 ProtocolVersion protocolVersion =
188 ProtocolVersion.valueOf(session.getProtocol());
189 if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
190 String[] peerSupportedSignAlgs = null;
191
192 if (session instanceof ExtendedSSLSession) {
193 ExtendedSSLSession extSession =
194 (ExtendedSSLSession)session;
195 peerSupportedSignAlgs =
196 extSession.getPeerSupportedSignatureAlgorithms();
197 }
198
199 return new SSLAlgorithmConstraints(
200 engine, peerSupportedSignAlgs, true);
201 }
202 }
203 }
204
205 return new SSLAlgorithmConstraints(engine, true);
206 }
207
208 // we construct the alias we return to JSSE as seen in the code below
209 // a unique id is included to allow us to reliably cache entries
210 // between the calls to getCertificateChain() and getPrivateKey()
211 // even if tokens are inserted or removed
212 private String makeAlias(EntryStatus entry) {
213 return uidCounter.incrementAndGet() + "." + entry.builderIndex + "."
214 + entry.alias;
215 }
216
217 private PrivateKeyEntry getEntry(String alias) {
218 // if the alias is null, return immediately
219 if (alias == null) {
220 return null;
221 }
222
223 // try to get the entry from cache
224 Reference<PrivateKeyEntry> ref = entryCacheMap.get(alias);
225 PrivateKeyEntry entry = (ref != null) ? ref.get() : null;
226 if (entry != null) {
227 return entry;
228 }
229
230 // parse the alias
231 int firstDot = alias.indexOf('.');
232 int secondDot = alias.indexOf('.', firstDot + 1);
233 if ((firstDot == -1) || (secondDot == firstDot)) {
234 // invalid alias
235 return null;
236 }
237 try {
238 int builderIndex = Integer.parseInt
239 (alias.substring(firstDot + 1, secondDot));
240 String keyStoreAlias = alias.substring(secondDot + 1);
241 Builder builder = builders.get(builderIndex);
242 KeyStore ks = builder.getKeyStore();
243 Entry newEntry = ks.getEntry
244 (keyStoreAlias, builder.getProtectionParameter(alias));
245 if (newEntry instanceof PrivateKeyEntry == false) {
246 // unexpected type of entry
247 return null;
248 }
249 entry = (PrivateKeyEntry)newEntry;
250 entryCacheMap.put(alias, new SoftReference(entry));
251 return entry;
252 } catch (Exception e) {
253 // ignore
254 return null;
255 }
256 }
257
258 // Class to help verify that the public key algorithm (and optionally
259 // the signature algorithm) of a certificate matches what we need.
260 private static class KeyType {
261
262 final String keyAlgorithm;
263
264 // In TLS 1.2, the signature algorithm has been obsoleted by the
265 // supported_signature_algorithms, and the certificate type no longer
266 // restricts the algorithm used to sign the certificate.
267 // However, because we don't support certificate type checking other
268 // than rsa_sign, dss_sign and ecdsa_sign, we don't have to check the
269 // protocol version here.
270 final String sigKeyAlgorithm;
271
272 KeyType(String algorithm) {
273 int k = algorithm.indexOf("_");
274 if (k == -1) {
275 keyAlgorithm = algorithm;
276 sigKeyAlgorithm = null;
277 } else {
278 keyAlgorithm = algorithm.substring(0, k);
279 sigKeyAlgorithm = algorithm.substring(k + 1);
280 }
281 }
282
283 boolean matches(Certificate[] chain) {
284 if (!chain[0].getPublicKey().getAlgorithm().equals(keyAlgorithm)) {
285 return false;
286 }
287 if (sigKeyAlgorithm == null) {
288 return true;
289 }
290 if (chain.length > 1) {
291 // if possible, check the public key in the issuer cert
292 return sigKeyAlgorithm.equals(
293 chain[1].getPublicKey().getAlgorithm());
294 } else {
295 // Check the signature algorithm of the certificate itself.
296 // Look for the "withRSA" in "SHA1withRSA", etc.
297 X509Certificate issuer = (X509Certificate)chain[0];
298 String sigAlgName = issuer.getSigAlgName().toUpperCase(ENGLISH);
299 String pattern = "WITH" + sigKeyAlgorithm.toUpperCase(ENGLISH);
300 return sigAlgName.contains(pattern);
301 }
302 }
303 }
304
305 private static List<KeyType> getKeyTypes(String ... keyTypes) {
306 if ((keyTypes == null) ||
307 (keyTypes.length == 0) || (keyTypes[0] == null)) {
308 return null;
309 }
310 List<KeyType> list = new ArrayList<>(keyTypes.length);
311 for (String keyType : keyTypes) {
312 list.add(new KeyType(keyType));
313 }
314 return list;
315 }
316
317 /*
318 * Return the best alias that fits the given parameters.
319 * The algorithm we use is:
320 * . scan through all the aliases in all builders in order
321 * . as soon as we find a perfect match, return
322 * (i.e. a match with a cert that has appropriate key usage
323 * and is not expired).
324 * . if we do not find a perfect match, keep looping and remember
325 * the imperfect matches
326 * . at the end, sort the imperfect matches. we prefer expired certs
327 * with appropriate key usage to certs with the wrong key usage.
328 * return the first one of them.
329 */
330 private String chooseAlias(List<KeyType> keyTypeList, Principal[] issuers,
331 CheckType checkType, AlgorithmConstraints constraints) {
332 if (keyTypeList == null || keyTypeList.size() == 0) {
333 return null;
334 }
335
336 Set<Principal> issuerSet = getIssuerSet(issuers);
337 List<EntryStatus> allResults = null;
338 for (int i = 0, n = builders.size(); i < n; i++) {
339 try {
340 List<EntryStatus> results = getAliases(i, keyTypeList,
341 issuerSet, false, checkType, constraints);
342 if (results != null) {
343 // the results will either be a single perfect match
344 // or 1 or more imperfect matches
345 // if it's a perfect match, return immediately
346 EntryStatus status = results.get(0);
347 if (status.checkResult == CheckResult.OK) {
348 if (useDebug) {
349 debug.println("KeyMgr: choosing key: " + status);
350 }
351 return makeAlias(status);
352 }
353 if (allResults == null) {
354 allResults = new ArrayList<EntryStatus>();
355 }
356 allResults.addAll(results);
357 }
358 } catch (Exception e) {
359 // ignore
360 }
361 }
362 if (allResults == null) {
363 if (useDebug) {
364 debug.println("KeyMgr: no matching key found");
365 }
366 return null;
367 }
368 Collections.sort(allResults);
369 if (useDebug) {
370 debug.println("KeyMgr: no good matching key found, "
371 + "returning best match out of:");
372 debug.println(allResults.toString());
373 }
374 return makeAlias(allResults.get(0));
375 }
376
377 /*
378 * Return all aliases that (approximately) fit the parameters.
379 * These are perfect matches plus imperfect matches (expired certificates
380 * and certificates with the wrong extensions).
381 * The perfect matches will be first in the array.
382 */
383 public String[] getAliases(String keyType, Principal[] issuers,
384 CheckType checkType, AlgorithmConstraints constraints) {
385 if (keyType == null) {
386 return null;
387 }
388
389 Set<Principal> issuerSet = getIssuerSet(issuers);
390 List<KeyType> keyTypeList = getKeyTypes(keyType);
391 List<EntryStatus> allResults = null;
392 for (int i = 0, n = builders.size(); i < n; i++) {
393 try {
394 List<EntryStatus> results = getAliases(i, keyTypeList,
395 issuerSet, true, checkType, constraints);
396 if (results != null) {
397 if (allResults == null) {
398 allResults = new ArrayList<EntryStatus>();
399 }
400 allResults.addAll(results);
401 }
402 } catch (Exception e) {
403 // ignore
404 }
405 }
406 if (allResults == null || allResults.size() == 0) {
407 if (useDebug) {
408 debug.println("KeyMgr: no matching alias found");
409 }
410 return null;
411 }
412 Collections.sort(allResults);
413 if (useDebug) {
414 debug.println("KeyMgr: getting aliases: " + allResults);
415 }
416 return toAliases(allResults);
417 }
418
419 // turn candidate entries into unique aliases we can return to JSSE
420 private String[] toAliases(List<EntryStatus> results) {
421 String[] s = new String[results.size()];
422 int i = 0;
423 for (EntryStatus result : results) {
424 s[i++] = makeAlias(result);
425 }
426 return s;
427 }
428
429 // make a Set out of the array
430 private Set<Principal> getIssuerSet(Principal[] issuers) {
431 if ((issuers != null) && (issuers.length != 0)) {
432 return new HashSet<>(Arrays.asList(issuers));
433 } else {
434 return null;
435 }
436 }
437
438 // a candidate match
439 // identifies the entry by builder and alias
440 // and includes the result of the certificate check
441 private static class EntryStatus implements Comparable<EntryStatus> {
442
443 final int builderIndex;
444 final int keyIndex;
445 final String alias;
446 final CheckResult checkResult;
447
448 EntryStatus(int builderIndex, int keyIndex, String alias,
449 Certificate[] chain, CheckResult checkResult) {
450 this.builderIndex = builderIndex;
451 this.keyIndex = keyIndex;
452 this.alias = alias;
453 this.checkResult = checkResult;
454 }
455
456 public int compareTo(EntryStatus other) {
457 int result = this.checkResult.compareTo(other.checkResult);
458 return (result == 0) ? (this.keyIndex - other.keyIndex) : result;
459 }
460
461 public String toString() {
462 String s = alias + " (verified: " + checkResult + ")";
463 if (builderIndex == 0) {
464 return s;
465 } else {
466 return "Builder #" + builderIndex + ", alias: " + s;
467 }
468 }
469 }
470
471 // enum for the type of certificate check we want to perform
472 // (client or server)
473 // also includes the check code itself
474 private static enum CheckType {
475
476 // enum constant for "no check" (currently not used)
477 NONE(Collections.<String>emptySet()),
478
479 // enum constant for "tls client" check
480 // valid EKU for TLS client: any, tls_client
481 CLIENT(new HashSet<String>(Arrays.asList(new String[] {
482 "2.5.29.37.0", "1.3.6.1.5.5.7.3.2" }))),
483
484 // enum constant for "tls server" check
485 // valid EKU for TLS server: any, tls_server, ns_sgc, ms_sgc
486 SERVER(new HashSet<String>(Arrays.asList(new String[] {
487 "2.5.29.37.0", "1.3.6.1.5.5.7.3.1", "2.16.840.1.113730.4.1",
488 "1.3.6.1.4.1.311.10.3.3" })));
489
490 // set of valid EKU values for this type
491 final Set<String> validEku;
492
493 CheckType(Set<String> validEku) {
494 this.validEku = validEku;
495 }
496
497 private static boolean getBit(boolean[] keyUsage, int bit) {
498 return (bit < keyUsage.length) && keyUsage[bit];
499 }
500
501 // check if this certificate is appropriate for this type of use
502 // first check extensions, if they match, check expiration
503 // note: we may want to move this code into the sun.security.validator
504 // package
505 CheckResult check(X509Certificate cert, Date date) {
506 if (this == NONE) {
507 return CheckResult.OK;
508 }
509
510 // check extensions
511 try {
512 // check extended key usage
513 List<String> certEku = cert.getExtendedKeyUsage();
514 if ((certEku != null) &&
515 Collections.disjoint(validEku, certEku)) {
516 // if extension present and it does not contain any of
517 // the valid EKU OIDs, return extension_mismatch
518 return CheckResult.EXTENSION_MISMATCH;
519 }
520
521 // check key usage
522 boolean[] ku = cert.getKeyUsage();
523 if (ku != null) {
524 String algorithm = cert.getPublicKey().getAlgorithm();
525 boolean kuSignature = getBit(ku, 0);
526 if (algorithm.equals("RSA")) {
527 // require either signature bit
528 // or if server also allow key encipherment bit
529 if (kuSignature == false) {
530 if ((this == CLIENT) || (getBit(ku, 2) == false)) {
531 return CheckResult.EXTENSION_MISMATCH;
532 }
533 }
534 } else if (algorithm.equals("DSA")) {
535 // require signature bit
536 if (kuSignature == false) {
537 return CheckResult.EXTENSION_MISMATCH;
538 }
539 } else if (algorithm.equals("DH")) {
540 // require keyagreement bit
541 if (getBit(ku, 4) == false) {
542 return CheckResult.EXTENSION_MISMATCH;
543 }
544 } else if (algorithm.equals("EC")) {
545 // require signature bit
546 if (kuSignature == false) {
547 return CheckResult.EXTENSION_MISMATCH;
548 }
549 // For servers, also require key agreement.
550 // This is not totally accurate as the keyAgreement bit
551 // is only necessary for static ECDH key exchange and
552 // not ephemeral ECDH. We leave it in for now until
553 // there are signs that this check causes problems
554 // for real world EC certificates.
555 if ((this == SERVER) && (getBit(ku, 4) == false)) {
556 return CheckResult.EXTENSION_MISMATCH;
557 }
558 }
559 }
560 } catch (CertificateException e) {
561 // extensions unparseable, return failure
562 return CheckResult.EXTENSION_MISMATCH;
563 }
564
565 try {
566 cert.checkValidity(date);
567 return CheckResult.OK;
568 } catch (CertificateException e) {
569 return CheckResult.EXPIRED;
570 }
571 }
572 }
573
574 // enum for the result of the extension check
575 // NOTE: the order of the constants is important as they are used
576 // for sorting, i.e. OK is best, followed by EXPIRED and EXTENSION_MISMATCH
577 private static enum CheckResult {
578 OK, // ok or not checked
579 EXPIRED, // extensions valid but cert expired
580 EXTENSION_MISMATCH, // extensions invalid (expiration not checked)
581 }
582
583 /*
584 * Return a List of all candidate matches in the specified builder
585 * that fit the parameters.
586 * We exclude entries in the KeyStore if they are not:
587 * . private key entries
588 * . the certificates are not X509 certificates
589 * . the algorithm of the key in the EE cert doesn't match one of keyTypes
590 * . none of the certs is issued by a Principal in issuerSet
591 * Using those entries would not be possible or they would almost
592 * certainly be rejected by the peer.
593 *
594 * In addition to those checks, we also check the extensions in the EE
595 * cert and its expiration. Even if there is a mismatch, we include
596 * such certificates because they technically work and might be accepted
597 * by the peer. This leads to more graceful failure and better error
598 * messages if the cert expires from one day to the next.
599 *
600 * The return values are:
601 * . null, if there are no matching entries at all
602 * . if 'findAll' is 'false' and there is a perfect match, a List
603 * with a single element (early return)
604 * . if 'findAll' is 'false' and there is NO perfect match, a List
605 * with all the imperfect matches (expired, wrong extensions)
606 * . if 'findAll' is 'true', a List with all perfect and imperfect
607 * matches
608 */
609 private List<EntryStatus> getAliases(int builderIndex,
610 List<KeyType> keyTypes, Set<Principal> issuerSet,
611 boolean findAll, CheckType checkType,
612 AlgorithmConstraints constraints) throws Exception {
613 Builder builder = builders.get(builderIndex);
614 KeyStore ks = builder.getKeyStore();
615 List<EntryStatus> results = null;
616 Date date = verificationDate;
617 boolean preferred = false;
618 for (Enumeration<String> e = ks.aliases(); e.hasMoreElements(); ) {
619 String alias = e.nextElement();
620 // check if it is a key entry (private key or secret key)
621 if (ks.isKeyEntry(alias) == false) {
622 continue;
623 }
624
625 Certificate[] chain = ks.getCertificateChain(alias);
626 if ((chain == null) || (chain.length == 0)) {
627 // must be secret key entry, ignore
628 continue;
629 }
630
631 boolean incompatible = false;
632 for (Certificate cert : chain) {
633 if (cert instanceof X509Certificate == false) {
634 // not an X509Certificate, ignore this alias
635 incompatible = true;
636 break;
637 }
638 }
639 if (incompatible) {
640 continue;
641 }
642
643 // check keytype
644 int keyIndex = -1;
645 int j = 0;
646 for (KeyType keyType : keyTypes) {
647 if (keyType.matches(chain)) {
648 keyIndex = j;
649 break;
650 }
651 j++;
652 }
653 if (keyIndex == -1) {
654 if (useDebug) {
655 debug.println("Ignoring alias " + alias
656 + ": key algorithm does not match");
657 }
658 continue;
659 }
660 // check issuers
661 if (issuerSet != null) {
662 boolean found = false;
663 for (Certificate cert : chain) {
664 X509Certificate xcert = (X509Certificate)cert;
665 if (issuerSet.contains(xcert.getIssuerX500Principal())) {
666 found = true;
667 break;
668 }
669 }
670 if (found == false) {
671 if (useDebug) {
672 debug.println("Ignoring alias " + alias
673 + ": issuers do not match");
674 }
675 continue;
676 }
677 }
678
679 // check the algorithm constraints
680 if (constraints != null &&
681 !conformsToAlgorithmConstraints(constraints, chain)) {
682
683 if (useDebug) {
684 debug.println("Ignoring alias " + alias +
685 ": certificate list does not conform to " +
686 "algorithm constraints");
687 }
688 continue;
689 }
690
691 if (date == null) {
692 date = new Date();
693 }
694 CheckResult checkResult =
695 checkType.check((X509Certificate)chain[0], date);
696 EntryStatus status =
697 new EntryStatus(builderIndex, keyIndex,
698 alias, chain, checkResult);
699 if (!preferred && checkResult == CheckResult.OK && keyIndex == 0) {
700 preferred = true;
701 }
702 if (preferred && (findAll == false)) {
703 // if we have a good match and do not need all matches,
704 // return immediately
705 return Collections.singletonList(status);
706 } else {
707 if (results == null) {
708 results = new ArrayList<EntryStatus>();
709 }
710 results.add(status);
711 }
712 }
713 return results;
714 }
715
716 private static boolean conformsToAlgorithmConstraints(
717 AlgorithmConstraints constraints, Certificate[] chain) {
718
719 AlgorithmChecker checker = new AlgorithmChecker(constraints);
720 try {
721 checker.init(false);
722 } catch (CertPathValidatorException cpve) {
723 // unlikely to happen
724 return false;
725 }
726
727 // It is a forward checker, so we need to check from trust to target.
728 for (int i = chain.length - 1; i >= 0; i--) {
729 Certificate cert = chain[i];
730 try {
731 // We don't care about the unresolved critical extensions.
732 checker.check(cert, Collections.<String>emptySet());
733 } catch (CertPathValidatorException cpve) {
734 return false;
735 }
736 }
737
738 return true;
739 }
740
741}