blob: c2144496b3e5002a2ceeeea3c984fd5542f03864 [file] [log] [blame]
/*
* Copyright 1999-2004 The Apache Software Foundation.
*
* Licensed 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.io.ByteArrayInputStream;
import java.io.IOException;
import java.security.PublicKey;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import org.apache.xml.security.exceptions.XMLSecurityException;
import org.apache.xml.security.keys.content.RetrievalMethod;
import org.apache.xml.security.keys.content.x509.XMLX509Certificate;
import org.apache.xml.security.keys.keyresolver.KeyResolver;
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.signature.XMLSignatureInput;
import org.apache.xml.security.transforms.Transforms;
import org.apache.xml.security.utils.Constants;
import org.apache.xml.security.utils.XMLUtils;
import org.apache.xml.security.utils.resolver.ResourceResolver;
import org.w3c.dom.Attr;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
/**
* The RetrievalMethodResolver can retrieve public keys and certificates from
* other locations. The location is specified using the ds:RetrievalMethod
* element which points to the location. This includes the handling of raw
* (binary) X.509 certificate which are not encapsulated in an XML structure.
* If the retrieval process encounters an element which the
* RetrievalMethodResolver cannot handle itself, resolving of the extracted
* element is delegated back to the KeyResolver mechanism.
*
* @author $Author$
*/
public class RetrievalMethodResolver extends KeyResolverSpi {
/** {@link org.apache.commons.logging} logging facility */
static org.apache.commons.logging.Log log =
org.apache.commons.logging.LogFactory.getLog(
RetrievalMethodResolver.class.getName());
/**
* Method engineCanResolve
* @inheritDoc
* @param element
* @param BaseURI
* @param storage
*
*/
public boolean engineCanResolve(Element element, String BaseURI,
StorageResolver storage) {
if
(!XMLUtils.elementIsInSignatureSpace(element,
Constants._TAG_RETRIEVALMETHOD)) {
return false;
}
return true;
}
/**
* Method engineResolvePublicKey
* @inheritDoc
* @param element
* @param BaseURI
* @param storage
*
*/
public PublicKey engineResolvePublicKey(
Element element, String BaseURI, StorageResolver storage)
{
try {
RetrievalMethod rm = new RetrievalMethod(element, BaseURI);
Attr uri = rm.getURIAttr();
// type can be null because it's optional
String type = rm.getType();
Transforms transforms = rm.getTransforms();
ResourceResolver resRes = ResourceResolver.getInstance(uri, BaseURI);
if (resRes != null) {
XMLSignatureInput resource = resRes.resolve(uri, BaseURI);
if (log.isDebugEnabled())
log.debug("Before applying Transforms, resource has "
+ resource.getBytes().length + "bytes");
if (transforms != null) {
log.debug("We have Transforms");
resource = transforms.performTransforms(resource);
}
if (log.isDebugEnabled()) {
log.debug("After applying Transforms, resource has "
+ resource.getBytes().length + "bytes");
log.debug("Resolved to resource " + resource.getSourceURI());
}
byte inputBytes[] = resource.getBytes();
if ((type != null) && type.equals(RetrievalMethod.TYPE_RAWX509)) {
// if the resource stores a raw certificate, we have to handle it
CertificateFactory certFact =
CertificateFactory
.getInstance(XMLX509Certificate.JCA_CERT_ID);
X509Certificate cert =
(X509Certificate) certFact
.generateCertificate(new ByteArrayInputStream(inputBytes));
if (cert != null) {
return cert.getPublicKey();
}
} else {
// otherwise, we parse the resource, create an Element and delegate
if (log.isDebugEnabled())
log.debug("we have to parse " + inputBytes.length + " bytes");
Element e = this.getDocFromBytes(inputBytes);
if (log.isDebugEnabled())
log.debug("Now we have a {" + e.getNamespaceURI() + "}"
+ e.getLocalName() + " Element");
if (e != null) {
KeyResolver newKeyResolver = KeyResolver.getInstance(getFirstElementChild(e),
BaseURI, storage);
if (newKeyResolver != null) {
return newKeyResolver.resolvePublicKey(getFirstElementChild(e), BaseURI,
storage);
}
}
}
}
} catch (XMLSecurityException ex) {
log.debug("XMLSecurityException", ex);
} catch (CertificateException ex) {
log.debug("CertificateException", ex);
} catch (IOException ex) {
log.debug("IOException", ex);
}
return null;
}
/**
* Method engineResolveX509Certificate
* @inheritDoc
* @param element
* @param BaseURI
* @param storage
*
*/
public X509Certificate engineResolveX509Certificate(
Element element, String BaseURI, StorageResolver storage)
{
try {
RetrievalMethod rm = new RetrievalMethod(element, BaseURI);
Attr uri = rm.getURIAttr();
Transforms transforms = rm.getTransforms();
if (log.isDebugEnabled())
log.debug("Asked to resolve URI " + uri);
ResourceResolver resRes = ResourceResolver.getInstance(uri, BaseURI);
if (resRes != null) {
XMLSignatureInput resource = resRes.resolve(uri, BaseURI);
if (log.isDebugEnabled())
log.debug("Before applying Transforms, resource has "
+ resource.getBytes().length + "bytes");
if (transforms != null) {
log.debug("We have Transforms");
resource = transforms.performTransforms(resource);
}
if (log.isDebugEnabled()) {
log.debug("After applying Transforms, resource has "
+ resource.getBytes().length + "bytes");
log.debug("Resolved to resource " + resource.getSourceURI());
}
byte inputBytes[] = resource.getBytes();
if ((rm.getType() != null)
&& rm.getType().equals(RetrievalMethod.TYPE_RAWX509)) {
// if the resource stores a raw certificate, we have to handle it
CertificateFactory certFact =
CertificateFactory
.getInstance(XMLX509Certificate.JCA_CERT_ID);
X509Certificate cert =
(X509Certificate) certFact
.generateCertificate(new ByteArrayInputStream(inputBytes));
if (cert != null) {
return cert;
}
} else {
// otherwise, we parse the resource, create an Element and delegate
if (log.isDebugEnabled())
log.debug("we have to parse " + inputBytes.length + " bytes");
Element e = this.getDocFromBytes(inputBytes);
if (log.isDebugEnabled())
log.debug("Now we have a {" + e.getNamespaceURI() + "}"
+ e.getLocalName() + " Element");
if (e != null) {
KeyResolver newKeyResolver = KeyResolver.getInstance(getFirstElementChild(e),
BaseURI, storage);
if (newKeyResolver != null) {
return newKeyResolver.resolveX509Certificate(getFirstElementChild(e), BaseURI,
storage);
}
}
}
}
} catch (XMLSecurityException ex) {
log.debug("XMLSecurityException", ex);
} catch (CertificateException ex) {
log.debug("CertificateException", ex);
} catch (IOException ex) {
log.debug("IOException", ex);
}
return null;
}
/**
* Parses a byte array and returns the parsed Element.
*
* @param bytes
* @return the Document Element after parsing bytes
* @throws KeyResolverException if something goes wrong
*/
Element getDocFromBytes(byte[] bytes) throws KeyResolverException {
try {
javax.xml.parsers.DocumentBuilderFactory dbf =
javax.xml.parsers.DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
javax.xml.parsers.DocumentBuilder db = dbf.newDocumentBuilder();
org.w3c.dom.Document doc =
db.parse(new java.io.ByteArrayInputStream(bytes));
return doc.getDocumentElement();
} catch (org.xml.sax.SAXException ex) {
throw new KeyResolverException("empty", ex);
} catch (java.io.IOException ex) {
throw new KeyResolverException("empty", ex);
} catch (javax.xml.parsers.ParserConfigurationException ex) {
throw new KeyResolverException("empty", ex);
}
}
/**
* Method engineResolveSecretKey
* @inheritDoc
* @param element
* @param BaseURI
* @param storage
*
*/
public javax.crypto.SecretKey engineResolveSecretKey(
Element element, String BaseURI, StorageResolver storage)
{
return null;
}
static Element getFirstElementChild(Element e){
Node n=e.getFirstChild();
while (n!=null && n.getNodeType()!=Node.ELEMENT_NODE) {
n=n.getNextSibling();
}
return (Element)n;
}
}