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 final KeyStore keyStore;
60     private final 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     /** {@inheritDoc} */
71     @Override
engineCanResolve(Element element, String baseURI, StorageResolver storage)72     protected boolean engineCanResolve(Element element, String baseURI, StorageResolver storage) {
73         return XMLUtils.elementIsInSignatureSpace(element, Constants._TAG_X509DATA)
74             || XMLUtils.elementIsInSignatureSpace(element, Constants._TAG_KEYNAME);
75     }
76 
77     /** {@inheritDoc} */
78     @Override
engineResolvePublicKey( Element element, String baseURI, StorageResolver storage, boolean secureValidation )79     protected PublicKey engineResolvePublicKey(
80         Element element, String baseURI, StorageResolver storage, boolean secureValidation
81     ) throws KeyResolverException {
82         return null;
83     }
84 
85     /** {@inheritDoc} */
86     @Override
engineResolveX509Certificate( Element element, String baseURI, StorageResolver storage, boolean secureValidation )87     protected X509Certificate engineResolveX509Certificate(
88         Element element, String baseURI, StorageResolver storage, boolean secureValidation
89     ) throws KeyResolverException {
90         return null;
91     }
92 
93     /** {@inheritDoc} */
94     @Override
engineResolveSecretKey( Element element, String baseURI, StorageResolver storage, boolean secureValidation )95     protected SecretKey engineResolveSecretKey(
96         Element element, String baseURI, StorageResolver storage, boolean secureValidation
97     ) throws KeyResolverException {
98         return null;
99     }
100 
101     /** {@inheritDoc} */
102     @Override
engineResolvePrivateKey( Element element, String baseURI, StorageResolver storage, boolean secureValidation )103     public PrivateKey engineResolvePrivateKey(
104         Element element, String baseURI, StorageResolver storage, boolean secureValidation
105     ) throws KeyResolverException {
106 
107         if (XMLUtils.elementIsInSignatureSpace(element, Constants._TAG_X509DATA)) {
108             PrivateKey privKey = resolveX509Data(element, baseURI);
109             if (privKey != null) {
110                 return privKey;
111             }
112         } else if (XMLUtils.elementIsInSignatureSpace(element, Constants._TAG_KEYNAME)) {
113             LOG.debug("Can I resolve KeyName?");
114             String keyName = element.getFirstChild().getNodeValue();
115 
116             try {
117                 Key key = keyStore.getKey(keyName, password);
118                 if (key instanceof PrivateKey) {
119                     return (PrivateKey) key;
120                 }
121             } catch (Exception e) {
122                 LOG.debug("Cannot recover the key", e);
123             }
124         }
125 
126         return null;
127     }
128 
resolveX509Data(Element element, String baseURI)129     private PrivateKey resolveX509Data(Element element, String baseURI) {
130         LOG.debug("Can I resolve X509Data?");
131 
132         try {
133             X509Data x509Data = new X509Data(element, baseURI);
134 
135             int len = x509Data.lengthSKI();
136             for (int i = 0; i < len; i++) {
137                 XMLX509SKI x509SKI = x509Data.itemSKI(i);
138                 PrivateKey privKey = resolveX509SKI(x509SKI);
139                 if (privKey != null) {
140                     return privKey;
141                 }
142             }
143 
144             len = x509Data.lengthIssuerSerial();
145             for (int i = 0; i < len; i++) {
146                 XMLX509IssuerSerial x509Serial = x509Data.itemIssuerSerial(i);
147                 PrivateKey privKey = resolveX509IssuerSerial(x509Serial);
148                 if (privKey != null) {
149                     return privKey;
150                 }
151             }
152 
153             len = x509Data.lengthSubjectName();
154             for (int i = 0; i < len; i++) {
155                 XMLX509SubjectName x509SubjectName = x509Data.itemSubjectName(i);
156                 PrivateKey privKey = resolveX509SubjectName(x509SubjectName);
157                 if (privKey != null) {
158                     return privKey;
159                 }
160             }
161 
162             len = x509Data.lengthCertificate();
163             for (int i = 0; i < len; i++) {
164                 XMLX509Certificate x509Cert = x509Data.itemCertificate(i);
165                 PrivateKey privKey = resolveX509Certificate(x509Cert);
166                 if (privKey != null) {
167                     return privKey;
168                 }
169             }
170         } catch (XMLSecurityException e) {
171             LOG.debug("XMLSecurityException", e);
172         } catch (KeyStoreException e) {
173             LOG.debug("KeyStoreException", e);
174         }
175 
176         return null;
177     }
178 
179     /*
180      * Search for a private key entry in the KeyStore with the same Subject Key Identifier
181      */
resolveX509SKI(XMLX509SKI x509SKI)182     private PrivateKey resolveX509SKI(XMLX509SKI x509SKI) throws XMLSecurityException, KeyStoreException {
183         LOG.debug("Can I resolve X509SKI?");
184 
185         Enumeration<String> aliases = keyStore.aliases();
186         while (aliases.hasMoreElements()) {
187             String alias = aliases.nextElement();
188             if (keyStore.isKeyEntry(alias)) {
189 
190                 Certificate cert = keyStore.getCertificate(alias);
191                 if (cert instanceof X509Certificate) {
192                     XMLX509SKI certSKI = new XMLX509SKI(x509SKI.getDocument(), (X509Certificate) cert);
193 
194                     if (certSKI.equals(x509SKI)) {
195                         LOG.debug("match !!! ");
196 
197                         try {
198                             Key key = keyStore.getKey(alias, password);
199                             if (key instanceof PrivateKey) {
200                                 return (PrivateKey) key;
201                             }
202                         } catch (Exception e) {
203                             LOG.debug("Cannot recover the key", e);
204                             // Keep searching
205                         }
206                     }
207                 }
208             }
209         }
210 
211         return null;
212     }
213 
214     /*
215      * Search for a private key entry in the KeyStore with the same Issuer/Serial Number pair.
216      */
resolveX509IssuerSerial(XMLX509IssuerSerial x509Serial)217     private PrivateKey resolveX509IssuerSerial(XMLX509IssuerSerial x509Serial) throws KeyStoreException {
218         LOG.debug("Can I resolve X509IssuerSerial?");
219 
220         Enumeration<String> aliases = keyStore.aliases();
221         while (aliases.hasMoreElements()) {
222             String alias = aliases.nextElement();
223             if (keyStore.isKeyEntry(alias)) {
224 
225                 Certificate cert = keyStore.getCertificate(alias);
226                 if (cert instanceof X509Certificate) {
227                     XMLX509IssuerSerial certSerial =
228                         new XMLX509IssuerSerial(x509Serial.getDocument(), (X509Certificate) cert);
229 
230                     if (certSerial.equals(x509Serial)) {
231                         LOG.debug("match !!! ");
232 
233                         try {
234                             Key key = keyStore.getKey(alias, password);
235                             if (key instanceof PrivateKey) {
236                                 return (PrivateKey) key;
237                             }
238                         } catch (Exception e) {
239                             LOG.debug("Cannot recover the key", e);
240                             // Keep searching
241                         }
242                     }
243                 }
244             }
245         }
246 
247         return null;
248     }
249 
250     /*
251      * Search for a private key entry in the KeyStore with the same Subject Name.
252      */
resolveX509SubjectName(XMLX509SubjectName x509SubjectName)253     private PrivateKey resolveX509SubjectName(XMLX509SubjectName x509SubjectName) throws KeyStoreException {
254         LOG.debug("Can I resolve X509SubjectName?");
255 
256         Enumeration<String> aliases = keyStore.aliases();
257         while (aliases.hasMoreElements()) {
258             String alias = aliases.nextElement();
259             if (keyStore.isKeyEntry(alias)) {
260 
261                 Certificate cert = keyStore.getCertificate(alias);
262                 if (cert instanceof X509Certificate) {
263                     XMLX509SubjectName certSN =
264                         new XMLX509SubjectName(x509SubjectName.getDocument(), (X509Certificate) cert);
265 
266                     if (certSN.equals(x509SubjectName)) {
267                         LOG.debug("match !!! ");
268 
269                         try {
270                             Key key = keyStore.getKey(alias, password);
271                             if (key instanceof PrivateKey) {
272                                 return (PrivateKey) key;
273                             }
274                         } catch (Exception e) {
275                             LOG.debug("Cannot recover the key", e);
276                             // Keep searching
277                         }
278                     }
279                 }
280             }
281         }
282 
283         return null;
284     }
285 
286     /*
287      * Search for a private key entry in the KeyStore with the same Certificate.
288      */
resolveX509Certificate( XMLX509Certificate x509Cert )289     private PrivateKey resolveX509Certificate(
290         XMLX509Certificate x509Cert
291     ) throws XMLSecurityException, KeyStoreException {
292         LOG.debug("Can I resolve X509Certificate?");
293         byte[] x509CertBytes = x509Cert.getCertificateBytes();
294 
295         Enumeration<String> aliases = keyStore.aliases();
296         while (aliases.hasMoreElements()) {
297             String alias = aliases.nextElement();
298             if (keyStore.isKeyEntry(alias)) {
299 
300                 Certificate cert = keyStore.getCertificate(alias);
301                 if (cert instanceof X509Certificate) {
302                     byte[] certBytes = null;
303 
304                     try {
305                         certBytes = cert.getEncoded();
306                     } catch (CertificateEncodingException e1) {
307                         LOG.debug("Cannot recover the key", e1);
308                     }
309 
310                     if (certBytes != null && Arrays.equals(certBytes, x509CertBytes)) {
311                         LOG.debug("match !!! ");
312 
313                         try {
314                             Key key = keyStore.getKey(alias, password);
315                             if (key instanceof PrivateKey) {
316                                 return (PrivateKey) key;
317                             }
318                         }
319                         catch (Exception e) {
320                             LOG.debug("Cannot recover the key", e);
321                             // Keep searching
322                         }
323                     }
324                 }
325             }
326         }
327 
328         return null;
329     }
330 }
331