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

eu.europa.esig.dss.xades.signature.XAdESLevelBaselineT 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 static eu.europa.esig.dss.SignatureLevel.XAdES_BASELINE_T;
import static eu.europa.esig.dss.SignaturePackaging.ENVELOPED;
import static eu.europa.esig.dss.XAdESNamespaces.XAdES;
import static eu.europa.esig.dss.XAdESNamespaces.XAdES141;
import static eu.europa.esig.dss.x509.TimestampType.SIGNATURE_TIMESTAMP;
import static eu.europa.esig.dss.xades.ProfileParameters.Operation.SIGNING;
import static javax.xml.crypto.dsig.XMLSignature.XMLNS;

import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;

import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.tsp.TimeStampToken;

import org.digidoc4j.dss.xades.BDocTmSupport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import eu.europa.esig.dss.DSSASN1Utils;
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.DomUtils;
import eu.europa.esig.dss.InMemoryDocument;
import eu.europa.esig.dss.MimeType;
import eu.europa.esig.dss.SignatureLevel;
import eu.europa.esig.dss.SignaturePackaging;
import eu.europa.esig.dss.TimestampParameters;
import eu.europa.esig.dss.signature.SignatureExtension;
import eu.europa.esig.dss.utils.Utils;
import eu.europa.esig.dss.validation.CertificateVerifier;
import eu.europa.esig.dss.validation.ValidationContext;
import eu.europa.esig.dss.x509.CertificatePool;
import eu.europa.esig.dss.x509.CertificateToken;
import eu.europa.esig.dss.x509.TimestampType;
import eu.europa.esig.dss.x509.tsp.TSPSource;
import eu.europa.esig.dss.xades.DSSXMLUtils;
import eu.europa.esig.dss.xades.ProfileParameters;
import eu.europa.esig.dss.xades.ProfileParameters.Operation;
import eu.europa.esig.dss.xades.XAdESSignatureParameters;
import eu.europa.esig.dss.xades.validation.XAdESSignature;

/**
 * -T profile of XAdES signature
 *
 */
public class XAdESLevelBaselineT extends ExtensionBuilder implements SignatureExtension, Serializable {

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

	/*
	 * The object encapsulating the Time Stamp Protocol needed to create the level -T, of the signature
	 */
	protected TSPSource tspSource;

	/**
	 * The default constructor for XAdESLevelBaselineT.
	 */
	public XAdESLevelBaselineT(final CertificateVerifier certificateVerifier) {

		super(certificateVerifier);
	}

	private void incorporateC14nMethod(final Element parentDom, final String signedInfoC14nMethod) {

		// 
		final Element canonicalizationMethodDom = documentDom.createElementNS(XMLNS, DS_CANONICALIZATION_METHOD);
		canonicalizationMethodDom.setAttribute(ALGORITHM, signedInfoC14nMethod);
		parentDom.appendChild(canonicalizationMethodDom);
	}

	@Override
	public InMemoryDocument extendSignatures(final DSSDocument dssDocument, final XAdESSignatureParameters params) throws DSSException {

		if (dssDocument == null) {
			throw new NullPointerException();
		}
		if (this.tspSource == null) {
			throw new NullPointerException();
		}
		this.params = params;
		final ProfileParameters context = params.getContext();
		if (LOG.isInfoEnabled()) {
			LOG.info("====> Extending: " + (dssDocument.getName() == null ? "IN MEMORY DOCUMENT" : dssDocument.getName()));
		}
		documentDom = DomUtils.buildDOM(dssDocument);

		final NodeList signatureNodeList = documentDom.getElementsByTagNameNS(XMLNS, SIGNATURE);
		if (signatureNodeList.getLength() == 0) {
			throw new DSSException("There is no signature to extend!");
		}

		// In the case of the enveloped signature we have a specific treatment:
// we will just extend the signature that is being created (during creation process) String signatureId = null; final SignaturePackaging signaturePackaging = params.getSignaturePackaging(); final Operation operationKind = context.getOperationKind(); if (SIGNING.equals(operationKind) && ENVELOPED.equals(signaturePackaging)) { signatureId = params.getDeterministicId(); } for (int ii = 0; ii < signatureNodeList.getLength(); ii++) { currentSignatureDom = (Element) signatureNodeList.item(ii); final String currentSignatureId = currentSignatureDom.getAttribute(ID); if ((signatureId != null) && !signatureId.equals(currentSignatureId)) { continue; } final CertificatePool certPool = new CertificatePool(); // TODO-Bob (13/07/2014): The XPath query holder can be inherited from the xadesSignature: to be analysed xadesSignature = new XAdESSignature(currentSignatureDom, certPool); xadesSignature.setDetachedContents(params.getDetachedContents()); extendSignatureTag(); } final byte[] documentBytes = DSSXMLUtils.serializeNode(documentDom); final InMemoryDocument inMemoryDocument = new InMemoryDocument(documentBytes); inMemoryDocument.setMimeType(MimeType.XML); return inMemoryDocument; } /** * Extends the signature to a desired level. This method is overridden by other profiles.
* For -T profile adds the SignatureTimeStamp element which contains a single HashDataInfo element that refers to * the * ds:SignatureValue element of the [XMLDSIG] signature. The timestamp token is obtained from TSP source.
* Adds segment into element. * * @throws eu.europa.esig.dss.DSSException */ protected void extendSignatureTag() throws DSSException { assertExtendSignaturePossible(); // We ensure that all XML segments needed for the construction of the extension -T are present. // If a segment does not exist then it is created. ensureUnsignedProperties(); ensureUnsignedSignatureProperties(); ensureSignedDataObjectProperties(); //BDoc support - do not add Timestamp for BDoc Timemark signatures if (BDocTmSupport.isBdocTmSignatureProfile(params)) { return; } //End of BDoc support // The timestamp must be added only if there is no one or the extension -T level is being created if (!xadesSignature.hasTProfile() || XAdES_BASELINE_T.equals(params.getSignatureLevel())) { final TimestampParameters signatureTimestampParameters = params.getSignatureTimestampParameters(); final String canonicalizationMethod = signatureTimestampParameters.getCanonicalizationMethod(); final byte[] canonicalisedValue = xadesSignature.getSignatureTimestampData(null, canonicalizationMethod); final DigestAlgorithm timestampDigestAlgorithm = signatureTimestampParameters.getDigestAlgorithm(); final byte[] digestValue = DSSUtils.digest(timestampDigestAlgorithm, canonicalisedValue); createXAdESTimeStampType(SIGNATURE_TIMESTAMP, canonicalizationMethod, digestValue); } } /** * Checks if the extension is possible. */ private void assertExtendSignaturePossible() throws DSSException { final SignatureLevel signatureLevel = params.getSignatureLevel(); if (XAdES_BASELINE_T.equals(signatureLevel) && (xadesSignature.hasLTProfile() || xadesSignature.hasLTAProfile())) { final String exceptionMessage = "Cannot extend signature. The signedData is already extended with [%s]."; throw new DSSException(String.format(exceptionMessage, "XAdES LT")); } } /** * Sets the TSP source to be used when extending the digital signature * * @param tspSource * the tspSource to set */ public void setTspSource(final TSPSource tspSource) { this.tspSource = tspSource; } /** * * This method incorporates all certificates passed as parameter. * * @param parentDom * @param toIncludeCertificates */ protected void incorporateCertificateValues(final Element parentDom, final List toIncludeCertificates) { // // ...MIIC9TC... if (!toIncludeCertificates.isEmpty()) { final Element certificateValuesDom = DomUtils.addElement(documentDom, parentDom, XAdES, XADES_CERTIFICATE_VALUES); final CertificatePool certificatePool = getCertificatePool(); final boolean trustAnchorBPPolicy = params.bLevel().isTrustAnchorBPPolicy(); boolean trustAnchorIncluded = false; //Custom Estonian functionality: OCSP responder certificate must have RESPONDER_CERT id attribute (needed only for jDigidoc interoperability) int responderCertCounter = 0; //End of Custom Estonian functionality for (final CertificateToken certificateToken : toIncludeCertificates) { if (trustAnchorBPPolicy && (certificatePool != null)) { final List certificateTokens = certificatePool.get(certificateToken.getSubjectX500Principal()); if (certificateTokens.size() > 0) { trustAnchorIncluded = true; } } final byte[] bytes = certificateToken.getEncoded(); final String base64EncodeCertificate = Base64.encodeBase64String(bytes); //DSSXMLUtils.addTextElement(documentDom, certificateValuesDom, XAdES, XADES_ENCAPSULATED_X509_CERTIFICATE, base64EncodeCertificate); Element element = DomUtils.addElement(documentDom, certificateValuesDom, XAdES, XADES_ENCAPSULATED_X509_CERTIFICATE); //BDoc-TM functionality: OCSP responder certificate must have RESPONDER_CERT id attribute (needed only for jDigidoc interoperability) boolean isCaCert = certificateToken.getCertificate().getBasicConstraints() != -1; if(DSSASN1Utils.isOCSPSigning(certificateToken) && !isCaCert) { element.setAttribute("Id", xadesSignature.getId() + "-RESPONDER_CERT-" + responderCertCounter); responderCertCounter++; } //End of BDoc-TM functionality DomUtils.setTextNode(documentDom, element, base64EncodeCertificate); } if (trustAnchorBPPolicy && !trustAnchorIncluded) { LOG.warn("The trust anchor is missing but its inclusion is required by the signature policy!"); } } } public Set getCertificatesForInclusion(final ValidationContext validationContext) { final Set certificates = new HashSet(); final List certWithinSignatures = xadesSignature.getCertificates(); for (final CertificateToken certificateToken : validationContext.getProcessedCertificates()) { if (certWithinSignatures.contains(certificateToken)) { continue; } certificates.add(certificateToken); } return certificates; } /** * Creates any XAdES TimeStamp object representation. The timestamp token is obtained from TSP source * * @param timestampType * {@code TimestampType} * @param timestampC14nMethod * canonicalization method * @param digestValue * array of {@code byte} representing the digest to timestamp * @throws DSSException * in case of any error */ protected void createXAdESTimeStampType(final TimestampType timestampType, final String timestampC14nMethod, final byte[] digestValue) throws DSSException { try { Element timeStampDom = null; final TimestampParameters signatureTimestampParameters = params.getSignatureTimestampParameters(); DigestAlgorithm timestampDigestAlgorithm = signatureTimestampParameters.getDigestAlgorithm(); switch (timestampType) { case SIGNATURE_TIMESTAMP: // timeStampDom = DomUtils.addElement(documentDom, unsignedSignaturePropertiesDom, XAdES, XADES_SIGNATURE_TIME_STAMP); break; case VALIDATION_DATA_REFSONLY_TIMESTAMP: // timeStampDom = DSSXMLUtils.addElement(documentDom, unsignedSignaturePropertiesDom, // XAdESNamespaces.XAdES, XADES_); break; case VALIDATION_DATA_TIMESTAMP: // if (params.isEn319132() && !SignatureLevel.XAdES_X.equals(params.getSignatureLevel())) { timeStampDom = DomUtils.addElement(documentDom, unsignedSignaturePropertiesDom, XAdES, XADES_SIG_AND_REFS_TIME_STAMP_V2); } else { timeStampDom = DomUtils.addElement(documentDom, unsignedSignaturePropertiesDom, XAdES, XADES_SIG_AND_REFS_TIME_STAMP); } break; case ARCHIVE_TIMESTAMP: // timeStampDom = DomUtils.addElement(documentDom, unsignedSignaturePropertiesDom, XAdES141, XADES141_ARCHIVE_TIME_STAMP); timestampDigestAlgorithm = params.getArchiveTimestampParameters().getDigestAlgorithm(); break; case ALL_DATA_OBJECTS_TIMESTAMP: timeStampDom = DomUtils.addElement(documentDom, signedDataObjectPropertiesDom, XAdES, XADES_ALL_DATA_OBJECTS_TIME_STAMP); break; case INDIVIDUAL_DATA_OBJECTS_TIMESTAMP: timeStampDom = DomUtils.addElement(documentDom, signedDataObjectPropertiesDom, XAdES, XADES_INDIVIDUAL_DATA_OBJECTS_TIME_STAMP); break; default: LOG.error("Unsupported timestamp type : " + timestampType); break; } if (LOG.isDebugEnabled()) { final String encodedDigestValue = Utils.toBase64(digestValue); LOG.debug("Timestamp generation: " + timestampDigestAlgorithm.getName() + " / " + timestampC14nMethod + " / " + encodedDigestValue); } final TimeStampToken timeStampToken = tspSource.getTimeStampResponse(timestampDigestAlgorithm, digestValue); final byte[] timeStampTokenBytes = timeStampToken.getEncoded(); final String base64EncodedTimeStampToken = Utils.toBase64(timeStampTokenBytes); final String timestampId = UUID.randomUUID().toString(); timeStampDom.setAttribute(ID, "TS-" + timestampId); // incorporateC14nMethod(timeStampDom, timestampC14nMethod); // MIAGCSqGSIb3DQEH final Element encapsulatedTimeStampDom = DomUtils.addElement(documentDom, timeStampDom, XAdES, XADES_ENCAPSULATED_TIME_STAMP); encapsulatedTimeStampDom.setAttribute(ID, "ETS-" + timestampId); DomUtils.setTextNode(documentDom, encapsulatedTimeStampDom, base64EncodedTimeStampToken); } catch (IOException e) { throw new DSSException("Error during the creation of the XAdES timestamp!", e); } } protected List getToIncludeCertificateTokens(final ValidationContext valContext) { // if the certificate is already present within the KeyInfo then it is ignored. final Set processedCertificates = valContext.getProcessedCertificates(); final List keyInfoCertificates = xadesSignature.getKeyInfoCertificates(); final List toIncludeCertificates = new ArrayList(); for (final CertificateToken processedCertificate : processedCertificates) { if (!keyInfoCertificates.contains(processedCertificate)) { toIncludeCertificates.add(processedCertificate); } } return toIncludeCertificates; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy