xades4j.production.SignedDataObjectsProcessor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of xades4j Show documentation
Show all versions of xades4j Show documentation
The XAdES4j library is an high-level, configurable and extensible Java implementation of XML Advanced
Electronic Signatures (XAdES 1.3.2 and 1.4.1). It enables producing, verifying and extending signatures in the
main XAdES forms: XAdES-BES, XAdES-EPES, XAdES-T and XAdES-C. Also, extended forms are supported through the
enrichment of an existing signature.
/*
* XAdES4j - A Java library for generation and verification of XAdES signatures.
* Copyright (C) 2010 Luis Goncalves.
*
* XAdES4j is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 3 of the License, or any later version.
*
* XAdES4j is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public License along
* with XAdES4j. If not, see .
*/
package xades4j.production;
import xades4j.algorithms.Algorithm;
import com.google.inject.Inject;
import java.util.Collection;
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.Map;
import org.apache.xml.security.signature.ObjectContainer;
import org.apache.xml.security.signature.Reference;
import org.apache.xml.security.signature.XMLSignature;
import org.apache.xml.security.signature.XMLSignatureException;
import org.apache.xml.security.transforms.Transforms;
import org.apache.xml.security.utils.resolver.ResourceResolver;
import org.apache.xml.security.utils.resolver.implementations.ResolverAnonymous;
import org.w3c.dom.Document;
import xades4j.UnsupportedAlgorithmException;
import xades4j.properties.DataObjectDesc;
import xades4j.providers.AlgorithmsProviderEx;
import xades4j.utils.TransformUtils;
import xades4j.xml.marshalling.algorithms.AlgorithmsParametersMarshallingProvider;
/**
* Helper class that processes a set of data object descriptions.
*
* @author Luís
*/
class SignedDataObjectsProcessor
{
private final AlgorithmsProviderEx algorithmsProvider;
private final AlgorithmsParametersMarshallingProvider algorithmsParametersMarshaller;
@Inject
SignedDataObjectsProcessor(AlgorithmsProviderEx algorithmsProvider, AlgorithmsParametersMarshallingProvider algorithmsParametersMarshaller)
{
this.algorithmsProvider = algorithmsProvider;
this.algorithmsParametersMarshaller = algorithmsParametersMarshaller;
}
/**
* Processes the signed data objects and adds the corresponding {@code Reference}s
* and {@code Object}s to the signature. This method must be invoked before
* adding any other {@code Reference}s to the signature.
*
* @return the reference mappings resulting from the data object descriptions.
*
* @throws UnsupportedAlgorithmException
* @throws IllegalStateException if the signature already contains {@code Reference}s
*/
Map process(
SignedDataObjects signedDataObjects,
XMLSignature xmlSignature) throws UnsupportedAlgorithmException
{
if(xmlSignature.getSignedInfo().getLength() != 0)
{
throw new IllegalStateException("XMLSignature already contais references");
}
for (ResourceResolver resolver : signedDataObjects.getResourceResolvers())
{
xmlSignature.addResourceResolver(resolver);
}
Collection dataObjsDescs = signedDataObjects.getDataObjectsDescs();
Map referenceMappings = new IdentityHashMap(dataObjsDescs.size());
String refUri, refType;
Transforms transforms;
String digestMethodUri = this.algorithmsProvider.getDigestAlgorithmForDataObjsReferences();
boolean hasNullURIReference = false;
/**/
try
{
for (DataObjectDesc dataObjDesc : dataObjsDescs)
{
transforms = processTransforms(dataObjDesc, xmlSignature.getDocument());
if (dataObjDesc instanceof DataObjectReference)
{
// If the data object info is a DataObjectReference, the Reference uri
// and type are the ones specified on the object.
DataObjectReference dataObjRef = (DataObjectReference) dataObjDesc;
refUri = dataObjRef.getUri();
refType = dataObjRef.getType();
}
else if (dataObjDesc instanceof EnvelopedXmlObject)
{
// If the data object info is a EnvelopedXmlObject we need to create a
// XMLObject to embed it. The Reference uri will refer the new
// XMLObject's id.
EnvelopedXmlObject envXmlObj = (EnvelopedXmlObject) dataObjDesc;
refUri = String.format("%s-object%d", xmlSignature.getId(), xmlSignature.getObjectLength());
refType = Reference.OBJECT_URI;
ObjectContainer xmlObj = new ObjectContainer(xmlSignature.getDocument());
xmlObj.setId(refUri);
xmlObj.appendChild(envXmlObj.getContent());
xmlObj.setMimeType(envXmlObj.getMimeType());
xmlObj.setEncoding(envXmlObj.getEncoding());
xmlSignature.appendObject(xmlObj);
refUri = '#' + refUri;
}
else if (dataObjDesc instanceof AnonymousDataObjectReference)
{
if (hasNullURIReference)
{
// This shouldn't happen because SignedDataObjects does the validation.
throw new IllegalStateException("Multiple AnonymousDataObjectReference detected");
}
hasNullURIReference = true;
refUri = refType = null;
AnonymousDataObjectReference anonymousRef = (AnonymousDataObjectReference) dataObjDesc;
xmlSignature.addResourceResolver(new ResolverAnonymous(anonymousRef.getDataStream()));
}
else
{
throw new ClassCastException("Unsupported SignedDataObjectDesc. Must be one of DataObjectReference, EnvelopedXmlObject and AnonymousDataObjectReference");
}
// Add the Reference. References need an ID because data object
// properties may refer them.
xmlSignature.addDocument(
refUri,
transforms,
digestMethodUri,
String.format("%s-ref%d", xmlSignature.getId(), referenceMappings.size()), // id
refType);
// SignedDataObjects doesn't allow repeated instances, so there's no
// need to check for duplicate entries on the map.
Reference ref = xmlSignature.getSignedInfo().item(referenceMappings.size());
referenceMappings.put(dataObjDesc, ref);
}
} catch (XMLSignatureException ex)
{
// -> xmlSignature.appendObject(xmlObj): not thrown when signing.
// -> xmlSignature.addDocument(...): appears to be thrown when the digest
// algorithm is not supported.
throw new UnsupportedAlgorithmException(
"Digest algorithm not supported in the XML Signature provider",
digestMethodUri, ex);
} catch (org.apache.xml.security.exceptions.XMLSecurityException ex)
{
// -> xmlSignature.getSignedInfo().item(...): shouldn't be thrown
// when signing.
throw new IllegalStateException(ex);
}
return Collections.unmodifiableMap(referenceMappings);
}
private Transforms processTransforms(
DataObjectDesc dataObjDesc,
Document document) throws UnsupportedAlgorithmException
{
Collection dObjTransfs = dataObjDesc.getTransforms();
if (dObjTransfs.isEmpty())
{
return null;
}
return TransformUtils.createTransforms(document, this.algorithmsParametersMarshaller, dObjTransfs);
}
}