1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.ws.soap.security.xwss.callback;
18
19 import java.io.IOException;
20 import java.math.BigInteger;
21 import java.security.GeneralSecurityException;
22 import java.security.InvalidAlgorithmParameterException;
23 import java.security.KeyStore;
24 import java.security.PrivateKey;
25 import java.security.PublicKey;
26 import java.security.cert.CertPathBuilder;
27 import java.security.cert.CertPathBuilderException;
28 import java.security.cert.Certificate;
29 import java.security.cert.CertificateExpiredException;
30 import java.security.cert.CertificateNotYetValidException;
31 import java.security.cert.PKIXBuilderParameters;
32 import java.security.cert.X509CertSelector;
33 import java.security.cert.X509Certificate;
34 import java.util.Arrays;
35 import java.util.Enumeration;
36 import javax.crypto.SecretKey;
37
38 import com.sun.xml.wss.impl.callback.CertificateValidationCallback;
39 import com.sun.xml.wss.impl.callback.DecryptionKeyCallback;
40 import com.sun.xml.wss.impl.callback.EncryptionKeyCallback;
41 import com.sun.xml.wss.impl.callback.SignatureKeyCallback;
42 import com.sun.xml.wss.impl.callback.SignatureVerificationKeyCallback;
43 import org.apache.xml.security.utils.RFC2253Parser;
44
45 import org.springframework.beans.factory.InitializingBean;
46 import org.springframework.ws.soap.security.support.KeyStoreUtils;
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109 public class KeyStoreCallbackHandler extends CryptographyCallbackHandler implements InitializingBean {
110
111 private static final String X_509_CERTIFICATE_TYPE = "X.509";
112
113 private static final String SUBJECT_KEY_IDENTIFIER_OID = "2.5.29.14";
114
115 private KeyStore keyStore;
116
117 private KeyStore symmetricStore;
118
119 private KeyStore trustStore;
120
121 private String defaultAlias;
122
123 private char[] privateKeyPassword;
124
125 private char[] symmetricKeyPassword;
126
127 private static X509Certificate getCertificate(String alias, KeyStore store) throws IOException {
128 try {
129 return (X509Certificate) store.getCertificate(alias);
130 }
131 catch (GeneralSecurityException e) {
132 throw new IOException(e.getMessage());
133 }
134 }
135
136 private static X509Certificate getCertificate(PublicKey pk, KeyStore store) throws IOException {
137 try {
138 Enumeration aliases = store.aliases();
139 while (aliases.hasMoreElements()) {
140 String alias = (String) aliases.nextElement();
141 Certificate cert = store.getCertificate(alias);
142 if (cert == null || !X_509_CERTIFICATE_TYPE.equals(cert.getType())) {
143 continue;
144 }
145 X509Certificate x509Cert = (X509Certificate) cert;
146 if (x509Cert.getPublicKey().equals(pk)) {
147 return x509Cert;
148 }
149 }
150 }
151 catch (GeneralSecurityException e) {
152 throw new IOException(e.getMessage());
153 }
154 return null;
155 }
156
157
158 public void setDefaultAlias(String defaultAlias) {
159 this.defaultAlias = defaultAlias;
160 }
161
162
163
164
165
166
167
168
169 public void setKeyStore(KeyStore keyStore) {
170 this.keyStore = keyStore;
171 }
172
173
174
175
176
177 public void setPrivateKeyPassword(String privateKeyPassword) {
178 if (privateKeyPassword != null) {
179 this.privateKeyPassword = privateKeyPassword.toCharArray();
180 }
181 }
182
183
184
185
186
187
188
189 public void setSymmetricKeyPassword(String symmetricKeyPassword) {
190 if (symmetricKeyPassword != null) {
191 this.symmetricKeyPassword = symmetricKeyPassword.toCharArray();
192 }
193 }
194
195
196
197
198
199
200
201
202 public void setSymmetricStore(KeyStore symmetricStore) {
203 this.symmetricStore = symmetricStore;
204 }
205
206
207
208
209
210
211
212
213 public void setTrustStore(KeyStore trustStore) {
214 this.trustStore = trustStore;
215 }
216
217 public void afterPropertiesSet() throws Exception {
218 if (keyStore == null) {
219 loadDefaultKeyStore();
220 }
221 if (trustStore == null) {
222 loadDefaultTrustStore();
223 }
224 if (symmetricStore == null) {
225 symmetricStore = keyStore;
226 }
227 if (symmetricKeyPassword == null) {
228 symmetricKeyPassword = privateKeyPassword;
229 }
230 }
231
232 protected final void handleAliasPrivKeyCertRequest(SignatureKeyCallback callback,
233 SignatureKeyCallback.AliasPrivKeyCertRequest request)
234 throws IOException {
235 PrivateKey privateKey = getPrivateKey(request.getAlias());
236 X509Certificate certificate = getCertificate(request.getAlias());
237 request.setPrivateKey(privateKey);
238 request.setX509Certificate(certificate);
239 }
240
241 protected final void handleAliasSymmetricKeyRequest(DecryptionKeyCallback callback,
242 DecryptionKeyCallback.AliasSymmetricKeyRequest request)
243 throws IOException {
244 SecretKey secretKey = getSymmetricKey(request.getAlias());
245 request.setSymmetricKey(secretKey);
246 }
247
248
249
250
251
252 protected final void handleAliasSymmetricKeyRequest(EncryptionKeyCallback callback,
253 EncryptionKeyCallback.AliasSymmetricKeyRequest request)
254 throws IOException {
255 SecretKey secretKey = getSymmetricKey(request.getAlias());
256 request.setSymmetricKey(secretKey);
257 }
258
259 protected final void handleAliasX509CertificateRequest(EncryptionKeyCallback callback,
260 EncryptionKeyCallback.AliasX509CertificateRequest request)
261 throws IOException {
262 X509Certificate certificate = getCertificateFromTrustStore(request.getAlias());
263 request.setX509Certificate(certificate);
264 }
265
266
267
268
269
270 protected final void handleCertificateValidationCallback(CertificateValidationCallback callback) {
271 callback.setValidator(new KeyStoreCertificateValidator());
272 }
273
274
275
276
277
278 protected final void handleDefaultPrivKeyCertRequest(SignatureKeyCallback callback,
279 SignatureKeyCallback.DefaultPrivKeyCertRequest request)
280 throws IOException {
281 PrivateKey privateKey = getPrivateKey(defaultAlias);
282 X509Certificate certificate = getCertificate(defaultAlias);
283 request.setPrivateKey(privateKey);
284 request.setX509Certificate(certificate);
285 }
286
287 protected final void handleDefaultX509CertificateRequest(EncryptionKeyCallback callback,
288 EncryptionKeyCallback.DefaultX509CertificateRequest request)
289 throws IOException {
290 X509Certificate certificate = getCertificateFromTrustStore(defaultAlias);
291 request.setX509Certificate(certificate);
292 }
293
294 protected final void handlePublicKeyBasedPrivKeyCertRequest(SignatureKeyCallback callback,
295 SignatureKeyCallback.PublicKeyBasedPrivKeyCertRequest request)
296 throws IOException {
297 PrivateKey privateKey = getPrivateKey(request.getPublicKey());
298 X509Certificate certificate = getCertificate(request.getPublicKey());
299 request.setPrivateKey(privateKey);
300 request.setX509Certificate(certificate);
301 }
302
303
304
305
306 protected final void handlePublicKeyBasedPrivKeyRequest(DecryptionKeyCallback callback,
307 DecryptionKeyCallback.PublicKeyBasedPrivKeyRequest request)
308 throws IOException {
309 PrivateKey key = getPrivateKey(request.getPublicKey());
310 request.setPrivateKey(key);
311 }
312
313 protected final void handlePublicKeyBasedRequest(EncryptionKeyCallback callback,
314 EncryptionKeyCallback.PublicKeyBasedRequest request)
315 throws IOException {
316 X509Certificate certificate = getCertificateFromTrustStore(request.getPublicKey());
317 request.setX509Certificate(certificate);
318 }
319
320 protected final void handlePublicKeyBasedRequest(SignatureVerificationKeyCallback callback,
321 SignatureVerificationKeyCallback.PublicKeyBasedRequest request)
322 throws IOException {
323 X509Certificate certificate = getCertificateFromTrustStore(request.getPublicKey());
324 request.setX509Certificate(certificate);
325 }
326
327 protected final void handleX509CertificateBasedRequest(DecryptionKeyCallback callback,
328 DecryptionKeyCallback.X509CertificateBasedRequest request)
329 throws IOException {
330 PrivateKey privKey = getPrivateKey(request.getX509Certificate());
331 request.setPrivateKey(privKey);
332 }
333
334 protected final void handleX509IssuerSerialBasedRequest(DecryptionKeyCallback callback,
335 DecryptionKeyCallback.X509IssuerSerialBasedRequest request)
336 throws IOException {
337 PrivateKey key = getPrivateKey(request.getIssuerName(), request.getSerialNumber());
338 request.setPrivateKey(key);
339 }
340
341 protected final void handleX509IssuerSerialBasedRequest(SignatureVerificationKeyCallback callback,
342 SignatureVerificationKeyCallback.X509IssuerSerialBasedRequest request)
343 throws IOException {
344 X509Certificate certificate = getCertificateFromTrustStore(request.getIssuerName(), request.getSerialNumber());
345 request.setX509Certificate(certificate);
346 }
347
348 protected final void handleX509SubjectKeyIdentifierBasedRequest(DecryptionKeyCallback callback,
349 DecryptionKeyCallback.X509SubjectKeyIdentifierBasedRequest request)
350 throws IOException {
351 PrivateKey key = getPrivateKey(request.getSubjectKeyIdentifier());
352 request.setPrivateKey(key);
353 }
354
355
356
357
358
359 protected final void handleX509SubjectKeyIdentifierBasedRequest(SignatureVerificationKeyCallback callback,
360 SignatureVerificationKeyCallback.X509SubjectKeyIdentifierBasedRequest request)
361 throws IOException {
362 X509Certificate certificate = getCertificateFromTrustStore(request.getSubjectKeyIdentifier());
363 request.setX509Certificate(certificate);
364 }
365
366
367
368 protected X509Certificate getCertificate(String alias) throws IOException {
369 return getCertificate(alias, keyStore);
370 }
371
372 protected X509Certificate getCertificate(PublicKey pk) throws IOException {
373 return getCertificate(pk, keyStore);
374 }
375
376 protected X509Certificate getCertificateFromTrustStore(String alias) throws IOException {
377 return getCertificate(alias, trustStore);
378 }
379
380 protected X509Certificate getCertificateFromTrustStore(byte[] subjectKeyIdentifier) throws IOException {
381 try {
382 Enumeration aliases = trustStore.aliases();
383 while (aliases.hasMoreElements()) {
384 String alias = (String) aliases.nextElement();
385 Certificate cert = trustStore.getCertificate(alias);
386 if (cert == null || !X_509_CERTIFICATE_TYPE.equals(cert.getType())) {
387 continue;
388 }
389 X509Certificate x509Cert = (X509Certificate) cert;
390 byte[] keyId = getSubjectKeyIdentifier(x509Cert);
391 if (keyId == null) {
392
393 continue;
394 }
395 if (Arrays.equals(subjectKeyIdentifier, keyId)) {
396 return x509Cert;
397 }
398 }
399 }
400 catch (GeneralSecurityException e) {
401 throw new IOException(e.getMessage());
402 }
403 return null;
404 }
405
406 protected X509Certificate getCertificateFromTrustStore(PublicKey pk) throws IOException {
407 return getCertificate(pk, trustStore);
408 }
409
410 protected X509Certificate getCertificateFromTrustStore(String issuerName, BigInteger serialNumber)
411 throws IOException {
412 try {
413 Enumeration aliases = trustStore.aliases();
414 while (aliases.hasMoreElements()) {
415 String alias = (String) aliases.nextElement();
416 Certificate cert = trustStore.getCertificate(alias);
417 if (cert == null || !X_509_CERTIFICATE_TYPE.equals(cert.getType())) {
418 continue;
419 }
420 X509Certificate x509Cert = (X509Certificate) cert;
421 String thisIssuerName = RFC2253Parser.normalize(x509Cert.getIssuerDN().getName());
422 BigInteger thisSerialNumber = x509Cert.getSerialNumber();
423 if (thisIssuerName.equals(issuerName) && thisSerialNumber.equals(serialNumber)) {
424 return x509Cert;
425 }
426 }
427 }
428 catch (GeneralSecurityException e) {
429 throw new IOException(e.getMessage());
430 }
431 return null;
432 }
433
434
435
436 protected PrivateKey getPrivateKey(String alias) throws IOException {
437 try {
438 return (PrivateKey) keyStore.getKey(alias, privateKeyPassword);
439 }
440 catch (GeneralSecurityException e) {
441 throw new IOException(e.getMessage());
442 }
443 }
444
445 protected PrivateKey getPrivateKey(PublicKey publicKey) throws IOException {
446 try {
447 Enumeration aliases = keyStore.aliases();
448 while (aliases.hasMoreElements()) {
449 String alias = (String) aliases.nextElement();
450 if (keyStore.isKeyEntry(alias)) {
451
452 return (PrivateKey) keyStore.getKey(alias, privateKeyPassword);
453 }
454 }
455 }
456 catch (GeneralSecurityException e) {
457 throw new IOException(e.getMessage());
458 }
459 return null;
460 }
461
462 protected PrivateKey getPrivateKey(X509Certificate certificate) throws IOException {
463 try {
464 Enumeration aliases = keyStore.aliases();
465 while (aliases.hasMoreElements()) {
466 String alias = (String) aliases.nextElement();
467 if (!keyStore.isKeyEntry(alias)) {
468 continue;
469 }
470 Certificate cert = keyStore.getCertificate(alias);
471 if (cert != null && cert.equals(certificate)) {
472 return (PrivateKey) keyStore.getKey(alias, privateKeyPassword);
473 }
474 }
475 }
476 catch (GeneralSecurityException e) {
477 throw new IOException(e.getMessage());
478 }
479 return null;
480 }
481
482 protected PrivateKey getPrivateKey(byte[] keyIdentifier) throws IOException {
483 try {
484 Enumeration aliases = keyStore.aliases();
485 while (aliases.hasMoreElements()) {
486 String alias = (String) aliases.nextElement();
487 if (!keyStore.isKeyEntry(alias)) {
488 continue;
489 }
490 Certificate cert = keyStore.getCertificate(alias);
491 if (cert == null || !"X.509".equals(cert.getType())) {
492 continue;
493 }
494 X509Certificate x509Cert = (X509Certificate) cert;
495 byte[] keyId = getSubjectKeyIdentifier(x509Cert);
496 if (keyId == null) {
497
498 continue;
499 }
500 if (Arrays.equals(keyIdentifier, keyId)) {
501 return (PrivateKey) keyStore.getKey(alias, privateKeyPassword);
502 }
503 }
504 }
505 catch (GeneralSecurityException e) {
506 throw new IOException(e.getMessage());
507 }
508 return null;
509 }
510
511 protected PrivateKey getPrivateKey(String issuerName, BigInteger serialNumber) throws IOException {
512 try {
513 Enumeration aliases = keyStore.aliases();
514 while (aliases.hasMoreElements()) {
515 String alias = (String) aliases.nextElement();
516 if (!keyStore.isKeyEntry(alias)) {
517 continue;
518 }
519 Certificate cert = keyStore.getCertificate(alias);
520 if (cert == null || !"X.509".equals(cert.getType())) {
521 continue;
522 }
523 X509Certificate x509Cert = (X509Certificate) cert;
524 String thisIssuerName = RFC2253Parser.normalize(x509Cert.getIssuerDN().getName());
525 BigInteger thisSerialNumber = x509Cert.getSerialNumber();
526 if (thisIssuerName.equals(issuerName) && thisSerialNumber.equals(serialNumber)) {
527 return (PrivateKey) keyStore.getKey(alias, privateKeyPassword);
528 }
529 }
530 }
531 catch (GeneralSecurityException e) {
532 throw new IOException(e.getMessage());
533 }
534 return null;
535 }
536
537
538
539 protected final byte[] getSubjectKeyIdentifier(X509Certificate cert) {
540 byte[] subjectKeyIdentifier = cert.getExtensionValue(SUBJECT_KEY_IDENTIFIER_OID);
541 if (subjectKeyIdentifier == null) {
542 return null;
543 }
544 byte[] dest = new byte[subjectKeyIdentifier.length - 4];
545 System.arraycopy(subjectKeyIdentifier, 4, dest, 0, subjectKeyIdentifier.length - 4);
546 return dest;
547 }
548
549
550
551
552
553 protected SecretKey getSymmetricKey(String alias) throws IOException {
554 try {
555 return (SecretKey) symmetricStore.getKey(alias, symmetricKeyPassword);
556 }
557 catch (GeneralSecurityException e) {
558 throw new IOException(e.getMessage());
559 }
560 }
561
562
563 protected void loadDefaultKeyStore() {
564 try {
565 keyStore = KeyStoreUtils.loadDefaultKeyStore();
566 if (logger.isDebugEnabled()) {
567 logger.debug("Loaded default key store");
568 }
569 }
570 catch (Exception ex) {
571 logger.warn("Could not open default key store", ex);
572 }
573 }
574
575
576 protected void loadDefaultTrustStore() {
577 try {
578 trustStore = KeyStoreUtils.loadDefaultTrustStore();
579 if (logger.isDebugEnabled()) {
580 logger.debug("Loaded default trust store");
581 }
582 }
583 catch (Exception ex) {
584 logger.warn("Could not open default trust store", ex);
585 }
586 }
587
588
589
590
591
592 private class KeyStoreCertificateValidator implements CertificateValidationCallback.CertificateValidator {
593
594 public boolean validate(X509Certificate certificate)
595 throws CertificateValidationCallback.CertificateValidationException {
596 if (isOwnedCert(certificate)) {
597 if (logger.isDebugEnabled()) {
598 logger.debug("Certificate with DN [" + certificate.getSubjectX500Principal().getName() +
599 "] is in private keystore");
600 }
601 return true;
602 }
603 else if (trustStore == null) {
604 return false;
605 }
606
607 try {
608 certificate.checkValidity();
609 }
610 catch (CertificateExpiredException e) {
611 if (logger.isDebugEnabled()) {
612 logger.debug("Certificate with DN [" + certificate.getSubjectX500Principal().getName() +
613 "] has expired");
614 }
615 return false;
616 }
617 catch (CertificateNotYetValidException e) {
618 if (logger.isDebugEnabled()) {
619 logger.debug("Certificate with DN [" + certificate.getSubjectX500Principal().getName() +
620 "] is not yet valid");
621 }
622 return false;
623 }
624
625 X509CertSelector certSelector = new X509CertSelector();
626 certSelector.setCertificate(certificate);
627
628 PKIXBuilderParameters parameters;
629 CertPathBuilder builder;
630 try {
631 parameters = new PKIXBuilderParameters(trustStore, certSelector);
632 parameters.setRevocationEnabled(false);
633 builder = CertPathBuilder.getInstance("PKIX");
634 }
635 catch (GeneralSecurityException ex) {
636 throw new CertificateValidationCallback.CertificateValidationException(
637 "Could not create PKIX CertPathBuilder", ex);
638 }
639
640 try {
641 builder.build(parameters);
642 }
643 catch (CertPathBuilderException e) {
644 if (logger.isDebugEnabled()) {
645 logger.debug("Certification path of certificate with DN [" +
646 certificate.getSubjectX500Principal().getName() + "] could not be validated");
647 }
648 return false;
649 }
650 catch (InvalidAlgorithmParameterException e) {
651 if (logger.isDebugEnabled()) {
652 logger.debug("Algorithm of certificate with DN [" +
653 certificate.getSubjectX500Principal().getName() + "] could not be validated");
654 }
655 return false;
656 }
657 if (logger.isDebugEnabled()) {
658 logger.debug("Certificate with DN [" + certificate.getSubjectX500Principal().getName() + "] validated");
659 }
660 return true;
661 }
662
663 private boolean isOwnedCert(X509Certificate cert)
664 throws CertificateValidationCallback.CertificateValidationException {
665 if (keyStore == null) {
666 return false;
667 }
668 try {
669 Enumeration aliases = keyStore.aliases();
670 while (aliases.hasMoreElements()) {
671 String alias = (String) aliases.nextElement();
672 if (keyStore.isKeyEntry(alias)) {
673 X509Certificate x509Cert = (X509Certificate) keyStore.getCertificate(alias);
674 if (x509Cert != null) {
675 if (x509Cert.equals(cert)) {
676 return true;
677 }
678 }
679 }
680 }
681 return false;
682 }
683 catch (GeneralSecurityException e) {
684 throw new CertificateValidationCallback.CertificateValidationException(
685 "Could not determine whether certificate is contained in main key store", e);
686 }
687 }
688 }
689 }