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

eu.europa.esig.dss.xades.signature.SignaturePolicyStoreBuilder Maven / Gradle / Ivy

/**
 * DSS - Digital Signature Services
 * Copyright (C) 2015 European Commission, provided under the CEF programme
 * 
 * This file is part of the "DSS - Digital Signature Services" project.
 * 
 * This library 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 2.1 of the License, or (at your option) any later version.
 * 
 * This library 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 this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */
package eu.europa.esig.dss.xades.signature;

import eu.europa.esig.dss.model.DSSDocument;
import eu.europa.esig.dss.model.DSSException;
import eu.europa.esig.dss.model.Digest;
import eu.europa.esig.dss.model.SignaturePolicyStore;
import eu.europa.esig.dss.model.SpDocSpecification;
import eu.europa.esig.dss.spi.DSSUtils;
import eu.europa.esig.dss.spi.exception.IllegalInputException;
import eu.europa.esig.dss.spi.policy.SignaturePolicyValidator;
import eu.europa.esig.dss.spi.signature.AdvancedSignature;
import eu.europa.esig.dss.utils.Utils;
import eu.europa.esig.dss.xades.XAdESSignatureParameters;
import eu.europa.esig.dss.xades.definition.xades141.XAdES141Attribute;
import eu.europa.esig.dss.xades.definition.xades141.XAdES141Element;
import eu.europa.esig.dss.xades.validation.XAdESSignature;
import eu.europa.esig.dss.xades.validation.XAdESSignaturePolicy;
import eu.europa.esig.dss.xades.validation.XMLDocumentAnalyzer;
import eu.europa.esig.dss.xades.validation.policy.XMLSignaturePolicyValidator;
import eu.europa.esig.dss.xml.utils.DomUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import java.util.Objects;

/**
 * Builds a XAdES SignaturePolicyStore
 *
 */
public class SignaturePolicyStoreBuilder extends ExtensionBuilder {

	private static final Logger LOG = LoggerFactory.getLogger(SignaturePolicyStoreBuilder.class);

	/**
	 * Default constructor
	 */
	public SignaturePolicyStoreBuilder() {
		// empty
	}

	/**
	 * Adds a signaturePolicyStore to all signatures inside the document, matching the incorporated signature policy
	 *
	 * @param signatureDocument {@link DSSDocument} containing signatures to add signature policy store into
	 * @param signaturePolicyStore {@link SignaturePolicyStore} to add
	 * @return {@link DSSDocument} with signaturePolicyStore
	 */
	public DSSDocument addSignaturePolicyStore(DSSDocument signatureDocument, SignaturePolicyStore signaturePolicyStore) {
		Objects.requireNonNull(signatureDocument, "Signature document must be provided!");
		assertConfigurationValid(signaturePolicyStore);

		final XMLDocumentAnalyzer documentValidator = initDocumentValidator(signatureDocument);

		boolean signaturePolicyStoreAdded = false;
		for (AdvancedSignature signature : documentValidator.getSignatures()) {
			boolean added = addSignaturePolicyStoreIfDigestMatch((XAdESSignature) signature, documentDom, signaturePolicyStore);
			signaturePolicyStoreAdded = signaturePolicyStoreAdded || added;
		}
		if (!signaturePolicyStoreAdded) {
			throw new IllegalInputException("The process did not find a signature to add SignaturePolicyStore!");
		}

		return createXmlDocument();
	}

	/**
	 * Adds a signaturePolicyStore to a signature with the given {@code signatureId},
	 * if the signature policy identifier matches the policy provided within {@code SignaturePolicyStore}
	 *
	 * @param signatureDocument {@link DSSDocument} containing signatures to add signature policy store into
	 * @param signaturePolicyStore {@link SignaturePolicyStore} to add
	 * @param signatureId {@link String} Id of a signature to add SignaturePolicyStore for
	 * @return {@link DSSDocument} with signaturePolicyStore
	 */
	public DSSDocument addSignaturePolicyStore(DSSDocument signatureDocument, SignaturePolicyStore signaturePolicyStore,
											   String signatureId) {
		Objects.requireNonNull(signatureDocument, "Signature document must be provided!");
		assertConfigurationValid(signaturePolicyStore);

		final XMLDocumentAnalyzer documentValidator = initDocumentValidator(signatureDocument);
		AdvancedSignature signature = documentValidator.getSignatureById(signatureId);
		if (signature == null) {
			throw new IllegalInputException(String.format("Unable to find a signature with Id : %s!", signatureId));
		}
		boolean added = addSignaturePolicyStoreIfDigestMatch((XAdESSignature) signature, documentDom, signaturePolicyStore);
		if (!added) {
			throw new IllegalInputException(String.format(
					"The process was not able to add SignaturePolicyStore to a signature with Id : %s!", signatureId));
		}

		return createXmlDocument();
	}

	private XMLDocumentAnalyzer initDocumentValidator(DSSDocument document) {
		params = new XAdESSignatureParameters();

		documentAnalyzer = new XMLDocumentAnalyzer(document);
		documentDom = documentAnalyzer.getRootElement();

		return documentAnalyzer;
	}

	/**
	 * This method adds {@code SignaturePolicyStore} to a {@code documentDom} if required
	 *
	 * @param xadesSignature {@link XAdESSignature} signature to add {@link SignaturePolicyStore}
	 * @param documentDom {@link Document} root DOM of the signature document
	 * @param signaturePolicyStore {@link SignaturePolicyStore} to be added
	 * @return TRUE if the signaturePolicyStore has been added for the particular signature, FALSE otherwise
	 */
	protected boolean addSignaturePolicyStoreIfDigestMatch(XAdESSignature xadesSignature, Document documentDom,
														SignaturePolicyStore signaturePolicyStore) {
		xadesSignature = initializeSignatureBuilder(xadesSignature);

		ensureUnsignedProperties();
		ensureUnsignedSignatureProperties();

		if (checkDigest(xadesSignature, signaturePolicyStore)) {
			Element signaturePolicyStoreElement = DomUtils.addElement(documentDom, unsignedSignaturePropertiesDom, getXades141Namespace(),
					XAdES141Element.SIGNATURE_POLICY_STORE);

			if (signaturePolicyStore.getId() != null) {
				signaturePolicyStoreElement.setAttribute(XAdES141Attribute.ID.getAttributeName(), signaturePolicyStore.getId());
			}

			SpDocSpecification spDocSpecification = signaturePolicyStore.getSpDocSpecification();
			incorporateSPDocSpecification(signaturePolicyStoreElement, spDocSpecification);

			DSSDocument signaturePolicyContent = signaturePolicyStore.getSignaturePolicyContent();
			if (signaturePolicyContent != null) {
				Element policyDocElement = DomUtils.addElement(documentDom, signaturePolicyStoreElement, getXades141Namespace(),
						XAdES141Element.SIGNATURE_POLICY_DOCUMENT);

				DomUtils.setTextNode(documentDom, policyDocElement,
						Utils.toBase64(DSSUtils.toByteArray(signaturePolicyContent)));
			}

			String sigPolDocLocalURI = signaturePolicyStore.getSigPolDocLocalURI();
			if (Utils.isStringNotEmpty(sigPolDocLocalURI)) {
				DomUtils.addTextElement(documentDom, signaturePolicyStoreElement, getXades141Namespace(),
						XAdES141Element.SIG_POL_DOC_LOCAL_URI, sigPolDocLocalURI);
			}

			return true;
		}

		return false;
	}

	/**
	 * This method verifies if the digests computed in the provided {@code SignaturePolicyStore} match
	 * the digest defined in the incorporated signature policy identifier
	 *
	 * @param xadesSignature {@link XAdESSignature} to check signature policy identifier
	 * @param signaturePolicyStore {@link SignaturePolicyStore} to be incorporated
	 * @return TRUE if the digest match and {@link SignaturePolicyStore} can be embedded, FALSE otherwise
	 */
	protected boolean checkDigest(XAdESSignature xadesSignature, SignaturePolicyStore signaturePolicyStore) {
		final String currentSignatureId = xadesSignature.getDAIdentifier();

		final XAdESSignaturePolicy signaturePolicy = xadesSignature.getSignaturePolicy();
		if (signaturePolicy == null) {
			LOG.warn("No defined SignaturePolicyIdentifier for signature with Id : {}", currentSignatureId);
			return false;
		}
		final Digest digest = signaturePolicy.getDigest();
		if (digest == null) {
			LOG.warn("No defined digest for signature with Id : {}", currentSignatureId);
			return false;
		}

		DSSDocument signaturePolicyContent = signaturePolicyStore.getSignaturePolicyContent();
		if (signaturePolicyContent == null) {
			LOG.info("No policy document has been provided. Digests are not checked!");
			return true;
		}
		signaturePolicy.setPolicyContent(signaturePolicyContent);

		Digest computedDigest;
		try {
			SignaturePolicyValidator validator = documentAnalyzer.getSignaturePolicyValidatorLoader().loadValidator(signaturePolicy);
			if (validator instanceof XMLSignaturePolicyValidator) {
				XMLSignaturePolicyValidator xmlSignaturePolicyValidator = (XMLSignaturePolicyValidator) validator;
				computedDigest = xmlSignaturePolicyValidator.getDigestAfterTransforms(signaturePolicyContent,
						digest.getAlgorithm(), signaturePolicy.getTransforms());
			} else {
				computedDigest = validator.getComputedDigest(signaturePolicyStore.getSignaturePolicyContent(), digest.getAlgorithm());
			}

		} catch (Exception e) {
			throw new DSSException(String.format("Unable to compute digest for a SignaturePolicyStore. " +
					"Reason : %s", e.getMessage()), e);
		}

		boolean digestMatch = digest.equals(computedDigest);
		if (!digestMatch) {
			LOG.warn("Signature policy's digest {} doesn't match the digest extracted from document {} for signature with Id : {}",
					computedDigest, digest, currentSignatureId);
		}
		return digestMatch;
	}

	private void assertConfigurationValid(SignaturePolicyStore signaturePolicyStore) {
		Objects.requireNonNull(signaturePolicyStore, "SignaturePolicyStore must be provided");
		Objects.requireNonNull(signaturePolicyStore.getSpDocSpecification(), "SpDocSpecification must be provided");
		Objects.requireNonNull(signaturePolicyStore.getSpDocSpecification().getId(), "ID (OID or URI) for SpDocSpecification must be provided");

		boolean signaturePolicyContentPresent = signaturePolicyStore.getSignaturePolicyContent() != null;
		boolean sigPolDocLocalURIPresent = signaturePolicyStore.getSigPolDocLocalURI() != null;
		if (!(signaturePolicyContentPresent ^ sigPolDocLocalURIPresent)) {
			throw new IllegalArgumentException("SignaturePolicyStore shall contain either " +
					"SignaturePolicyContent document or sigPolDocLocalURI!");
		}
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy