Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/**
* 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;
}
}