1 /*
2  * reserved comment block
3  * DO NOT REMOVE OR ALTER!
4  */
5 /**
6  * Licensed to the Apache Software Foundation (ASF) under one
7  * or more contributor license agreements. See the NOTICE file
8  * distributed with this work for additional information
9  * regarding copyright ownership. The ASF licenses this file
10  * to you under the Apache License, Version 2.0 (the
11  * "License"); you may not use this file except in compliance
12  * with the License. You may obtain a copy of the License at
13  *
14  * http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing,
17  * software distributed under the License is distributed on an
18  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
19  * KIND, either express or implied. See the License for the
20  * specific language governing permissions and limitations
21  * under the License.
22  */
23 package com.sun.org.apache.xml.internal.security.keys.keyresolver.implementations;
24 
25 import java.security.Key;
26 import java.security.KeyStore;
27 import java.security.KeyStoreException;
28 import java.security.PrivateKey;
29 import java.security.PublicKey;
30 import java.security.cert.Certificate;
31 import java.security.cert.CertificateEncodingException;
32 import java.security.cert.X509Certificate;
33 import java.util.Arrays;
34 import java.util.Enumeration;
35 import javax.crypto.SecretKey;
36 import com.sun.org.apache.xml.internal.security.exceptions.XMLSecurityException;
37 import com.sun.org.apache.xml.internal.security.keys.content.X509Data;
38 import com.sun.org.apache.xml.internal.security.keys.content.x509.XMLX509Certificate;
39 import com.sun.org.apache.xml.internal.security.keys.content.x509.XMLX509IssuerSerial;
40 import com.sun.org.apache.xml.internal.security.keys.content.x509.XMLX509SKI;
41 import com.sun.org.apache.xml.internal.security.keys.content.x509.XMLX509SubjectName;
42 import com.sun.org.apache.xml.internal.security.keys.keyresolver.KeyResolverException;
43 import com.sun.org.apache.xml.internal.security.keys.keyresolver.KeyResolverSpi;
44 import com.sun.org.apache.xml.internal.security.keys.storage.StorageResolver;
45 import com.sun.org.apache.xml.internal.security.utils.Constants;
46 import com.sun.org.apache.xml.internal.security.utils.XMLUtils;
47 import org.w3c.dom.Element;
48 
49 /**
50  * Resolves a PrivateKey within a KeyStore based on the KeyInfo hints.
51  * For X509Data hints, the certificate associated with the private key entry must match.
52  * For a KeyName hint, the KeyName must match the alias of a PrivateKey entry within the KeyStore.
53  */
54 public class PrivateKeyResolver extends KeyResolverSpi {
55 
56     private static final com.sun.org.slf4j.internal.Logger LOG =
57         com.sun.org.slf4j.internal.LoggerFactory.getLogger(PrivateKeyResolver.class);
58 
59     private KeyStore keyStore;
60     private char[] password;
61 
62     /**
63      * Constructor.
64      */
PrivateKeyResolver(KeyStore keyStore, char[] password)65     public PrivateKeyResolver(KeyStore keyStore, char[] password) {
66         this.keyStore = keyStore;
67         this.password = password;
68     }
69 
70     /**
71      * This method returns whether the KeyResolverSpi is able to perform the requested action.
72      *
73      * @param element
74      * @param baseURI
75      * @param storage
76      * @return whether the KeyResolverSpi is able to perform the requested action.
77      */
engineCanResolve(Element element, String baseURI, StorageResolver storage)78     public boolean engineCanResolve(Element element, String baseURI, StorageResolver storage) {
79         if (XMLUtils.elementIsInSignatureSpace(element, Constants._TAG_X509DATA)
80             || XMLUtils.elementIsInSignatureSpace(element, Constants._TAG_KEYNAME)) {
81             return true;
82         }
83 
84         return false;
85     }
86 
87     /**
88      * Method engineLookupAndResolvePublicKey
89      *
90      * @param element
91      * @param baseURI
92      * @param storage
93      * @return null if no {@link PublicKey} could be obtained
94      * @throws KeyResolverException
95      */
engineLookupAndResolvePublicKey( Element element, String baseURI, StorageResolver storage )96     public PublicKey engineLookupAndResolvePublicKey(
97         Element element, String baseURI, StorageResolver storage
98     ) throws KeyResolverException {
99         return null;
100     }
101 
102     /**
103      * Method engineResolveX509Certificate
104      * {@inheritDoc}
105      * @param element
106      * @param baseURI
107      * @param storage
108      * @throws KeyResolverException
109      */
engineLookupResolveX509Certificate( Element element, String baseURI, StorageResolver storage )110     public X509Certificate engineLookupResolveX509Certificate(
111         Element element, String baseURI, StorageResolver storage
112     ) throws KeyResolverException {
113         return null;
114     }
115 
116     /**
117      * Method engineResolveSecretKey
118      *
119      * @param element
120      * @param baseURI
121      * @param storage
122      * @return resolved SecretKey key or null if no {@link SecretKey} could be obtained
123      *
124      * @throws KeyResolverException
125      */
engineResolveSecretKey( Element element, String baseURI, StorageResolver storage )126     public SecretKey engineResolveSecretKey(
127         Element element, String baseURI, StorageResolver storage
128     ) throws KeyResolverException {
129         return null;
130     }
131 
132     /**
133      * Method engineResolvePrivateKey
134      * {@inheritDoc}
135      * @param element
136      * @param baseURI
137      * @param storage
138      * @return resolved PrivateKey key or null if no {@link PrivateKey} could be obtained
139      * @throws KeyResolverException
140      */
engineLookupAndResolvePrivateKey( Element element, String baseURI, StorageResolver storage )141     public PrivateKey engineLookupAndResolvePrivateKey(
142         Element element, String baseURI, StorageResolver storage
143     ) throws KeyResolverException {
144         LOG.debug("Can I resolve {}?", element.getTagName());
145 
146         if (XMLUtils.elementIsInSignatureSpace(element, Constants._TAG_X509DATA)) {
147             PrivateKey privKey = resolveX509Data(element, baseURI);
148             if (privKey != null) {
149                 return privKey;
150             }
151         } else if (XMLUtils.elementIsInSignatureSpace(element, Constants._TAG_KEYNAME)) {
152             LOG.debug("Can I resolve KeyName?");
153             String keyName = element.getFirstChild().getNodeValue();
154 
155             try {
156                 Key key = keyStore.getKey(keyName, password);
157                 if (key instanceof PrivateKey) {
158                     return (PrivateKey) key;
159                 }
160             } catch (Exception e) {
161                 LOG.debug("Cannot recover the key", e);
162             }
163         }
164 
165         LOG.debug("I can't");
166         return null;
167     }
168 
resolveX509Data(Element element, String baseURI)169     private PrivateKey resolveX509Data(Element element, String baseURI) {
170         LOG.debug("Can I resolve X509Data?");
171 
172         try {
173             X509Data x509Data = new X509Data(element, baseURI);
174 
175             int len = x509Data.lengthSKI();
176             for (int i = 0; i < len; i++) {
177                 XMLX509SKI x509SKI = x509Data.itemSKI(i);
178                 PrivateKey privKey = resolveX509SKI(x509SKI);
179                 if (privKey != null) {
180                     return privKey;
181                 }
182             }
183 
184             len = x509Data.lengthIssuerSerial();
185             for (int i = 0; i < len; i++) {
186                 XMLX509IssuerSerial x509Serial = x509Data.itemIssuerSerial(i);
187                 PrivateKey privKey = resolveX509IssuerSerial(x509Serial);
188                 if (privKey != null) {
189                     return privKey;
190                 }
191             }
192 
193             len = x509Data.lengthSubjectName();
194             for (int i = 0; i < len; i++) {
195                 XMLX509SubjectName x509SubjectName = x509Data.itemSubjectName(i);
196                 PrivateKey privKey = resolveX509SubjectName(x509SubjectName);
197                 if (privKey != null) {
198                     return privKey;
199                 }
200             }
201 
202             len = x509Data.lengthCertificate();
203             for (int i = 0; i < len; i++) {
204                 XMLX509Certificate x509Cert = x509Data.itemCertificate(i);
205                 PrivateKey privKey = resolveX509Certificate(x509Cert);
206                 if (privKey != null) {
207                     return privKey;
208                 }
209             }
210         } catch (XMLSecurityException e) {
211             LOG.debug("XMLSecurityException", e);
212         } catch (KeyStoreException e) {
213             LOG.debug("KeyStoreException", e);
214         }
215 
216         return null;
217     }
218 
219     /*
220      * Search for a private key entry in the KeyStore with the same Subject Key Identifier
221      */
resolveX509SKI(XMLX509SKI x509SKI)222     private PrivateKey resolveX509SKI(XMLX509SKI x509SKI) throws XMLSecurityException, KeyStoreException {
223         LOG.debug("Can I resolve X509SKI?");
224 
225         Enumeration<String> aliases = keyStore.aliases();
226         while (aliases.hasMoreElements()) {
227             String alias = aliases.nextElement();
228             if (keyStore.isKeyEntry(alias)) {
229 
230                 Certificate cert = keyStore.getCertificate(alias);
231                 if (cert instanceof X509Certificate) {
232                     XMLX509SKI certSKI = new XMLX509SKI(x509SKI.getDocument(), (X509Certificate) cert);
233 
234                     if (certSKI.equals(x509SKI)) {
235                         LOG.debug("match !!! ");
236 
237                         try {
238                             Key key = keyStore.getKey(alias, password);
239                             if (key instanceof PrivateKey) {
240                                 return (PrivateKey) key;
241                             }
242                         } catch (Exception e) {
243                             LOG.debug("Cannot recover the key", e);
244                             // Keep searching
245                         }
246                     }
247                 }
248             }
249         }
250 
251         return null;
252     }
253 
254     /*
255      * Search for a private key entry in the KeyStore with the same Issuer/Serial Number pair.
256      */
resolveX509IssuerSerial(XMLX509IssuerSerial x509Serial)257     private PrivateKey resolveX509IssuerSerial(XMLX509IssuerSerial x509Serial) throws KeyStoreException {
258         LOG.debug("Can I resolve X509IssuerSerial?");
259 
260         Enumeration<String> aliases = keyStore.aliases();
261         while (aliases.hasMoreElements()) {
262             String alias = aliases.nextElement();
263             if (keyStore.isKeyEntry(alias)) {
264 
265                 Certificate cert = keyStore.getCertificate(alias);
266                 if (cert instanceof X509Certificate) {
267                     XMLX509IssuerSerial certSerial =
268                         new XMLX509IssuerSerial(x509Serial.getDocument(), (X509Certificate) cert);
269 
270                     if (certSerial.equals(x509Serial)) {
271                         LOG.debug("match !!! ");
272 
273                         try {
274                             Key key = keyStore.getKey(alias, password);
275                             if (key instanceof PrivateKey) {
276                                 return (PrivateKey) key;
277                             }
278                         } catch (Exception e) {
279                             LOG.debug("Cannot recover the key", e);
280                             // Keep searching
281                         }
282                     }
283                 }
284             }
285         }
286 
287         return null;
288     }
289 
290     /*
291      * Search for a private key entry in the KeyStore with the same Subject Name.
292      */
resolveX509SubjectName(XMLX509SubjectName x509SubjectName)293     private PrivateKey resolveX509SubjectName(XMLX509SubjectName x509SubjectName) throws KeyStoreException {
294         LOG.debug("Can I resolve X509SubjectName?");
295 
296         Enumeration<String> aliases = keyStore.aliases();
297         while (aliases.hasMoreElements()) {
298             String alias = aliases.nextElement();
299             if (keyStore.isKeyEntry(alias)) {
300 
301                 Certificate cert = keyStore.getCertificate(alias);
302                 if (cert instanceof X509Certificate) {
303                     XMLX509SubjectName certSN =
304                         new XMLX509SubjectName(x509SubjectName.getDocument(), (X509Certificate) cert);
305 
306                     if (certSN.equals(x509SubjectName)) {
307                         LOG.debug("match !!! ");
308 
309                         try {
310                             Key key = keyStore.getKey(alias, password);
311                             if (key instanceof PrivateKey) {
312                                 return (PrivateKey) key;
313                             }
314                         } catch (Exception e) {
315                             LOG.debug("Cannot recover the key", e);
316                             // Keep searching
317                         }
318                     }
319                 }
320             }
321         }
322 
323         return null;
324     }
325 
326     /*
327      * Search for a private key entry in the KeyStore with the same Certificate.
328      */
resolveX509Certificate( XMLX509Certificate x509Cert )329     private PrivateKey resolveX509Certificate(
330         XMLX509Certificate x509Cert
331     ) throws XMLSecurityException, KeyStoreException {
332         LOG.debug("Can I resolve X509Certificate?");
333         byte[] x509CertBytes = x509Cert.getCertificateBytes();
334 
335         Enumeration<String> aliases = keyStore.aliases();
336         while (aliases.hasMoreElements()) {
337             String alias = aliases.nextElement();
338             if (keyStore.isKeyEntry(alias)) {
339 
340                 Certificate cert = keyStore.getCertificate(alias);
341                 if (cert instanceof X509Certificate) {
342                     byte[] certBytes = null;
343 
344                     try {
345                         certBytes = cert.getEncoded();
346                     } catch (CertificateEncodingException e1) {
347                         LOG.debug("Cannot recover the key", e1);
348                     }
349 
350                     if (certBytes != null && Arrays.equals(certBytes, x509CertBytes)) {
351                         LOG.debug("match !!! ");
352 
353                         try {
354                             Key key = keyStore.getKey(alias, password);
355                             if (key instanceof PrivateKey) {
356                                 return (PrivateKey) key;
357                             }
358                         }
359                         catch (Exception e) {
360                             LOG.debug("Cannot recover the key", e);
361                             // Keep searching
362                         }
363                     }
364                 }
365             }
366         }
367 
368         return null;
369     }
370 }
371