All Downloads are FREE. Search and download functionalities are using the official Maven repository.

xades4j.production.SignedDataObjectsProcessor Maven / Gradle / Ivy

Go to download

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.

There is a newer version: 2.3.0
Show newest version
/*
 * 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);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy