|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
package com.sun.org.apache.xml.internal.security.signature; |
|
|
|
import java.io.IOException; |
|
import java.security.AccessController; |
|
import java.security.PrivilegedAction; |
|
import java.util.ArrayList; |
|
import java.util.Collections; |
|
import java.util.HashMap; |
|
import java.util.Iterator; |
|
import java.util.List; |
|
import java.util.Map; |
|
import java.util.Set; |
|
|
|
import javax.xml.parsers.ParserConfigurationException; |
|
|
|
import com.sun.org.apache.xml.internal.security.c14n.CanonicalizationException; |
|
import com.sun.org.apache.xml.internal.security.c14n.InvalidCanonicalizerException; |
|
import com.sun.org.apache.xml.internal.security.exceptions.XMLSecurityException; |
|
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.I18n; |
|
import com.sun.org.apache.xml.internal.security.utils.SignatureElementProxy; |
|
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.ResourceResolverSpi; |
|
import org.w3c.dom.Attr; |
|
import org.w3c.dom.DOMException; |
|
import org.w3c.dom.Document; |
|
import org.w3c.dom.Element; |
|
import org.w3c.dom.Node; |
|
import org.xml.sax.SAXException; |
|
|
|
|
|
|
|
|
|
*/ |
|
public class Manifest extends SignatureElementProxy { |
|
|
|
|
|
|
|
*/ |
|
public static final int MAXIMUM_REFERENCE_COUNT = 30; |
|
|
|
private static final com.sun.org.slf4j.internal.Logger LOG = |
|
com.sun.org.slf4j.internal.LoggerFactory.getLogger(Manifest.class); |
|
|
|
private static Integer referenceCount = |
|
AccessController.doPrivileged( |
|
(PrivilegedAction<Integer>) () -> Integer.parseInt(System.getProperty("com.sun.org.apache.xml.internal.security.maxReferences", |
|
Integer.toString(MAXIMUM_REFERENCE_COUNT)))); |
|
|
|
|
|
private List<Reference> references; |
|
private Element[] referencesEl; |
|
|
|
|
|
private List<VerifiedReference> verificationResults; |
|
|
|
|
|
private Map<String, String> resolverProperties; |
|
|
|
|
|
private List<ResourceResolver> perManifestResolvers; |
|
|
|
private boolean secureValidation; |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public Manifest(Document doc) { |
|
super(doc); |
|
|
|
addReturnToSelf(); |
|
|
|
this.references = new ArrayList<>(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public Manifest(Element element, String baseURI) throws XMLSecurityException { |
|
this(element, baseURI, true); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public Manifest( |
|
Element element, String baseURI, boolean secureValidation |
|
) throws XMLSecurityException { |
|
super(element, baseURI); |
|
|
|
Attr attr = element.getAttributeNodeNS(null, "Id"); |
|
if (attr != null) { |
|
element.setIdAttributeNode(attr, true); |
|
} |
|
this.secureValidation = secureValidation; |
|
|
|
|
|
this.referencesEl = |
|
XMLUtils.selectDsNodes( |
|
getFirstChild(), Constants._TAG_REFERENCE |
|
); |
|
int le = this.referencesEl.length; |
|
if (le == 0) { |
|
|
|
Object exArgs[] = { Constants._TAG_REFERENCE, Constants._TAG_MANIFEST }; |
|
|
|
throw new DOMException(DOMException.WRONG_DOCUMENT_ERR, |
|
I18n.translate("xml.WrongContent", exArgs)); |
|
} |
|
|
|
if (secureValidation && le > referenceCount) { |
|
Object exArgs[] = { le, referenceCount }; |
|
|
|
throw new XMLSecurityException("signature.tooManyReferences", exArgs); |
|
} |
|
|
|
|
|
this.references = new ArrayList<>(le); |
|
|
|
for (int i = 0; i < le; i++) { |
|
Element refElem = referencesEl[i]; |
|
Attr refAttr = refElem.getAttributeNodeNS(null, "Id"); |
|
if (refAttr != null) { |
|
refElem.setIdAttributeNode(refAttr, true); |
|
} |
|
this.references.add(null); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public void addDocument( |
|
String baseURI, String referenceURI, Transforms transforms, |
|
String digestURI, String referenceId, String referenceType |
|
) throws XMLSignatureException { |
|
|
|
Reference ref = |
|
new Reference(getDocument(), baseURI, referenceURI, this, transforms, digestURI); |
|
|
|
if (referenceId != null) { |
|
ref.setId(referenceId); |
|
} |
|
|
|
if (referenceType != null) { |
|
ref.setType(referenceType); |
|
} |
|
|
|
|
|
this.references.add(ref); |
|
|
|
|
|
appendSelf(ref); |
|
addReturnToSelf(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public void generateDigestValues() |
|
throws XMLSignatureException, ReferenceNotInitializedException { |
|
for (int i = 0; i < this.getLength(); i++) { |
|
|
|
Reference currentRef = this.references.get(i); |
|
currentRef.generateDigestValue(); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public int getLength() { |
|
return this.references.size(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public Reference item(int i) throws XMLSecurityException { |
|
if (this.references.get(i) == null) { |
|
|
|
Reference ref = |
|
new Reference(referencesEl[i], this.baseURI, this, secureValidation); |
|
|
|
this.references.set(i, ref); |
|
} |
|
|
|
return this.references.get(i); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public void setId(String Id) { |
|
if (Id != null) { |
|
setLocalIdAttribute(Constants._ATT_ID, Id); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public String getId() { |
|
return getLocalAttribute(Constants._ATT_ID); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public boolean verifyReferences() |
|
throws MissingResourceFailureException, XMLSecurityException { |
|
return this.verifyReferences(false); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public boolean verifyReferences(boolean followManifests) |
|
throws MissingResourceFailureException, XMLSecurityException { |
|
if (referencesEl == null) { |
|
this.referencesEl = |
|
XMLUtils.selectDsNodes( |
|
getFirstChild(), Constants._TAG_REFERENCE |
|
); |
|
} |
|
LOG.debug("verify {} References", referencesEl.length); |
|
LOG.debug("I am {} requested to follow nested Manifests", (followManifests |
|
? "" : "not")); |
|
if (referencesEl.length == 0) { |
|
throw new XMLSecurityException("empty", new Object[]{"References are empty"}); |
|
} |
|
if (secureValidation && referencesEl.length > referenceCount) { |
|
Object exArgs[] = { referencesEl.length, referenceCount }; |
|
|
|
throw new XMLSecurityException("signature.tooManyReferences", exArgs); |
|
} |
|
|
|
this.verificationResults = new ArrayList<>(referencesEl.length); |
|
boolean verify = true; |
|
for (int i = 0; i < this.referencesEl.length; i++) { |
|
Reference currentRef = |
|
new Reference(referencesEl[i], this.baseURI, this, secureValidation); |
|
|
|
this.references.set(i, currentRef); |
|
|
|
|
|
try { |
|
boolean currentRefVerified = currentRef.verify(); |
|
|
|
if (!currentRefVerified) { |
|
verify = false; |
|
} |
|
LOG.debug("The Reference has Type {}", currentRef.getType()); |
|
|
|
List<VerifiedReference> manifestReferences = Collections.emptyList(); |
|
|
|
|
|
if (verify && followManifests && currentRef.typeIsReferenceToManifest()) { |
|
LOG.debug("We have to follow a nested Manifest"); |
|
|
|
try { |
|
XMLSignatureInput signedManifestNodes = |
|
currentRef.dereferenceURIandPerformTransforms(null); |
|
Set<Node> nl = signedManifestNodes.getNodeSet(); |
|
Manifest referencedManifest = null; |
|
Iterator<Node> nlIterator = nl.iterator(); |
|
|
|
while (nlIterator.hasNext()) { |
|
Node n = nlIterator.next(); |
|
|
|
if (n.getNodeType() == Node.ELEMENT_NODE |
|
&& ((Element) n).getNamespaceURI().equals(Constants.SignatureSpecNS) |
|
&& ((Element) n).getLocalName().equals(Constants._TAG_MANIFEST) |
|
) { |
|
try { |
|
referencedManifest = |
|
new Manifest( |
|
(Element)n, signedManifestNodes.getSourceURI(), secureValidation |
|
); |
|
break; |
|
} catch (XMLSecurityException ex) { |
|
LOG.debug(ex.getMessage(), ex); |
|
// Hm, seems not to be a ds:Manifest |
|
} |
|
} |
|
} |
|
|
|
if (referencedManifest == null) { |
|
// The Reference stated that it points to a ds:Manifest |
|
|
|
throw new MissingResourceFailureException(currentRef, "empty", |
|
new Object[]{"No Manifest found"}); |
|
} |
|
|
|
referencedManifest.perManifestResolvers = this.perManifestResolvers; |
|
referencedManifest.resolverProperties = this.resolverProperties; |
|
|
|
boolean referencedManifestValid = |
|
referencedManifest.verifyReferences(followManifests); |
|
|
|
if (!referencedManifestValid) { |
|
verify = false; |
|
|
|
LOG.warn("The nested Manifest was invalid (bad)"); |
|
} else { |
|
LOG.debug("The nested Manifest was valid (good)"); |
|
} |
|
|
|
manifestReferences = referencedManifest.getVerificationResults(); |
|
} catch (IOException ex) { |
|
throw new ReferenceNotInitializedException(ex); |
|
} catch (ParserConfigurationException ex) { |
|
throw new ReferenceNotInitializedException(ex); |
|
} catch (SAXException ex) { |
|
throw new ReferenceNotInitializedException(ex); |
|
} |
|
} |
|
|
|
verificationResults.add(new VerifiedReference(currentRefVerified, currentRef.getURI(), manifestReferences)); |
|
} catch (ReferenceNotInitializedException ex) { |
|
Object exArgs[] = { currentRef.getURI() }; |
|
|
|
throw new MissingResourceFailureException( |
|
ex, currentRef, "signature.Verification.Reference.NoInput", exArgs |
|
); |
|
} |
|
} |
|
|
|
return verify; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public boolean getVerificationResult(int index) throws XMLSecurityException { |
|
if (index < 0 || index > this.getLength() - 1) { |
|
Object exArgs[] = { Integer.toString(index), Integer.toString(this.getLength()) }; |
|
Exception e = |
|
new IndexOutOfBoundsException( |
|
I18n.translate("signature.Verification.IndexOutOfBounds", exArgs) |
|
); |
|
|
|
throw new XMLSecurityException(e); |
|
} |
|
|
|
if (this.verificationResults == null) { |
|
try { |
|
this.verifyReferences(); |
|
} catch (Exception ex) { |
|
throw new XMLSecurityException(ex); |
|
} |
|
} |
|
|
|
return ((ArrayList<VerifiedReference>)verificationResults).get(index).isValid(); |
|
} |
|
|
|
|
|
|
|
*/ |
|
public List<VerifiedReference> getVerificationResults() { |
|
if (verificationResults == null) { |
|
return Collections.emptyList(); |
|
} |
|
return Collections.unmodifiableList(verificationResults); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public void addResourceResolver(ResourceResolver resolver) { |
|
if (resolver == null) { |
|
return; |
|
} |
|
if (perManifestResolvers == null) { |
|
perManifestResolvers = new ArrayList<>(); |
|
} |
|
this.perManifestResolvers.add(resolver); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public void addResourceResolver(ResourceResolverSpi resolverSpi) { |
|
if (resolverSpi == null) { |
|
return; |
|
} |
|
if (perManifestResolvers == null) { |
|
perManifestResolvers = new ArrayList<>(); |
|
} |
|
perManifestResolvers.add(new ResourceResolver(resolverSpi)); |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
public List<ResourceResolver> getPerManifestResolvers() { |
|
return perManifestResolvers; |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
public Map<String, String> getResolverProperties() { |
|
return resolverProperties; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public void setResolverProperty(String key, String value) { |
|
if (resolverProperties == null) { |
|
resolverProperties = new HashMap<>(10); |
|
} |
|
this.resolverProperties.put(key, value); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public String getResolverProperty(String key) { |
|
return this.resolverProperties.get(key); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public byte[] getSignedContentItem(int i) throws XMLSignatureException { |
|
try { |
|
return this.getReferencedContentAfterTransformsItem(i).getBytes(); |
|
} catch (IOException ex) { |
|
throw new XMLSignatureException(ex); |
|
} catch (CanonicalizationException ex) { |
|
throw new XMLSignatureException(ex); |
|
} catch (InvalidCanonicalizerException ex) { |
|
throw new XMLSignatureException(ex); |
|
} catch (XMLSecurityException ex) { |
|
throw new XMLSignatureException(ex); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public XMLSignatureInput getReferencedContentBeforeTransformsItem(int i) |
|
throws XMLSecurityException { |
|
return this.item(i).getContentsBeforeTransformation(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public XMLSignatureInput getReferencedContentAfterTransformsItem(int i) |
|
throws XMLSecurityException { |
|
return this.item(i).getContentsAfterTransformation(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public int getSignedContentLength() { |
|
return this.getLength(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public String getBaseLocalName() { |
|
return Constants._TAG_MANIFEST; |
|
} |
|
|
|
public boolean isSecureValidation() { |
|
return secureValidation; |
|
} |
|
} |