CertPathValidatorUtilities.java revision c4fa740cf84a54fceb87964ca8ea666fd41b5b8f
1package org.bouncycastle.jce.provider;
2
3import java.io.ByteArrayOutputStream;
4import java.io.IOException;
5import java.math.BigInteger;
6import java.security.GeneralSecurityException;
7import java.security.KeyFactory;
8import java.security.PublicKey;
9import java.security.cert.CertPath;
10import java.security.cert.CertPathValidatorException;
11import java.security.cert.CertStore;
12import java.security.cert.CertStoreException;
13import java.security.cert.Certificate;
14import java.security.cert.CertificateParsingException;
15import java.security.cert.PKIXParameters;
16import java.security.cert.PolicyQualifierInfo;
17import java.security.cert.TrustAnchor;
18import java.security.cert.X509CRL;
19import java.security.cert.X509CRLSelector;
20import java.security.cert.X509CertSelector;
21import java.security.cert.X509Certificate;
22import java.security.interfaces.DSAParams;
23import java.security.interfaces.DSAPublicKey;
24import java.security.spec.DSAPublicKeySpec;
25import java.text.ParseException;
26import java.util.ArrayList;
27import java.util.Arrays;
28import java.util.Collection;
29import java.util.Date;
30import java.util.Enumeration;
31import java.util.HashSet;
32import java.util.Iterator;
33import java.util.List;
34import java.util.Map;
35import java.util.Set;
36
37import javax.security.auth.x500.X500Principal;
38
39import org.bouncycastle.asn1.ASN1InputStream;
40import org.bouncycastle.asn1.ASN1Object;
41import org.bouncycastle.asn1.ASN1OctetString;
42import org.bouncycastle.asn1.ASN1OutputStream;
43import org.bouncycastle.asn1.ASN1Sequence;
44import org.bouncycastle.asn1.DEREnumerated;
45import org.bouncycastle.asn1.DERGeneralizedTime;
46import org.bouncycastle.asn1.DERIA5String;
47import org.bouncycastle.asn1.DERObject;
48import org.bouncycastle.asn1.DERObjectIdentifier;
49import org.bouncycastle.asn1.DERSequence;
50import org.bouncycastle.asn1.isismtt.ISISMTTObjectIdentifiers;
51import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
52import org.bouncycastle.asn1.x509.CRLDistPoint;
53import org.bouncycastle.asn1.x509.CRLNumber;
54import org.bouncycastle.asn1.x509.CRLReason;
55import org.bouncycastle.asn1.x509.CertificateList;
56import org.bouncycastle.asn1.x509.DistributionPoint;
57import org.bouncycastle.asn1.x509.DistributionPointName;
58import org.bouncycastle.asn1.x509.GeneralName;
59import org.bouncycastle.asn1.x509.GeneralNames;
60import org.bouncycastle.asn1.x509.PolicyInformation;
61import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
62import org.bouncycastle.asn1.x509.X509Extensions;
63// BEGIN android-removed
64// import org.bouncycastle.jce.X509LDAPCertStoreParameters;
65// END android-removed
66import org.bouncycastle.jce.exception.ExtCertPathValidatorException;
67import org.bouncycastle.util.Selector;
68import org.bouncycastle.util.StoreException;
69import org.bouncycastle.x509.ExtendedPKIXBuilderParameters;
70import org.bouncycastle.x509.ExtendedPKIXParameters;
71// BEGIN android-removed
72// import org.bouncycastle.x509.X509AttributeCertStoreSelector;
73// END android-removed
74import org.bouncycastle.x509.X509AttributeCertificate;
75import org.bouncycastle.x509.X509CRLStoreSelector;
76import org.bouncycastle.x509.X509CertStoreSelector;
77import org.bouncycastle.x509.X509Store;
78
79public class CertPathValidatorUtilities
80{
81    protected static final PKIXCRLUtil CRL_UTIL = new PKIXCRLUtil();
82
83    protected static final String CERTIFICATE_POLICIES = X509Extensions.CertificatePolicies.getId();
84    protected static final String BASIC_CONSTRAINTS = X509Extensions.BasicConstraints.getId();
85    protected static final String POLICY_MAPPINGS = X509Extensions.PolicyMappings.getId();
86    protected static final String SUBJECT_ALTERNATIVE_NAME = X509Extensions.SubjectAlternativeName.getId();
87    protected static final String NAME_CONSTRAINTS = X509Extensions.NameConstraints.getId();
88    protected static final String KEY_USAGE = X509Extensions.KeyUsage.getId();
89    protected static final String INHIBIT_ANY_POLICY = X509Extensions.InhibitAnyPolicy.getId();
90    protected static final String ISSUING_DISTRIBUTION_POINT = X509Extensions.IssuingDistributionPoint.getId();
91    protected static final String DELTA_CRL_INDICATOR = X509Extensions.DeltaCRLIndicator.getId();
92    protected static final String POLICY_CONSTRAINTS = X509Extensions.PolicyConstraints.getId();
93    protected static final String FRESHEST_CRL = X509Extensions.FreshestCRL.getId();
94    protected static final String CRL_DISTRIBUTION_POINTS = X509Extensions.CRLDistributionPoints.getId();
95    protected static final String AUTHORITY_KEY_IDENTIFIER = X509Extensions.AuthorityKeyIdentifier.getId();
96
97    protected static final String ANY_POLICY = "2.5.29.32.0";
98
99    protected static final String CRL_NUMBER = X509Extensions.CRLNumber.getId();
100
101    /*
102     * key usage bits
103     */
104    protected static final int    KEY_CERT_SIGN = 5;
105    protected static final int    CRL_SIGN = 6;
106
107    protected static final String[] crlReasons = new String[] {
108        "unspecified",
109        "keyCompromise",
110        "cACompromise",
111        "affiliationChanged",
112        "superseded",
113        "cessationOfOperation",
114        "certificateHold",
115        "unknown",
116        "removeFromCRL",
117        "privilegeWithdrawn",
118        "aACompromise" };
119
120    /**
121     * Search the given Set of TrustAnchor's for one that is the
122     * issuer of the given X509 certificate. Uses the default provider
123     * for signature verification.
124     *
125     * @param cert the X509 certificate
126     * @param trustAnchors a Set of TrustAnchor's
127     *
128     * @return the <code>TrustAnchor</code> object if found or
129     * <code>null</code> if not.
130     *
131     * @exception AnnotatedException
132     *                if a TrustAnchor was found but the signature verification
133     *                on the given certificate has thrown an exception.
134     */
135    protected static TrustAnchor findTrustAnchor(
136        X509Certificate cert,
137        Set             trustAnchors)
138            throws AnnotatedException
139    {
140        return findTrustAnchor(cert, trustAnchors, null);
141    }
142
143    /**
144     * Search the given Set of TrustAnchor's for one that is the
145     * issuer of the given X509 certificate. Uses the specified
146     * provider for signature verification, or the default provider
147     * if null.
148     *
149     * @param cert the X509 certificate
150     * @param trustAnchors a Set of TrustAnchor's
151     * @param sigProvider the provider to use for signature verification
152     *
153     * @return the <code>TrustAnchor</code> object if found or
154     * <code>null</code> if not.
155     *
156     * @exception AnnotatedException
157     *                if a TrustAnchor was found but the signature verification
158     *                on the given certificate has thrown an exception.
159     */
160    protected static TrustAnchor findTrustAnchor(
161        X509Certificate cert,
162        Set             trustAnchors,
163        String          sigProvider)
164            throws AnnotatedException
165    {
166        TrustAnchor trust = null;
167        PublicKey trustPublicKey = null;
168        Exception invalidKeyEx = null;
169
170        X509CertSelector certSelectX509 = new X509CertSelector();
171        X500Principal certIssuer = getEncodedIssuerPrincipal(cert);
172
173        try
174        {
175            certSelectX509.setSubject(certIssuer.getEncoded());
176        }
177        catch (IOException ex)
178        {
179            throw new AnnotatedException("Cannot set subject search criteria for trust anchor.", ex);
180        }
181
182        Iterator iter = trustAnchors.iterator();
183        while (iter.hasNext() && trust == null)
184        {
185            trust = (TrustAnchor) iter.next();
186            if (trust.getTrustedCert() != null)
187            {
188                if (certSelectX509.match(trust.getTrustedCert()))
189                {
190                    trustPublicKey = trust.getTrustedCert().getPublicKey();
191                }
192                else
193                {
194                    trust = null;
195                }
196            }
197            else if (trust.getCAName() != null
198                    && trust.getCAPublicKey() != null)
199            {
200                try
201                {
202                    X500Principal caName = new X500Principal(trust.getCAName());
203                    if (certIssuer.equals(caName))
204                    {
205                        trustPublicKey = trust.getCAPublicKey();
206                    }
207                    else
208                    {
209                        trust = null;
210                    }
211                }
212                catch (IllegalArgumentException ex)
213                {
214                    trust = null;
215                }
216            }
217            else
218            {
219                trust = null;
220            }
221
222            if (trustPublicKey != null)
223            {
224                try
225                {
226                    verifyX509Certificate(cert, trustPublicKey, sigProvider);
227                }
228                catch (Exception ex)
229                {
230                    invalidKeyEx = ex;
231                    trust = null;
232                }
233            }
234        }
235
236        if (trust == null && invalidKeyEx != null)
237        {
238            throw new AnnotatedException("TrustAnchor found but certificate validation failed.", invalidKeyEx);
239        }
240
241        return trust;
242    }
243
244    protected static void addAdditionalStoresFromAltNames(
245            X509Certificate cert,
246            ExtendedPKIXParameters pkixParams)
247            throws CertificateParsingException
248    {
249        // if in the IssuerAltName extension an URI
250        // is given, add an additinal X.509 store
251        if (cert.getIssuerAlternativeNames() != null)
252        {
253            Iterator it = cert.getIssuerAlternativeNames().iterator();
254            while (it.hasNext())
255            {
256                // look for URI
257                List list = (List) it.next();
258                // BEGIN android-changed
259                if (list.get(0).equals(Integer.valueOf(GeneralName.uniformResourceIdentifier)))
260                // END android-changed
261                {
262                    // found
263                    String temp = (String) list.get(1);
264                    CertPathValidatorUtilities.addAdditionalStoreFromLocation(temp, pkixParams);
265                }
266            }
267        }
268    }
269    /**
270     * Returns the issuer of an attribute certificate or certificate.
271     * @param cert The attribute certificate or certificate.
272     * @return The issuer as <code>X500Principal</code>.
273     */
274    protected static X500Principal getEncodedIssuerPrincipal(
275        Object cert)
276    {
277        if (cert instanceof X509Certificate)
278        {
279            return ((X509Certificate)cert).getIssuerX500Principal();
280        }
281        else
282        {
283            return (X500Principal)((X509AttributeCertificate)cert).getIssuer().getPrincipals()[0];
284        }
285    }
286
287    protected static Date getValidDate(PKIXParameters paramsPKIX)
288    {
289        Date validDate = paramsPKIX.getDate();
290
291        if (validDate == null)
292        {
293            validDate = new Date();
294        }
295
296        return validDate;
297    }
298
299    protected static X500Principal getSubjectPrincipal(X509Certificate cert)
300    {
301        return cert.getSubjectX500Principal();
302    }
303
304    protected static boolean isSelfIssued(X509Certificate cert)
305    {
306        return cert.getSubjectDN().equals(cert.getIssuerDN());
307    }
308
309
310    /**
311     * Extract the value of the given extension, if it exists.
312     *
313     * @param ext
314     *            The extension object.
315     * @param oid
316     *            The object identifier to obtain.
317     * @throws AnnotatedException
318     *             if the extension cannot be read.
319     */
320    protected static DERObject getExtensionValue(
321        java.security.cert.X509Extension    ext,
322        String                              oid)
323        throws AnnotatedException
324    {
325        byte[]  bytes = ext.getExtensionValue(oid);
326        if (bytes == null)
327        {
328            return null;
329        }
330
331        return getObject(oid, bytes);
332    }
333
334    private static DERObject getObject(
335            String oid,
336            byte[] ext)
337            throws AnnotatedException
338    {
339        try
340        {
341            ASN1InputStream aIn = new ASN1InputStream(ext);
342            ASN1OctetString octs = (ASN1OctetString)aIn.readObject();
343
344            aIn = new ASN1InputStream(octs.getOctets());
345            return aIn.readObject();
346        }
347        catch (Exception e)
348        {
349            throw new AnnotatedException("exception processing extension " + oid, e);
350        }
351    }
352
353    protected static X500Principal getIssuerPrincipal(X509CRL crl)
354    {
355        return crl.getIssuerX500Principal();
356    }
357
358    protected static AlgorithmIdentifier getAlgorithmIdentifier(
359        PublicKey key)
360        throws CertPathValidatorException
361    {
362        try
363        {
364            ASN1InputStream      aIn = new ASN1InputStream(key.getEncoded());
365
366            SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(aIn.readObject());
367
368            return info.getAlgorithmId();
369        }
370        catch (Exception e)
371        {
372            throw new ExtCertPathValidatorException("Subject public key cannot be decoded.", e);
373        }
374    }
375
376    // crl checking
377
378
379    //
380    // policy checking
381    //
382
383    protected static final Set getQualifierSet(ASN1Sequence qualifiers)
384        throws CertPathValidatorException
385    {
386        Set             pq   = new HashSet();
387
388        if (qualifiers == null)
389        {
390            return pq;
391        }
392
393        ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
394        ASN1OutputStream        aOut = new ASN1OutputStream(bOut);
395
396        Enumeration e = qualifiers.getObjects();
397
398        while (e.hasMoreElements())
399        {
400            try
401            {
402                aOut.writeObject(e.nextElement());
403
404                pq.add(new PolicyQualifierInfo(bOut.toByteArray()));
405            }
406            catch (IOException ex)
407            {
408                throw new ExtCertPathValidatorException("Policy qualifier info cannot be decoded.", ex);
409            }
410
411            bOut.reset();
412        }
413
414        return pq;
415    }
416
417    protected static PKIXPolicyNode removePolicyNode(
418        PKIXPolicyNode  validPolicyTree,
419        List     []        policyNodes,
420        PKIXPolicyNode _node)
421    {
422        PKIXPolicyNode _parent = (PKIXPolicyNode)_node.getParent();
423
424        if (validPolicyTree == null)
425        {
426            return null;
427        }
428
429        if (_parent == null)
430        {
431            for (int j = 0; j < policyNodes.length; j++)
432            {
433                policyNodes[j] = new ArrayList();
434            }
435
436            return null;
437        }
438        else
439        {
440            _parent.removeChild(_node);
441            removePolicyNodeRecurse(policyNodes, _node);
442
443            return validPolicyTree;
444        }
445    }
446
447    private static void removePolicyNodeRecurse(
448        List     []        policyNodes,
449        PKIXPolicyNode  _node)
450    {
451        policyNodes[_node.getDepth()].remove(_node);
452
453        if (_node.hasChildren())
454        {
455            Iterator _iter = _node.getChildren();
456            while (_iter.hasNext())
457            {
458                PKIXPolicyNode _child = (PKIXPolicyNode)_iter.next();
459                removePolicyNodeRecurse(policyNodes, _child);
460            }
461        }
462    }
463
464
465    protected static boolean processCertD1i(
466        int                 index,
467        List     []            policyNodes,
468        DERObjectIdentifier pOid,
469        Set                 pq)
470    {
471        List       policyNodeVec = policyNodes[index - 1];
472
473        for (int j = 0; j < policyNodeVec.size(); j++)
474        {
475            PKIXPolicyNode node = (PKIXPolicyNode)policyNodeVec.get(j);
476            Set            expectedPolicies = node.getExpectedPolicies();
477
478            if (expectedPolicies.contains(pOid.getId()))
479            {
480                Set childExpectedPolicies = new HashSet();
481                childExpectedPolicies.add(pOid.getId());
482
483                PKIXPolicyNode child = new PKIXPolicyNode(new ArrayList(),
484                                                           index,
485                                                           childExpectedPolicies,
486                                                           node,
487                                                           pq,
488                                                           pOid.getId(),
489                                                           false);
490                node.addChild(child);
491                policyNodes[index].add(child);
492
493                return true;
494            }
495        }
496
497        return false;
498    }
499
500    protected static void processCertD1ii(
501        int                 index,
502        List     []            policyNodes,
503        DERObjectIdentifier _poid,
504        Set _pq)
505    {
506        List       policyNodeVec = policyNodes[index - 1];
507
508        for (int j = 0; j < policyNodeVec.size(); j++)
509        {
510            PKIXPolicyNode _node = (PKIXPolicyNode)policyNodeVec.get(j);
511
512            if (ANY_POLICY.equals(_node.getValidPolicy()))
513            {
514                Set _childExpectedPolicies = new HashSet();
515                _childExpectedPolicies.add(_poid.getId());
516
517                PKIXPolicyNode _child = new PKIXPolicyNode(new ArrayList(),
518                                                           index,
519                                                           _childExpectedPolicies,
520                                                           _node,
521                                                           _pq,
522                                                           _poid.getId(),
523                                                           false);
524                _node.addChild(_child);
525                policyNodes[index].add(_child);
526                return;
527            }
528        }
529    }
530
531    protected static void prepareNextCertB1(
532            int i,
533            List[] policyNodes,
534            String id_p,
535            Map m_idp,
536            X509Certificate cert
537            ) throws AnnotatedException,CertPathValidatorException
538    {
539        boolean idp_found = false;
540        Iterator nodes_i = policyNodes[i].iterator();
541        while (nodes_i.hasNext())
542        {
543            PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next();
544            if (node.getValidPolicy().equals(id_p))
545            {
546                idp_found = true;
547                node.expectedPolicies = (Set)m_idp.get(id_p);
548                break;
549            }
550        }
551
552        if (!idp_found)
553        {
554            nodes_i = policyNodes[i].iterator();
555            while (nodes_i.hasNext())
556            {
557                PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next();
558                if (ANY_POLICY.equals(node.getValidPolicy()))
559                {
560                    Set pq = null;
561                    ASN1Sequence policies = null;
562                    try
563                    {
564                        policies = DERSequence.getInstance(getExtensionValue(cert, CERTIFICATE_POLICIES));
565                    }
566                    catch (Exception e)
567                    {
568                        throw
569
570                        new AnnotatedException("Certificate policies cannot be decoded.", e);
571                    }
572                    Enumeration e = policies.getObjects();
573                    while (e.hasMoreElements())
574                    {
575                        PolicyInformation pinfo = null;
576
577                        try
578                        {
579                            pinfo = PolicyInformation.getInstance(e.nextElement());
580                        }
581                        catch (Exception ex)
582                        {
583                            throw new AnnotatedException("Policy information cannot be decoded.", ex);
584                        }
585                        if (ANY_POLICY.equals(pinfo.getPolicyIdentifier().getId()))
586                        {
587                            try
588                            {
589                            pq = getQualifierSet(pinfo.getPolicyQualifiers());
590                            }
591                            catch (CertPathValidatorException ex)
592                            {
593                                throw new ExtCertPathValidatorException(
594                                        "Policy qualifier info set could not be built.", ex);
595                            }
596                            break;
597                        }
598                    }
599                    boolean ci = false;
600                    if (cert.getCriticalExtensionOIDs() != null)
601                    {
602                        ci = cert.getCriticalExtensionOIDs().contains(CERTIFICATE_POLICIES);
603                    }
604
605                    PKIXPolicyNode p_node = (PKIXPolicyNode)node.getParent();
606                    if (ANY_POLICY.equals(p_node.getValidPolicy()))
607                    {
608                        PKIXPolicyNode c_node = new PKIXPolicyNode(
609                                new ArrayList(), i,
610                                (Set)m_idp.get(id_p),
611                                p_node, pq, id_p, ci);
612                        p_node.addChild(c_node);
613                        policyNodes[i].add(c_node);
614                    }
615                    break;
616                }
617            }
618        }
619    }
620
621    protected static PKIXPolicyNode prepareNextCertB2(
622            int i,
623            List[] policyNodes,
624            String id_p,
625            PKIXPolicyNode validPolicyTree)
626    {
627        Iterator nodes_i = policyNodes[i].iterator();
628        while (nodes_i.hasNext())
629        {
630            PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next();
631            if (node.getValidPolicy().equals(id_p))
632            {
633                PKIXPolicyNode p_node = (PKIXPolicyNode)node.getParent();
634                p_node.removeChild(node);
635                nodes_i.remove();
636                for (int k = (i - 1); k >= 0; k--)
637                {
638                    List nodes = policyNodes[k];
639                    for (int l = 0; l < nodes.size(); l++)
640                    {
641                        PKIXPolicyNode node2 = (PKIXPolicyNode)nodes.get(l);
642                        if (!node2.hasChildren())
643                        {
644                            validPolicyTree = removePolicyNode(validPolicyTree, policyNodes, node2);
645                            if (validPolicyTree == null)
646                            {
647                                break;
648                            }
649                        }
650                    }
651                }
652            }
653        }
654        return validPolicyTree;
655    }
656
657    protected static boolean isAnyPolicy(
658        Set policySet)
659    {
660        return policySet == null || policySet.contains(ANY_POLICY) || policySet.isEmpty();
661    }
662
663    protected static void addAdditionalStoreFromLocation(String location,
664        ExtendedPKIXParameters pkixParams)
665    {
666        if (pkixParams.isAdditionalLocationsEnabled())
667        {
668            try
669            {
670                // BEGIN android-removed
671                // if (location.startsWith("ldap://"))
672                // {
673                //     // ldap://directory.d-trust.net/CN=D-TRUST
674                //     // Qualified CA 2003 1:PN,O=D-Trust GmbH,C=DE
675                //     // skip "ldap://"
676                //     location = location.substring(7);
677                //     // after first / baseDN starts
678                //     String base = null;
679                //     String url = null;
680                //     if (location.indexOf("/") != -1)
681                //     {
682                //         base = location.substring(location.indexOf("/"));
683                //         // URL
684                //         url = "ldap://"
685                //             + location.substring(0, location.indexOf("/"));
686                //     }
687                //     else
688                //     {
689                //         url = "ldap://" + location;
690                //     }
691                //     // use all purpose parameters
692                //     X509LDAPCertStoreParameters params = new X509LDAPCertStoreParameters.Builder(
693                //         url, base).build();
694                //     pkixParams.addAdditionalStore(X509Store.getInstance(
695                //         "CERTIFICATE/LDAP", params, BouncyCastleProvider.PROVIDER_NAME));
696                //     pkixParams.addAdditionalStore(X509Store.getInstance(
697                //         "CRL/LDAP", params, BouncyCastleProvider.PROVIDER_NAME));
698                //     pkixParams.addAdditionalStore(X509Store.getInstance(
699                //         "ATTRIBUTECERTIFICATE/LDAP", params, BouncyCastleProvider.PROVIDER_NAME));
700                //     pkixParams.addAdditionalStore(X509Store.getInstance(
701                //         "CERTIFICATEPAIR/LDAP", params, BouncyCastleProvider.PROVIDER_NAME));
702                // }
703                // END android-removed
704            }
705            catch (Exception e)
706            {
707                // cannot happen
708                throw new RuntimeException("Exception adding X.509 stores.");
709            }
710        }
711    }
712
713    /**
714     * Return a Collection of all certificates or attribute certificates found
715     * in the X509Store's that are matching the certSelect criteriums.
716     *
717     * @param certSelect a {@link Selector} object that will be used to select
718     *            the certificates
719     * @param certStores a List containing only {@link X509Store} objects. These
720     *            are used to search for certificates.
721     *
722     * @return a Collection of all found {@link X509Certificate} or
723     *         {@link org.bouncycastle.x509.X509AttributeCertificate} objects.
724     *         May be empty but never <code>null</code>.
725     */
726    protected static Collection findCertificates(X509CertStoreSelector certSelect,
727        List certStores) throws AnnotatedException
728    {
729        Set certs = new HashSet();
730        Iterator iter = certStores.iterator();
731
732        while (iter.hasNext())
733        {
734            Object obj = iter.next();
735
736            if (obj instanceof X509Store)
737            {
738                X509Store certStore = (X509Store)obj;
739                try
740                {
741                    certs.addAll(certStore.getMatches(certSelect));
742                }
743                catch (StoreException e)
744                {
745                    throw
746
747                    new AnnotatedException(
748                        "Problem while picking certificates from X.509 store.", e);
749                }
750            }
751            else
752            {
753                CertStore certStore = (CertStore)obj;
754
755                try
756                {
757                    certs.addAll(certStore.getCertificates(certSelect));
758                }
759                catch (CertStoreException e)
760                {
761                    throw new AnnotatedException(
762                        "Problem while picking certificates from certificate store.",
763                        e);
764                }
765            }
766        }
767        return certs;
768    }
769
770    // BEGIN android-removed
771    // protected static Collection findCertificates(X509AttributeCertStoreSelector certSelect,
772    //                                              List certStores)
773    // throws AnnotatedException
774    // {
775    //     Set certs = new HashSet();
776    //     Iterator iter = certStores.iterator();
777    //
778    //     while (iter.hasNext())
779    //     {
780    //         Object obj = iter.next();
781    //
782    //         if (obj instanceof X509Store)
783    //         {
784    //             X509Store certStore = (X509Store)obj;
785    //             try
786    //             {
787    //                 certs.addAll(certStore.getMatches(certSelect));
788    //             }
789    //             catch (StoreException e)
790    //             {
791    //                 throw
792    //
793    //                     new AnnotatedException(
794    //                         "Problem while picking certificates from X.509 store.", e);
795    //             }
796    //         }
797    //     }
798    //     return certs;
799    // }
800    // END android-removed
801
802    protected static void addAdditionalStoresFromCRLDistributionPoint(
803        CRLDistPoint crldp, ExtendedPKIXParameters pkixParams)
804        throws AnnotatedException
805    {
806        if (crldp != null)
807        {
808            DistributionPoint dps[] = null;
809            try
810            {
811                dps = crldp.getDistributionPoints();
812            }
813            catch (Exception e)
814            {
815                throw new AnnotatedException(
816                    "Distribution points could not be read.", e);
817            }
818            for (int i = 0; i < dps.length; i++)
819            {
820                DistributionPointName dpn = dps[i].getDistributionPoint();
821                // look for URIs in fullName
822                if (dpn != null)
823                {
824                    if (dpn.getType() == DistributionPointName.FULL_NAME)
825                    {
826                        GeneralName[] genNames = GeneralNames.getInstance(
827                            dpn.getName()).getNames();
828                        // look for an URI
829                        for (int j = 0; j < genNames.length; j++)
830                        {
831                            if (genNames[j].getTagNo() == GeneralName.uniformResourceIdentifier)
832                            {
833                                String location = DERIA5String.getInstance(
834                                    genNames[j].getName()).getString();
835                                CertPathValidatorUtilities
836                                    .addAdditionalStoreFromLocation(location,
837                                        pkixParams);
838                            }
839                        }
840                    }
841                }
842            }
843        }
844    }
845
846    /**
847     * Add the CRL issuers from the cRLIssuer field of the distribution point or
848     * from the certificate if not given to the issuer criterion of the
849     * <code>selector</code>.
850     * <p>
851     * The <code>issuerPrincipals</code> are a collection with a single
852     * <code>X500Principal</code> for <code>X509Certificate</code>s. For
853     * {@link X509AttributeCertificate}s the issuer may contain more than one
854     * <code>X500Principal</code>.
855     *
856     * @param dp The distribution point.
857     * @param issuerPrincipals The issuers of the certificate or attribute
858     *            certificate which contains the distribution point.
859     * @param selector The CRL selector.
860     * @param pkixParams The PKIX parameters containing the cert stores.
861     * @throws AnnotatedException if an exception occurs while processing.
862     * @throws ClassCastException if <code>issuerPrincipals</code> does not
863     * contain only <code>X500Principal</code>s.
864     */
865    protected static void getCRLIssuersFromDistributionPoint(
866        DistributionPoint dp,
867        Collection issuerPrincipals,
868        X509CRLSelector selector,
869        ExtendedPKIXParameters pkixParams)
870        throws AnnotatedException
871    {
872        List issuers = new ArrayList();
873        // indirect CRL
874        if (dp.getCRLIssuer() != null)
875        {
876            GeneralName genNames[] = dp.getCRLIssuer().getNames();
877            // look for a DN
878            for (int j = 0; j < genNames.length; j++)
879            {
880                if (genNames[j].getTagNo() == GeneralName.directoryName)
881                {
882                    try
883                    {
884                        issuers.add(new X500Principal(genNames[j].getName()
885                            .getDERObject().getEncoded()));
886                    }
887                    catch (IOException e)
888                    {
889                        throw new AnnotatedException(
890                            "CRL issuer information from distribution point cannot be decoded.",
891                            e);
892                    }
893                }
894            }
895        }
896        else
897        {
898            /*
899             * certificate issuer is CRL issuer, distributionPoint field MUST be
900             * present.
901             */
902            if (dp.getDistributionPoint() == null)
903            {
904                throw new AnnotatedException(
905                    "CRL issuer is omitted from distribution point but no distributionPoint field present.");
906            }
907            // add and check issuer principals
908            for (Iterator it=issuerPrincipals.iterator(); it.hasNext();)
909            {
910                issuers.add((X500Principal)it.next());
911            }
912        }
913        // TODO: is not found although this should correctly add the rel name. selector of Sun is buggy here or PKI test case is invalid
914        // distributionPoint
915//        if (dp.getDistributionPoint() != null)
916//        {
917//            // look for nameRelativeToCRLIssuer
918//            if (dp.getDistributionPoint().getType() == DistributionPointName.NAME_RELATIVE_TO_CRL_ISSUER)
919//            {
920//                // append fragment to issuer, only one
921//                // issuer can be there, if this is given
922//                if (issuers.size() != 1)
923//                {
924//                    throw new AnnotatedException(
925//                        "nameRelativeToCRLIssuer field is given but more than one CRL issuer is given.");
926//                }
927//                DEREncodable relName = dp.getDistributionPoint().getName();
928//                Iterator it = issuers.iterator();
929//                List issuersTemp = new ArrayList(issuers.size());
930//                while (it.hasNext())
931//                {
932//                    Enumeration e = null;
933//                    try
934//                    {
935//                        e = ASN1Sequence.getInstance(
936//                            new ASN1InputStream(((X500Principal) it.next())
937//                                .getEncoded()).readObject()).getObjects();
938//                    }
939//                    catch (IOException ex)
940//                    {
941//                        throw new AnnotatedException(
942//                            "Cannot decode CRL issuer information.", ex);
943//                    }
944//                    ASN1EncodableVector v = new ASN1EncodableVector();
945//                    while (e.hasMoreElements())
946//                    {
947//                        v.add((DEREncodable) e.nextElement());
948//                    }
949//                    v.add(relName);
950//                    issuersTemp.add(new X500Principal(new DERSequence(v)
951//                        .getDEREncoded()));
952//                }
953//                issuers.clear();
954//                issuers.addAll(issuersTemp);
955//            }
956//        }
957        Iterator it = issuers.iterator();
958        while (it.hasNext())
959        {
960            try
961            {
962                selector.addIssuerName(((X500Principal)it.next()).getEncoded());
963            }
964            catch (IOException ex)
965            {
966                throw new AnnotatedException(
967                    "Cannot decode CRL issuer information.", ex);
968            }
969        }
970    }
971
972    private static BigInteger getSerialNumber(
973            Object cert)
974    {
975        if (cert instanceof X509Certificate)
976        {
977            return ((X509Certificate) cert).getSerialNumber();
978        }
979        else
980        {
981            return ((X509AttributeCertificate) cert).getSerialNumber();
982        }
983    }
984
985    protected static void getCertStatus(
986            Date validDate,
987            X509CRL crl,
988            Object cert,
989            CertStatus certStatus)
990        throws AnnotatedException
991    {
992        // use BC X509CRLObject so that indirect CRLs are supported
993        X509CRLObject bcCRL = null;
994        try
995        {
996            bcCRL = new X509CRLObject(new CertificateList((ASN1Sequence) ASN1Sequence.fromByteArray(crl.getEncoded())));
997        }
998        catch (Exception exception)
999        {
1000            throw new AnnotatedException("Bouncy Castle X509CRLObject could not be created.", exception);
1001        }
1002        // use BC X509CRLEntryObject, so that getCertificateIssuer() is
1003        // supported.
1004        X509CRLEntryObject crl_entry = (X509CRLEntryObject) bcCRL.getRevokedCertificate(getSerialNumber(cert));
1005        if (crl_entry != null
1006                && (getEncodedIssuerPrincipal(cert).equals(crl_entry.getCertificateIssuer()) || getEncodedIssuerPrincipal(cert)
1007                        .equals(getIssuerPrincipal(crl))))
1008        {
1009            DEREnumerated reasonCode = null;
1010            if (crl_entry.hasExtensions())
1011            {
1012                try
1013                {
1014                    reasonCode = DEREnumerated
1015                        .getInstance(CertPathValidatorUtilities
1016                            .getExtensionValue(crl_entry,
1017                                X509Extensions.ReasonCode.getId()));
1018                }
1019                catch (Exception e)
1020                {
1021                    new AnnotatedException(
1022                        "Reason code CRL entry extension could not be decoded.",
1023                        e);
1024                }
1025            }
1026
1027            // for reason keyCompromise, caCompromise, aACompromise or
1028            // unspecified
1029            if (!(validDate.getTime() < crl_entry.getRevocationDate().getTime())
1030                || reasonCode == null
1031                || reasonCode.getValue().intValue() == 0
1032                || reasonCode.getValue().intValue() == 1
1033                || reasonCode.getValue().intValue() == 2
1034                || reasonCode.getValue().intValue() == 8)
1035            {
1036
1037                // (i) or (j) (1)
1038                if (reasonCode != null)
1039                {
1040                    certStatus.setCertStatus(reasonCode.getValue().intValue());
1041                }
1042                // (i) or (j) (2)
1043                else
1044                {
1045                    certStatus.setCertStatus(CRLReason.unspecified);
1046                }
1047                certStatus.setRevocationDate(crl_entry.getRevocationDate());
1048            }
1049        }
1050    }
1051
1052    /**
1053     * Fetches delta CRLs according to RFC 3280 section 5.2.4.
1054     *
1055     * @param currentDate The date for which the delta CRLs must be valid.
1056     * @param paramsPKIX The extended PKIX parameters.
1057     * @param completeCRL The complete CRL the delta CRL is for.
1058     * @return A <code>Set</code> of <code>X509CRL</code>s with delta CRLs.
1059     * @throws AnnotatedException if an exception occurs while picking the delta
1060     *             CRLs.
1061     */
1062    protected static Set getDeltaCRLs(Date currentDate,
1063        ExtendedPKIXParameters paramsPKIX, X509CRL completeCRL)
1064        throws AnnotatedException
1065    {
1066
1067        X509CRLStoreSelector deltaSelect = new X509CRLStoreSelector();
1068
1069        // 5.2.4 (a)
1070        try
1071        {
1072            deltaSelect.addIssuerName(CertPathValidatorUtilities
1073                .getIssuerPrincipal(completeCRL).getEncoded());
1074        }
1075        catch (IOException e)
1076        {
1077            new AnnotatedException("Cannot extract issuer from CRL.", e);
1078        }
1079
1080        BigInteger completeCRLNumber = null;
1081        try
1082        {
1083            DERObject derObject = CertPathValidatorUtilities.getExtensionValue(completeCRL,
1084                    CRL_NUMBER);
1085            if (derObject != null)
1086            {
1087                completeCRLNumber = CRLNumber.getInstance(derObject).getPositiveValue();
1088            }
1089        }
1090        catch (Exception e)
1091        {
1092            throw new AnnotatedException(
1093                "CRL number extension could not be extracted from CRL.", e);
1094        }
1095
1096        // 5.2.4 (b)
1097        byte[] idp = null;
1098        try
1099        {
1100            idp = completeCRL.getExtensionValue(ISSUING_DISTRIBUTION_POINT);
1101        }
1102        catch (Exception e)
1103        {
1104            throw new AnnotatedException(
1105                "Issuing distribution point extension value could not be read.",
1106                e);
1107        }
1108
1109        // 5.2.4 (d)
1110
1111        deltaSelect.setMinCRLNumber(completeCRLNumber == null ? null : completeCRLNumber
1112            .add(BigInteger.valueOf(1)));
1113
1114        deltaSelect.setIssuingDistributionPoint(idp);
1115        deltaSelect.setIssuingDistributionPointEnabled(true);
1116
1117        // 5.2.4 (c)
1118        deltaSelect.setMaxBaseCRLNumber(completeCRLNumber);
1119
1120        // find delta CRLs
1121        Set temp = CRL_UTIL.findCRLs(deltaSelect, paramsPKIX, currentDate);
1122
1123        Set result = new HashSet();
1124
1125        for (Iterator it = temp.iterator(); it.hasNext();)
1126        {
1127            X509CRL crl = (X509CRL)it.next();
1128
1129            if (isDeltaCRL(crl))
1130            {
1131                result.add(crl);
1132            }
1133        }
1134
1135        return result;
1136    }
1137
1138    private static boolean isDeltaCRL(X509CRL crl)
1139    {
1140        Set critical = crl.getCriticalExtensionOIDs();
1141
1142        return critical.contains(RFC3280CertPathUtilities.DELTA_CRL_INDICATOR);
1143    }
1144
1145    /**
1146     * Fetches complete CRLs according to RFC 3280.
1147     *
1148     * @param dp The distribution point for which the complete CRL
1149     * @param cert The <code>X509Certificate</code> or
1150     *            {@link org.bouncycastle.x509.X509AttributeCertificate} for
1151     *            which the CRL should be searched.
1152     * @param currentDate The date for which the delta CRLs must be valid.
1153     * @param paramsPKIX The extended PKIX parameters.
1154     * @return A <code>Set</code> of <code>X509CRL</code>s with complete
1155     *         CRLs.
1156     * @throws AnnotatedException if an exception occurs while picking the CRLs
1157     *             or no CRLs are found.
1158     */
1159    protected static Set getCompleteCRLs(DistributionPoint dp, Object cert,
1160        Date currentDate, ExtendedPKIXParameters paramsPKIX)
1161        throws AnnotatedException
1162    {
1163        X509CRLStoreSelector crlselect = new X509CRLStoreSelector();
1164        try
1165        {
1166            Set issuers = new HashSet();
1167            if (cert instanceof X509AttributeCertificate)
1168            {
1169                issuers.add(((X509AttributeCertificate)cert)
1170                    .getIssuer().getPrincipals()[0]);
1171            }
1172            else
1173            {
1174                issuers.add(getEncodedIssuerPrincipal(cert));
1175            }
1176            CertPathValidatorUtilities.getCRLIssuersFromDistributionPoint(dp, issuers, crlselect, paramsPKIX);
1177        }
1178        catch (AnnotatedException e)
1179        {
1180            new AnnotatedException(
1181                "Could not get issuer information from distribution point.", e);
1182        }
1183        if (cert instanceof X509Certificate)
1184        {
1185            crlselect.setCertificateChecking((X509Certificate)cert);
1186        }
1187        else if (cert instanceof X509AttributeCertificate)
1188        {
1189            crlselect.setAttrCertificateChecking((X509AttributeCertificate)cert);
1190        }
1191
1192
1193
1194        crlselect.setCompleteCRLEnabled(true);
1195
1196        Set crls = CRL_UTIL.findCRLs(crlselect, paramsPKIX, currentDate);
1197
1198        if (crls.isEmpty())
1199        {
1200            if (cert instanceof X509AttributeCertificate)
1201            {
1202                X509AttributeCertificate aCert = (X509AttributeCertificate)cert;
1203
1204                throw new AnnotatedException("No CRLs found for issuer \"" + aCert.getIssuer().getPrincipals()[0] + "\"");
1205            }
1206            else
1207            {
1208                X509Certificate xCert = (X509Certificate)cert;
1209
1210                throw new AnnotatedException("No CRLs found for issuer \"" + xCert.getIssuerX500Principal() + "\"");
1211            }
1212        }
1213        return crls;
1214    }
1215
1216    protected static Date getValidCertDateFromValidityModel(
1217        ExtendedPKIXParameters paramsPKIX, CertPath certPath, int index)
1218        throws AnnotatedException
1219    {
1220        if (paramsPKIX.getValidityModel() == ExtendedPKIXParameters.CHAIN_VALIDITY_MODEL)
1221        {
1222            // if end cert use given signing/encryption/... time
1223            if (index <= 0)
1224            {
1225                return CertPathValidatorUtilities.getValidDate(paramsPKIX);
1226                // else use time when previous cert was created
1227            }
1228            else
1229            {
1230                if (index - 1 == 0)
1231                {
1232                    DERGeneralizedTime dateOfCertgen = null;
1233                    try
1234                    {
1235                        byte[] extBytes = ((X509Certificate)certPath.getCertificates().get(index - 1)).getExtensionValue(ISISMTTObjectIdentifiers.id_isismtt_at_dateOfCertGen.getId());
1236                        if (extBytes != null)
1237                        {
1238                            dateOfCertgen = DERGeneralizedTime.getInstance(ASN1Object.fromByteArray(extBytes));
1239                        }
1240                    }
1241                    catch (IOException e)
1242                    {
1243                        throw new AnnotatedException(
1244                            "Date of cert gen extension could not be read.");
1245                    }
1246                    catch (IllegalArgumentException e)
1247                    {
1248                        throw new AnnotatedException(
1249                            "Date of cert gen extension could not be read.");
1250                    }
1251                    if (dateOfCertgen != null)
1252                    {
1253                        try
1254                        {
1255                            return dateOfCertgen.getDate();
1256                        }
1257                        catch (ParseException e)
1258                        {
1259                            throw new AnnotatedException(
1260                                "Date from date of cert gen extension could not be parsed.",
1261                                e);
1262                        }
1263                    }
1264                    return ((X509Certificate) certPath.getCertificates().get(
1265                        index - 1)).getNotBefore();
1266                }
1267                else
1268                {
1269                    return ((X509Certificate) certPath.getCertificates().get(
1270                        index - 1)).getNotBefore();
1271                }
1272            }
1273        }
1274        else
1275        {
1276            return getValidDate(paramsPKIX);
1277        }
1278    }
1279
1280    /**
1281     * Return the next working key inheriting DSA parameters if necessary.
1282     * <p>
1283     * This methods inherits DSA parameters from the indexed certificate or
1284     * previous certificates in the certificate chain to the returned
1285     * <code>PublicKey</code>. The list is searched upwards, meaning the end
1286     * certificate is at position 0 and previous certificates are following.
1287     * </p>
1288     * <p>
1289     * If the indexed certificate does not contain a DSA key this method simply
1290     * returns the public key. If the DSA key already contains DSA parameters
1291     * the key is also only returned.
1292     * </p>
1293     *
1294     * @param certs The certification path.
1295     * @param index The index of the certificate which contains the public key
1296     *            which should be extended with DSA parameters.
1297     * @return The public key of the certificate in list position
1298     *         <code>index</code> extended with DSA parameters if applicable.
1299     * @throws AnnotatedException if DSA parameters cannot be inherited.
1300     */
1301    protected static PublicKey getNextWorkingKey(List certs, int index)
1302        throws CertPathValidatorException
1303    {
1304        Certificate cert = (Certificate) certs.get(index);
1305        PublicKey pubKey = cert.getPublicKey();
1306        if (!(pubKey instanceof DSAPublicKey))
1307        {
1308            return pubKey;
1309        }
1310        DSAPublicKey dsaPubKey = (DSAPublicKey) pubKey;
1311        if (dsaPubKey.getParams() != null)
1312        {
1313            return dsaPubKey;
1314        }
1315        for (int i = index + 1; i < certs.size(); i++)
1316        {
1317            X509Certificate parentCert = (X509Certificate)certs.get(i);
1318            pubKey = parentCert.getPublicKey();
1319            if (!(pubKey instanceof DSAPublicKey))
1320            {
1321                throw new CertPathValidatorException(
1322                    "DSA parameters cannot be inherited from previous certificate.");
1323            }
1324            DSAPublicKey prevDSAPubKey = (DSAPublicKey) pubKey;
1325            if (prevDSAPubKey.getParams() == null)
1326            {
1327                continue;
1328            }
1329            DSAParams dsaParams = prevDSAPubKey.getParams();
1330            DSAPublicKeySpec dsaPubKeySpec = new DSAPublicKeySpec(
1331                dsaPubKey.getY(), dsaParams.getP(), dsaParams.getQ(), dsaParams.getG());
1332            try
1333            {
1334                KeyFactory keyFactory = KeyFactory.getInstance("DSA", BouncyCastleProvider.PROVIDER_NAME);
1335                return keyFactory.generatePublic(dsaPubKeySpec);
1336            }
1337            catch (Exception exception)
1338            {
1339                throw new RuntimeException(exception.getMessage());
1340            }
1341        }
1342        throw new CertPathValidatorException("DSA parameters cannot be inherited from previous certificate.");
1343    }
1344
1345    /**
1346     * Find the issuer certificates of a given certificate.
1347     *
1348     * @param cert
1349     *            The certificate for which an issuer should be found.
1350     * @param pkixParams
1351     * @return A <code>Collection</code> object containing the issuer
1352     *         <code>X509Certificate</code>s. Never <code>null</code>.
1353     *
1354     * @exception AnnotatedException
1355     *                if an error occurs.
1356     */
1357    protected static Collection findIssuerCerts(
1358        X509Certificate cert,
1359        ExtendedPKIXBuilderParameters pkixParams)
1360            throws AnnotatedException
1361    {
1362        X509CertStoreSelector certSelect = new X509CertStoreSelector();
1363        Set certs = new HashSet();
1364        try
1365        {
1366            certSelect.setSubject(cert.getIssuerX500Principal().getEncoded());
1367        }
1368        catch (IOException ex)
1369        {
1370            throw new AnnotatedException(
1371                    "Subject criteria for certificate selector to find issuer certificate could not be set.", ex);
1372        }
1373
1374        Iterator iter;
1375
1376        try
1377        {
1378            List matches = new ArrayList();
1379
1380            matches.addAll(CertPathValidatorUtilities.findCertificates(certSelect, pkixParams.getCertStores()));
1381            matches.addAll(CertPathValidatorUtilities.findCertificates(certSelect, pkixParams.getStores()));
1382            matches.addAll(CertPathValidatorUtilities.findCertificates(certSelect, pkixParams.getAdditionalStores()));
1383
1384            iter = matches.iterator();
1385        }
1386        catch (AnnotatedException e)
1387        {
1388            throw new AnnotatedException("Issuer certificate cannot be searched.", e);
1389        }
1390
1391        X509Certificate issuer = null;
1392        while (iter.hasNext())
1393        {
1394            issuer = (X509Certificate) iter.next();
1395            // issuer cannot be verified because possible DSA inheritance
1396            // parameters are missing
1397            certs.add(issuer);
1398        }
1399        return certs;
1400    }
1401
1402    protected static void verifyX509Certificate(X509Certificate cert, PublicKey publicKey,
1403        String sigProvider)
1404            throws GeneralSecurityException
1405    {
1406        if (sigProvider == null)
1407        {
1408            cert.verify(publicKey);
1409        }
1410        else
1411        {
1412            cert.verify(publicKey, sigProvider);
1413        }
1414    }
1415}
1416