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 org.springframework.beans.factory.InitializingBean;
39 import org.springframework.ws.soap.security.support.KeyStoreUtils;
40
41 import com.sun.xml.wss.impl.callback.CertificateValidationCallback;
42 import com.sun.xml.wss.impl.callback.DecryptionKeyCallback;
43 import com.sun.xml.wss.impl.callback.EncryptionKeyCallback;
44 import com.sun.xml.wss.impl.callback.SignatureKeyCallback;
45 import com.sun.xml.wss.impl.callback.SignatureVerificationKeyCallback;
46 import org.apache.xml.security.utils.RFC2253Parser;
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<String> aliases = store.aliases();
139 while (aliases.hasMoreElements()) {
140 String alias = 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 @Override
233 protected final void handleAliasPrivKeyCertRequest(SignatureKeyCallback callback,
234 SignatureKeyCallback.AliasPrivKeyCertRequest request)
235 throws IOException {
236 PrivateKey privateKey = getPrivateKey(request.getAlias());
237 X509Certificate certificate = getCertificate(request.getAlias());
238 request.setPrivateKey(privateKey);
239 request.setX509Certificate(certificate);
240 }
241
242 @Override
243 protected final void handleAliasSymmetricKeyRequest(DecryptionKeyCallback callback,
244 DecryptionKeyCallback.AliasSymmetricKeyRequest request)
245 throws IOException {
246 SecretKey secretKey = getSymmetricKey(request.getAlias());
247 request.setSymmetricKey(secretKey);
248 }
249
250
251
252
253
254 @Override
255 protected final void handleAliasSymmetricKeyRequest(EncryptionKeyCallback callback,
256 EncryptionKeyCallback.AliasSymmetricKeyRequest request)
257 throws IOException {
258 SecretKey secretKey = getSymmetricKey(request.getAlias());
259 request.setSymmetricKey(secretKey);
260 }
261
262 @Override
263 protected final void handleAliasX509CertificateRequest(EncryptionKeyCallback callback,
264 EncryptionKeyCallback.AliasX509CertificateRequest request)
265 throws IOException {
266 X509Certificate certificate = getCertificateFromTrustStore(request.getAlias());
267 request.setX509Certificate(certificate);
268 }
269
270
271
272
273
274 @Override
275 protected final void handleCertificateValidationCallback(CertificateValidationCallback callback) {
276 callback.setValidator(new KeyStoreCertificateValidator());
277 }
278
279
280
281
282
283 @Override
284 protected final void handleDefaultPrivKeyCertRequest(SignatureKeyCallback callback,
285 SignatureKeyCallback.DefaultPrivKeyCertRequest request)
286 throws IOException {
287 PrivateKey privateKey = getPrivateKey(defaultAlias);
288 X509Certificate certificate = getCertificate(defaultAlias);
289 request.setPrivateKey(privateKey);
290 request.setX509Certificate(certificate);
291 }
292
293 @Override
294 protected final void handleDefaultX509CertificateRequest(EncryptionKeyCallback callback,
295 EncryptionKeyCallback.DefaultX509CertificateRequest request)
296 throws IOException {
297 X509Certificate certificate = getCertificateFromTrustStore(defaultAlias);
298 request.setX509Certificate(certificate);
299 }
300
301 @Override
302 protected final void handlePublicKeyBasedPrivKeyCertRequest(SignatureKeyCallback callback,
303 SignatureKeyCallback.PublicKeyBasedPrivKeyCertRequest request)
304 throws IOException {
305 PrivateKey privateKey = getPrivateKey(request.getPublicKey());
306 X509Certificate certificate = getCertificate(request.getPublicKey());
307 request.setPrivateKey(privateKey);
308 request.setX509Certificate(certificate);
309 }
310
311
312
313
314 @Override
315 protected final void handlePublicKeyBasedPrivKeyRequest(DecryptionKeyCallback callback,
316 DecryptionKeyCallback.PublicKeyBasedPrivKeyRequest request)
317 throws IOException {
318 PrivateKey key = getPrivateKey(request.getPublicKey());
319 request.setPrivateKey(key);
320 }
321
322 @Override
323 protected final void handlePublicKeyBasedRequest(EncryptionKeyCallback callback,
324 EncryptionKeyCallback.PublicKeyBasedRequest request)
325 throws IOException {
326 X509Certificate certificate = getCertificateFromTrustStore(request.getPublicKey());
327 request.setX509Certificate(certificate);
328 }
329
330 @Override
331 protected final void handlePublicKeyBasedRequest(SignatureVerificationKeyCallback callback,
332 SignatureVerificationKeyCallback.PublicKeyBasedRequest request)
333 throws IOException {
334 X509Certificate certificate = getCertificateFromTrustStore(request.getPublicKey());
335 request.setX509Certificate(certificate);
336 }
337
338 @Override
339 protected final void handleX509CertificateBasedRequest(DecryptionKeyCallback callback,
340 DecryptionKeyCallback.X509CertificateBasedRequest request)
341 throws IOException {
342 PrivateKey privKey = getPrivateKey(request.getX509Certificate());
343 request.setPrivateKey(privKey);
344 }
345
346 @Override
347 protected final void handleX509IssuerSerialBasedRequest(DecryptionKeyCallback callback,
348 DecryptionKeyCallback.X509IssuerSerialBasedRequest request)
349 throws IOException {
350 PrivateKey key = getPrivateKey(request.getIssuerName(), request.getSerialNumber());
351 request.setPrivateKey(key);
352 }
353
354 @Override
355 protected final void handleX509IssuerSerialBasedRequest(SignatureVerificationKeyCallback callback,
356 SignatureVerificationKeyCallback.X509IssuerSerialBasedRequest request)
357 throws IOException {
358 X509Certificate certificate = getCertificateFromTrustStore(request.getIssuerName(), request.getSerialNumber());
359 request.setX509Certificate(certificate);
360 }
361
362 @Override
363 protected final void handleX509SubjectKeyIdentifierBasedRequest(DecryptionKeyCallback callback,
364 DecryptionKeyCallback.X509SubjectKeyIdentifierBasedRequest request)
365 throws IOException {
366 PrivateKey key = getPrivateKey(request.getSubjectKeyIdentifier());
367 request.setPrivateKey(key);
368 }
369
370
371
372
373
374 @Override
375 protected final void handleX509SubjectKeyIdentifierBasedRequest(SignatureVerificationKeyCallback callback,
376 SignatureVerificationKeyCallback.X509SubjectKeyIdentifierBasedRequest request)
377 throws IOException {
378 X509Certificate certificate = getCertificateFromTrustStore(request.getSubjectKeyIdentifier());
379 request.setX509Certificate(certificate);
380 }
381
382
383
384 protected X509Certificate getCertificate(String alias) throws IOException {
385 return getCertificate(alias, keyStore);
386 }
387
388 protected X509Certificate getCertificate(PublicKey pk) throws IOException {
389 return getCertificate(pk, keyStore);
390 }
391
392 protected X509Certificate getCertificateFromTrustStore(String alias) throws IOException {
393 return getCertificate(alias, trustStore);
394 }
395
396 protected X509Certificate getCertificateFromTrustStore(byte[] subjectKeyIdentifier) throws IOException {
397 try {
398 Enumeration<String> aliases = trustStore.aliases();
399 while (aliases.hasMoreElements()) {
400 String alias = aliases.nextElement();
401 Certificate cert = trustStore.getCertificate(alias);
402 if (cert == null || !X_509_CERTIFICATE_TYPE.equals(cert.getType())) {
403 continue;
404 }
405 X509Certificate x509Cert = (X509Certificate) cert;
406 byte[] keyId = getSubjectKeyIdentifier(x509Cert);
407 if (keyId == null) {
408
409 continue;
410 }
411 if (Arrays.equals(subjectKeyIdentifier, keyId)) {
412 return x509Cert;
413 }
414 }
415 }
416 catch (GeneralSecurityException e) {
417 throw new IOException(e.getMessage());
418 }
419 return null;
420 }
421
422 protected X509Certificate getCertificateFromTrustStore(PublicKey pk) throws IOException {
423 return getCertificate(pk, trustStore);
424 }
425
426 protected X509Certificate getCertificateFromTrustStore(String issuerName, BigInteger serialNumber)
427 throws IOException {
428 try {
429 Enumeration<String> aliases = trustStore.aliases();
430 while (aliases.hasMoreElements()) {
431 String alias = aliases.nextElement();
432 Certificate cert = trustStore.getCertificate(alias);
433 if (cert == null || !X_509_CERTIFICATE_TYPE.equals(cert.getType())) {
434 continue;
435 }
436 X509Certificate x509Cert = (X509Certificate) cert;
437 String thisIssuerName = RFC2253Parser.normalize(x509Cert.getIssuerDN().getName());
438 BigInteger thisSerialNumber = x509Cert.getSerialNumber();
439 if (thisIssuerName.equals(issuerName) && thisSerialNumber.equals(serialNumber)) {
440 return x509Cert;
441 }
442 }
443 }
444 catch (GeneralSecurityException e) {
445 throw new IOException(e.getMessage());
446 }
447 return null;
448 }
449
450
451
452 protected PrivateKey getPrivateKey(String alias) throws IOException {
453 try {
454 return (PrivateKey) keyStore.getKey(alias, privateKeyPassword);
455 }
456 catch (GeneralSecurityException e) {
457 throw new IOException(e.getMessage());
458 }
459 }
460
461 protected PrivateKey getPrivateKey(PublicKey publicKey) throws IOException {
462 try {
463 Enumeration<String> aliases = keyStore.aliases();
464 while (aliases.hasMoreElements()) {
465 String alias = aliases.nextElement();
466 if (keyStore.isKeyEntry(alias)) {
467
468 return (PrivateKey) keyStore.getKey(alias, privateKeyPassword);
469 }
470 }
471 }
472 catch (GeneralSecurityException e) {
473 throw new IOException(e.getMessage());
474 }
475 return null;
476 }
477
478 protected PrivateKey getPrivateKey(X509Certificate certificate) throws IOException {
479 try {
480 Enumeration<String> aliases = keyStore.aliases();
481 while (aliases.hasMoreElements()) {
482 String alias = aliases.nextElement();
483 if (!keyStore.isKeyEntry(alias)) {
484 continue;
485 }
486 Certificate cert = keyStore.getCertificate(alias);
487 if (cert != null && cert.equals(certificate)) {
488 return (PrivateKey) keyStore.getKey(alias, privateKeyPassword);
489 }
490 }
491 }
492 catch (GeneralSecurityException e) {
493 throw new IOException(e.getMessage());
494 }
495 return null;
496 }
497
498 protected PrivateKey getPrivateKey(byte[] keyIdentifier) throws IOException {
499 try {
500 Enumeration<String> aliases = keyStore.aliases();
501 while (aliases.hasMoreElements()) {
502 String alias = aliases.nextElement();
503 if (!keyStore.isKeyEntry(alias)) {
504 continue;
505 }
506 Certificate cert = keyStore.getCertificate(alias);
507 if (cert == null || !"X.509".equals(cert.getType())) {
508 continue;
509 }
510 X509Certificate x509Cert = (X509Certificate) cert;
511 byte[] keyId = getSubjectKeyIdentifier(x509Cert);
512 if (keyId == null) {
513
514 continue;
515 }
516 if (Arrays.equals(keyIdentifier, keyId)) {
517 return (PrivateKey) keyStore.getKey(alias, privateKeyPassword);
518 }
519 }
520 }
521 catch (GeneralSecurityException e) {
522 throw new IOException(e.getMessage());
523 }
524 return null;
525 }
526
527 protected PrivateKey getPrivateKey(String issuerName, BigInteger serialNumber) throws IOException {
528 try {
529 Enumeration<String> aliases = keyStore.aliases();
530 while (aliases.hasMoreElements()) {
531 String alias = aliases.nextElement();
532 if (!keyStore.isKeyEntry(alias)) {
533 continue;
534 }
535 Certificate cert = keyStore.getCertificate(alias);
536 if (cert == null || !"X.509".equals(cert.getType())) {
537 continue;
538 }
539 X509Certificate x509Cert = (X509Certificate) cert;
540 String thisIssuerName = RFC2253Parser.normalize(x509Cert.getIssuerDN().getName());
541 BigInteger thisSerialNumber = x509Cert.getSerialNumber();
542 if (thisIssuerName.equals(issuerName) && thisSerialNumber.equals(serialNumber)) {
543 return (PrivateKey) keyStore.getKey(alias, privateKeyPassword);
544 }
545 }
546 }
547 catch (GeneralSecurityException e) {
548 throw new IOException(e.getMessage());
549 }
550 return null;
551 }
552
553
554
555 protected final byte[] getSubjectKeyIdentifier(X509Certificate cert) {
556 byte[] subjectKeyIdentifier = cert.getExtensionValue(SUBJECT_KEY_IDENTIFIER_OID);
557 if (subjectKeyIdentifier == null) {
558 return null;
559 }
560 byte[] dest = new byte[subjectKeyIdentifier.length - 4];
561 System.arraycopy(subjectKeyIdentifier, 4, dest, 0, subjectKeyIdentifier.length - 4);
562 return dest;
563 }
564
565
566
567
568
569 protected SecretKey getSymmetricKey(String alias) throws IOException {
570 try {
571 return (SecretKey) symmetricStore.getKey(alias, symmetricKeyPassword);
572 }
573 catch (GeneralSecurityException e) {
574 throw new IOException(e.getMessage());
575 }
576 }
577
578
579 protected void loadDefaultKeyStore() {
580 try {
581 keyStore = KeyStoreUtils.loadDefaultKeyStore();
582 if (logger.isDebugEnabled()) {
583 logger.debug("Loaded default key store");
584 }
585 }
586 catch (Exception ex) {
587 logger.warn("Could not open default key store", ex);
588 }
589 }
590
591
592 protected void loadDefaultTrustStore() {
593 try {
594 trustStore = KeyStoreUtils.loadDefaultTrustStore();
595 if (logger.isDebugEnabled()) {
596 logger.debug("Loaded default trust store");
597 }
598 }
599 catch (Exception ex) {
600 logger.warn("Could not open default trust store", ex);
601 }
602 }
603
604
605
606
607
608 private class KeyStoreCertificateValidator implements CertificateValidationCallback.CertificateValidator {
609
610 public boolean validate(X509Certificate certificate)
611 throws CertificateValidationCallback.CertificateValidationException {
612 if (isOwnedCert(certificate)) {
613 if (logger.isDebugEnabled()) {
614 logger.debug("Certificate with DN [" + certificate.getSubjectX500Principal().getName() +
615 "] is in private keystore");
616 }
617 return true;
618 }
619 else if (trustStore == null) {
620 return false;
621 }
622
623 try {
624 certificate.checkValidity();
625 }
626 catch (CertificateExpiredException e) {
627 if (logger.isDebugEnabled()) {
628 logger.debug("Certificate with DN [" + certificate.getSubjectX500Principal().getName() +
629 "] has expired");
630 }
631 return false;
632 }
633 catch (CertificateNotYetValidException e) {
634 if (logger.isDebugEnabled()) {
635 logger.debug("Certificate with DN [" + certificate.getSubjectX500Principal().getName() +
636 "] is not yet valid");
637 }
638 return false;
639 }
640
641 X509CertSelector certSelector = new X509CertSelector();
642 certSelector.setCertificate(certificate);
643
644 PKIXBuilderParameters parameters;
645 CertPathBuilder builder;
646 try {
647 parameters = new PKIXBuilderParameters(trustStore, certSelector);
648 parameters.setRevocationEnabled(false);
649 builder = CertPathBuilder.getInstance("PKIX");
650 }
651 catch (GeneralSecurityException ex) {
652 throw new CertificateValidationCallback.CertificateValidationException(
653 "Could not create PKIX CertPathBuilder", ex);
654 }
655
656 try {
657 builder.build(parameters);
658 }
659 catch (CertPathBuilderException e) {
660 if (logger.isDebugEnabled()) {
661 logger.debug("Certification path of certificate with DN [" +
662 certificate.getSubjectX500Principal().getName() + "] could not be validated");
663 }
664 return false;
665 }
666 catch (InvalidAlgorithmParameterException e) {
667 if (logger.isDebugEnabled()) {
668 logger.debug("Algorithm of certificate with DN [" +
669 certificate.getSubjectX500Principal().getName() + "] could not be validated");
670 }
671 return false;
672 }
673 if (logger.isDebugEnabled()) {
674 logger.debug("Certificate with DN [" + certificate.getSubjectX500Principal().getName() + "] validated");
675 }
676 return true;
677 }
678
679 private boolean isOwnedCert(X509Certificate cert)
680 throws CertificateValidationCallback.CertificateValidationException {
681 if (keyStore == null) {
682 return false;
683 }
684 try {
685 Enumeration<String> aliases = keyStore.aliases();
686 while (aliases.hasMoreElements()) {
687 String alias = aliases.nextElement();
688 if (keyStore.isKeyEntry(alias)) {
689 X509Certificate x509Cert = (X509Certificate) keyStore.getCertificate(alias);
690 if (x509Cert != null) {
691 if (x509Cert.equals(cert)) {
692 return true;
693 }
694 }
695 }
696 }
697 return false;
698 }
699 catch (GeneralSecurityException e) {
700 throw new CertificateValidationCallback.CertificateValidationException(
701 "Could not determine whether certificate is contained in main key store", e);
702 }
703 }
704 }
705 }