| /** |
| * 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.signature; |
| |
| import java.io.IOException; |
| import java.io.OutputStream; |
| import java.security.AccessController; |
| import java.security.PrivilegedAction; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.Set; |
| |
| import org.apache.xml.security.algorithms.Algorithm; |
| import org.apache.xml.security.algorithms.MessageDigestAlgorithm; |
| import org.apache.xml.security.c14n.CanonicalizationException; |
| import org.apache.xml.security.c14n.InvalidCanonicalizerException; |
| import org.apache.xml.security.exceptions.XMLSecurityException; |
| import org.apache.xml.security.signature.reference.ReferenceData; |
| import org.apache.xml.security.signature.reference.ReferenceNodeSetData; |
| import org.apache.xml.security.signature.reference.ReferenceOctetStreamData; |
| import org.apache.xml.security.signature.reference.ReferenceSubTreeData; |
| import org.apache.xml.security.transforms.InvalidTransformException; |
| import org.apache.xml.security.transforms.Transform; |
| import org.apache.xml.security.transforms.TransformationException; |
| import org.apache.xml.security.transforms.Transforms; |
| import org.apache.xml.security.transforms.params.InclusiveNamespaces; |
| import org.apache.xml.security.utils.Constants; |
| import org.apache.xml.security.utils.DigesterOutputStream; |
| import org.apache.xml.security.utils.SignatureElementProxy; |
| import org.apache.xml.security.utils.UnsyncBufferedOutputStream; |
| import org.apache.xml.security.utils.XMLUtils; |
| import org.apache.xml.security.utils.resolver.ResourceResolver; |
| import org.apache.xml.security.utils.resolver.ResourceResolverException; |
| import org.w3c.dom.Attr; |
| import org.w3c.dom.Document; |
| import org.w3c.dom.Element; |
| import org.w3c.dom.Node; |
| import org.w3c.dom.Text; |
| |
| /** |
| * Handles <code><ds:Reference></code> elements. |
| * |
| * This includes: |
| * |
| * Construct a <CODE>ds:Reference</CODE> from an {@link org.w3c.dom.Element}. |
| * |
| * <p>Create a new reference</p> |
| * <pre> |
| * Document doc; |
| * MessageDigestAlgorithm sha1 = MessageDigestAlgorithm.getInstance("http://#sha1"); |
| * Reference ref = new Reference(new XMLSignatureInput(new FileInputStream("1.gif"), |
| * "http://localhost/1.gif", |
| * (Transforms) null, sha1); |
| * Element refElem = ref.toElement(doc); |
| * </pre> |
| * |
| * <p>Verify a reference</p> |
| * <pre> |
| * Element refElem = doc.getElement("Reference"); // PSEUDO |
| * Reference ref = new Reference(refElem); |
| * String url = ref.getURI(); |
| * ref.setData(new XMLSignatureInput(new FileInputStream(url))); |
| * if (ref.verify()) { |
| * System.out.println("verified"); |
| * } |
| * </pre> |
| * |
| * <pre> |
| * <element name="Reference" type="ds:ReferenceType"/> |
| * <complexType name="ReferenceType"> |
| * <sequence> |
| * <element ref="ds:Transforms" minOccurs="0"/> |
| * <element ref="ds:DigestMethod"/> |
| * <element ref="ds:DigestValue"/> |
| * </sequence> |
| * <attribute name="Id" type="ID" use="optional"/> |
| * <attribute name="URI" type="anyURI" use="optional"/> |
| * <attribute name="Type" type="anyURI" use="optional"/> |
| * </complexType> |
| * </pre> |
| * |
| * @see ObjectContainer |
| * @see Manifest |
| */ |
| public class Reference extends SignatureElementProxy { |
| |
| /** Field OBJECT_URI */ |
| public static final String OBJECT_URI = Constants.SignatureSpecNS + Constants._TAG_OBJECT; |
| |
| /** Field MANIFEST_URI */ |
| public static final String MANIFEST_URI = Constants.SignatureSpecNS + Constants._TAG_MANIFEST; |
| |
| /** |
| * The maximum number of transforms per reference, if secure validation is enabled. |
| */ |
| public static final int MAXIMUM_TRANSFORM_COUNT = 5; |
| |
| private boolean secureValidation; |
| |
| /** |
| * Look up useC14N11 system property. If true, an explicit C14N11 transform |
| * will be added if necessary when generating the signature. See section |
| * 3.1.1 of http://www.w3.org/2007/xmlsec/Drafts/xmldsig-core/ for more info. |
| */ |
| private static boolean useC14N11 = |
| AccessController.doPrivileged((PrivilegedAction<Boolean>) |
| () -> Boolean.getBoolean("org.apache.xml.security.useC14N11")); |
| |
| private static final org.slf4j.Logger LOG = |
| org.slf4j.LoggerFactory.getLogger(Reference.class); |
| |
| private Manifest manifest; |
| private XMLSignatureInput transformsOutput; |
| |
| private Transforms transforms; |
| |
| private Element digestMethodElem; |
| |
| private Element digestValueElement; |
| |
| private ReferenceData referenceData; |
| |
| /** |
| * Constructor Reference |
| * |
| * @param doc the {@link Document} in which <code>XMLsignature</code> is placed |
| * @param baseURI the URI of the resource where the XML instance will be stored |
| * @param referenceURI URI indicate where is data which will digested |
| * @param manifest |
| * @param transforms {@link Transforms} applied to data |
| * @param messageDigestAlgorithm {@link MessageDigestAlgorithm Digest algorithm} which is |
| * applied to the data |
| * TODO should we throw XMLSignatureException if MessageDigestAlgoURI is wrong? |
| * @throws XMLSignatureException |
| */ |
| protected Reference( |
| Document doc, String baseURI, String referenceURI, Manifest manifest, |
| Transforms transforms, String messageDigestAlgorithm |
| ) throws XMLSignatureException { |
| super(doc); |
| |
| addReturnToSelf(); |
| |
| this.baseURI = baseURI; |
| this.manifest = manifest; |
| |
| this.setURI(referenceURI); |
| |
| // important: The ds:Reference must be added to the associated ds:Manifest |
| // or ds:SignedInfo _before_ the this.resolverResult() is called. |
| // this.manifest.appendChild(this.constructionElement); |
| // this.manifest.appendChild(this.doc.createTextNode("\n")); |
| |
| if (transforms != null) { |
| this.transforms = transforms; |
| appendSelf(transforms); |
| addReturnToSelf(); |
| } |
| |
| // Create DigestMethod Element without actually instantiating a MessageDigest Object |
| Algorithm digestAlgorithm = new Algorithm(getDocument(), messageDigestAlgorithm) { |
| public String getBaseNamespace() { |
| return Constants.SignatureSpecNS; |
| } |
| |
| public String getBaseLocalName() { |
| return Constants._TAG_DIGESTMETHOD; |
| } |
| }; |
| |
| digestMethodElem = digestAlgorithm.getElement(); |
| |
| appendSelf(digestMethodElem); |
| addReturnToSelf(); |
| |
| digestValueElement = |
| XMLUtils.createElementInSignatureSpace(getDocument(), Constants._TAG_DIGESTVALUE); |
| |
| appendSelf(digestValueElement); |
| addReturnToSelf(); |
| } |
| |
| |
| /** |
| * Build a {@link Reference} from an {@link Element} |
| * |
| * @param element <code>Reference</code> element |
| * @param baseURI the URI of the resource where the XML instance was stored |
| * @param manifest is the {@link Manifest} of {@link SignedInfo} in which the Reference occurs. |
| * We need this because the Manifest has the individual {@link ResourceResolver}s which have |
| * been set by the user |
| * @throws XMLSecurityException |
| */ |
| protected Reference(Element element, String baseURI, Manifest manifest) throws XMLSecurityException { |
| this(element, baseURI, manifest, true); |
| } |
| |
| /** |
| * Build a {@link Reference} from an {@link Element} |
| * |
| * @param element <code>Reference</code> element |
| * @param baseURI the URI of the resource where the XML instance was stored |
| * @param manifest is the {@link Manifest} of {@link SignedInfo} in which the Reference occurs. |
| * @param secureValidation whether secure validation is enabled or not |
| * We need this because the Manifest has the individual {@link ResourceResolver}s which have |
| * been set by the user |
| * @throws XMLSecurityException |
| */ |
| protected Reference(Element element, String baseURI, Manifest manifest, boolean secureValidation) |
| throws XMLSecurityException { |
| super(element, baseURI); |
| this.secureValidation = secureValidation; |
| this.baseURI = baseURI; |
| Element el = XMLUtils.getNextElement(element.getFirstChild()); |
| |
| if (el != null && Constants._TAG_TRANSFORMS.equals(el.getLocalName()) |
| && Constants.SignatureSpecNS.equals(el.getNamespaceURI())) { |
| transforms = new Transforms(el, this.baseURI); |
| transforms.setSecureValidation(secureValidation); |
| if (secureValidation && transforms.getLength() > MAXIMUM_TRANSFORM_COUNT) { |
| Object[] exArgs = { transforms.getLength(), MAXIMUM_TRANSFORM_COUNT }; |
| |
| throw new XMLSecurityException("signature.tooManyTransforms", exArgs); |
| } |
| el = XMLUtils.getNextElement(el.getNextSibling()); |
| } |
| |
| digestMethodElem = el; |
| if (digestMethodElem == null) { |
| throw new XMLSecurityException("signature.Reference.NoDigestMethod"); |
| } |
| |
| digestValueElement = XMLUtils.getNextElement(digestMethodElem.getNextSibling()); |
| if (digestValueElement == null) { |
| throw new XMLSecurityException("signature.Reference.NoDigestValue"); |
| } |
| this.manifest = manifest; |
| } |
| |
| /** |
| * Returns {@link MessageDigestAlgorithm} |
| * |
| * |
| * @return {@link MessageDigestAlgorithm} |
| * |
| * @throws XMLSignatureException |
| */ |
| public MessageDigestAlgorithm getMessageDigestAlgorithm() throws XMLSignatureException { |
| if (digestMethodElem == null) { |
| return null; |
| } |
| |
| String uri = digestMethodElem.getAttributeNS(null, Constants._ATT_ALGORITHM); |
| |
| if ("".equals(uri)) { |
| return null; |
| } |
| |
| if (secureValidation && MessageDigestAlgorithm.ALGO_ID_DIGEST_NOT_RECOMMENDED_MD5.equals(uri)) { |
| Object[] exArgs = { uri }; |
| |
| throw new XMLSignatureException("signature.signatureAlgorithm", exArgs); |
| } |
| |
| return MessageDigestAlgorithm.getInstance(getDocument(), uri); |
| } |
| |
| /** |
| * Sets the <code>URI</code> of this <code>Reference</code> element |
| * |
| * @param uri the <code>URI</code> of this <code>Reference</code> element |
| */ |
| public void setURI(String uri) { |
| if (uri != null) { |
| setLocalAttribute(Constants._ATT_URI, uri); |
| } |
| } |
| |
| /** |
| * Returns the <code>URI</code> of this <code>Reference</code> element |
| * |
| * @return URI the <code>URI</code> of this <code>Reference</code> element |
| */ |
| public String getURI() { |
| return getLocalAttribute(Constants._ATT_URI); |
| } |
| |
| /** |
| * Sets the <code>Id</code> attribute of this <code>Reference</code> element |
| * |
| * @param id the <code>Id</code> attribute of this <code>Reference</code> element |
| */ |
| public void setId(String id) { |
| if (id != null) { |
| setLocalIdAttribute(Constants._ATT_ID, id); |
| } |
| } |
| |
| /** |
| * Returns the <code>Id</code> attribute of this <code>Reference</code> element |
| * |
| * @return Id the <code>Id</code> attribute of this <code>Reference</code> element |
| */ |
| public String getId() { |
| return getLocalAttribute(Constants._ATT_ID); |
| } |
| |
| /** |
| * Sets the <code>type</code> atttibute of the Reference indicate whether an |
| * <code>ds:Object</code>, <code>ds:SignatureProperty</code>, or <code>ds:Manifest</code> |
| * element. |
| * |
| * @param type the <code>type</code> attribute of the Reference |
| */ |
| public void setType(String type) { |
| if (type != null) { |
| setLocalAttribute(Constants._ATT_TYPE, type); |
| } |
| } |
| |
| /** |
| * Return the <code>type</code> atttibute of the Reference indicate whether an |
| * <code>ds:Object</code>, <code>ds:SignatureProperty</code>, or <code>ds:Manifest</code> |
| * element |
| * |
| * @return the <code>type</code> attribute of the Reference |
| */ |
| public String getType() { |
| return getLocalAttribute(Constants._ATT_TYPE); |
| } |
| |
| /** |
| * Method isReferenceToObject |
| * |
| * This returns true if the <CODE>Type</CODE> attribute of the |
| * <CODE>Reference</CODE> element points to a <CODE>#Object</CODE> element |
| * |
| * @return true if the Reference type indicates that this Reference points to an |
| * <code>Object</code> |
| */ |
| public boolean typeIsReferenceToObject() { |
| return Reference.OBJECT_URI.equals(this.getType()); |
| } |
| |
| /** |
| * Method isReferenceToManifest |
| * |
| * This returns true if the <CODE>Type</CODE> attribute of the |
| * <CODE>Reference</CODE> element points to a <CODE>#Manifest</CODE> element |
| * |
| * @return true if the Reference type indicates that this Reference points to a |
| * {@link Manifest} |
| */ |
| public boolean typeIsReferenceToManifest() { |
| return Reference.MANIFEST_URI.equals(this.getType()); |
| } |
| |
| /** |
| * Method setDigestValueElement |
| * |
| * @param digestValue |
| */ |
| private void setDigestValueElement(byte[] digestValue) { |
| Node n = digestValueElement.getFirstChild(); |
| while (n != null) { |
| digestValueElement.removeChild(n); |
| n = n.getNextSibling(); |
| } |
| |
| String base64codedValue = XMLUtils.encodeToString(digestValue); |
| Text t = createText(base64codedValue); |
| |
| digestValueElement.appendChild(t); |
| } |
| |
| /** |
| * Method generateDigestValue |
| * |
| * @throws ReferenceNotInitializedException |
| * @throws XMLSignatureException |
| */ |
| public void generateDigestValue() |
| throws XMLSignatureException, ReferenceNotInitializedException { |
| this.setDigestValueElement(this.calculateDigest(false)); |
| } |
| |
| /** |
| * Returns the XMLSignatureInput which is created by de-referencing the URI attribute. |
| * @return the XMLSignatureInput of the source of this reference |
| * @throws ReferenceNotInitializedException If the resolver found any |
| * problem resolving the reference |
| */ |
| public XMLSignatureInput getContentsBeforeTransformation() |
| throws ReferenceNotInitializedException { |
| try { |
| Attr uriAttr = |
| getElement().getAttributeNodeNS(null, Constants._ATT_URI); |
| |
| ResourceResolver resolver = |
| ResourceResolver.getInstance( |
| uriAttr, this.baseURI, this.manifest.getPerManifestResolvers(), secureValidation |
| ); |
| resolver.addProperties(this.manifest.getResolverProperties()); |
| |
| return resolver.resolve(uriAttr, this.baseURI, secureValidation); |
| } catch (ResourceResolverException ex) { |
| throw new ReferenceNotInitializedException(ex); |
| } |
| } |
| |
| private XMLSignatureInput getContentsAfterTransformation( |
| XMLSignatureInput input, OutputStream os |
| ) throws XMLSignatureException { |
| try { |
| Transforms transforms = this.getTransforms(); |
| XMLSignatureInput output = null; |
| |
| if (transforms != null) { |
| output = transforms.performTransforms(input, os); |
| this.transformsOutput = output;//new XMLSignatureInput(output.getBytes()); |
| |
| //this.transformsOutput.setSourceURI(output.getSourceURI()); |
| } else { |
| output = input; |
| } |
| |
| return output; |
| } catch (ResourceResolverException ex) { |
| throw new XMLSignatureException(ex); |
| } catch (CanonicalizationException ex) { |
| throw new XMLSignatureException(ex); |
| } catch (InvalidCanonicalizerException ex) { |
| throw new XMLSignatureException(ex); |
| } catch (TransformationException ex) { |
| throw new XMLSignatureException(ex); |
| } catch (XMLSecurityException ex) { |
| throw new XMLSignatureException(ex); |
| } |
| } |
| |
| /** |
| * Returns the XMLSignatureInput which is the result of the Transforms. |
| * @return a XMLSignatureInput with all transformations applied. |
| * @throws XMLSignatureException |
| */ |
| public XMLSignatureInput getContentsAfterTransformation() |
| throws XMLSignatureException { |
| XMLSignatureInput input = this.getContentsBeforeTransformation(); |
| cacheDereferencedElement(input); |
| |
| return this.getContentsAfterTransformation(input, null); |
| } |
| |
| /** |
| * This method returns the XMLSignatureInput which represents the node set before |
| * some kind of canonicalization is applied for the first time. |
| * @return Gets a the node doing everything till the first c14n is needed |
| * |
| * @throws XMLSignatureException |
| */ |
| public XMLSignatureInput getNodesetBeforeFirstCanonicalization() |
| throws XMLSignatureException { |
| try { |
| XMLSignatureInput input = this.getContentsBeforeTransformation(); |
| cacheDereferencedElement(input); |
| XMLSignatureInput output = input; |
| Transforms transforms = this.getTransforms(); |
| |
| if (transforms != null) { |
| for (int i = 0; i < transforms.getLength(); i++) { |
| Transform t = transforms.item(i); |
| String uri = t.getURI(); |
| |
| if (uri.equals(Transforms.TRANSFORM_C14N_EXCL_OMIT_COMMENTS) |
| || uri.equals(Transforms.TRANSFORM_C14N_EXCL_WITH_COMMENTS) |
| || uri.equals(Transforms.TRANSFORM_C14N_OMIT_COMMENTS) |
| || uri.equals(Transforms.TRANSFORM_C14N_WITH_COMMENTS) |
| || uri.equals(Transforms.TRANSFORM_C14N11_OMIT_COMMENTS) |
| || uri.equals(Transforms.TRANSFORM_C14N11_WITH_COMMENTS)) { |
| break; |
| } |
| |
| output = t.performTransform(output, null); |
| } |
| |
| output.setSourceURI(input.getSourceURI()); |
| } |
| return output; |
| } catch (IOException ex) { |
| throw new XMLSignatureException(ex); |
| } catch (ResourceResolverException ex) { |
| throw new XMLSignatureException(ex); |
| } catch (CanonicalizationException ex) { |
| throw new XMLSignatureException(ex); |
| } catch (InvalidCanonicalizerException ex) { |
| throw new XMLSignatureException(ex); |
| } catch (TransformationException ex) { |
| throw new XMLSignatureException(ex); |
| } catch (XMLSecurityException ex) { |
| throw new XMLSignatureException(ex); |
| } |
| } |
| |
| /** |
| * Method getHTMLRepresentation |
| * @return The HTML of the transformation |
| * @throws XMLSignatureException |
| */ |
| public String getHTMLRepresentation() throws XMLSignatureException { |
| try { |
| XMLSignatureInput nodes = this.getNodesetBeforeFirstCanonicalization(); |
| |
| Transforms transforms = this.getTransforms(); |
| Transform c14nTransform = null; |
| |
| if (transforms != null) { |
| for (int i = 0; i < transforms.getLength(); i++) { |
| Transform t = transforms.item(i); |
| String uri = t.getURI(); |
| |
| if (uri.equals(Transforms.TRANSFORM_C14N_EXCL_OMIT_COMMENTS) |
| || uri.equals(Transforms.TRANSFORM_C14N_EXCL_WITH_COMMENTS)) { |
| c14nTransform = t; |
| break; |
| } |
| } |
| } |
| |
| Set<String> inclusiveNamespaces = new HashSet<>(); |
| if (c14nTransform != null |
| && c14nTransform.length( |
| InclusiveNamespaces.ExclusiveCanonicalizationNamespace, |
| InclusiveNamespaces._TAG_EC_INCLUSIVENAMESPACES) == 1) { |
| |
| // there is one InclusiveNamespaces element |
| InclusiveNamespaces in = |
| new InclusiveNamespaces( |
| XMLUtils.selectNode( |
| c14nTransform.getElement().getFirstChild(), |
| InclusiveNamespaces.ExclusiveCanonicalizationNamespace, |
| InclusiveNamespaces._TAG_EC_INCLUSIVENAMESPACES, |
| 0 |
| ), this.getBaseURI()); |
| |
| inclusiveNamespaces = |
| InclusiveNamespaces.prefixStr2Set(in.getInclusiveNamespaces()); |
| } |
| |
| return nodes.getHTMLRepresentation(inclusiveNamespaces); |
| } catch (TransformationException ex) { |
| throw new XMLSignatureException(ex); |
| } catch (InvalidTransformException ex) { |
| throw new XMLSignatureException(ex); |
| } catch (XMLSecurityException ex) { |
| throw new XMLSignatureException(ex); |
| } |
| } |
| |
| /** |
| * This method only works after a call to verify. |
| * @return the transformed output(i.e. what is going to be digested). |
| */ |
| public XMLSignatureInput getTransformsOutput() { |
| return this.transformsOutput; |
| } |
| |
| /** |
| * Get the ReferenceData that corresponds to the cached representation of the dereferenced |
| * object before transformation. |
| */ |
| public ReferenceData getReferenceData() { |
| return referenceData; |
| } |
| |
| /** |
| * This method returns the {@link XMLSignatureInput} which is referenced by the |
| * <CODE>URI</CODE> Attribute. |
| * @param os where to write the transformation can be null. |
| * @return the element to digest |
| * |
| * @throws XMLSignatureException |
| * @see Manifest#verifyReferences() |
| */ |
| protected XMLSignatureInput dereferenceURIandPerformTransforms(OutputStream os) |
| throws XMLSignatureException { |
| try { |
| XMLSignatureInput input = this.getContentsBeforeTransformation(); |
| cacheDereferencedElement(input); |
| |
| XMLSignatureInput output = this.getContentsAfterTransformation(input, os); |
| this.transformsOutput = output; |
| return output; |
| } catch (XMLSecurityException ex) { |
| throw new ReferenceNotInitializedException(ex); |
| } |
| } |
| |
| /** |
| * Store the dereferenced Element(s) so that it/they can be retrieved later. |
| */ |
| private void cacheDereferencedElement(XMLSignatureInput input) { |
| if (input.isNodeSet()) { |
| try { |
| final Set<Node> s = input.getNodeSet(); |
| referenceData = new ReferenceNodeSetData() { |
| public Iterator<Node> iterator() { |
| return new Iterator<Node>() { |
| |
| Iterator<Node> sIterator = s.iterator(); |
| |
| @Override |
| public boolean hasNext() { |
| return sIterator.hasNext(); |
| } |
| |
| @Override |
| public Node next() { |
| return sIterator.next(); |
| } |
| |
| @Override |
| public void remove() { |
| throw new UnsupportedOperationException(); |
| } |
| }; |
| } |
| }; |
| } catch (Exception e) { |
| // LOG a warning |
| LOG.warn("cannot cache dereferenced data: " + e); |
| } |
| } else if (input.isElement()) { |
| referenceData = new ReferenceSubTreeData |
| (input.getSubNode(), input.isExcludeComments()); |
| } else if (input.isOctetStream() || input.isByteArray()) { |
| try { |
| referenceData = new ReferenceOctetStreamData |
| (input.getOctetStream(), input.getSourceURI(), |
| input.getMIMEType()); |
| } catch (IOException ioe) { |
| // LOG a warning |
| LOG.warn("cannot cache dereferenced data: " + ioe); |
| } |
| } |
| } |
| |
| /** |
| * Method getTransforms |
| * |
| * @return The transforms that applied this reference. |
| * @throws InvalidTransformException |
| * @throws TransformationException |
| * @throws XMLSecurityException |
| * @throws XMLSignatureException |
| */ |
| public Transforms getTransforms() |
| throws XMLSignatureException, InvalidTransformException, |
| TransformationException, XMLSecurityException { |
| return transforms; |
| } |
| |
| /** |
| * Method getReferencedBytes |
| * |
| * @return the bytes that will be used to generated digest. |
| * @throws ReferenceNotInitializedException |
| * @throws XMLSignatureException |
| */ |
| public byte[] getReferencedBytes() |
| throws ReferenceNotInitializedException, XMLSignatureException { |
| try { |
| XMLSignatureInput output = this.dereferenceURIandPerformTransforms(null); |
| return output.getBytes(); |
| } catch (IOException ex) { |
| throw new ReferenceNotInitializedException(ex); |
| } catch (CanonicalizationException ex) { |
| throw new ReferenceNotInitializedException(ex); |
| } |
| } |
| |
| |
| /** |
| * Method calculateDigest |
| * |
| * @param validating true if validating the reference |
| * @return reference Calculate the digest of this reference. |
| * @throws ReferenceNotInitializedException |
| * @throws XMLSignatureException |
| */ |
| private byte[] calculateDigest(boolean validating) |
| throws ReferenceNotInitializedException, XMLSignatureException { |
| XMLSignatureInput input = this.getContentsBeforeTransformation(); |
| if (input.isPreCalculatedDigest()) { |
| return getPreCalculatedDigest(input); |
| } |
| |
| cacheDereferencedElement(input); |
| |
| MessageDigestAlgorithm mda = this.getMessageDigestAlgorithm(); |
| mda.reset(); |
| |
| try (DigesterOutputStream diOs = new DigesterOutputStream(mda); |
| OutputStream os = new UnsyncBufferedOutputStream(diOs)) { |
| |
| XMLSignatureInput output = this.getContentsAfterTransformation(input, os); |
| this.transformsOutput = output; |
| |
| // if signing and c14n11 property == true explicitly add |
| // C14N11 transform if needed |
| if (Reference.useC14N11 && !validating && !output.isOutputStreamSet() |
| && !output.isOctetStream()) { |
| if (transforms == null) { |
| transforms = new Transforms(getDocument()); |
| transforms.setSecureValidation(secureValidation); |
| getElement().insertBefore(transforms.getElement(), digestMethodElem); |
| } |
| transforms.addTransform(Transforms.TRANSFORM_C14N11_OMIT_COMMENTS); |
| output.updateOutputStream(os, true); |
| } else { |
| output.updateOutputStream(os); |
| } |
| os.flush(); |
| |
| if (output.getOctetStreamReal() != null) { |
| output.getOctetStreamReal().close(); |
| } |
| |
| //this.getReferencedBytes(diOs); |
| //mda.update(data); |
| |
| return diOs.getDigestValue(); |
| } catch (XMLSecurityException ex) { |
| throw new ReferenceNotInitializedException(ex); |
| } catch (IOException ex) { |
| throw new ReferenceNotInitializedException(ex); |
| } |
| } |
| |
| /** |
| * Get the pre-calculated digest value from the XMLSignatureInput. |
| * |
| * @param input XMLSignature |
| * @return a pre-calculated digest value. |
| * @throws ReferenceNotInitializedException if there is an error decoding digest value |
| * in Base64. Properly encoded pre-calculated digest value must be set. |
| */ |
| private byte[] getPreCalculatedDigest(XMLSignatureInput input) |
| throws ReferenceNotInitializedException { |
| LOG.debug("Verifying element with pre-calculated digest"); |
| String preCalculatedDigest = input.getPreCalculatedDigest(); |
| return XMLUtils.decode(preCalculatedDigest); |
| } |
| |
| /** |
| * Returns the digest value. |
| * |
| * @return the digest value. |
| * @throws XMLSecurityException if the Reference does not contain a DigestValue element |
| */ |
| public byte[] getDigestValue() throws XMLSecurityException { |
| if (digestValueElement == null) { |
| // The required element is not in the XML! |
| Object[] exArgs ={ Constants._TAG_DIGESTVALUE, Constants.SignatureSpecNS }; |
| throw new XMLSecurityException( |
| "signature.Verification.NoSignatureElement", exArgs |
| ); |
| } |
| String content = XMLUtils.getFullTextChildrenFromNode(digestValueElement); |
| return XMLUtils.decode(content); |
| } |
| |
| |
| /** |
| * Tests reference validation is success or false |
| * |
| * @return true if reference validation is success, otherwise false |
| * @throws ReferenceNotInitializedException |
| * @throws XMLSecurityException |
| */ |
| public boolean verify() |
| throws ReferenceNotInitializedException, XMLSecurityException { |
| byte[] elemDig = this.getDigestValue(); |
| byte[] calcDig = this.calculateDigest(true); |
| boolean equal = MessageDigestAlgorithm.isEqual(elemDig, calcDig); |
| |
| if (!equal) { |
| LOG.warn("Verification failed for URI \"" + this.getURI() + "\""); |
| LOG.warn("Expected Digest: " + XMLUtils.encodeToString(elemDig)); |
| LOG.warn("Actual Digest: " + XMLUtils.encodeToString(calcDig)); |
| } else { |
| LOG.debug("Verification successful for URI \"{}\"", this.getURI()); |
| } |
| |
| return equal; |
| } |
| |
| /** |
| * Method getBaseLocalName |
| * {@inheritDoc} |
| */ |
| public String getBaseLocalName() { |
| return Constants._TAG_REFERENCE; |
| } |
| } |