|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
package com.sun.org.apache.xml.internal.security.keys.keyresolver.implementations; |
|
|
|
import java.io.ByteArrayInputStream; |
|
import java.io.IOException; |
|
import java.io.InputStream; |
|
import java.security.PrivateKey; |
|
import java.security.PublicKey; |
|
import java.security.cert.CertificateException; |
|
import java.security.cert.CertificateFactory; |
|
import java.security.cert.X509Certificate; |
|
import java.util.ArrayList; |
|
import java.util.Iterator; |
|
import java.util.List; |
|
import java.util.ListIterator; |
|
import java.util.Set; |
|
|
|
import com.sun.org.apache.xml.internal.security.c14n.CanonicalizationException; |
|
import com.sun.org.apache.xml.internal.security.exceptions.XMLSecurityException; |
|
import com.sun.org.apache.xml.internal.security.keys.content.RetrievalMethod; |
|
import com.sun.org.apache.xml.internal.security.keys.content.x509.XMLX509Certificate; |
|
import com.sun.org.apache.xml.internal.security.keys.keyresolver.KeyResolver; |
|
import com.sun.org.apache.xml.internal.security.keys.keyresolver.KeyResolverException; |
|
import com.sun.org.apache.xml.internal.security.keys.keyresolver.KeyResolverSpi; |
|
import com.sun.org.apache.xml.internal.security.keys.storage.StorageResolver; |
|
import com.sun.org.apache.xml.internal.security.parser.XMLParserException; |
|
import com.sun.org.apache.xml.internal.security.signature.XMLSignatureInput; |
|
import com.sun.org.apache.xml.internal.security.transforms.Transforms; |
|
import com.sun.org.apache.xml.internal.security.utils.Constants; |
|
import com.sun.org.apache.xml.internal.security.utils.XMLUtils; |
|
import com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolver; |
|
import com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolverContext; |
|
import org.w3c.dom.Attr; |
|
import org.w3c.dom.Element; |
|
import org.w3c.dom.Node; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public class RetrievalMethodResolver extends KeyResolverSpi { |
|
|
|
private static final com.sun.org.slf4j.internal.Logger LOG = |
|
com.sun.org.slf4j.internal.LoggerFactory.getLogger(RetrievalMethodResolver.class); |
|
|
|
|
|
@Override |
|
protected boolean engineCanResolve(Element element, String baseURI, StorageResolver storage) { |
|
return XMLUtils.elementIsInSignatureSpace(element, Constants._TAG_RETRIEVALMETHOD); |
|
} |
|
|
|
|
|
@Override |
|
protected PublicKey engineResolvePublicKey( |
|
Element element, String baseURI, StorageResolver storage, boolean secureValidation |
|
) { |
|
try { |
|
|
|
RetrievalMethod rm = new RetrievalMethod(element, baseURI); |
|
String type = rm.getType(); |
|
XMLSignatureInput resource = resolveInput(rm, baseURI, secureValidation); |
|
if (RetrievalMethod.TYPE_RAWX509.equals(type)) { |
|
|
|
X509Certificate cert = getRawCertificate(resource); |
|
if (cert != null) { |
|
return cert.getPublicKey(); |
|
} |
|
return null; |
|
} |
|
Element e = obtainReferenceElement(resource, secureValidation); |
|
|
|
// Check to make sure that the reference is not to another RetrievalMethod |
|
|
|
if (XMLUtils.elementIsInSignatureSpace(e, Constants._TAG_RETRIEVALMETHOD)) { |
|
if (secureValidation) { |
|
if (LOG.isDebugEnabled()) { |
|
String error = "Error: It is forbidden to have one RetrievalMethod " |
|
+ "point to another with secure validation"; |
|
LOG.debug(error); |
|
} |
|
return null; |
|
} |
|
RetrievalMethod rm2 = new RetrievalMethod(e, baseURI); |
|
XMLSignatureInput resource2 = resolveInput(rm2, baseURI, secureValidation); |
|
Element e2 = obtainReferenceElement(resource2, secureValidation); |
|
if (e2 == element) { |
|
LOG.debug("Error: Can't have RetrievalMethods pointing to each other"); |
|
return null; |
|
} |
|
} |
|
|
|
return resolveKey(e, baseURI, storage, secureValidation); |
|
} catch (XMLSecurityException ex) { |
|
LOG.debug("XMLSecurityException", ex); |
|
} catch (CertificateException ex) { |
|
LOG.debug("CertificateException", ex); |
|
} catch (IOException ex) { |
|
LOG.debug("IOException", ex); |
|
} |
|
return null; |
|
} |
|
|
|
|
|
@Override |
|
protected X509Certificate engineResolveX509Certificate( |
|
Element element, String baseURI, StorageResolver storage, boolean secureValidation) { |
|
try { |
|
RetrievalMethod rm = new RetrievalMethod(element, baseURI); |
|
String type = rm.getType(); |
|
XMLSignatureInput resource = resolveInput(rm, baseURI, secureValidation); |
|
if (RetrievalMethod.TYPE_RAWX509.equals(type)) { |
|
return getRawCertificate(resource); |
|
} |
|
|
|
Element e = obtainReferenceElement(resource, secureValidation); |
|
|
|
// Check to make sure that the reference is not to another RetrievalMethod |
|
|
|
if (XMLUtils.elementIsInSignatureSpace(e, Constants._TAG_RETRIEVALMETHOD)) { |
|
if (secureValidation) { |
|
if (LOG.isDebugEnabled()) { |
|
String error = "Error: It is forbidden to have one RetrievalMethod " |
|
+ "point to another with secure validation"; |
|
LOG.debug(error); |
|
} |
|
return null; |
|
} |
|
RetrievalMethod rm2 = new RetrievalMethod(e, baseURI); |
|
XMLSignatureInput resource2 = resolveInput(rm2, baseURI, secureValidation); |
|
Element e2 = obtainReferenceElement(resource2, secureValidation); |
|
if (e2 == element) { |
|
LOG.debug("Error: Can't have RetrievalMethods pointing to each other"); |
|
return null; |
|
} |
|
} |
|
|
|
return resolveCertificate(e, baseURI, storage, secureValidation); |
|
} catch (XMLSecurityException ex) { |
|
LOG.debug("XMLSecurityException", ex); |
|
} catch (CertificateException ex) { |
|
LOG.debug("CertificateException", ex); |
|
} catch (IOException ex) { |
|
LOG.debug("IOException", ex); |
|
} |
|
return null; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private static X509Certificate resolveCertificate( |
|
Element e, String baseURI, StorageResolver storage, boolean secureValidation |
|
) throws KeyResolverException { |
|
|
|
if (e != null) { |
|
if (LOG.isDebugEnabled()) { |
|
LOG.debug("Now we have a {" + e.getNamespaceURI() + "}" |
|
+ e.getLocalName() + " Element"); |
|
} |
|
return KeyResolver.getX509Certificate(e, baseURI, storage, secureValidation); |
|
} |
|
return null; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private static PublicKey resolveKey( |
|
Element e, String baseURI, StorageResolver storage, boolean secureValidation |
|
) throws KeyResolverException { |
|
|
|
if (e != null) { |
|
if (LOG.isDebugEnabled()) { |
|
LOG.debug("Now we have a {" + e.getNamespaceURI() + "}" |
|
+ e.getLocalName() + " Element"); |
|
} |
|
return KeyResolver.getPublicKey(e, baseURI, storage, secureValidation); |
|
} |
|
return null; |
|
} |
|
|
|
private static Element obtainReferenceElement(XMLSignatureInput resource, boolean secureValidation) |
|
throws CanonicalizationException, XMLParserException, IOException, KeyResolverException { |
|
Element e; |
|
if (resource.isElement()) { |
|
e = (Element) resource.getSubNode(); |
|
} else if (resource.isNodeSet()) { |
|
|
|
e = getDocumentElement(resource.getNodeSet()); |
|
} else { |
|
|
|
byte[] inputBytes = resource.getBytes(); |
|
e = getDocFromBytes(inputBytes, secureValidation); |
|
|
|
LOG.debug("we have to parse {} bytes", inputBytes.length); |
|
} |
|
return e; |
|
} |
|
|
|
private static X509Certificate getRawCertificate(XMLSignatureInput resource) |
|
throws CanonicalizationException, IOException, CertificateException { |
|
byte[] inputBytes = resource.getBytes(); |
|
|
|
CertificateFactory certFact = |
|
CertificateFactory.getInstance(XMLX509Certificate.JCA_CERT_ID); |
|
try (InputStream is = new ByteArrayInputStream(inputBytes)) { |
|
return (X509Certificate) certFact.generateCertificate(is); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private static XMLSignatureInput resolveInput( |
|
RetrievalMethod rm, String baseURI, boolean secureValidation |
|
) throws XMLSecurityException { |
|
Attr uri = rm.getURIAttr(); |
|
|
|
Transforms transforms = rm.getTransforms(); |
|
ResourceResolverContext resContext = new ResourceResolverContext(uri, baseURI, secureValidation); |
|
XMLSignatureInput resource = ResourceResolver.resolve(resContext); |
|
if (transforms != null) { |
|
LOG.debug("We have Transforms"); |
|
resource = transforms.performTransforms(resource); |
|
} |
|
return resource; |
|
} |
|
|
|
|
|
@Override |
|
public javax.crypto.SecretKey engineResolveSecretKey( |
|
Element element, String baseURI, StorageResolver storage, boolean secureValidation |
|
) { |
|
return null; |
|
} |
|
|
|
|
|
@Override |
|
protected PrivateKey engineResolvePrivateKey( |
|
Element element, String baseURI, StorageResolver storage, boolean secureValidation |
|
) { |
|
return null; |
|
} |
|
|
|
private static Element getDocumentElement(Set<Node> set) { |
|
Iterator<Node> it = set.iterator(); |
|
Element e = null; |
|
while (it.hasNext()) { |
|
Node currentNode = it.next(); |
|
if (currentNode != null && Node.ELEMENT_NODE == currentNode.getNodeType()) { |
|
e = (Element) currentNode; |
|
break; |
|
} |
|
} |
|
List<Node> parents = new ArrayList<>(); |
|
|
|
|
|
while (e != null) { |
|
parents.add(e); |
|
Node n = e.getParentNode(); |
|
if (n == null || Node.ELEMENT_NODE != n.getNodeType()) { |
|
break; |
|
} |
|
e = (Element) n; |
|
} |
|
|
|
ListIterator<Node> it2 = parents.listIterator(parents.size()-1); |
|
Element ele = null; |
|
while (it2.hasPrevious()) { |
|
ele = (Element) it2.previous(); |
|
if (set.contains(ele)) { |
|
return ele; |
|
} |
|
} |
|
return null; |
|
} |
|
} |