1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.wss4j.common.crypto;
21
22 import java.math.BigInteger;
23 import java.security.MessageDigest;
24 import java.security.NoSuchAlgorithmException;
25 import java.security.PrivateKey;
26 import java.security.PublicKey;
27 import java.security.cert.CertPath;
28 import java.security.cert.CertPathValidator;
29 import java.security.cert.CertificateEncodingException;
30 import java.security.cert.PKIXParameters;
31 import java.security.cert.TrustAnchor;
32 import java.security.cert.X509Certificate;
33 import java.util.Arrays;
34 import java.util.Collection;
35 import java.util.HashSet;
36 import java.util.List;
37 import java.util.Set;
38 import java.util.regex.Pattern;
39
40 import javax.security.auth.callback.CallbackHandler;
41 import javax.security.auth.x500.X500Principal;
42
43 import org.apache.wss4j.common.ext.WSSecurityException;
44
45
46
47
48
49 public class CertificateStore extends CryptoBase {
50
51 private static final org.slf4j.Logger LOG =
52 org.slf4j.LoggerFactory.getLogger(CertificateStore.class);
53
54 private X509Certificate[] trustedCerts;
55
56
57
58
59 public CertificateStore(X509Certificate[] trustedCerts) {
60 this.trustedCerts = trustedCerts;
61 }
62
63
64
65
66
67
68
69
70
71
72
73 public X509Certificate[] getX509Certificates(CryptoType cryptoType) throws WSSecurityException {
74 if (cryptoType == null) {
75 return new X509Certificate[0];
76 }
77 CryptoType.TYPE type = cryptoType.getType();
78 X509Certificate[] certs = new X509Certificate[0];
79 switch (type) {
80 case ISSUER_SERIAL:
81 certs = getX509Certificates(cryptoType.getIssuer(), cryptoType.getSerial());
82 break;
83 case THUMBPRINT_SHA1:
84 certs = getX509Certificates(cryptoType.getBytes());
85 break;
86 case SKI_BYTES:
87 certs = getX509CertificatesSKI(cryptoType.getBytes());
88 break;
89 case SUBJECT_DN:
90 certs = getX509CertificatesSubjectDN(cryptoType.getSubjectDN());
91 break;
92 case ALIAS:
93 throw new WSSecurityException(
94 WSSecurityException.ErrorCode.FAILURE, "generic.EmptyMessage",
95 new Object[] {"The alias CryptoType is not allowed for CertificateStore"}
96 );
97 case ENDPOINT:
98 break;
99 }
100 return certs;
101 }
102
103
104
105
106
107
108
109
110 public String getX509Identifier(X509Certificate cert) throws WSSecurityException {
111 return cert.getSubjectX500Principal().toString();
112 }
113
114
115
116
117
118
119
120
121 public PrivateKey getPrivateKey(
122 X509Certificate certificate, CallbackHandler callbackHandler
123 ) throws WSSecurityException {
124 return null;
125 }
126
127
128
129
130
131
132
133
134 public PrivateKey getPrivateKey(
135 PublicKey publicKey,
136 CallbackHandler callbackHandler
137 ) throws WSSecurityException {
138 return null;
139 }
140
141
142
143
144
145
146
147
148 public PrivateKey getPrivateKey(
149 String identifier,
150 String password
151 ) throws WSSecurityException {
152 return null;
153 }
154
155
156
157
158
159
160
161
162
163 protected void verifyTrust(
164 X509Certificate[] certs,
165 boolean enableRevocation,
166 Collection<Pattern> subjectCertConstraints
167 ) throws WSSecurityException {
168
169
170
171 if (certs.length == 1 && !enableRevocation) {
172 String issuerString = certs[0].getIssuerX500Principal().getName();
173 BigInteger issuerSerial = certs[0].getSerialNumber();
174
175 CryptoType cryptoType = new CryptoType(CryptoType.TYPE.ISSUER_SERIAL);
176 cryptoType.setIssuerSerial(issuerString, issuerSerial);
177 X509Certificate[] foundCerts = getX509Certificates(cryptoType);
178
179
180
181
182
183 if (foundCerts != null && foundCerts.length > 0 && foundCerts[0] != null && foundCerts[0].equals(certs[0])) {
184 LOG.debug(
185 "Direct trust for certificate with {}", certs[0].getSubjectX500Principal().getName()
186 );
187 return;
188 }
189 }
190
191
192
193
194
195
196 String issuerString = certs[0].getIssuerX500Principal().getName();
197 X509Certificate[] foundCerts = new X509Certificate[0];
198 if (certs.length == 1) {
199 CryptoType cryptoType = new CryptoType(CryptoType.TYPE.SUBJECT_DN);
200 cryptoType.setSubjectDN(issuerString);
201 foundCerts = getX509Certificates(cryptoType);
202
203
204
205 if (foundCerts == null || foundCerts.length < 1) {
206 String subjectString = certs[0].getSubjectX500Principal().getName();
207 LOG.debug(
208 "No certs found in keystore for issuer {} of certificate for {}", issuerString, subjectString
209 );
210 throw new WSSecurityException(
211 WSSecurityException.ErrorCode.FAILURE, "certpath",
212 new Object[] {"No trusted certs found"}
213 );
214 }
215 }
216
217
218
219
220
221 LOG.debug(
222 "Preparing to validate certificate path for issuer {}", issuerString
223 );
224
225 try {
226 Set<TrustAnchor> set = new HashSet<>();
227 if (trustedCerts != null) {
228 for (X509Certificate cert : trustedCerts) {
229 TrustAnchor anchor =
230 new TrustAnchor(cert, null);
231 set.add(anchor);
232 }
233 }
234
235
236 String provider = getCryptoProvider();
237 CertPathValidator validator = null;
238 if (provider == null || provider.length() == 0) {
239 validator = CertPathValidator.getInstance("PKIX");
240 } else {
241 validator = CertPathValidator.getInstance("PKIX", provider);
242 }
243
244 PKIXParameters param = new PKIXParameters(set);
245 param.setRevocationEnabled(enableRevocation);
246
247 if (foundCerts.length > 0) {
248
249
250
251
252 X509Certificate[] x509certs = new X509Certificate[foundCerts.length + 1];
253 x509certs[0] = certs[0];
254 System.arraycopy(foundCerts, 0, x509certs, 1, foundCerts.length);
255
256
257 List<X509Certificate> certList = Arrays.asList(x509certs);
258 CertPath path = getCertificateFactory().generateCertPath(certList);
259
260 validator.validate(path, param);
261 } else {
262 List<X509Certificate> certList = Arrays.asList(certs);
263 CertPath path = getCertificateFactory().generateCertPath(certList);
264
265 validator.validate(path, param);
266 }
267 } catch (java.security.NoSuchProviderException | NoSuchAlgorithmException
268 | java.security.cert.CertificateException
269 | java.security.InvalidAlgorithmParameterException
270 | java.security.cert.CertPathValidatorException e) {
271 throw new WSSecurityException(
272 WSSecurityException.ErrorCode.FAILURE, e, "certpath",
273 new Object[] {e.getMessage()}
274 );
275 }
276
277
278 if (!matchesSubjectDnPattern(certs[0], subjectCertConstraints)) {
279 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_AUTHENTICATION);
280 }
281 }
282
283 @Override
284 public void verifyTrust(X509Certificate[] certs, boolean enableRevocation, Collection<Pattern> subjectCertConstraints,
285 Collection<Pattern> issuerCertConstraints) throws WSSecurityException {
286 verifyTrust(certs, enableRevocation, subjectCertConstraints);
287 if (!matchesIssuerDnPattern(certs[0], issuerCertConstraints)) {
288 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_AUTHENTICATION);
289 }
290 }
291
292
293
294
295
296
297
298 public void verifyTrust(PublicKey publicKey) throws WSSecurityException {
299
300
301
302 if (publicKey == null) {
303 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_AUTHENTICATION);
304 }
305
306
307
308
309 for (X509Certificate trustedCert : trustedCerts) {
310 if (publicKey.equals(trustedCert.getPublicKey())) {
311 return;
312 }
313 }
314 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_AUTHENTICATION);
315 }
316
317
318
319
320
321
322
323
324
325 private X509Certificate[] getX509Certificates(
326 String issuer,
327 BigInteger serialNumber
328 ) throws WSSecurityException {
329
330
331
332
333
334
335
336
337 Object issuerName = null;
338 try {
339 X500Principal issuerRDN = new X500Principal(issuer);
340 issuerName = createBCX509Name(issuerRDN.getName());
341 } catch (IllegalArgumentException ex) {
342 issuerName = createBCX509Name(issuer);
343 }
344
345 for (X509Certificate trustedCert : trustedCerts) {
346 if (trustedCert.getSerialNumber().compareTo(serialNumber) == 0) {
347 Object certName =
348 createBCX509Name(trustedCert.getIssuerX500Principal().getName());
349 if (certName.equals(issuerName)) {
350 return new X509Certificate[]{trustedCert};
351 }
352 }
353 }
354
355 return new X509Certificate[0];
356 }
357
358
359
360
361
362
363
364
365 private X509Certificate[] getX509Certificates(byte[] thumb) throws WSSecurityException {
366 MessageDigest sha = null;
367
368 if (trustedCerts == null) {
369 return new X509Certificate[0];
370 }
371
372 try {
373 sha = MessageDigest.getInstance("SHA1");
374 } catch (NoSuchAlgorithmException e) {
375 throw new WSSecurityException(
376 WSSecurityException.ErrorCode.FAILURE, e, "decoding.general"
377 );
378 }
379 for (X509Certificate trustedCert : trustedCerts) {
380 try {
381 sha.update(trustedCert.getEncoded());
382 } catch (CertificateEncodingException ex) {
383 throw new WSSecurityException(
384 WSSecurityException.ErrorCode.SECURITY_TOKEN_UNAVAILABLE, ex, "encodeError"
385 );
386 }
387 byte[] data = sha.digest();
388
389 if (Arrays.equals(data, thumb)) {
390 return new X509Certificate[]{trustedCert};
391 }
392 }
393 return new X509Certificate[0];
394 }
395
396
397
398
399
400
401
402 private X509Certificate[] getX509CertificatesSKI(byte[] skiBytes) throws WSSecurityException {
403 if (trustedCerts == null) {
404 return new X509Certificate[0];
405 }
406 for (X509Certificate trustedCert : trustedCerts) {
407 byte[] data = getSKIBytesFromCert(trustedCert);
408 if (data.length == skiBytes.length && Arrays.equals(data, skiBytes)) {
409 return new X509Certificate[]{trustedCert};
410 }
411 }
412 return new X509Certificate[0];
413 }
414
415
416
417
418
419
420
421
422 private X509Certificate[] getX509CertificatesSubjectDN(String subjectDN)
423 throws WSSecurityException {
424
425
426
427
428
429
430
431
432 Object subject;
433 try {
434 X500Principal subjectRDN = new X500Principal(subjectDN);
435 subject = createBCX509Name(subjectRDN.getName());
436 } catch (IllegalArgumentException ex) {
437 subject = createBCX509Name(subjectDN);
438 }
439
440 if (trustedCerts != null) {
441 for (X509Certificate trustedCert : trustedCerts) {
442 X500Principal foundRDN = trustedCert.getSubjectX500Principal();
443 Object certName = createBCX509Name(foundRDN.getName());
444
445 if (subject.equals(certName)) {
446 return new X509Certificate[]{trustedCert};
447 }
448 }
449 }
450
451 return new X509Certificate[0];
452 }
453
454 }