~brian-thomason/+junk/bouncycastle

1 by Brian Thomason
Initial import
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
}