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