1 package org.bouncycastle.x509;
2 
3 import java.io.ByteArrayInputStream;
4 import java.io.ByteArrayOutputStream;
5 import java.io.IOException;
6 import java.math.BigInteger;
7 import java.security.GeneralSecurityException;
8 import java.security.KeyFactory;
9 import java.security.PublicKey;
10 import java.security.cert.CRLException;
11 import java.security.cert.CertPathValidatorException;
12 import java.security.cert.CertStore;
13 import java.security.cert.CertStoreException;
14 import java.security.cert.Certificate;
15 import java.security.cert.CertificateException;
16 import java.security.cert.PKIXParameters;
17 import java.security.cert.PolicyQualifierInfo;
18 import java.security.cert.X509CRL;
19 import java.security.cert.X509CRLEntry;
20 import java.security.cert.X509Certificate;
21 import java.security.interfaces.DSAParams;
22 import java.security.interfaces.DSAPublicKey;
23 import java.security.spec.DSAPublicKeySpec;
24 import java.util.ArrayList;
25 import java.util.Collection;
26 import java.util.Date;
27 import java.util.Enumeration;
28 import java.util.HashSet;
29 import java.util.Iterator;
30 import java.util.List;
31 import java.util.Map;
32 import java.util.Set;
33 
34 import javax.security.auth.x500.X500Principal;
35 
36 import org.bouncycastle.asn1.ASN1Encodable;
37 import org.bouncycastle.asn1.ASN1Enumerated;
38 import org.bouncycastle.asn1.ASN1InputStream;
39 import org.bouncycastle.asn1.ASN1ObjectIdentifier;
40 import org.bouncycastle.asn1.ASN1OctetString;
41 import org.bouncycastle.asn1.ASN1OutputStream;
42 import org.bouncycastle.asn1.ASN1Primitive;
43 import org.bouncycastle.asn1.ASN1Sequence;
44 import org.bouncycastle.asn1.DERSequence;
45 import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
46 import org.bouncycastle.asn1.x509.CRLReason;
47 import org.bouncycastle.asn1.x509.Extension;
48 import org.bouncycastle.asn1.x509.IssuingDistributionPoint;
49 import org.bouncycastle.asn1.x509.PolicyInformation;
50 import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
51 import org.bouncycastle.asn1.x509.X509Extension;
52 import org.bouncycastle.jcajce.PKIXCertStoreSelector;
53 import org.bouncycastle.jce.exception.ExtCertPathValidatorException;
54 import org.bouncycastle.jce.provider.AnnotatedException;
55 import org.bouncycastle.jce.provider.BouncyCastleProvider;
56 import org.bouncycastle.jce.provider.PKIXPolicyNode;
57 import org.bouncycastle.util.Encodable;
58 import org.bouncycastle.util.Selector;
59 import org.bouncycastle.util.Store;
60 import org.bouncycastle.util.StoreException;
61 
62 class CertPathValidatorUtilities
63 {
64     protected static final String CERTIFICATE_POLICIES = Extension.certificatePolicies.getId();
65     protected static final String BASIC_CONSTRAINTS = Extension.basicConstraints.getId();
66     protected static final String POLICY_MAPPINGS = Extension.policyMappings.getId();
67     protected static final String SUBJECT_ALTERNATIVE_NAME = Extension.subjectAlternativeName.getId();
68     protected static final String NAME_CONSTRAINTS = Extension.nameConstraints.getId();
69     protected static final String KEY_USAGE = Extension.keyUsage.getId();
70     protected static final String INHIBIT_ANY_POLICY = Extension.inhibitAnyPolicy.getId();
71     protected static final String ISSUING_DISTRIBUTION_POINT = Extension.issuingDistributionPoint.getId();
72     protected static final String DELTA_CRL_INDICATOR = Extension.deltaCRLIndicator.getId();
73     protected static final String POLICY_CONSTRAINTS = Extension.policyConstraints.getId();
74 //    protected static final String FRESHEST_CRL = Extension.freshestCRL.getId();
75 //    protected static final String CRL_DISTRIBUTION_POINTS = Extension.cRLDistributionPoints.getId();
76 //    protected static final String AUTHORITY_KEY_IDENTIFIER = Extension.authorityKeyIdentifier.getId();
77     protected static final String CRL_NUMBER = Extension.cRLNumber.getId();
78 
79     protected static final String ANY_POLICY = "2.5.29.32.0";
80 
81     /*
82     * key usage bits
83     */
84     protected static final int KEY_CERT_SIGN = 5;
85     protected static final int CRL_SIGN = 6;
86 
87     protected static final String[] crlReasons = new String[]{
88         "unspecified",
89         "keyCompromise",
90         "cACompromise",
91         "affiliationChanged",
92         "superseded",
93         "cessationOfOperation",
94         "certificateHold",
95         "unknown",
96         "removeFromCRL",
97         "privilegeWithdrawn",
98         "aACompromise"};
99 
100     /**
101      * Returns the issuer of an attribute certificate or certificate.
102      *
103      * @param cert The attribute certificate or certificate.
104      * @return The issuer as <code>X500Principal</code>.
105      */
getEncodedIssuerPrincipal( Object cert)106     protected static X500Principal getEncodedIssuerPrincipal(
107         Object cert)
108     {
109         if (cert instanceof X509Certificate)
110         {
111             return ((X509Certificate)cert).getIssuerX500Principal();
112         }
113         else
114         {
115             return (X500Principal)((X509AttributeCertificate)cert).getIssuer().getPrincipals()[0];
116         }
117     }
118 
getValidityDate(PKIXParameters paramsPKIX, Date currentDate)119     protected static Date getValidityDate(PKIXParameters paramsPKIX, Date currentDate)
120     {
121         Date validityDate = paramsPKIX.getDate();
122 
123         return null == validityDate ? currentDate : validityDate;
124     }
125 
getSubjectPrincipal(X509Certificate cert)126     protected static X500Principal getSubjectPrincipal(X509Certificate cert)
127     {
128         return cert.getSubjectX500Principal();
129     }
130 
isSelfIssued(X509Certificate cert)131     protected static boolean isSelfIssued(X509Certificate cert)
132     {
133         return cert.getSubjectDN().equals(cert.getIssuerDN());
134     }
135 
136 
137     /**
138      * Extract the value of the given extension, if it exists.
139      *
140      * @param ext The extension object.
141      * @param oid The object identifier to obtain.
142      * @throws AnnotatedException if the extension cannot be read.
143      */
getExtensionValue( java.security.cert.X509Extension ext, String oid)144     protected static ASN1Primitive getExtensionValue(
145         java.security.cert.X509Extension ext,
146         String oid)
147         throws AnnotatedException
148     {
149         byte[] bytes = ext.getExtensionValue(oid);
150         if (bytes == null)
151         {
152             return null;
153         }
154 
155         return getObject(oid, bytes);
156     }
157 
getObject( String oid, byte[] ext)158     private static ASN1Primitive getObject(
159         String oid,
160         byte[] ext)
161         throws AnnotatedException
162     {
163         try
164         {
165             ASN1InputStream aIn = new ASN1InputStream(ext);
166             ASN1OctetString octs = (ASN1OctetString)aIn.readObject();
167 
168             aIn = new ASN1InputStream(octs.getOctets());
169             return aIn.readObject();
170         }
171         catch (Exception e)
172         {
173             throw new AnnotatedException("exception processing extension " + oid, e);
174         }
175     }
176 
getIssuerPrincipal(X509CRL crl)177     protected static X500Principal getIssuerPrincipal(X509CRL crl)
178     {
179         return crl.getIssuerX500Principal();
180     }
181 
getAlgorithmIdentifier( PublicKey key)182     protected static AlgorithmIdentifier getAlgorithmIdentifier(
183         PublicKey key)
184         throws CertPathValidatorException
185     {
186         try
187         {
188             ASN1InputStream aIn = new ASN1InputStream(key.getEncoded());
189 
190             SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(aIn.readObject());
191 
192             return info.getAlgorithmId();
193         }
194         catch (Exception e)
195         {
196             throw new ExtCertPathValidatorException("Subject public key cannot be decoded.", e);
197         }
198     }
199 
200     // crl checking
201 
202 
203     //
204     // policy checking
205     //
206 
getQualifierSet(ASN1Sequence qualifiers)207     protected static final Set getQualifierSet(ASN1Sequence qualifiers)
208         throws CertPathValidatorException
209     {
210         Set pq = new HashSet();
211 
212         if (qualifiers == null)
213         {
214             return pq;
215         }
216 
217         ByteArrayOutputStream bOut = new ByteArrayOutputStream();
218         ASN1OutputStream aOut = ASN1OutputStream.create(bOut);
219 
220         Enumeration e = qualifiers.getObjects();
221 
222         while (e.hasMoreElements())
223         {
224             try
225             {
226                 aOut.writeObject((ASN1Encodable)e.nextElement());
227 
228                 pq.add(new PolicyQualifierInfo(bOut.toByteArray()));
229             }
230             catch (IOException ex)
231             {
232                 throw new ExtCertPathValidatorException("Policy qualifier info cannot be decoded.", ex);
233             }
234 
235             bOut.reset();
236         }
237 
238         return pq;
239     }
240 
removePolicyNode( PKIXPolicyNode validPolicyTree, List[] policyNodes, PKIXPolicyNode _node)241     protected static PKIXPolicyNode removePolicyNode(
242         PKIXPolicyNode validPolicyTree,
243         List[] policyNodes,
244         PKIXPolicyNode _node)
245     {
246         PKIXPolicyNode _parent = (PKIXPolicyNode)_node.getParent();
247 
248         if (validPolicyTree == null)
249         {
250             return null;
251         }
252 
253         if (_parent == null)
254         {
255             for (int j = 0; j < policyNodes.length; j++)
256             {
257                 policyNodes[j] = new ArrayList();
258             }
259 
260             return null;
261         }
262         else
263         {
264             _parent.removeChild(_node);
265             removePolicyNodeRecurse(policyNodes, _node);
266 
267             return validPolicyTree;
268         }
269     }
270 
removePolicyNodeRecurse( List[] policyNodes, PKIXPolicyNode _node)271     private static void removePolicyNodeRecurse(
272         List[] policyNodes,
273         PKIXPolicyNode _node)
274     {
275         policyNodes[_node.getDepth()].remove(_node);
276 
277         if (_node.hasChildren())
278         {
279             Iterator _iter = _node.getChildren();
280             while (_iter.hasNext())
281             {
282                 PKIXPolicyNode _child = (PKIXPolicyNode)_iter.next();
283                 removePolicyNodeRecurse(policyNodes, _child);
284             }
285         }
286     }
287 
288 
processCertD1i( int index, List[] policyNodes, ASN1ObjectIdentifier pOid, Set pq)289     protected static boolean processCertD1i(
290         int index,
291         List[] policyNodes,
292         ASN1ObjectIdentifier pOid,
293         Set pq)
294     {
295         List policyNodeVec = policyNodes[index - 1];
296 
297         for (int j = 0; j < policyNodeVec.size(); j++)
298         {
299             PKIXPolicyNode node = (PKIXPolicyNode)policyNodeVec.get(j);
300             Set expectedPolicies = node.getExpectedPolicies();
301 
302             if (expectedPolicies.contains(pOid.getId()))
303             {
304                 Set childExpectedPolicies = new HashSet();
305                 childExpectedPolicies.add(pOid.getId());
306 
307                 PKIXPolicyNode child = new PKIXPolicyNode(new ArrayList(),
308                     index,
309                     childExpectedPolicies,
310                     node,
311                     pq,
312                     pOid.getId(),
313                     false);
314                 node.addChild(child);
315                 policyNodes[index].add(child);
316 
317                 return true;
318             }
319         }
320 
321         return false;
322     }
323 
processCertD1ii( int index, List[] policyNodes, ASN1ObjectIdentifier _poid, Set _pq)324     protected static void processCertD1ii(
325         int index,
326         List[] policyNodes,
327         ASN1ObjectIdentifier _poid,
328         Set _pq)
329     {
330         List policyNodeVec = policyNodes[index - 1];
331 
332         for (int j = 0; j < policyNodeVec.size(); j++)
333         {
334             PKIXPolicyNode _node = (PKIXPolicyNode)policyNodeVec.get(j);
335 
336             if (ANY_POLICY.equals(_node.getValidPolicy()))
337             {
338                 Set _childExpectedPolicies = new HashSet();
339                 _childExpectedPolicies.add(_poid.getId());
340 
341                 PKIXPolicyNode _child = new PKIXPolicyNode(new ArrayList(),
342                     index,
343                     _childExpectedPolicies,
344                     _node,
345                     _pq,
346                     _poid.getId(),
347                     false);
348                 _node.addChild(_child);
349                 policyNodes[index].add(_child);
350                 return;
351             }
352         }
353     }
354 
prepareNextCertB1( int i, List[] policyNodes, String id_p, Map m_idp, X509Certificate cert )355     protected static void prepareNextCertB1(
356         int i,
357         List[] policyNodes,
358         String id_p,
359         Map m_idp,
360         X509Certificate cert
361     )
362         throws AnnotatedException, CertPathValidatorException
363     {
364         boolean idp_found = false;
365         Iterator nodes_i = policyNodes[i].iterator();
366         while (nodes_i.hasNext())
367         {
368             PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next();
369             if (node.getValidPolicy().equals(id_p))
370             {
371                 idp_found = true;
372                 node.setExpectedPolicies((Set)m_idp.get(id_p));
373                 break;
374             }
375         }
376 
377         if (!idp_found)
378         {
379             nodes_i = policyNodes[i].iterator();
380             while (nodes_i.hasNext())
381             {
382                 PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next();
383                 if (ANY_POLICY.equals(node.getValidPolicy()))
384                 {
385                     Set pq = null;
386                     ASN1Sequence policies = null;
387                     try
388                     {
389                         policies = DERSequence.getInstance(getExtensionValue(cert, CERTIFICATE_POLICIES));
390                     }
391                     catch (Exception e)
392                     {
393                         throw new AnnotatedException("Certificate policies cannot be decoded.", e);
394                     }
395                     Enumeration e = policies.getObjects();
396                     while (e.hasMoreElements())
397                     {
398                         PolicyInformation pinfo = null;
399 
400                         try
401                         {
402                             pinfo = PolicyInformation.getInstance(e.nextElement());
403                         }
404                         catch (Exception ex)
405                         {
406                             throw new AnnotatedException("Policy information cannot be decoded.", ex);
407                         }
408                         if (ANY_POLICY.equals(pinfo.getPolicyIdentifier().getId()))
409                         {
410                             try
411                             {
412                                 pq = getQualifierSet(pinfo.getPolicyQualifiers());
413                             }
414                             catch (CertPathValidatorException ex)
415                             {
416                                 throw new ExtCertPathValidatorException(
417                                     "Policy qualifier info set could not be built.", ex);
418                             }
419                             break;
420                         }
421                     }
422                     boolean ci = false;
423                     if (cert.getCriticalExtensionOIDs() != null)
424                     {
425                         ci = cert.getCriticalExtensionOIDs().contains(CERTIFICATE_POLICIES);
426                     }
427 
428                     PKIXPolicyNode p_node = (PKIXPolicyNode)node.getParent();
429                     if (ANY_POLICY.equals(p_node.getValidPolicy()))
430                     {
431                         PKIXPolicyNode c_node = new PKIXPolicyNode(
432                             new ArrayList(), i,
433                             (Set)m_idp.get(id_p),
434                             p_node, pq, id_p, ci);
435                         p_node.addChild(c_node);
436                         policyNodes[i].add(c_node);
437                     }
438                     break;
439                 }
440             }
441         }
442     }
443 
prepareNextCertB2( int i, List[] policyNodes, String id_p, PKIXPolicyNode validPolicyTree)444     protected static PKIXPolicyNode prepareNextCertB2(
445         int i,
446         List[] policyNodes,
447         String id_p,
448         PKIXPolicyNode validPolicyTree)
449     {
450         Iterator nodes_i = policyNodes[i].iterator();
451         while (nodes_i.hasNext())
452         {
453             PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next();
454             if (node.getValidPolicy().equals(id_p))
455             {
456                 PKIXPolicyNode p_node = (PKIXPolicyNode)node.getParent();
457                 p_node.removeChild(node);
458                 nodes_i.remove();
459                 for (int k = (i - 1); k >= 0; k--)
460                 {
461                     List nodes = policyNodes[k];
462                     for (int l = 0; l < nodes.size(); l++)
463                     {
464                         PKIXPolicyNode node2 = (PKIXPolicyNode)nodes.get(l);
465                         if (!node2.hasChildren())
466                         {
467                             validPolicyTree = removePolicyNode(validPolicyTree, policyNodes, node2);
468                             if (validPolicyTree == null)
469                             {
470                                 break;
471                             }
472                         }
473                     }
474                 }
475             }
476         }
477         return validPolicyTree;
478     }
479 
isAnyPolicy( Set policySet)480     protected static boolean isAnyPolicy(
481         Set policySet)
482     {
483         return policySet == null || policySet.contains(ANY_POLICY) || policySet.isEmpty();
484     }
485 
486     /**
487      * Return a Collection of all certificates or attribute certificates found
488      * in the X509Store's that are matching the certSelect criteriums.
489      *
490      * @param certSelect a {@link Selector} object that will be used to select
491      *                   the certificates
492      * @param certStores a List containing only {@link X509Store} objects. These
493      *                   are used to search for certificates.
494      * @return a Collection of all found {@link X509Certificate} or
495      *         {@link org.bouncycastle.x509.X509AttributeCertificate} objects.
496      *         May be empty but never <code>null</code>.
497      */
findCertificates(X509CertStoreSelector certSelect, List certStores)498     protected static Collection findCertificates(X509CertStoreSelector certSelect,
499                                                  List certStores)
500         throws AnnotatedException
501     {
502         Set certs = new HashSet();
503         Iterator iter = certStores.iterator();
504         org.bouncycastle.jcajce.provider.asymmetric.x509.CertificateFactory certFact = new org.bouncycastle.jcajce.provider.asymmetric.x509.CertificateFactory();
505 
506         while (iter.hasNext())
507         {
508             Object obj = iter.next();
509 
510             if (obj instanceof Store)
511             {
512                 Store certStore = (Store)obj;
513                 try
514                 {
515                     for (Iterator it = certStore.getMatches(certSelect).iterator(); it.hasNext();)
516                     {
517                         Object cert = it.next();
518 
519                         if (cert instanceof Encodable)
520                         {
521                             certs.add(certFact.engineGenerateCertificate(new ByteArrayInputStream(((Encodable)cert).getEncoded())));
522                         }
523                         else if (cert instanceof Certificate)
524                         {
525                              certs.add(cert);
526                         }
527                         else
528                         {
529                             throw new AnnotatedException(
530                                     "Unknown object found in certificate store.");
531                         }
532                     }
533                 }
534                 catch (StoreException e)
535                 {
536                     throw new AnnotatedException(
537                             "Problem while picking certificates from X.509 store.", e);
538                 }
539                 catch (IOException e)
540                 {
541                     throw new AnnotatedException(
542                             "Problem while extracting certificates from X.509 store.", e);
543                 }
544                 catch (CertificateException e)
545                 {
546                     throw new AnnotatedException(
547                             "Problem while extracting certificates from X.509 store.", e);
548                 }
549             }
550             else
551             {
552                 CertStore certStore = (CertStore)obj;
553 
554                 try
555                 {
556                     certs.addAll(certStore.getCertificates(certSelect));
557                 }
558                 catch (CertStoreException e)
559                 {
560                     throw new AnnotatedException(
561                         "Problem while picking certificates from certificate store.",
562                         e);
563                 }
564             }
565         }
566         return certs;
567     }
568 
findCertificates(PKIXCertStoreSelector certSelect, List certStores)569     protected static Collection findCertificates(PKIXCertStoreSelector certSelect,
570                                                  List certStores)
571         throws AnnotatedException
572     {
573         Set certs = new HashSet();
574         Iterator iter = certStores.iterator();
575 
576         while (iter.hasNext())
577         {
578             Object obj = iter.next();
579 
580             if (obj instanceof Store)
581             {
582                 Store certStore = (Store)obj;
583                 try
584                 {
585                     certs.addAll(certStore.getMatches(certSelect));
586                 }
587                 catch (StoreException e)
588                 {
589                     throw new AnnotatedException(
590                             "Problem while picking certificates from X.509 store.", e);
591                 }
592             }
593             else
594             {
595                 CertStore certStore = (CertStore)obj;
596 
597                 try
598                 {
599                     certs.addAll(PKIXCertStoreSelector.getCertificates(certSelect, certStore));
600                 }
601                 catch (CertStoreException e)
602                 {
603                     throw new AnnotatedException(
604                         "Problem while picking certificates from certificate store.",
605                         e);
606                 }
607             }
608         }
609         return certs;
610     }
611 
findCertificates(X509AttributeCertStoreSelector certSelect, List certStores)612     protected static Collection findCertificates(X509AttributeCertStoreSelector certSelect,
613                                                  List certStores)
614         throws AnnotatedException
615     {
616         Set certs = new HashSet();
617         Iterator iter = certStores.iterator();
618 
619         while (iter.hasNext())
620         {
621             Object obj = iter.next();
622 
623             if (obj instanceof X509Store)
624             {
625                 X509Store certStore = (X509Store)obj;
626                 try
627                 {
628                     certs.addAll(certStore.getMatches(certSelect));
629                 }
630                 catch (StoreException e)
631                 {
632                     throw new AnnotatedException(
633                             "Problem while picking certificates from X.509 store.", e);
634                 }
635             }
636         }
637         return certs;
638     }
639 
getSerialNumber( Object cert)640     private static BigInteger getSerialNumber(
641         Object cert)
642     {
643         if (cert instanceof X509Certificate)
644         {
645             return ((X509Certificate)cert).getSerialNumber();
646         }
647         else
648         {
649             return ((X509AttributeCertificate)cert).getSerialNumber();
650         }
651     }
652 
getCertStatus( Date validDate, X509CRL crl, Object cert, CertStatus certStatus)653     protected static void getCertStatus(
654         Date validDate,
655         X509CRL crl,
656         Object cert,
657         CertStatus certStatus)
658         throws AnnotatedException
659     {
660         X509CRLEntry crl_entry = null;
661 
662         boolean isIndirect;
663         try
664         {
665             isIndirect = isIndirectCRL(crl);
666         }
667         catch (CRLException exception)
668         {
669             throw new AnnotatedException("Failed check for indirect CRL.", exception);
670         }
671 
672         if (isIndirect)
673         {
674             crl_entry = crl.getRevokedCertificate(getSerialNumber(cert));
675 
676             if (crl_entry == null)
677             {
678                 return;
679             }
680 
681             X500Principal certIssuer = crl_entry.getCertificateIssuer();
682 
683             if (certIssuer == null)
684             {
685                 certIssuer = getIssuerPrincipal(crl);
686             }
687 
688             if (!getEncodedIssuerPrincipal(cert).equals(certIssuer))
689             {
690                 return;
691             }
692         }
693         else if (!getEncodedIssuerPrincipal(cert).equals(getIssuerPrincipal(crl)))
694         {
695             return;  // not for our issuer, ignore
696         }
697         else
698         {
699             crl_entry = crl.getRevokedCertificate(getSerialNumber(cert));
700 
701             if (crl_entry == null)
702             {
703                 return;
704             }
705         }
706 
707         ASN1Enumerated reasonCode = null;
708         if (crl_entry.hasExtensions())
709         {
710             try
711             {
712                 reasonCode = ASN1Enumerated
713                     .getInstance(CertPathValidatorUtilities
714                         .getExtensionValue(crl_entry,
715                             X509Extension.reasonCode.getId()));
716             }
717             catch (Exception e)
718             {
719                 throw new AnnotatedException(
720                     "Reason code CRL entry extension could not be decoded.",
721                     e);
722             }
723         }
724 
725         int reasonCodeValue = (null == reasonCode)
726             ?   CRLReason.unspecified
727             :   reasonCode.intValueExact();
728 
729         // for reason keyCompromise, caCompromise, aACompromise or unspecified
730         if (!(validDate.getTime() < crl_entry.getRevocationDate().getTime())
731             || reasonCodeValue == CRLReason.unspecified
732             || reasonCodeValue == CRLReason.keyCompromise
733             || reasonCodeValue == CRLReason.cACompromise
734             || reasonCodeValue == CRLReason.aACompromise)
735         {
736             // (i) or (j)
737             certStatus.setCertStatus(reasonCodeValue);
738             certStatus.setRevocationDate(crl_entry.getRevocationDate());
739         }
740     }
741 
742     /**
743      * Return the next working key inheriting DSA parameters if necessary.
744      * <p>
745      * This methods inherits DSA parameters from the indexed certificate or
746      * previous certificates in the certificate chain to the returned
747      * <code>PublicKey</code>. The list is searched upwards, meaning the end
748      * certificate is at position 0 and previous certificates are following.
749      * </p>
750      * <p>
751      * If the indexed certificate does not contain a DSA key this method simply
752      * returns the public key. If the DSA key already contains DSA parameters
753      * the key is also only returned.
754      * </p>
755      *
756      * @param certs The certification path.
757      * @param index The index of the certificate which contains the public key
758      *              which should be extended with DSA parameters.
759      * @return The public key of the certificate in list position
760      *         <code>index</code> extended with DSA parameters if applicable.
761      * @throws CertPathValidatorException if DSA parameters cannot be inherited.
762      */
getNextWorkingKey(List certs, int index)763     protected static PublicKey getNextWorkingKey(List certs, int index)
764         throws CertPathValidatorException
765     {
766         Certificate cert = (Certificate)certs.get(index);
767         PublicKey pubKey = cert.getPublicKey();
768         if (!(pubKey instanceof DSAPublicKey))
769         {
770             return pubKey;
771         }
772         DSAPublicKey dsaPubKey = (DSAPublicKey)pubKey;
773         if (dsaPubKey.getParams() != null)
774         {
775             return dsaPubKey;
776         }
777         for (int i = index + 1; i < certs.size(); i++)
778         {
779             X509Certificate parentCert = (X509Certificate)certs.get(i);
780             pubKey = parentCert.getPublicKey();
781             if (!(pubKey instanceof DSAPublicKey))
782             {
783                 throw new CertPathValidatorException(
784                     "DSA parameters cannot be inherited from previous certificate.");
785             }
786             DSAPublicKey prevDSAPubKey = (DSAPublicKey)pubKey;
787             if (prevDSAPubKey.getParams() == null)
788             {
789                 continue;
790             }
791             DSAParams dsaParams = prevDSAPubKey.getParams();
792             DSAPublicKeySpec dsaPubKeySpec = new DSAPublicKeySpec(
793                 dsaPubKey.getY(), dsaParams.getP(), dsaParams.getQ(), dsaParams.getG());
794             try
795             {
796                 KeyFactory keyFactory = KeyFactory.getInstance("DSA", BouncyCastleProvider.PROVIDER_NAME);
797                 return keyFactory.generatePublic(dsaPubKeySpec);
798             }
799             catch (Exception exception)
800             {
801                 throw new RuntimeException(exception.getMessage());
802             }
803         }
804         throw new CertPathValidatorException("DSA parameters cannot be inherited from previous certificate.");
805     }
806 
verifyX509Certificate(X509Certificate cert, PublicKey publicKey, String sigProvider)807     protected static void verifyX509Certificate(X509Certificate cert, PublicKey publicKey,
808                                                 String sigProvider)
809         throws GeneralSecurityException
810     {
811         if (sigProvider == null)
812         {
813             cert.verify(publicKey);
814         }
815         else
816         {
817             cert.verify(publicKey, sigProvider);
818         }
819     }
820 
isIndirectCRL(X509CRL crl)821     static boolean isIndirectCRL(X509CRL crl)
822         throws CRLException
823     {
824         try
825         {
826             byte[] idp = crl.getExtensionValue(Extension.issuingDistributionPoint.getId());
827             return idp != null
828                 && IssuingDistributionPoint.getInstance(ASN1OctetString.getInstance(idp).getOctets()).isIndirectCRL();
829         }
830         catch (Exception e)
831         {
832             throw new CRLException(
833                     "Exception reading IssuingDistributionPoint: " + e);
834         }
835     }
836 }
837