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 Security.setProperty("ocsp.enable","true");
236
237
238 System.setProperty("com.sun.security.enableCRLDP","true");
239
240
241 CertPathBuilderResult buildResult = CertPathBuilder.getInstance("PKIX").build(pbParams);
242
243
244 CertPathValidator.getInstance("PKIX").validate(buildResult.getCertPath(),pbParams);
245 }
246 catch (GeneralSecurityException gse)
247 {
248 LOG.debug(gse);
249 throw new CertificateException("Unable to validate certificate: " + gse.getMessage(), gse);
250 }
251 }
252
253 public KeyStore getTrustStore()
254 {
255 return _trustStore;
256 }
257
258 public Collection<? extends CRL> getCrls()
259 {
260 return _crls;
261 }
262
263
264
265
266
267 public int getMaxCertPathLength()
268 {
269 return _maxCertPathLength;
270 }
271
272
273
274
275
276
277
278 public void setMaxCertPathLength(int maxCertPathLength)
279 {
280 _maxCertPathLength = maxCertPathLength;
281 }
282
283
284
285
286
287 public boolean isEnableCRLDP()
288 {
289 return _enableCRLDP;
290 }
291
292
293
294
295
296 public void setEnableCRLDP(boolean enableCRLDP)
297 {
298 _enableCRLDP = enableCRLDP;
299 }
300
301
302
303
304
305 public boolean isEnableOCSP()
306 {
307 return _enableOCSP;
308 }
309
310
311
312
313
314 public void setEnableOCSP(boolean enableOCSP)
315 {
316 _enableOCSP = enableOCSP;
317 }
318
319
320
321
322
323 public String getOcspResponderURL()
324 {
325 return _ocspResponderURL;
326 }
327
328
329
330
331
332 public void setOcspResponderURL(String ocspResponderURL)
333 {
334 _ocspResponderURL = ocspResponderURL;
335 }
336 }