Home | History | Annotate | Download | only in provider
      1 package org.bouncycastle.jce.provider;
      2 
      3 import java.security.InvalidAlgorithmParameterException;
      4 import java.security.cert.CertPath;
      5 import java.security.cert.CertPathBuilderException;
      6 import java.security.cert.CertPathBuilderResult;
      7 import java.security.cert.CertPathBuilderSpi;
      8 import java.security.cert.CertPathParameters;
      9 import java.security.cert.CertPathValidator;
     10 import java.security.cert.CertificateFactory;
     11 import java.security.cert.CertificateParsingException;
     12 import java.security.cert.PKIXBuilderParameters;
     13 import java.security.cert.PKIXCertPathBuilderResult;
     14 import java.security.cert.PKIXCertPathValidatorResult;
     15 import java.security.cert.X509Certificate;
     16 import java.util.ArrayList;
     17 import java.util.Collection;
     18 import java.util.HashSet;
     19 import java.util.Iterator;
     20 import java.util.List;
     21 
     22 import org.bouncycastle.jce.exception.ExtCertPathBuilderException;
     23 import org.bouncycastle.util.Selector;
     24 import org.bouncycastle.x509.ExtendedPKIXBuilderParameters;
     25 import org.bouncycastle.x509.X509CertStoreSelector;
     26 
     27 /**
     28  * Implements the PKIX CertPathBuilding algorithm for BouncyCastle.
     29  *
     30  * @see CertPathBuilderSpi
     31  */
     32 public class PKIXCertPathBuilderSpi
     33     extends CertPathBuilderSpi
     34 {
     35     /**
     36      * Build and validate a CertPath using the given parameter.
     37      *
     38      * @param params PKIXBuilderParameters object containing all information to
     39      *            build the CertPath
     40      */
     41     public CertPathBuilderResult engineBuild(CertPathParameters params)
     42         throws CertPathBuilderException, InvalidAlgorithmParameterException
     43     {
     44         if (!(params instanceof PKIXBuilderParameters)
     45             && !(params instanceof ExtendedPKIXBuilderParameters))
     46         {
     47             throw new InvalidAlgorithmParameterException(
     48                 "Parameters must be an instance of "
     49                     + PKIXBuilderParameters.class.getName() + " or "
     50                     + ExtendedPKIXBuilderParameters.class.getName() + ".");
     51         }
     52 
     53         ExtendedPKIXBuilderParameters pkixParams = null;
     54         if (params instanceof ExtendedPKIXBuilderParameters)
     55         {
     56             pkixParams = (ExtendedPKIXBuilderParameters) params;
     57         }
     58         else
     59         {
     60             pkixParams = (ExtendedPKIXBuilderParameters) ExtendedPKIXBuilderParameters
     61                 .getInstance((PKIXBuilderParameters) params);
     62         }
     63 
     64         Collection targets;
     65         Iterator targetIter;
     66         List certPathList = new ArrayList();
     67         X509Certificate cert;
     68 
     69         // search target certificates
     70 
     71         Selector certSelect = pkixParams.getTargetConstraints();
     72         if (!(certSelect instanceof X509CertStoreSelector))
     73         {
     74             throw new CertPathBuilderException(
     75                 "TargetConstraints must be an instance of "
     76                     + X509CertStoreSelector.class.getName() + " for "
     77                     + this.getClass().getName() + " class.");
     78         }
     79 
     80         try
     81         {
     82             targets = CertPathValidatorUtilities.findCertificates((X509CertStoreSelector)certSelect, pkixParams.getStores());
     83             targets.addAll(CertPathValidatorUtilities.findCertificates((X509CertStoreSelector)certSelect, pkixParams.getCertStores()));
     84         }
     85         catch (AnnotatedException e)
     86         {
     87             throw new ExtCertPathBuilderException(
     88                 "Error finding target certificate.", e);
     89         }
     90 
     91         if (targets.isEmpty())
     92         {
     93 
     94             throw new CertPathBuilderException(
     95                 "No certificate found matching targetContraints.");
     96         }
     97 
     98         CertPathBuilderResult result = null;
     99 
    100         // check all potential target certificates
    101         targetIter = targets.iterator();
    102         while (targetIter.hasNext() && result == null)
    103         {
    104             cert = (X509Certificate) targetIter.next();
    105             result = build(cert, pkixParams, certPathList);
    106         }
    107 
    108         if (result == null && certPathException != null)
    109         {
    110             if (certPathException instanceof AnnotatedException)
    111             {
    112                 throw new CertPathBuilderException(certPathException.getMessage(), certPathException.getCause());
    113             }
    114             throw new CertPathBuilderException(
    115                 "Possible certificate chain could not be validated.",
    116                 certPathException);
    117         }
    118 
    119         if (result == null && certPathException == null)
    120         {
    121             throw new CertPathBuilderException(
    122                 "Unable to find certificate chain.");
    123         }
    124 
    125         return result;
    126     }
    127 
    128     private Exception certPathException;
    129 
    130     protected CertPathBuilderResult build(X509Certificate tbvCert,
    131         ExtendedPKIXBuilderParameters pkixParams, List tbvPath)
    132     {
    133         // If tbvCert is readily present in tbvPath, it indicates having run
    134         // into a cycle in the
    135         // PKI graph.
    136         if (tbvPath.contains(tbvCert))
    137         {
    138             return null;
    139         }
    140         // step out, the certificate is not allowed to appear in a certification
    141         // chain.
    142         if (pkixParams.getExcludedCerts().contains(tbvCert))
    143         {
    144             return null;
    145         }
    146         // test if certificate path exceeds maximum length
    147         if (pkixParams.getMaxPathLength() != -1)
    148         {
    149             if (tbvPath.size() - 1 > pkixParams.getMaxPathLength())
    150             {
    151                 return null;
    152             }
    153         }
    154 
    155         tbvPath.add(tbvCert);
    156 
    157         CertificateFactory cFact;
    158         CertPathValidator validator;
    159         CertPathBuilderResult builderResult = null;
    160 
    161         try
    162         {
    163             cFact = CertificateFactory.getInstance("X.509", BouncyCastleProvider.PROVIDER_NAME);
    164             validator = CertPathValidator.getInstance("PKIX", BouncyCastleProvider.PROVIDER_NAME);
    165         }
    166         catch (Exception e)
    167         {
    168             // cannot happen
    169             throw new RuntimeException("Exception creating support classes.");
    170         }
    171 
    172         try
    173         {
    174             // check whether the issuer of <tbvCert> is a TrustAnchor
    175             if (CertPathValidatorUtilities.findTrustAnchor(tbvCert, pkixParams.getTrustAnchors(),
    176                 pkixParams.getSigProvider()) != null)
    177             {
    178                 // exception message from possibly later tried certification
    179                 // chains
    180                 CertPath certPath = null;
    181                 PKIXCertPathValidatorResult result = null;
    182                 try
    183                 {
    184                     certPath = cFact.generateCertPath(tbvPath);
    185                 }
    186                 catch (Exception e)
    187                 {
    188                     throw new AnnotatedException(
    189                         "Certification path could not be constructed from certificate list.",
    190                         e);
    191                 }
    192 
    193                 try
    194                 {
    195                     result = (PKIXCertPathValidatorResult) validator.validate(
    196                         certPath, pkixParams);
    197                 }
    198                 catch (Exception e)
    199                 {
    200                     throw new AnnotatedException(
    201                         "Certification path could not be validated.", e);
    202                 }
    203 
    204                 return new PKIXCertPathBuilderResult(certPath, result
    205                     .getTrustAnchor(), result.getPolicyTree(), result
    206                     .getPublicKey());
    207 
    208             }
    209             else
    210             {
    211                 // add additional X.509 stores from locations in certificate
    212                 try
    213                 {
    214                     CertPathValidatorUtilities.addAdditionalStoresFromAltNames(
    215                         tbvCert, pkixParams);
    216                 }
    217                 catch (CertificateParsingException e)
    218                 {
    219                     throw new AnnotatedException(
    220                         "No additiontal X.509 stores can be added from certificate locations.",
    221                         e);
    222                 }
    223                 Collection issuers = new HashSet();
    224                 // try to get the issuer certificate from one
    225                 // of the stores
    226                 try
    227                 {
    228                     issuers.addAll(CertPathValidatorUtilities.findIssuerCerts(tbvCert, pkixParams));
    229                 }
    230                 catch (AnnotatedException e)
    231                 {
    232                     throw new AnnotatedException(
    233                         "Cannot find issuer certificate for certificate in certification path.",
    234                         e);
    235                 }
    236                 if (issuers.isEmpty())
    237                 {
    238                     throw new AnnotatedException(
    239                         "No issuer certificate for certificate in certification path found.");
    240                 }
    241                 Iterator it = issuers.iterator();
    242 
    243                 while (it.hasNext() && builderResult == null)
    244                 {
    245                     X509Certificate issuer = (X509Certificate) it.next();
    246                     builderResult = build(issuer, pkixParams, tbvPath);
    247                 }
    248             }
    249         }
    250         catch (AnnotatedException e)
    251         {
    252             certPathException = e;
    253         }
    254         if (builderResult == null)
    255         {
    256             tbvPath.remove(tbvCert);
    257         }
    258         return builderResult;
    259     }
    260 
    261 }
    262