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

eu.europa.esig.dss.cookbook.timestamp.TimestampService Maven / Gradle / Ivy

There is a newer version: 6.0.d4j.2
Show newest version
/**
 * 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.cookbook.timestamp;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.xml.security.signature.Reference;
import org.apache.xml.security.signature.XMLSignatureException;
import org.bouncycastle.tsp.TimeStampToken;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import eu.europa.esig.dss.DSSDocument;
import eu.europa.esig.dss.DSSException;
import eu.europa.esig.dss.DSSUtils;
import eu.europa.esig.dss.DigestAlgorithm;
import eu.europa.esig.dss.InMemoryDocument;
import eu.europa.esig.dss.SignatureLevel;
import eu.europa.esig.dss.SignaturePackaging;
import eu.europa.esig.dss.TimestampParameters;
import eu.europa.esig.dss.utils.Utils;
import eu.europa.esig.dss.validation.AdvancedSignature;
import eu.europa.esig.dss.validation.CommonCertificateVerifier;
import eu.europa.esig.dss.validation.SignedDocumentValidator;
import eu.europa.esig.dss.validation.TimestampInclude;
import eu.europa.esig.dss.validation.TimestampToken;
import eu.europa.esig.dss.x509.CertificatePool;
import eu.europa.esig.dss.x509.TimestampType;
import eu.europa.esig.dss.x509.tsp.TSPSource;
import eu.europa.esig.dss.xades.DSSReference;
import eu.europa.esig.dss.xades.XAdESSignatureParameters;
import eu.europa.esig.dss.xades.XPathQueryHolder;
import eu.europa.esig.dss.xades.signature.XAdESLevelBaselineB;
import eu.europa.esig.dss.xades.validation.XAdESSignature;
import eu.europa.esig.dss.xades.validation.XMLDocumentValidator;

/**
 * Class providing (content) timestamp generating methods
 */
public class TimestampService {

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

	private final TSPSource tspSource;
	private final CertificatePool certificatePool;
	private final XPathQueryHolder xPathQueryHolder;
	private final CommonCertificateVerifier commonCertificateVerifier = new CommonCertificateVerifier(true);

	// TODO (12/09/2014): To be replaced for the new release (4.2.0)
	private final String fakeSignatureValue = "kKk8sPvKC4RN1/W8Uqan2zgqNCH2Uh6I4/uQPha25W6Lz6poWuxmi9y8/iCR2anbFb1k4n3d0eJxzWzdD4ubz478it9J0jhFi/4ANFJG+FVrWqH9gw/nXnfy2nULQOY466HE172mIAjKjWdPrpo6z1IRWHYbzNbL4iSO8BxqMx0=";

	/**
	 * Basic constructor, new CertificatePool created
	 *
	 * @param tspSource
	 *            The TSPSource to be used for the Timestamp generation
	 */
	public TimestampService(final TSPSource tspSource) {
		if (tspSource == null) {
			throw new NullPointerException();
		}
		this.tspSource = tspSource;
		certificatePool = new CertificatePool();
		xPathQueryHolder = new XPathQueryHolder();
	}

	/**
	 * Alternative constructor
	 *
	 * @param tspSource
	 *            The TSPSource to be used for the Timestamp generation
	 * @param certificatePool
	 *            The CertificatePool to be used for the TimestampToken
	 */
	public TimestampService(final TSPSource tspSource, final CertificatePool certificatePool) {

		if (tspSource == null) {
			throw new NullPointerException();
		}
		this.tspSource = tspSource;

		if (certificatePool == null) {
			throw new NullPointerException();
		}
		this.certificatePool = certificatePool;
		xPathQueryHolder = new XPathQueryHolder();
	}

	/**
	 * Method that generates a ContentTimestamp as a DSSDocument
	 *
	 * @param externalParameters
	 *            the original signature parameters
	 * @return contentTimestamp as an InMemoryDocument
	 */
	public DSSDocument generateCAdESContentTimestamp(final XAdESSignatureParameters externalParameters) {

		final TimestampToken contentTimestampToken = generateCAdESContentTimestampAsTimestampToken(externalParameters);
		final InMemoryDocument document = new InMemoryDocument(contentTimestampToken.getEncoded());

		return document;
	}

	/**
	 * Method that generates a ContentTimestamp as a DSS TimestampToken
	 * *
	 *
	 * @param externalParameters
	 *            the original signature parameters
	 * @return the ContentTimestamp as a DSS TimestampToken
	 */
	public TimestampToken generateCAdESContentTimestampAsTimestampToken(final XAdESSignatureParameters externalParameters) {
		final byte[] bytes = DSSUtils.toByteArray(externalParameters.getDetachedContents().get(0));
		final TimestampToken token = generateTimestampToken(TimestampType.CONTENT_TIMESTAMP, externalParameters, bytes);
		return token;
	}

	/**
	 * Method that generates a XAdES ContentTimestamp (either an ALL DATA OBJECTS TIMESTAMP or an INDIVIDUAL DATA
	 * OBJECTS TIMESTAMP) and returns
	 * it as a TimestampToken
	 *
	 * @param toSignDocument
	 * @param externalParameters
	 * @param timestampType
	 * @return
	 */
	public TimestampToken generateXAdESContentTimestampAsTimestampToken(final DSSDocument toSignDocument, final XAdESSignatureParameters externalParameters,
			final TimestampType timestampType) {

		if (externalParameters == null) {
			throw new NullPointerException();
		}
		// 1. Set initial parameters
		final XAdESSignatureParameters signatureParameters = setSignatureParameters(externalParameters);

		// 2. Build temporary signature structure
		final XAdESLevelBaselineB levelBaselineB = new XAdESLevelBaselineB(commonCertificateVerifier);

		byte[] signatureValueBytes = Utils.fromBase64(fakeSignatureValue);
		final DSSDocument fullSignature = levelBaselineB.signDocument(toSignDocument, signatureParameters, signatureValueBytes);

		final List references = getReferencesFromValidatedSignature(toSignDocument, fullSignature);

		// 4. Concatenate byte value of references, excluding references of type SignedProperties
		byte[] concatenatedReferences = concatenateReferencesAsByteArray(references);

		// 5. Generate ContentTimestamp using the concatenated references
		switch (timestampType) {
		case ALL_DATA_OBJECTS_TIMESTAMP:
		case INDIVIDUAL_DATA_OBJECTS_TIMESTAMP:
			return generateTimestampToken(timestampType, externalParameters, concatenatedReferences);
		default:
			throw new DSSException("Incompatible timestamp type");
		}
	}

	/**
	 * Concatenates a set of given {@code Reference} into a byte array
	 *
	 * @param references
	 *            the references to concatenate
	 * @return the concatenated references as a byte array
	 */
	private byte[] concatenateReferencesAsByteArray(final List references) {

		LOG.debug("Building ContentTimestamp - Concatenating references...");
		final ByteArrayOutputStream buffer = new ByteArrayOutputStream();

		for (final Reference reference : references) {
			// References of type "SignedProperties" are excluded
			if (!xPathQueryHolder.XADES_SIGNED_PROPERTIES.equals(reference.getType())) {
				try {
					final byte[] referencedBytes = reference.getReferencedBytes();
					buffer.write(referencedBytes);
				} catch (XMLSignatureException e) {
					throw new DSSException(e);
				} catch (IOException e) {
					throw new DSSException(e);
				}
			}
		}
		LOG.debug("Result: " + new String(buffer.toByteArray()));
		return buffer.toByteArray();
	}

	/**
	 * Method that generates a XAdES ContentTimestamp (either an ALL DATA OBJECTS TIMESTAMP or an INDIVIDUAL DATA
	 * OBJECTS TIMESTAMP) and returns
	 * it as a DSSDocument
	 *
	 * @param toSignDocument
	 *            the document for which a content timestamp must be generated
	 * @param externalParameters
	 *            the original signature parameters
	 * @param timestampType
	 *            the contentTimestamp type, either ALL_DATA_OBJECTS_TIMESTAMP or INDIVIDUAL_DATA_OBJECTS_TIMESTAMP
	 * @return a ContentTimestamp as a DSSDocument
	 */
	public DSSDocument generateXAdESContentTimestampAsDSSDocument(final DSSDocument toSignDocument, final XAdESSignatureParameters externalParameters,
			final TimestampType timestampType) {
		final TimestampToken timestampToken = generateXAdESContentTimestampAsTimestampToken(toSignDocument, externalParameters, timestampType);
		return new InMemoryDocument(timestampToken.getEncoded());
	}

	/**
	 * Method that generates a TimestampToken given a TimestampType, a set of signature parameters and a byte array
	 * containing the concatenated references
	 *
	 * @param timestampType
	 *            The TimestampType for the TimestampToken
	 * @param signatureParameters
	 *            The signature parameters from which the contentTimestamp parameters must be retrieved
	 * @param references
	 * @return
	 */
	public TimestampToken generateTimestampToken(final TimestampType timestampType, final XAdESSignatureParameters signatureParameters,
			final byte[] references) {

		if (timestampType == null) {
			throw new NullPointerException();
		}
		if (signatureParameters == null) {
			throw new NullPointerException();
		}
		final TimestampParameters contentTimestampParameters = signatureParameters.getContentTimestampParameters();
		if (contentTimestampParameters == null) {
			throw new NullPointerException();
		}

		final DigestAlgorithm digestAlgorithm = contentTimestampParameters.getDigestAlgorithm();
		if (digestAlgorithm == null) {

			throw new NullPointerException();
		}
		byte[] digest = DSSUtils.digest(digestAlgorithm, references);
		if (LOG.isTraceEnabled()) {

			LOG.trace("Bytes to digest : [" + new String(references) + "]");
			LOG.trace("Digest to timestamp: " + Utils.toBase64(digest));
		}
		final TimeStampToken timeStampResponse = tspSource.getTimeStampResponse(digestAlgorithm, digest);
		final TimestampToken token = new TimestampToken(timeStampResponse, timestampType, certificatePool);

		token.setCanonicalizationMethod(contentTimestampParameters.getCanonicalizationMethod());

		// Case of XAdES INDIVIDUAL DATA OBJECTS TIMESTAMP: Timestamp Includes must be generated for each reference
		if (TimestampType.INDIVIDUAL_DATA_OBJECTS_TIMESTAMP.equals(timestampType)) {
			addTimestampTokenIncludes(signatureParameters.getReferences(), token);
		}
		return token;
	}

	/**
	 * Method setting the signature parameters used to generate the intermediary signature (XAdES-specific)
	 *
	 * @param externalParameters
	 *            the original signature parameters
	 * @return a set of signature parameters
	 */
	private XAdESSignatureParameters setSignatureParameters(final XAdESSignatureParameters externalParameters) {

		final XAdESSignatureParameters signatureParameters = new XAdESSignatureParameters();
		signatureParameters.setReferences(externalParameters.getReferences());
		signatureParameters.setSignatureTimestampParameters(externalParameters.getSignatureTimestampParameters());
		signatureParameters.setSigningCertificate(externalParameters.getSigningCertificate());
		signatureParameters.setSignaturePackaging(SignaturePackaging.DETACHED);
		signatureParameters.setSignatureLevel(SignatureLevel.XAdES_BASELINE_B);

		return signatureParameters;
	}

	/**
	 * @param toSignDocument
	 * @param signature
	 * @return
	 */
	private SignedDocumentValidator validateTemporarySignature(final DSSDocument toSignDocument, final DSSDocument signature) {

		final SignedDocumentValidator validator = XMLDocumentValidator.fromDocument(signature);
		validator.setCertificateVerifier(commonCertificateVerifier);
		final List detachedContents = new ArrayList();
		detachedContents.add(toSignDocument);
		validator.setDetachedContents(detachedContents);

		return validator;
	}

	/**
	 * Retrieves the references from a validated signature
	 *
	 * @param toSignDocument
	 *            the document for which a content timestamp must be generated
	 * @param signature
	 *            the signature value
	 * @return
	 */
	private List getReferencesFromValidatedSignature(final DSSDocument toSignDocument, final DSSDocument signature) {

		final SignedDocumentValidator validator = validateTemporarySignature(toSignDocument, signature);
		// validator.validateDocument();
		final List signatures = validator.getSignatures();
		final XAdESSignature xAdESSignature = (XAdESSignature) signatures.get(0);
		xAdESSignature.checkSignatureIntegrity();
		final List references = xAdESSignature.getReferences();

		return references;
	}

	/**
	 * Adds a set of Timestamp Includes to a given Timestamp Token, based on the references that the Timestamp Token was
	 * built upon
	 *
	 * @param references
	 *            the references the timestamp token was built upon
	 * @param token
	 *            the timestamp token to which the includes must be added
	 * @return the updated Timestamp token, containing the set of Includes
	 */
	private TimestampToken addTimestampTokenIncludes(final List references, final TimestampToken token) {

		final List includes = new ArrayList();
		for (DSSReference reference : references) {

			TimestampInclude include = new TimestampInclude(reference.getUri(), "true");
			includes.add(include);
		}
		token.setTimestampIncludes(includes);

		return token;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy