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