blob: 3ef445853cfdb6241019a2ccd38823daaf32a514 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.xml.security.keys.keyresolver.implementations;
import java.security.Key;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.Enumeration;
import javax.crypto.SecretKey;
import org.apache.xml.security.exceptions.XMLSecurityException;
import org.apache.xml.security.keys.content.X509Data;
import org.apache.xml.security.keys.content.x509.XMLX509Certificate;
import org.apache.xml.security.keys.content.x509.XMLX509IssuerSerial;
import org.apache.xml.security.keys.content.x509.XMLX509SKI;
import org.apache.xml.security.keys.content.x509.XMLX509SubjectName;
import org.apache.xml.security.keys.keyresolver.KeyResolverException;
import org.apache.xml.security.keys.keyresolver.KeyResolverSpi;
import org.apache.xml.security.keys.storage.StorageResolver;
import org.apache.xml.security.utils.Constants;
import org.apache.xml.security.utils.XMLUtils;
import org.w3c.dom.Element;
/**
* Resolves a PrivateKey within a KeyStore based on the KeyInfo hints.
* For X509Data hints, the certificate associated with the private key entry must match.
* For a KeyName hint, the KeyName must match the alias of a PrivateKey entry within the KeyStore.
*/
public class PrivateKeyResolver extends KeyResolverSpi {
private static final org.slf4j.Logger LOG =
org.slf4j.LoggerFactory.getLogger(PrivateKeyResolver.class);
private KeyStore keyStore;
private char[] password;
/**
* Constructor.
*/
public PrivateKeyResolver(KeyStore keyStore, char[] password) {
this.keyStore = keyStore;
this.password = password;
}
/**
* This method returns whether the KeyResolverSpi is able to perform the requested action.
*
* @param element
* @param baseURI
* @param storage
* @return whether the KeyResolverSpi is able to perform the requested action.
*/
public boolean engineCanResolve(Element element, String baseURI, StorageResolver storage) {
if (XMLUtils.elementIsInSignatureSpace(element, Constants._TAG_X509DATA)
|| XMLUtils.elementIsInSignatureSpace(element, Constants._TAG_KEYNAME)) {
return true;
}
return false;
}
/**
* Method engineLookupAndResolvePublicKey
*
* @param element
* @param baseURI
* @param storage
* @return null if no {@link PublicKey} could be obtained
* @throws KeyResolverException
*/
public PublicKey engineLookupAndResolvePublicKey(
Element element, String baseURI, StorageResolver storage
) throws KeyResolverException {
return null;
}
/**
* Method engineResolveX509Certificate
* {@inheritDoc}
* @param element
* @param baseURI
* @param storage
* @throws KeyResolverException
*/
public X509Certificate engineLookupResolveX509Certificate(
Element element, String baseURI, StorageResolver storage
) throws KeyResolverException {
return null;
}
/**
* Method engineResolveSecretKey
*
* @param element
* @param baseURI
* @param storage
* @return resolved SecretKey key or null if no {@link SecretKey} could be obtained
*
* @throws KeyResolverException
*/
public SecretKey engineResolveSecretKey(
Element element, String baseURI, StorageResolver storage
) throws KeyResolverException {
return null;
}
/**
* Method engineResolvePrivateKey
* {@inheritDoc}
* @param element
* @param baseURI
* @param storage
* @return resolved PrivateKey key or null if no {@link PrivateKey} could be obtained
* @throws KeyResolverException
*/
public PrivateKey engineLookupAndResolvePrivateKey(
Element element, String baseURI, StorageResolver storage
) throws KeyResolverException {
LOG.debug("Can I resolve {}?", element.getTagName());
if (XMLUtils.elementIsInSignatureSpace(element, Constants._TAG_X509DATA)) {
PrivateKey privKey = resolveX509Data(element, baseURI);
if (privKey != null) {
return privKey;
}
} else if (XMLUtils.elementIsInSignatureSpace(element, Constants._TAG_KEYNAME)) {
LOG.debug("Can I resolve KeyName?");
String keyName = element.getFirstChild().getNodeValue();
try {
Key key = keyStore.getKey(keyName, password);
if (key instanceof PrivateKey) {
return (PrivateKey) key;
}
} catch (Exception e) {
LOG.debug("Cannot recover the key", e);
}
}
LOG.debug("I can't");
return null;
}
private PrivateKey resolveX509Data(Element element, String baseURI) {
LOG.debug("Can I resolve X509Data?");
try {
X509Data x509Data = new X509Data(element, baseURI);
int len = x509Data.lengthSKI();
for (int i = 0; i < len; i++) {
XMLX509SKI x509SKI = x509Data.itemSKI(i);
PrivateKey privKey = resolveX509SKI(x509SKI);
if (privKey != null) {
return privKey;
}
}
len = x509Data.lengthIssuerSerial();
for (int i = 0; i < len; i++) {
XMLX509IssuerSerial x509Serial = x509Data.itemIssuerSerial(i);
PrivateKey privKey = resolveX509IssuerSerial(x509Serial);
if (privKey != null) {
return privKey;
}
}
len = x509Data.lengthSubjectName();
for (int i = 0; i < len; i++) {
XMLX509SubjectName x509SubjectName = x509Data.itemSubjectName(i);
PrivateKey privKey = resolveX509SubjectName(x509SubjectName);
if (privKey != null) {
return privKey;
}
}
len = x509Data.lengthCertificate();
for (int i = 0; i < len; i++) {
XMLX509Certificate x509Cert = x509Data.itemCertificate(i);
PrivateKey privKey = resolveX509Certificate(x509Cert);
if (privKey != null) {
return privKey;
}
}
} catch (XMLSecurityException e) {
LOG.debug("XMLSecurityException", e);
} catch (KeyStoreException e) {
LOG.debug("KeyStoreException", e);
}
return null;
}
/*
* Search for a private key entry in the KeyStore with the same Subject Key Identifier
*/
private PrivateKey resolveX509SKI(XMLX509SKI x509SKI) throws XMLSecurityException, KeyStoreException {
LOG.debug("Can I resolve X509SKI?");
Enumeration<String> aliases = keyStore.aliases();
while (aliases.hasMoreElements()) {
String alias = aliases.nextElement();
if (keyStore.isKeyEntry(alias)) {
Certificate cert = keyStore.getCertificate(alias);
if (cert instanceof X509Certificate) {
XMLX509SKI certSKI = new XMLX509SKI(x509SKI.getDocument(), (X509Certificate) cert);
if (certSKI.equals(x509SKI)) {
LOG.debug("match !!! ");
try {
Key key = keyStore.getKey(alias, password);
if (key instanceof PrivateKey) {
return (PrivateKey) key;
}
} catch (Exception e) {
LOG.debug("Cannot recover the key", e);
// Keep searching
}
}
}
}
}
return null;
}
/*
* Search for a private key entry in the KeyStore with the same Issuer/Serial Number pair.
*/
private PrivateKey resolveX509IssuerSerial(XMLX509IssuerSerial x509Serial) throws KeyStoreException {
LOG.debug("Can I resolve X509IssuerSerial?");
Enumeration<String> aliases = keyStore.aliases();
while (aliases.hasMoreElements()) {
String alias = aliases.nextElement();
if (keyStore.isKeyEntry(alias)) {
Certificate cert = keyStore.getCertificate(alias);
if (cert instanceof X509Certificate) {
XMLX509IssuerSerial certSerial =
new XMLX509IssuerSerial(x509Serial.getDocument(), (X509Certificate) cert);
if (certSerial.equals(x509Serial)) {
LOG.debug("match !!! ");
try {
Key key = keyStore.getKey(alias, password);
if (key instanceof PrivateKey) {
return (PrivateKey) key;
}
} catch (Exception e) {
LOG.debug("Cannot recover the key", e);
// Keep searching
}
}
}
}
}
return null;
}
/*
* Search for a private key entry in the KeyStore with the same Subject Name.
*/
private PrivateKey resolveX509SubjectName(XMLX509SubjectName x509SubjectName) throws KeyStoreException {
LOG.debug("Can I resolve X509SubjectName?");
Enumeration<String> aliases = keyStore.aliases();
while (aliases.hasMoreElements()) {
String alias = aliases.nextElement();
if (keyStore.isKeyEntry(alias)) {
Certificate cert = keyStore.getCertificate(alias);
if (cert instanceof X509Certificate) {
XMLX509SubjectName certSN =
new XMLX509SubjectName(x509SubjectName.getDocument(), (X509Certificate) cert);
if (certSN.equals(x509SubjectName)) {
LOG.debug("match !!! ");
try {
Key key = keyStore.getKey(alias, password);
if (key instanceof PrivateKey) {
return (PrivateKey) key;
}
} catch (Exception e) {
LOG.debug("Cannot recover the key", e);
// Keep searching
}
}
}
}
}
return null;
}
/*
* Search for a private key entry in the KeyStore with the same Certificate.
*/
private PrivateKey resolveX509Certificate(
XMLX509Certificate x509Cert
) throws XMLSecurityException, KeyStoreException {
LOG.debug("Can I resolve X509Certificate?");
byte[] x509CertBytes = x509Cert.getCertificateBytes();
Enumeration<String> aliases = keyStore.aliases();
while (aliases.hasMoreElements()) {
String alias = aliases.nextElement();
if (keyStore.isKeyEntry(alias)) {
Certificate cert = keyStore.getCertificate(alias);
if (cert instanceof X509Certificate) {
byte[] certBytes = null;
try {
certBytes = cert.getEncoded();
} catch (CertificateEncodingException e1) {
LOG.debug("Cannot recover the key", e1);
}
if (certBytes != null && Arrays.equals(certBytes, x509CertBytes)) {
LOG.debug("match !!! ");
try {
Key key = keyStore.getKey(alias, password);
if (key instanceof PrivateKey) {
return (PrivateKey) key;
}
}
catch (Exception e) {
LOG.debug("Cannot recover the key", e);
// Keep searching
}
}
}
}
}
return null;
}
}