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