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