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