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