View Javadoc

1   /*
2    * Copyright 2005-2010 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
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   * Callback handler that uses Java Security <code>KeyStore</code>s to handle cryptographic callbacks. Allows for
50   * specific key stores to be set for various cryptographic operations.
51   * <p/>
52   * This handler requires one or more key stores to be set. You can configure them in your application context by using a
53   * <code>KeyStoreFactoryBean</code>. The exact stores to be set depends on the cryptographic operations that are to be
54   * performed by this handler. The table underneath show the key store to be used for each operation: <table border="1">
55   * <tr> <td><strong>Cryptographic operation</strong></td> <td><strong>Key store used</strong></td> </tr> <tr>
56   * <td>Certificate validation</td> <td>first <code>keyStore</code>, then <code>trustStore</code></td> </tr> <tr>
57   * <td>Decryption based on private key</td> <td><code>keyStore</code></td> </tr> <tr> <td>Decryption based on symmetric
58   * key</td> <td><code>symmetricStore</code></td> </tr> <tr> <td>Encryption based on certificate</td>
59   * <td><code>trustStore</code></td> </tr> <tr> <td>Encryption based on symmetric key</td>
60   * <td><code>symmetricStore</code></td> </tr> <tr> <td>Signing</td> <td><code>keyStore</code></td> </tr> <tr>
61   * <td>Signature verification</td> <td><code>trustStore</code></td> </tr> </table>
62   * <p/>
63   * <h3>Default key stores</h3> If the <code>symmetricStore</code> is not set, it will default to the
64   * <code>keyStore</code>. If the key or trust store is not set, this handler will use the standard Java mechanism to
65   * load or create it. See {@link #loadDefaultKeyStore()} and {@link #loadDefaultTrustStore()}.
66   * <p/>
67   * <h3>Examples</h3> For instance, if you want to use the <code>KeyStoreCallbackHandler</code> to validate incoming
68   * certificates or signatures, you would use a trust store, like so:
69   * <pre>
70   * &lt;bean id="keyStoreHandler" class="org.springframework.ws.soap.security.xwss.callback.KeyStoreCallbackHandler"&gt;
71   *     &lt;property name="trustStore" ref="trustStore"/&gt;
72   * &lt;/bean&gt;
73   * <p/>
74   * &lt;bean id="trustStore" class="org.springframework.ws.soap.security.support.KeyStoreFactoryBean"&gt;
75   *     &lt;property name="location" value="classpath:truststore.jks"/&gt;
76   *     &lt;property name="password" value="changeit"/&gt;
77   * &lt;/bean&gt;
78   * </pre>
79   * If you want to use it to decrypt incoming certificates or sign outgoing messages, you would use a key store, like
80   * so:
81   * <pre>
82   * &lt;bean id="keyStoreHandler" class="org.springframework.ws.soap.security.xwss.callback.KeyStoreCallbackHandler"&gt;
83   *     &lt;property name="keyStore" ref="keyStore"/&gt;
84   *     &lt;property name="privateKeyPassword" value="changeit"/&gt;
85   * &lt;/bean&gt;
86   * <p/>
87   * &lt;bean id="keyStore" class="org.springframework.ws.soap.security.support.KeyStoreFactoryBean"&gt;
88   *     &lt;property name="location" value="classpath:keystore.jks"/&gt;
89   *     &lt;property name="password" value="changeit"/&gt;
90   * &lt;/bean&gt;
91   * </pre>
92   * <p/>
93   * <h3>Handled callbacks</h3> This class handles <code>CertificateValidationCallback</code>s,
94   * <code>DecryptionKeyCallback</code>s, <code>EncryptionKeyCallback</code>s, <code>SignatureKeyCallback</code>s, and
95   * <code>SignatureVerificationKeyCallback</code>s. It throws an <code>UnsupportedCallbackException</code> for others.
96   *
97   * @author Arjen Poutsma
98   * @see KeyStore
99   * @see org.springframework.ws.soap.security.support.KeyStoreFactoryBean
100  * @see CertificateValidationCallback
101  * @see DecryptionKeyCallback
102  * @see EncryptionKeyCallback
103  * @see SignatureKeyCallback
104  * @see SignatureVerificationKeyCallback
105  * @see <a href="http://java.sun.com/j2se/1.4.2/docs/guide/security/jsse/JSSERefGuide.html#X509TrustManager">The
106  *      standard Java trust store mechanism</a>
107  * @since 1.0.0
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     /** Sets the key store alias for the default certificate and private key. */
158     public void setDefaultAlias(String defaultAlias) {
159         this.defaultAlias = defaultAlias;
160     }
161 
162     /**
163      * Sets the default key store. This property is required for decription based on private keys, and signing. If this
164      * property is not set, a default key store is loaded.
165      *
166      * @see org.springframework.ws.soap.security.support.KeyStoreFactoryBean
167      * @see #loadDefaultTrustStore()
168      */
169     public void setKeyStore(KeyStore keyStore) {
170         this.keyStore = keyStore;
171     }
172 
173     /**
174      * Sets the password used to retrieve private keys from the keystore. This property is required for decription based
175      * on private keys, and signing.
176      */
177     public void setPrivateKeyPassword(String privateKeyPassword) {
178         if (privateKeyPassword != null) {
179             this.privateKeyPassword = privateKeyPassword.toCharArray();
180         }
181     }
182 
183     /**
184      * Sets the password used to retrieve keys from the symmetric keystore. If this property is not set, it default to
185      * the private key password.
186      *
187      * @see #setPrivateKeyPassword(String)
188      */
189     public void setSymmetricKeyPassword(String symmetricKeyPassword) {
190         if (symmetricKeyPassword != null) {
191             this.symmetricKeyPassword = symmetricKeyPassword.toCharArray();
192         }
193     }
194 
195     /**
196      * Sets the key store used for encryption and decryption using symmetric keys. If this property is not set, it
197      * defaults to the <code>keyStore</code> property.
198      *
199      * @see org.springframework.ws.soap.security.support.KeyStoreFactoryBean
200      * @see #setKeyStore(java.security.KeyStore)
201      */
202     public void setSymmetricStore(KeyStore symmetricStore) {
203         this.symmetricStore = symmetricStore;
204     }
205 
206     /**
207      * Sets the key store used for signature verifications and encryptions. If this property is not set, a default key
208      * store will be loaded.
209      *
210      * @see org.springframework.ws.soap.security.support.KeyStoreFactoryBean
211      * @see #loadDefaultTrustStore()
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     // Encryption
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     // Certificate validation
272     //
273 
274     @Override
275     protected final void handleCertificateValidationCallback(CertificateValidationCallback callback) {
276         callback.setValidator(new KeyStoreCertificateValidator());
277     }
278 
279     //
280     // Signing
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     // Decryption
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     // Signature verification
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     // Certificate methods
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                     // Cert does not contain a key identifier
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     // Private Key methods
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                     // Just returning the first one here
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                     // Cert does not contain a key identifier
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     // Utility methods
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     // Symmetric key methods
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     /** Loads the key store indicated by system properties. Delegates to {@link KeyStoreUtils#loadDefaultKeyStore()}. */
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     /** Loads a default trust store. Delegates to {@link KeyStoreUtils#loadDefaultTrustStore()}. */
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     // Inner classes
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 }