1:
37:
38:
39: package ;
40:
41: import ;
42: import ;
43: import ;
44: import ;
45: import ;
46: import ;
47: import ;
48: import ;
49: import ;
50: import ;
51: import ;
52: import ;
53: import ;
54:
55: import ;
56: import ;
57: import ;
58: import ;
59: import ;
60: import ;
61: import ;
62: import ;
63: import ;
64: import ;
65: import ;
66: import ;
67: import ;
68: import ;
69: import ;
70: import ;
71: import ;
72: import ;
73: import ;
74: import ;
75: import ;
76: import ;
77: import ;
78: import ;
79: import ;
80: import ;
81: import ;
82: import ;
83: import ;
84: import ;
85: import ;
86:
87:
97: public class PKIXCertPathValidatorImpl
98: extends CertPathValidatorSpi
99: {
100: private static final Logger log = Logger.getLogger(PKIXCertPathValidatorImpl.class.getName());
101:
102: public static final String ANY_POLICY = "2.5.29.32.0";
103:
104: public PKIXCertPathValidatorImpl()
105: {
106: super();
107: }
108:
109: public CertPathValidatorResult engineValidate(CertPath path,
110: CertPathParameters params)
111: throws CertPathValidatorException, InvalidAlgorithmParameterException
112: {
113: if (! (params instanceof PKIXParameters))
114: throw new InvalidAlgorithmParameterException("not a PKIXParameters object");
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127: PolicyNodeImpl rootNode = new PolicyNodeImpl();
128: Set initPolicies = ((PKIXParameters) params).getInitialPolicies();
129: rootNode.setValidPolicy(ANY_POLICY);
130: rootNode.setCritical(false);
131: rootNode.setDepth(0);
132: if (initPolicies != null)
133: rootNode.addAllExpectedPolicies(initPolicies);
134: else
135: rootNode.addExpectedPolicy(ANY_POLICY);
136: List checks = ((PKIXParameters) params).getCertPathCheckers();
137: List l = path.getCertificates();
138: if (l == null || l.size() == 0)
139: throw new CertPathValidatorException();
140: X509Certificate[] p = null;
141: try
142: {
143: p = (X509Certificate[]) l.toArray(new X509Certificate[l.size()]);
144: }
145: catch (ClassCastException cce)
146: {
147: throw new CertPathValidatorException("invalid certificate path");
148: }
149: String sigProvider = ((PKIXParameters) params).getSigProvider();
150: PublicKey prevKey = null;
151: Date now = ((PKIXParameters) params).getDate();
152: if (now == null)
153: now = new Date();
154: LinkedList policyConstraints = new LinkedList();
155: for (int i = p.length - 1; i >= 0; i--)
156: {
157: try
158: {
159: p[i].checkValidity(now);
160: }
161: catch (CertificateException ce)
162: {
163: throw new CertPathValidatorException(ce.toString());
164: }
165: Set uce = getCritExts(p[i]);
166: for (Iterator check = checks.iterator(); check.hasNext();)
167: {
168: try
169: {
170: ((PKIXCertPathChecker) check.next()).check(p[i], uce);
171: }
172: catch (Exception x)
173: {
174: }
175: }
176: PolicyConstraint constr = null;
177: if (p[i] instanceof GnuPKIExtension)
178: {
179: Extension pcx = ((GnuPKIExtension) p[i]).getExtension(PolicyConstraint.ID);
180: if (pcx != null)
181: constr = (PolicyConstraint) pcx.getValue();
182: }
183: else
184: {
185: byte[] pcx = p[i].getExtensionValue(PolicyConstraint.ID.toString());
186: if (pcx != null)
187: {
188: try
189: {
190: constr = new PolicyConstraint(pcx);
191: }
192: catch (Exception x)
193: {
194: }
195: }
196: }
197: if (constr != null && constr.getRequireExplicitPolicy() >= 0)
198: policyConstraints.add(new int[] { p.length - i,
199: constr.getRequireExplicitPolicy() });
200: updatePolicyTree(p[i], rootNode, p.length - i, (PKIXParameters) params,
201: checkExplicitPolicy(p.length - i, policyConstraints));
202:
203:
204: if (i == 0)
205: break;
206:
207: basicSanity(p, i);
208: PublicKey pubKey = null;
209: try
210: {
211: pubKey = p[i].getPublicKey();
212: if (pubKey instanceof DSAPublicKey)
213: {
214: DSAParams dsa = ((DSAPublicKey) pubKey).getParams();
215:
216:
217: if (dsa == null || dsa.getP() == null || dsa.getG() == null
218: || dsa.getQ() == null)
219: {
220: if (prevKey == null)
221: throw new InvalidKeyException("DSA keys not chainable");
222: if (! (prevKey instanceof DSAPublicKey))
223: throw new InvalidKeyException("DSA keys not chainable");
224: dsa = ((DSAPublicKey) prevKey).getParams();
225: pubKey = new DSSPublicKey(Registry.X509_ENCODING_ID,
226: dsa.getP(), dsa.getQ(),
227: dsa.getG(),
228: ((DSAPublicKey) pubKey).getY());
229: }
230: }
231: if (sigProvider == null)
232: p[i - 1].verify(pubKey);
233: else
234: p[i - 1].verify(pubKey, sigProvider);
235: prevKey = pubKey;
236: }
237: catch (Exception e)
238: {
239: throw new CertPathValidatorException(e.toString());
240: }
241: if (! p[i].getSubjectDN().equals(p[i - 1].getIssuerDN()))
242: throw new CertPathValidatorException("issuer DN mismatch");
243: boolean[] issuerUid = p[i - 1].getIssuerUniqueID();
244: boolean[] subjectUid = p[i].getSubjectUniqueID();
245: if (issuerUid != null && subjectUid != null)
246: if (! Arrays.equals(issuerUid, subjectUid))
247: throw new CertPathValidatorException("UID mismatch");
248:
249:
250: if (((PKIXParameters) params).isRevocationEnabled())
251: {
252: X509CRLSelectorImpl selector = new X509CRLSelectorImpl();
253: try
254: {
255: selector.addIssuerName(p[i].getSubjectDN());
256: }
257: catch (IOException ioe)
258: {
259: throw new CertPathValidatorException("error selecting CRLs");
260: }
261: List certStores = ((PKIXParameters) params).getCertStores();
262: List crls = new LinkedList();
263: for (Iterator it = certStores.iterator(); it.hasNext();)
264: {
265: CertStore cs = (CertStore) it.next();
266: try
267: {
268: Collection c = cs.getCRLs(selector);
269: crls.addAll(c);
270: }
271: catch (CertStoreException cse)
272: {
273: }
274: }
275: if (crls.isEmpty())
276: throw new CertPathValidatorException("no CRLs for issuer");
277: boolean certOk = false;
278: for (Iterator it = crls.iterator(); it.hasNext();)
279: {
280: CRL crl = (CRL) it.next();
281: if (! (crl instanceof X509CRL))
282: continue;
283: X509CRL xcrl = (X509CRL) crl;
284: if (! checkCRL(xcrl, p, now, p[i], pubKey, certStores))
285: continue;
286: if (xcrl.isRevoked(p[i - 1]))
287: throw new CertPathValidatorException("certificate is revoked");
288: else
289: certOk = true;
290: }
291: if (! certOk)
292: throw new CertPathValidatorException(
293: "certificate's validity could not be determined");
294: }
295: }
296: rootNode.setReadOnly();
297:
298:
299: Exception cause = null;
300: Set anchors = ((PKIXParameters) params).getTrustAnchors();
301: for (Iterator i = anchors.iterator(); i.hasNext();)
302: {
303: TrustAnchor anchor = (TrustAnchor) i.next();
304: X509Certificate anchorCert = null;
305: PublicKey anchorKey = null;
306: if (anchor.getTrustedCert() != null)
307: {
308: anchorCert = anchor.getTrustedCert();
309: anchorKey = anchorCert.getPublicKey();
310: }
311: else
312: anchorKey = anchor.getCAPublicKey();
313: if (anchorKey == null)
314: continue;
315: try
316: {
317: if (anchorCert != null)
318: anchorCert.checkValidity(now);
319: p[p.length - 1].verify(anchorKey);
320: if (anchorCert != null && anchorCert.getBasicConstraints() >= 0
321: && anchorCert.getBasicConstraints() < p.length)
322: continue;
323:
324: if (((PKIXParameters) params).isRevocationEnabled())
325: {
326: X509CRLSelectorImpl selector = new X509CRLSelectorImpl();
327: if (anchorCert != null)
328: try
329: {
330: selector.addIssuerName(anchorCert.getSubjectDN());
331: }
332: catch (IOException ioe)
333: {
334: }
335: else
336: selector.addIssuerName(anchor.getCAName());
337: List certStores = ((PKIXParameters) params).getCertStores();
338: List crls = new LinkedList();
339: for (Iterator it = certStores.iterator(); it.hasNext();)
340: {
341: CertStore cs = (CertStore) it.next();
342: try
343: {
344: Collection c = cs.getCRLs(selector);
345: crls.addAll(c);
346: }
347: catch (CertStoreException cse)
348: {
349: }
350: }
351: if (crls.isEmpty())
352: continue;
353: for (Iterator it = crls.iterator(); it.hasNext();)
354: {
355: CRL crl = (CRL) it.next();
356: if (! (crl instanceof X509CRL))
357: continue;
358: X509CRL xcrl = (X509CRL) crl;
359: try
360: {
361: xcrl.verify(anchorKey);
362: }
363: catch (Exception x)
364: {
365: continue;
366: }
367: Date nextUpdate = xcrl.getNextUpdate();
368: if (nextUpdate != null && nextUpdate.compareTo(now) < 0)
369: continue;
370: if (xcrl.isRevoked(p[p.length - 1]))
371: throw new CertPathValidatorException("certificate is revoked");
372: }
373: }
374:
375: return new PKIXCertPathValidatorResult(anchor, rootNode,
376: p[0].getPublicKey());
377: }
378: catch (Exception ignored)
379: {
380: cause = ignored;
381: continue;
382: }
383: }
384:
385: CertPathValidatorException cpve =
386: new CertPathValidatorException("path validation failed");
387: if (cause != null)
388: cpve.initCause(cause);
389: throw cpve;
390: }
391:
392:
414: private static boolean checkCRL(X509CRL crl, X509Certificate[] path,
415: Date now, X509Certificate pubKeyCert,
416: PublicKey pubKey, List certStores)
417: {
418: Date nextUpdate = crl.getNextUpdate();
419: if (nextUpdate != null && nextUpdate.compareTo(now) < 0)
420: return false;
421: if (crl.hasUnsupportedCriticalExtension())
422: return false;
423: for (int i = 0; i < path.length; i++)
424: {
425: if (! path[i].getSubjectDN().equals(crl.getIssuerDN()))
426: continue;
427: boolean[] keyUsage = path[i].getKeyUsage();
428: if (keyUsage != null)
429: {
430: if (! keyUsage[KeyUsage.CRL_SIGN])
431: continue;
432: }
433: try
434: {
435: crl.verify(path[i].getPublicKey());
436: return true;
437: }
438: catch (Exception x)
439: {
440: }
441: }
442: if (crl.getIssuerDN().equals(pubKeyCert.getSubjectDN()))
443: {
444: try
445: {
446: boolean[] keyUsage = pubKeyCert.getKeyUsage();
447: if (keyUsage != null)
448: {
449: if (! keyUsage[KeyUsage.CRL_SIGN])
450: throw new Exception();
451: }
452: crl.verify(pubKey);
453: return true;
454: }
455: catch (Exception x)
456: {
457: }
458: }
459: try
460: {
461: X509CertSelectorImpl select = new X509CertSelectorImpl();
462: select.addSubjectName(crl.getIssuerDN());
463: List certs = new LinkedList();
464: for (Iterator it = certStores.iterator(); it.hasNext();)
465: {
466: CertStore cs = (CertStore) it.next();
467: try
468: {
469: certs.addAll(cs.getCertificates(select));
470: }
471: catch (CertStoreException cse)
472: {
473: }
474: }
475: for (Iterator it = certs.iterator(); it.hasNext();)
476: {
477: X509Certificate c = (X509Certificate) it.next();
478: for (int i = 0; i < path.length; i++)
479: {
480: if (! c.getIssuerDN().equals(path[i].getSubjectDN()))
481: continue;
482: boolean[] keyUsage = c.getKeyUsage();
483: if (keyUsage != null)
484: {
485: if (! keyUsage[KeyUsage.CRL_SIGN])
486: continue;
487: }
488: try
489: {
490: c.verify(path[i].getPublicKey());
491: crl.verify(c.getPublicKey());
492: return true;
493: }
494: catch (Exception x)
495: {
496: }
497: }
498: if (c.getIssuerDN().equals(pubKeyCert.getSubjectDN()))
499: {
500: c.verify(pubKey);
501: crl.verify(c.getPublicKey());
502: }
503: }
504: }
505: catch (Exception x)
506: {
507: }
508: return false;
509: }
510:
511: private static Set getCritExts(X509Certificate cert)
512: {
513: HashSet s = new HashSet();
514: if (cert instanceof GnuPKIExtension)
515: {
516: Collection exts = ((GnuPKIExtension) cert).getExtensions();
517: for (Iterator it = exts.iterator(); it.hasNext();)
518: {
519: Extension ext = (Extension) it.next();
520: if (ext.isCritical() && ! ext.isSupported())
521: s.add(ext.getOid().toString());
522: }
523: }
524: else
525: s.addAll(cert.getCriticalExtensionOIDs());
526: return s;
527: }
528:
529:
532: private static void basicSanity(X509Certificate[] path, int index)
533: throws CertPathValidatorException
534: {
535: X509Certificate cert = path[index];
536: int pathLen = 0;
537: for (int i = index - 1; i > 0; i--)
538: {
539: if (! path[i].getIssuerDN().equals(path[i].getSubjectDN()))
540: pathLen++;
541: }
542: Extension e = null;
543: if (cert instanceof GnuPKIExtension)
544: {
545: e = ((GnuPKIExtension) cert).getExtension(BasicConstraints.ID);
546: }
547: else
548: {
549: try
550: {
551: e = new Extension(cert.getExtensionValue(BasicConstraints.ID.toString()));
552: }
553: catch (Exception x)
554: {
555: }
556: }
557: if (e == null)
558: throw new CertPathValidatorException("no basicConstraints");
559: BasicConstraints bc = (BasicConstraints) e.getValue();
560: if (! bc.isCA())
561: throw new CertPathValidatorException(
562: "certificate cannot be used to verify signatures");
563: if (bc.getPathLengthConstraint() >= 0
564: && bc.getPathLengthConstraint() < pathLen)
565: throw new CertPathValidatorException("path is too long");
566:
567: boolean[] keyUsage = cert.getKeyUsage();
568: if (keyUsage != null)
569: {
570: if (! keyUsage[KeyUsage.KEY_CERT_SIGN])
571: throw new CertPathValidatorException(
572: "certificate cannot be used to sign certificates");
573: }
574: }
575:
576: private static void updatePolicyTree(X509Certificate cert,
577: PolicyNodeImpl root, int depth,
578: PKIXParameters params,
579: boolean explicitPolicy)
580: throws CertPathValidatorException
581: {
582: if (Configuration.DEBUG)
583: log.fine("updatePolicyTree depth == " + depth);
584: Set nodes = new HashSet();
585: LinkedList stack = new LinkedList();
586: Iterator current = null;
587: stack.addLast(Collections.singleton(root).iterator());
588: do
589: {
590: current = (Iterator) stack.removeLast();
591: while (current.hasNext())
592: {
593: PolicyNodeImpl p = (PolicyNodeImpl) current.next();
594: if (Configuration.DEBUG)
595: log.fine("visiting node == " + p);
596: if (p.getDepth() == depth - 1)
597: {
598: if (Configuration.DEBUG)
599: log.fine("added node");
600: nodes.add(p);
601: }
602: else
603: {
604: if (Configuration.DEBUG)
605: log.fine("skipped node");
606: stack.addLast(current);
607: current = p.getChildren();
608: }
609: }
610: }
611: while (! stack.isEmpty());
612:
613: Extension e = null;
614: CertificatePolicies policies = null;
615: List qualifierInfos = null;
616: if (cert instanceof GnuPKIExtension)
617: {
618: e = ((GnuPKIExtension) cert).getExtension(CertificatePolicies.ID);
619: if (e != null)
620: policies = (CertificatePolicies) e.getValue();
621: }
622:
623: List cp = null;
624: if (policies != null)
625: cp = policies.getPolicies();
626: else
627: cp = Collections.EMPTY_LIST;
628: boolean match = false;
629: if (Configuration.DEBUG)
630: {
631: log.fine("nodes are == " + nodes);
632: log.fine("cert policies are == " + cp);
633: }
634: for (Iterator it = nodes.iterator(); it.hasNext();)
635: {
636: PolicyNodeImpl parent = (PolicyNodeImpl) it.next();
637: if (Configuration.DEBUG)
638: log.fine("adding policies to " + parent);
639: for (Iterator it2 = cp.iterator(); it2.hasNext();)
640: {
641: OID policy = (OID) it2.next();
642: if (Configuration.DEBUG)
643: log.fine("trying to add policy == " + policy);
644: if (policy.toString().equals(ANY_POLICY)
645: && params.isAnyPolicyInhibited())
646: continue;
647: PolicyNodeImpl child = new PolicyNodeImpl();
648: child.setValidPolicy(policy.toString());
649: child.addExpectedPolicy(policy.toString());
650: if (parent.getExpectedPolicies().contains(policy.toString()))
651: {
652: parent.addChild(child);
653: match = true;
654: }
655: else if (parent.getExpectedPolicies().contains(ANY_POLICY))
656: {
657: parent.addChild(child);
658: match = true;
659: }
660: else if (ANY_POLICY.equals(policy.toString()))
661: {
662: parent.addChild(child);
663: match = true;
664: }
665: if (match && policies != null)
666: {
667: List qualifiers = policies.getPolicyQualifierInfos(policy);
668: if (qualifiers != null)
669: child.addAllPolicyQualifiers(qualifiers);
670: }
671: }
672: }
673: if (! match && (params.isExplicitPolicyRequired() || explicitPolicy))
674: throw new CertPathValidatorException("policy tree building failed");
675: }
676:
677: private boolean checkExplicitPolicy(int depth, List explicitPolicies)
678: {
679: if (Configuration.DEBUG)
680: log.fine("checkExplicitPolicy depth=" + depth);
681: for (Iterator it = explicitPolicies.iterator(); it.hasNext();)
682: {
683: int[] i = (int[]) it.next();
684: int caDepth = i[0];
685: int limit = i[1];
686: if (Configuration.DEBUG)
687: log.fine(" caDepth=" + caDepth + " limit=" + limit);
688: if (depth - caDepth >= limit)
689: return true;
690: }
691: return false;
692: }
693: }