1 package org.astrogrid.security.rfc3820;
2
3 import java.security.InvalidKeyException;
4 import java.security.NoSuchAlgorithmException;
5 import java.security.NoSuchProviderException;
6 import java.security.PublicKey;
7 import java.security.SignatureException;
8 import java.security.cert.CertificateException;
9 import java.security.cert.X509Certificate;
10 import javax.security.auth.x500.X500Principal;
11 import org.globus.gsi.TrustedCertificates;
12 import org.globus.gsi.proxy.ProxyPathValidator;
13 import org.globus.gsi.proxy.ProxyPathValidatorException;
14
15 /***
16 * A validator for certificate chains formed according to RFC3820.
17 * These chains are the kind that can include proxy certificates.
18 *
19 * Most of the checking is done in the superclass,
20 * org.globus.gsi.proxy.ProxyPathValidator; see that class for details.
21 * This current class adds checks on the signatures of the certificates.
22 *
23 * @author Guy Rixon
24 */
25 public class CertificateChainValidator extends ProxyPathValidator {
26
27 /***
28 * Constructs a new instance of CertificateChainValidator.
29 */
30 public CertificateChainValidator() {
31 super();
32 }
33
34 /***
35 * Validates a certificate chain conforming to RFC3820. Such a chain
36 * may include proxy certificates. The equivalent method in the
37 * Globus superclass is called to check the subject-issuer relationships
38 * and the use of the ProxyCert and BasicConstraints extensions. The
39 * signatures on the certificates are then checked. This method assumes that
40 * the given chain is complete and includes the trust anchor in the last
41 * element of the array.
42 *
43 * @param chain The chain to be checked, with the trust anchor in the last place.
44 * @throws ProxyPathException - if the use of proxy certificates is invalid.
45 * @throws NoSuchAlgorithmException - on unsupported signature algorithms.
46 * @throws InvalidKeyException - on incorrect key.
47 * @throws NoSuchProviderException - if there's no default provider for the JCE.
48 * @throws SignatureException - on signature errors.
49 * @throws CertificateException - on encoding errors.
50 */
51 public void validateChain(X509Certificate[] chain)
52 throws CertificateException,
53 InvalidKeyException,
54 NoSuchAlgorithmException,
55 NoSuchProviderException,
56 ProxyPathValidatorException,
57 SignatureException {
58
59
60
61
62 super.validate(chain);
63
64
65
66
67
68 for (int i = 0; i < chain.length - 1; i++) {
69 PublicKey key = chain[i+1].getPublicKey();
70 chain[i].verify(key);
71 }
72 }
73
74 /***
75 * Validates a certificate chain conforming to RFC3820. Such as chain
76 * may include proxy certificates. The equivalent method in the
77 * Globus superclass is called to check the subject-issuer relationships
78 * and the use of the ProxyCert and BasicConstraints extensions. The
79 * signatures on the certificates are then checked. This method assumes that
80 * the given chain lacks a trust anchor and that a set of possible
81 * trust-anchors is passed separately.
82 *
83 * @param chain The chain to be checked.
84 * @param trustAnchors The set of trusted certificates.
85 * @throws ProxyPathException - if the use of proxy certificates is invalid.
86 * @throws NoSuchAlgorithmException - on unsupported signature algorithms.
87 * @throws InvalidKeyException - on incorrect key.
88 * @throws NoSuchProviderException - if there's no default provider for the JCE.
89 * @throws SignatureException - on signature errors.
90 * @throws CertificateException - on encoding errors.
91 */
92 public void validateChain(X509Certificate[] chain,
93 TrustedCertificates trustAnchors)
94 throws CertificateException,
95 InvalidKeyException,
96 NoSuchAlgorithmException,
97 NoSuchProviderException,
98 ProxyPathValidatorException,
99 SignatureException {
100
101
102
103
104 super.validate(chain, trustAnchors);
105
106
107
108
109 for (int i = 0; i < chain.length - 1; i++) {
110 X509Certificate signatory = chain[i+1];
111 chain[i].verify(signatory.getPublicKey());
112 }
113
114
115
116 X509Certificate lastInGivenChain = chain[chain.length-1];
117 X500Principal issuer = lastInGivenChain.getIssuerX500Principal();
118 X509Certificate[] anchors = trustAnchors.getCertificates();
119 for (int j = 0; j < anchors.length; j++) {
120 X509Certificate anchor = anchors[j];
121
122
123
124
125 if(issuer.equals(anchor.getSubjectX500Principal())) {
126 lastInGivenChain.verify(anchor.getPublicKey());
127 return;
128 }
129 }
130 throw new ProxyPathValidatorException(ProxyPathValidatorException.UNKNOWN_CA,
131 lastInGivenChain,
132 "No trusted certificate with subject " +
133 issuer.getName() +
134 " is available.");
135 }
136
137 }