Remove old autovect-branch by moving to "dead" directory.
[official-gcc.git] / old-autovect-branch / libjava / classpath / gnu / java / security / provider / PKIXCertPathValidatorImpl.java
blobab8943443ec3269399e901eb41b112955308c353
1 /* PKIXCertPathValidatorImpl.java -- PKIX certificate path validator.
2 Copyright (C) 2004, 2005 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 package gnu.java.security.provider;
41 import gnu.java.security.OID;
42 import gnu.java.security.x509.GnuPKIExtension;
43 import gnu.java.security.x509.PolicyNodeImpl;
44 import gnu.java.security.x509.X509CRLSelectorImpl;
45 import gnu.java.security.x509.X509CertSelectorImpl;
46 import gnu.java.security.x509.ext.BasicConstraints;
47 import gnu.java.security.x509.ext.CertificatePolicies;
48 import gnu.java.security.x509.ext.Extension;
49 import gnu.java.security.x509.ext.KeyUsage;
50 import gnu.java.security.x509.ext.PolicyConstraint;
52 import java.io.IOException;
53 import java.security.InvalidAlgorithmParameterException;
54 import java.security.InvalidKeyException;
55 import java.security.PublicKey;
56 import java.security.cert.CRL;
57 import java.security.cert.CertPath;
58 import java.security.cert.CertPathParameters;
59 import java.security.cert.CertPathValidatorException;
60 import java.security.cert.CertPathValidatorResult;
61 import java.security.cert.CertPathValidatorSpi;
62 import java.security.cert.CertStore;
63 import java.security.cert.CertStoreException;
64 import java.security.cert.CertificateException;
65 import java.security.cert.PKIXCertPathChecker;
66 import java.security.cert.PKIXCertPathValidatorResult;
67 import java.security.cert.PKIXParameters;
68 import java.security.cert.TrustAnchor;
69 import java.security.cert.X509CRL;
70 import java.security.cert.X509Certificate;
71 import java.security.interfaces.DSAParams;
72 import java.security.interfaces.DSAPublicKey;
73 import java.util.Arrays;
74 import java.util.Collection;
75 import java.util.Collections;
76 import java.util.Date;
77 import java.util.HashSet;
78 import java.util.Iterator;
79 import java.util.LinkedList;
80 import java.util.List;
81 import java.util.Set;
83 /**
84 * An implementation of the Public Key Infrastructure's X.509
85 * certificate path validation algorithm.
87 * <p>See <a href="http://www.ietf.org/rfc/rfc3280.txt">RFC 3280:
88 * Internet X.509 Public Key Infrastructure Certificate and
89 * Certificate Revocation List (CRL) Profile</a>.
91 * @author Casey Marshall (rsdio@metastatic.org)
93 public class PKIXCertPathValidatorImpl extends CertPathValidatorSpi
96 // Constants.
97 // -------------------------------------------------------------------------
99 private static final boolean DEBUG = false;
100 private static void debug (String msg)
102 System.err.print (">> PKIXCertPathValidatorImpl: ");
103 System.err.println (msg);
106 public static final String ANY_POLICY = "2.5.29.32.0";
108 // Constructor.
109 // -------------------------------------------------------------------------
111 public PKIXCertPathValidatorImpl()
113 super();
116 // Instance methods.
117 // -------------------------------------------------------------------------
119 public CertPathValidatorResult engineValidate(CertPath path,
120 CertPathParameters params)
121 throws CertPathValidatorException, InvalidAlgorithmParameterException
123 if (!(params instanceof PKIXParameters))
124 throw new InvalidAlgorithmParameterException("not a PKIXParameters object");
126 // First check if the certificate path is valid.
128 // This means that:
130 // (a) for all x in {1, ..., n-1}, the subject of certificate x is
131 // the issuer of certificate x+1;
133 // (b) for all x in {1, ..., n}, the certificate was valid at the
134 // time in question.
136 // Because this is the X.509 algorithm, we also check if all
137 // cerificates are of type X509Certificate.
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;
155 p = (X509Certificate[]) l.toArray(new X509Certificate[l.size()]);
157 catch (ClassCastException cce)
159 throw new CertPathValidatorException("invalid certificate path");
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--)
172 p[i].checkValidity(now);
174 catch (CertificateException ce)
176 throw new CertPathValidatorException(ce.toString());
178 Set uce = getCritExts(p[i]);
179 for (Iterator check = checks.iterator(); check.hasNext(); )
183 ((PKIXCertPathChecker) check.next()).check(p[i], uce);
185 catch (Exception x)
190 PolicyConstraint constr = null;
191 if (p[i] instanceof GnuPKIExtension)
193 Extension pcx =
194 ((GnuPKIExtension) p[i]).getExtension (PolicyConstraint.ID);
195 if (pcx != null)
196 constr = (PolicyConstraint) pcx.getValue();
198 else
200 byte[] pcx = p[i].getExtensionValue (PolicyConstraint.ID.toString());
201 if (pcx != null)
205 constr = new PolicyConstraint (pcx);
207 catch (Exception x)
212 if (constr != null && constr.getRequireExplicitPolicy() >= 0)
214 policyConstraints.add (new int[]
215 { p.length-i, constr.getRequireExplicitPolicy() });
218 updatePolicyTree(p[i], rootNode, p.length-i, (PKIXParameters) params,
219 checkExplicitPolicy (p.length-i, policyConstraints));
221 // The rest of the tests involve this cert's relationship with the
222 // next in the path. If this cert is the end entity, we can stop.
223 if (i == 0)
224 break;
226 basicSanity(p, i);
227 PublicKey pubKey = null;
230 pubKey = p[i].getPublicKey();
231 if (pubKey instanceof DSAPublicKey)
233 DSAParams dsa = ((DSAPublicKey) pubKey).getParams();
234 // If the DSA public key is missing its parameters, use those
235 // from the previous cert's key.
236 if (dsa == null || dsa.getP() == null || dsa.getG() == null
237 || dsa.getQ() == null)
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());
248 if (sigProvider == null)
249 p[i-1].verify(pubKey);
250 else
251 p[i-1].verify(pubKey, sigProvider);
252 prevKey = pubKey;
254 catch (Exception e)
256 throw new CertPathValidatorException(e.toString());
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");
266 // Check the certificate against the revocation lists.
267 if (((PKIXParameters) params).isRevocationEnabled())
269 X509CRLSelectorImpl selector = new X509CRLSelectorImpl();
272 selector.addIssuerName(p[i].getSubjectDN());
274 catch (IOException ioe)
276 throw new CertPathValidatorException("error selecting CRLs");
278 List certStores = ((PKIXParameters) params).getCertStores();
279 List crls = new LinkedList();
280 for (Iterator it = certStores.iterator(); it.hasNext(); )
282 CertStore cs = (CertStore) it.next();
285 Collection c = cs.getCRLs(selector);
286 crls.addAll(c);
288 catch (CertStoreException cse)
292 if (crls.isEmpty())
293 throw new CertPathValidatorException("no CRLs for issuer");
294 boolean certOk = false;
295 for (Iterator it = crls.iterator(); it.hasNext(); )
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;
308 if (!certOk)
309 throw new CertPathValidatorException("certificate's validity could not be determined");
312 rootNode.setReadOnly();
314 // Now ensure that the first certificate in the chain was issued
315 // by a trust anchor.
316 Exception cause = null;
317 Set anchors = ((PKIXParameters) params).getTrustAnchors();
318 for (Iterator i = anchors.iterator(); i.hasNext(); )
320 TrustAnchor anchor = (TrustAnchor) i.next();
321 X509Certificate anchorCert = null;
322 PublicKey anchorKey = null;
323 if (anchor.getTrustedCert() != null)
325 anchorCert = anchor.getTrustedCert();
326 anchorKey = anchorCert.getPublicKey();
328 else
329 anchorKey = anchor.getCAPublicKey();
330 if (anchorKey == null)
331 continue;
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;
341 if (((PKIXParameters) params).isRevocationEnabled())
343 X509CRLSelectorImpl selector = new X509CRLSelectorImpl();
344 if (anchorCert != null)
347 selector.addIssuerName(anchorCert.getSubjectDN());
349 catch (IOException ioe)
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(); )
358 CertStore cs = (CertStore) it.next();
361 Collection c = cs.getCRLs(selector);
362 crls.addAll(c);
364 catch (CertStoreException cse)
368 if (crls.isEmpty())
369 continue;
370 for (Iterator it = crls.iterator(); it.hasNext(); )
372 CRL crl = (CRL) it.next();
373 if (!(crl instanceof X509CRL))
374 continue;
375 X509CRL xcrl = (X509CRL) crl;
378 xcrl.verify(anchorKey);
380 catch (Exception x)
382 continue;
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");
392 // The chain is valid; return the result.
393 return new PKIXCertPathValidatorResult(anchor, rootNode,
394 p[0].getPublicKey());
396 catch (Exception ignored)
398 cause = ignored;
399 continue;
403 // The path is not valid.
404 CertPathValidatorException cpve =
405 new CertPathValidatorException("path validation failed");
406 if (cause != null)
407 cpve.initCause (cause);
408 throw cpve;
411 // Own methods.
412 // -------------------------------------------------------------------------
415 * Check if a given CRL is acceptable for checking the revocation status
416 * of certificates in the path being checked.
418 * <p>The CRL is accepted iff:</p>
420 * <ol>
421 * <li>The <i>nextUpdate</i> field (if present) is in the future.</li>
422 * <li>The CRL does not contain any unsupported critical extensions.</li>
423 * <li>The CRL is signed by one of the certificates in the path, or,</li>
424 * <li>The CRL is signed by the given public key and was issued by the
425 * public key's subject, or,</li>
426 * <li>The CRL is signed by a certificate in the given cert stores, and
427 * that cert is signed by one of the certificates in the path.</li>
428 * </ol>
430 * @param crl The CRL being checked.
431 * @param path The path this CRL is being checked against.
432 * @param now The value to use as 'now'.
433 * @param pubKeySubject The subject of the public key.
434 * @param pubKey The public key to check.
435 * @return True if the CRL is acceptable.
437 private static boolean checkCRL(X509CRL crl, X509Certificate[] path, Date now,
438 X509Certificate pubKeyCert, PublicKey pubKey,
439 List certStores)
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++)
448 if (!path[i].getSubjectDN().equals(crl.getIssuerDN()))
449 continue;
450 boolean[] keyUsage = path[i].getKeyUsage();
451 if (keyUsage != null)
453 if (!keyUsage[KeyUsage.CRL_SIGN])
454 continue;
458 crl.verify(path[i].getPublicKey());
459 return true;
461 catch (Exception x)
465 if (crl.getIssuerDN().equals(pubKeyCert.getSubjectDN()))
469 boolean[] keyUsage = pubKeyCert.getKeyUsage();
470 if (keyUsage != null)
472 if (!keyUsage[KeyUsage.CRL_SIGN])
473 throw new Exception();
475 crl.verify(pubKey);
476 return true;
478 catch (Exception x)
484 X509CertSelectorImpl select = new X509CertSelectorImpl();
485 select.addSubjectName(crl.getIssuerDN());
486 List certs = new LinkedList();
487 for (Iterator it = certStores.iterator(); it.hasNext(); )
489 CertStore cs = (CertStore) it.next();
492 certs.addAll(cs.getCertificates(select));
494 catch (CertStoreException cse)
498 for (Iterator it = certs.iterator(); it.hasNext(); )
500 X509Certificate c = (X509Certificate) it.next();
501 for (int i = 0; i < path.length; i++)
503 if (!c.getIssuerDN().equals(path[i].getSubjectDN()))
504 continue;
505 boolean[] keyUsage = c.getKeyUsage();
506 if (keyUsage != null)
508 if (!keyUsage[KeyUsage.CRL_SIGN])
509 continue;
513 c.verify(path[i].getPublicKey());
514 crl.verify(c.getPublicKey());
515 return true;
517 catch (Exception x)
521 if (c.getIssuerDN().equals(pubKeyCert.getSubjectDN()))
523 c.verify(pubKey);
524 crl.verify(c.getPublicKey());
528 catch (Exception x)
531 return false;
534 private static Set getCritExts(X509Certificate cert)
536 HashSet s = new HashSet();
537 if (cert instanceof GnuPKIExtension)
539 Collection exts = ((GnuPKIExtension) cert).getExtensions();
540 for (Iterator it = exts.iterator(); it.hasNext(); )
542 Extension ext = (Extension) it.next();
543 if (ext.isCritical() && !ext.isSupported())
544 s.add(ext.getOid().toString());
547 else
548 s.addAll(cert.getCriticalExtensionOIDs());
549 return s;
553 * Perform a basic sanity check on the CA certificate at <code>index</code>.
555 private static void basicSanity(X509Certificate[] path, int index)
556 throws CertPathValidatorException
558 X509Certificate cert = path[index];
559 int pathLen = 0;
560 for (int i = index - 1; i > 0; i--)
562 if (!path[i].getIssuerDN().equals(path[i].getSubjectDN()))
563 pathLen++;
565 Extension e = null;
566 if (cert instanceof GnuPKIExtension)
568 e = ((GnuPKIExtension) cert).getExtension(BasicConstraints.ID);
570 else
574 e = new Extension(cert.getExtensionValue(BasicConstraints.ID.toString()));
576 catch (Exception x)
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");
588 boolean[] keyUsage = cert.getKeyUsage();
589 if (keyUsage != null)
591 if (!keyUsage[KeyUsage.KEY_CERT_SIGN])
592 throw new CertPathValidatorException("certificate cannot be used to sign certificates");
596 private static void updatePolicyTree(X509Certificate cert, PolicyNodeImpl root,
597 int depth, PKIXParameters params,
598 boolean explicitPolicy)
599 throws CertPathValidatorException
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());
608 current = (Iterator) stack.removeLast();
609 while (current.hasNext())
611 PolicyNodeImpl p = (PolicyNodeImpl) current.next();
612 if (DEBUG) debug("visiting node == " + p);
613 if (p.getDepth() == depth - 1)
615 if (DEBUG) debug("added node");
616 nodes.add(p);
618 else
620 if (DEBUG) debug("skipped node");
621 stack.addLast(current);
622 current = p.getChildren();
626 while (!stack.isEmpty());
628 Extension e = null;
629 CertificatePolicies policies = null;
630 List qualifierInfos = null;
631 if (cert instanceof GnuPKIExtension)
633 e = ((GnuPKIExtension) cert).getExtension(CertificatePolicies.ID);
634 if (e != null)
635 policies = (CertificatePolicies) e.getValue();
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(); )
648 PolicyNodeImpl parent = (PolicyNodeImpl) it.next();
649 if (DEBUG) debug("adding policies to " + parent);
650 for (Iterator it2 = cp.iterator(); it2.hasNext(); )
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()))
662 parent.addChild(child);
663 match = true;
665 else if (parent.getExpectedPolicies().contains(ANY_POLICY))
667 parent.addChild(child);
668 match = true;
670 else if (ANY_POLICY.equals (policy.toString()))
672 parent.addChild (child);
673 match = true;
675 if (match && policies != null)
677 List qualifiers = policies.getPolicyQualifierInfos (policy);
678 if (qualifiers != null)
679 child.addAllPolicyQualifiers (qualifiers);
683 if (!match && (params.isExplicitPolicyRequired() || explicitPolicy))
684 throw new CertPathValidatorException("policy tree building failed");
687 private boolean checkExplicitPolicy (int depth, List explicitPolicies)
689 if (DEBUG) debug ("checkExplicitPolicy depth=" + depth);
690 for (Iterator it = explicitPolicies.iterator(); it.hasNext(); )
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;
699 return false;