~brian-thomason/+junk/bouncycastle

« back to all changes in this revision

Viewing changes to src/org/bouncycastle/jce/provider/PKIXAttrCertPathBuilderSpi.java

  • Committer: Brian Thomason
  • Date: 2011-12-20 17:20:32 UTC
  • Revision ID: brian.thomason@canonical.com-20111220172032-rdtm13jgdxtksacr
Initial import

Show diffs side-by-side

added added

removed removed

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