1 package org.eclipse.jetty.util.security;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 import java.security.GeneralSecurityException;
20 import java.security.InvalidParameterException;
21 import java.security.KeyStore;
22 import java.security.KeyStoreException;
23 import java.security.Security;
24 import java.security.cert.CRL;
25 import java.security.cert.CertPathBuilder;
26 import java.security.cert.CertPathBuilderResult;
27 import java.security.cert.CertPathValidator;
28 import java.security.cert.CertStore;
29 import java.security.cert.Certificate;
30 import java.security.cert.CertificateException;
31 import java.security.cert.CollectionCertStoreParameters;
32 import java.security.cert.PKIXBuilderParameters;
33 import java.security.cert.X509CertSelector;
34 import java.security.cert.X509Certificate;
35 import java.util.ArrayList;
36 import java.util.Collection;
37 import java.util.Enumeration;
38 import java.util.concurrent.atomic.AtomicLong;
39
40 import org.eclipse.jetty.util.log.Log;
41
42
43
44
45
46
47
48
49
50
51
52 public class CertificateValidator
53 {
54 private static AtomicLong __aliasCount = new AtomicLong();
55
56 private KeyStore _trustStore;
57 private Collection<? extends CRL> _crls;
58
59
60 private int _maxCertPathLength = -1;
61
62 private boolean _enableCRLDP = false;
63
64 private boolean _enableOCSP = false;
65
66 private String _ocspResponderURL;
67
68
69
70
71
72
73
74 public CertificateValidator(KeyStore trustStore, Collection<? extends CRL> crls)
75 {
76 if (trustStore == null)
77 {
78 throw new InvalidParameterException("TrustStore must be specified for CertificateValidator.");
79 }
80
81 _trustStore = trustStore;
82 _crls = crls;
83 }
84
85
86
87
88
89
90
91 public void validate( KeyStore keyStore ) throws CertificateException
92 {
93 try
94 {
95 Enumeration<String> aliases = keyStore.aliases();
96
97 for ( ; aliases.hasMoreElements(); )
98 {
99 String alias = aliases.nextElement();
100
101 validate(keyStore,alias);
102 }
103
104 }
105 catch ( KeyStoreException kse )
106 {
107 throw new CertificateException("Unable to retrieve aliases from keystore", kse);
108 }
109 }
110
111
112
113
114
115
116
117
118
119
120 public String validate(KeyStore keyStore, String keyAlias) throws CertificateException
121 {
122 String result = null;
123
124 if (keyAlias != null)
125 {
126 try
127 {
128 validate(keyStore, keyStore.getCertificate(keyAlias));
129 }
130 catch (KeyStoreException kse)
131 {
132 Log.debug(kse);
133 throw new CertificateException("Unable to validate certificate" +
134 " for alias [" + keyAlias + "]: " + kse.getMessage(), kse);
135 }
136 result = keyAlias;
137 }
138
139 return result;
140 }
141
142
143
144
145
146
147
148
149 public void validate(KeyStore keyStore, Certificate cert) throws CertificateException
150 {
151 Certificate[] certChain = null;
152
153 if (cert != null && cert instanceof X509Certificate)
154 {
155 ((X509Certificate)cert).checkValidity();
156
157 String certAlias = null;
158 try
159 {
160 if (keyStore == null)
161 {
162 throw new InvalidParameterException("Keystore cannot be null");
163 }
164
165 certAlias = keyStore.getCertificateAlias((X509Certificate)cert);
166 if (certAlias == null)
167 {
168 certAlias = "JETTY" + String.format("%016X",__aliasCount.incrementAndGet());
169 keyStore.setCertificateEntry(certAlias, cert);
170 }
171
172 certChain = keyStore.getCertificateChain(certAlias);
173 if (certChain == null || certChain.length == 0)
174 {
175 throw new IllegalStateException("Unable to retrieve certificate chain");
176 }
177 }
178 catch (KeyStoreException kse)
179 {
180 Log.debug(kse);
181 throw new CertificateException("Unable to validate certificate" +
182 (certAlias == null ? "":" for alias [" +certAlias + "]") + ": " + kse.getMessage(), kse);
183 }
184
185 validate(certChain);
186 }
187 }
188
189 public void validate(Certificate[] certChain) throws CertificateException
190 {
191 try
192 {
193 ArrayList<X509Certificate> certList = new ArrayList<X509Certificate>();
194 for (Certificate item : certChain)
195 {
196 if (item == null)
197 continue;
198
199 if (!(item instanceof X509Certificate))
200 {
201 throw new IllegalStateException("Invalid certificate type in chain");
202 }
203
204 certList.add((X509Certificate)item);
205 }
206
207 if (certList.isEmpty())
208 {
209 throw new IllegalStateException("Invalid certificate chain");
210
211 }
212
213 X509CertSelector certSelect = new X509CertSelector();
214 certSelect.setCertificate(certList.get(0));
215
216
217 PKIXBuilderParameters pbParams = new PKIXBuilderParameters(_trustStore, certSelect);
218 pbParams.addCertStore(CertStore.getInstance("Collection", new CollectionCertStoreParameters(certList)));
219
220
221 pbParams.setMaxPathLength(_maxCertPathLength);
222
223
224 pbParams.setRevocationEnabled(true);
225
226
227 if (_crls != null && !_crls.isEmpty())
228 {
229 pbParams.addCertStore(CertStore.getInstance("Collection", new CollectionCertStoreParameters(_crls)));
230 }
231
232
233 Security.setProperty("ocsp.enable","true");
234
235
236 System.setProperty("com.sun.security.enableCRLDP","true");
237
238
239 CertPathBuilderResult buildResult = CertPathBuilder.getInstance("PKIX").build(pbParams);
240
241
242 CertPathValidator.getInstance("PKIX").validate(buildResult.getCertPath(),pbParams);
243 }
244 catch (GeneralSecurityException gse)
245 {
246 Log.debug(gse);
247 throw new CertificateException("Unable to validate certificate: " + gse.getMessage(), gse);
248 }
249 }
250
251 public KeyStore getTrustStore()
252 {
253 return _trustStore;
254 }
255
256 public Collection<? extends CRL> getCrls()
257 {
258 return _crls;
259 }
260
261
262
263
264
265 public int getMaxCertPathLength()
266 {
267 return _maxCertPathLength;
268 }
269
270
271
272
273
274
275
276 public void setMaxCertPathLength(int maxCertPathLength)
277 {
278 _maxCertPathLength = maxCertPathLength;
279 }
280
281
282
283
284
285 public boolean isEnableCRLDP()
286 {
287 return _enableCRLDP;
288 }
289
290
291
292
293
294 public void setEnableCRLDP(boolean enableCRLDP)
295 {
296 _enableCRLDP = enableCRLDP;
297 }
298
299
300
301
302
303 public boolean isEnableOCSP()
304 {
305 return _enableOCSP;
306 }
307
308
309
310
311
312 public void setEnableOCSP(boolean enableOCSP)
313 {
314 _enableOCSP = enableOCSP;
315 }
316
317
318
319
320
321 public String getOcspResponderURL()
322 {
323 return _ocspResponderURL;
324 }
325
326
327
328
329
330 public void setOcspResponderURL(String ocspResponderURL)
331 {
332 _ocspResponderURL = ocspResponderURL;
333 }
334 }