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