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.cades.signature;
import eu.europa.esig.dss.cades.CAdESSignatureParameters;
import eu.europa.esig.dss.enumerations.DigestAlgorithm;
import eu.europa.esig.dss.enumerations.SignatureAlgorithm;
import eu.europa.esig.dss.enumerations.SignatureLevel;
import eu.europa.esig.dss.enumerations.SignaturePackaging;
import eu.europa.esig.dss.enumerations.TimestampType;
import eu.europa.esig.dss.model.DSSDocument;
import eu.europa.esig.dss.model.DSSException;
import eu.europa.esig.dss.model.DigestDocument;
import eu.europa.esig.dss.model.InMemoryDocument;
import eu.europa.esig.dss.model.SignaturePolicyStore;
import eu.europa.esig.dss.model.SignatureValue;
import eu.europa.esig.dss.model.TimestampBinary;
import eu.europa.esig.dss.model.ToBeSigned;
import eu.europa.esig.dss.signature.AbstractSignatureService;
import eu.europa.esig.dss.signature.CounterSignatureService;
import eu.europa.esig.dss.signature.SigningOperation;
import eu.europa.esig.dss.spi.DSSASN1Utils;
import eu.europa.esig.dss.spi.DSSUtils;
import eu.europa.esig.dss.spi.x509.CMSSignedDataBuilder;
import eu.europa.esig.dss.spi.x509.tsp.TimestampToken;
import eu.europa.esig.dss.utils.Utils;
import eu.europa.esig.dss.spi.validation.CertificateVerifier;
import org.bouncycastle.cms.CMSException;
import org.bouncycastle.cms.CMSSignedData;
import org.bouncycastle.cms.CMSTypedData;
import org.bouncycastle.cms.SignerInfoGenerator;
import org.bouncycastle.cms.SignerInformation;
import org.bouncycastle.tsp.TSPException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
/**
* CAdES implementation of DocumentSignatureService
*/
public class CAdESService extends
AbstractSignatureService
implements CounterSignatureService {
private static final long serialVersionUID = -7744554779153433450L;
private static final Logger LOG = LoggerFactory.getLogger(CAdESService.class);
/**
* This is the constructor to create an instance of the {@code CAdESService}. A certificate verifier must be
* provided.
*
* @param certificateVerifier
* {@code CertificateVerifier} provides information on the sources to be used in the validation process
* in the context of a signature.
*/
public CAdESService(final CertificateVerifier certificateVerifier) {
super(certificateVerifier);
LOG.debug("+ CAdESService created");
}
@Override
public TimestampToken getContentTimestamp(DSSDocument toSignDocument, CAdESSignatureParameters parameters) {
Objects.requireNonNull(tspSource, "A TSPSource is required !");
DigestAlgorithm digestAlgorithm = parameters.getContentTimestampParameters().getDigestAlgorithm();
TimestampBinary timeStampResponse = tspSource.getTimeStampResponse(digestAlgorithm, toSignDocument.getDigestValue(digestAlgorithm));
try {
return new TimestampToken(timeStampResponse.getBytes(), TimestampType.CONTENT_TIMESTAMP);
} catch (TSPException | IOException | CMSException e) {
throw new DSSException("Cannot create a content TimestampToken", e);
}
}
@Override
public ToBeSigned getDataToSign(final DSSDocument toSignDocument, final CAdESSignatureParameters parameters) {
Objects.requireNonNull(toSignDocument, "toSignDocument cannot be null!");
Objects.requireNonNull(parameters, "SignatureParameters cannot be null!");
assertSigningCertificateValid(parameters);
final SignaturePackaging packaging = parameters.getSignaturePackaging();
assertSignaturePackaging(packaging);
final SignatureAlgorithm signatureAlgorithm = parameters.getSignatureAlgorithm();
final CustomContentSigner customContentSigner = new CustomContentSigner(signatureAlgorithm.getJCEId());
final CMSSignedData originalCmsSignedData = getCmsSignedData(toSignDocument, parameters);
final DSSDocument contentToSign = getContentToSign(toSignDocument, parameters, originalCmsSignedData);
final SignerInfoGenerator signerInfoGenerator = new CMSSignerInfoGeneratorBuilder()
.build(contentToSign, parameters, customContentSigner);
final CMSSignedDataBuilder cmsSignedDataBuilder = getCMSSignedDataBuilder(parameters)
.setOriginalCMSSignedData(originalCmsSignedData);
cmsSignedDataBuilder.createCMSSignedData(signerInfoGenerator, contentToSign);
final byte[] bytes = customContentSigner.getOutputStream().toByteArray();
return new ToBeSigned(bytes);
}
@Override
public DSSDocument signDocument(final DSSDocument toSignDocument, final CAdESSignatureParameters parameters, SignatureValue signatureValue) {
Objects.requireNonNull(toSignDocument, "toSignDocument cannot be null!");
Objects.requireNonNull(parameters, "SignatureParameters cannot be null!");
Objects.requireNonNull(signatureValue, "SignatureValue cannot be null!");
assertSigningCertificateValid(parameters);
final SignaturePackaging packaging = parameters.getSignaturePackaging();
assertSignaturePackaging(packaging);
final SignatureAlgorithm signatureAlgorithm = parameters.getSignatureAlgorithm();
signatureValue = ensureSignatureValue(signatureAlgorithm, signatureValue);
final CustomContentSigner customContentSigner = new CustomContentSigner(signatureAlgorithm.getJCEId(), signatureValue.getValue());
final CMSSignedData originalCmsSignedData = getCmsSignedData(toSignDocument, parameters);
if (originalCmsSignedData == null && SignaturePackaging.DETACHED.equals(packaging) && Utils.isCollectionEmpty(parameters.getDetachedContents())) {
parameters.getContext().setDetachedContents(Arrays.asList(toSignDocument));
}
final DSSDocument contentToSign = getContentToSign(toSignDocument, parameters, originalCmsSignedData);
final SignerInfoGenerator signerInfoGenerator = new CMSSignerInfoGeneratorBuilder()
.setIncludeUnsignedAttributes(true)
.build(contentToSign, parameters, customContentSigner);
final CMSSignedData cmsSignedData = getCMSSignedDataBuilder(parameters)
.setOriginalCMSSignedData(originalCmsSignedData)
.createCMSSignedData(signerInfoGenerator, contentToSign);
DSSDocument signature = new CMSSignedDocument(cmsSignedData);
final SignatureLevel signatureLevel = parameters.getSignatureLevel();
if (!SignatureLevel.CAdES_BASELINE_B.equals(signatureLevel)) {
// Only the last signature will be extended
final SignerInformation newSignerInformation = getNewSignerInformation(originalCmsSignedData, cmsSignedData);
final CAdESSignatureExtension extension = getExtensionProfile(parameters);
CMSSignedData extendedCMSSignature = extension.extendCMSSignatures(cmsSignedData, newSignerInformation, parameters);
signature = new CMSSignedDocument(extendedCMSSignature);
}
signature.setName(getFinalFileName(toSignDocument, SigningOperation.SIGN,
parameters.getSignatureLevel(), parameters.getSignaturePackaging()));
parameters.reinit();
return signature;
}
@Override
public DSSDocument extendDocument(final DSSDocument toExtendDocument, final CAdESSignatureParameters parameters) {
Objects.requireNonNull(toExtendDocument, "toExtendDocument is not defined!");
Objects.requireNonNull(parameters, "Cannot extend the signature. SignatureParameters are not defined!");
// false: All signature are extended
final CAdESSignatureExtension extension = getExtensionProfile(parameters);
final DSSDocument dssDocument = extension.extendSignatures(toExtendDocument, parameters);
dssDocument.setName(getFinalFileName(toExtendDocument, SigningOperation.EXTEND, parameters.getSignatureLevel()));
return dssDocument;
}
/**
* This method retrieves the data to be signed. If this data is located within a signature then it is extracted.
*
* @param toSignDocument
* document to sign
* @param parameters
* set of the driving signing parameters
* @param originalCmsSignedData
* the signed data extracted from an existing signature or null
* @return {@link DSSDocument} toSignData
*/
private DSSDocument getContentToSign(final DSSDocument toSignDocument, final CAdESSignatureParameters parameters,
final CMSSignedData originalCmsSignedData) {
final List detachedContents = parameters.getDetachedContents();
if (Utils.isCollectionNotEmpty(detachedContents)) {
// * CAdES only can sign one document
// * ASiC-S -> the document to sign or package.zip
// * ASiC-E -> ASiCManifest
return detachedContents.get(0);
} else {
if (originalCmsSignedData == null) {
return toSignDocument;
} else {
return getSignedContent(originalCmsSignedData);
}
}
}
/**
* This method returns the signed content of CMSSignedData.
*
* @param cmsSignedData
* the already signed {@code CMSSignedData}
* @return the original toSignDocument or null
*/
private DSSDocument getSignedContent(final CMSSignedData cmsSignedData) {
final CMSTypedData signedContent = cmsSignedData.getSignedContent();
if (signedContent == null) {
throw new DSSException("Unknown SignedContent");
}
final byte[] documentBytes = (byte[]) signedContent.getContent();
return new InMemoryDocument(documentBytes);
}
private SignerInformation getNewSignerInformation(CMSSignedData originalSignedData, CMSSignedData cmsSignedData) {
Collection signers = cmsSignedData.getSignerInfos().getSigners();
if (originalSignedData != null) {
for (SignerInformation signerInformation : signers) {
if (!containsSignerInfo(originalSignedData, signerInformation)) {
return signerInformation;
}
}
}
// return the first one if originalSignedData is null (single signature creation)
return signers.iterator().next();
}
private boolean containsSignerInfo(CMSSignedData signedData, SignerInformation signerInformationToFind) {
for (SignerInformation signerInformation : signedData.getSignerInfos()) {
if (signerInformationToFind.toASN1Structure() == signerInformation.toASN1Structure()) {
return true;
}
}
return false;
}
/**
* This method returns the extension profile to be used for a CAdES signature augmentation
*
* @param parameters
* set of driving signing parameters
* @return {@code CAdESSignatureExtension} related to the pre-defined profile
*/
private CAdESSignatureExtension getExtensionProfile(final CAdESSignatureParameters parameters) {
final SignatureLevel signatureLevel = parameters.getSignatureLevel();
Objects.requireNonNull(signatureLevel, "SignatureLevel must be defined!");
switch (signatureLevel) {
case CAdES_BASELINE_T:
return new CAdESLevelBaselineT(tspSource, certificateVerifier);
case CAdES_BASELINE_LT:
return new CAdESLevelBaselineLT(tspSource, certificateVerifier);
case CAdES_BASELINE_LTA:
return new CAdESLevelBaselineLTA(tspSource, certificateVerifier);
default:
throw new UnsupportedOperationException(
String.format("Unsupported signature format '%s' for extension.", signatureLevel));
}
}
/**
* In case of an enveloping signature if the signed content's content is null then the null is returned.
*
* @param dssDocument
* {@code DSSDocument} containing the data to be signed or {@code CMSSignedData}
* @param parameters
* set of driving signing parameters
* @return the {@code CMSSignedData} if the dssDocument is an CMS signed message. Null otherwise.
*/
private CMSSignedData getCmsSignedData(final DSSDocument dssDocument, final CAdESSignatureParameters parameters) {
CMSSignedData cmsSignedData = null;
if (!(dssDocument instanceof DigestDocument) && DSSASN1Utils.isASN1SequenceTag(DSSUtils.readFirstByte(dssDocument))) {
try {
cmsSignedData = DSSUtils.toCMSSignedData(dssDocument);
if (SignaturePackaging.ENVELOPING == parameters.getSignaturePackaging() && cmsSignedData.getSignedContent().getContent() == null) {
cmsSignedData = null;
}
} catch (Exception e) {
// not a parallel signature
}
}
return cmsSignedData;
}
private CMSSignedDataBuilder getCMSSignedDataBuilder(CAdESSignatureParameters parameters) {
return new CMSSignedDataBuilder()
.setSigningCertificate(parameters.getSigningCertificate())
.setCertificateChain(parameters.getCertificateChain())
.setGenerateWithoutCertificates(parameters.isGenerateTBSWithoutCertificate())
.setTrustAnchorBPPolicy(parameters.bLevel().isTrustAnchorBPPolicy())
.setTrustedCertificateSource(certificateVerifier.getTrustedCertSources())
.setEncapsulate(isEncapsulateSignerData(parameters));
}
private boolean isEncapsulateSignerData(CAdESSignatureParameters signatureParameters) {
return !SignaturePackaging.DETACHED.equals(signatureParameters.getSignaturePackaging());
}
/**
* @param packaging
* {@code SignaturePackaging} to be checked
* @throws DSSException
* if the packaging is not supported for this kind of signature
*/
private void assertSignaturePackaging(final SignaturePackaging packaging) {
if ((packaging != SignaturePackaging.ENVELOPING) && (packaging != SignaturePackaging.DETACHED)) {
throw new IllegalArgumentException("Unsupported signature packaging: " + packaging);
}
}
/**
* Incorporates a Signature Policy Store as an unsigned property into the CAdES Signature
*
* @param document {@link DSSDocument} containing a CAdES Signature
* to add a SignaturePolicyStore to
* @param signaturePolicyStore {@link SignaturePolicyStore} to add
* @return {@link DSSDocument} CAdESSignature with an incorporated SignaturePolicyStore
*/
public DSSDocument addSignaturePolicyStore(DSSDocument document, SignaturePolicyStore signaturePolicyStore) {
Objects.requireNonNull(document, "The document cannot be null");
Objects.requireNonNull(signaturePolicyStore, "The signaturePolicyStore cannot be null");
CAdESSignaturePolicyStoreBuilder builder = new CAdESSignaturePolicyStoreBuilder();
DSSDocument documentWithPolicyStore = builder.addSignaturePolicyStore(document, signaturePolicyStore);
documentWithPolicyStore.setName(getFinalFileName(document, SigningOperation.EXTEND, null));
return documentWithPolicyStore;
}
@Override
public ToBeSigned getDataToBeCounterSigned(DSSDocument signatureDocument, CAdESCounterSignatureParameters parameters) {
Objects.requireNonNull(signatureDocument, "signatureDocument cannot be null!");
Objects.requireNonNull(parameters, "parameters cannot be null!");
Objects.requireNonNull(parameters.getSignatureIdToCounterSign(), "The signature to be counter-signed must be specified");
assertSigningCertificateValid(parameters);
assertCounterSignaturePossible(parameters);
final CAdESCounterSignatureBuilder counterSignatureBuilder = new CAdESCounterSignatureBuilder(certificateVerifier);
final SignerInformation signerInfoToCounterSign = counterSignatureBuilder
.getSignerInformationToBeCounterSigned(signatureDocument, parameters);
return getDataToBeCounterSigned(signerInfoToCounterSign, parameters);
}
/**
* Returns a data toBeSigned for a counter signature on the given {@code signerInfoToCounterSign}
*
* @param signerInfoToCounterSign {@link SignerInformation} to counter-sign
* @param parameters {@link CAdESSignatureParameters}
* @return {@link ToBeSigned}
*/
public ToBeSigned getDataToBeCounterSigned(SignerInformation signerInfoToCounterSign,
CAdESSignatureParameters parameters) {
final SignatureAlgorithm signatureAlgorithm = parameters.getSignatureAlgorithm();
final CustomContentSigner customContentSigner = new CustomContentSigner(signatureAlgorithm.getJCEId());
final CAdESCounterSignatureBuilder counterSignatureBuilder = new CAdESCounterSignatureBuilder(certificateVerifier);
counterSignatureBuilder.generateCounterSignature(signerInfoToCounterSign, parameters, customContentSigner);
return new ToBeSigned(customContentSigner.getOutputStream().toByteArray());
}
@Override
public DSSDocument counterSignSignature(DSSDocument signatureDocument, CAdESCounterSignatureParameters parameters, SignatureValue signatureValue) {
Objects.requireNonNull(signatureDocument, "signatureDocument cannot be null!");
Objects.requireNonNull(parameters, "parameters cannot be null!");
Objects.requireNonNull(parameters.getSignatureIdToCounterSign(), "The signature to be counter-signed must be specified");
Objects.requireNonNull(signatureValue, "signatureValue cannot be null!");
assertSigningCertificateValid(parameters);
assertCounterSignaturePossible(parameters);
signatureValue = ensureSignatureValue(parameters.getSignatureAlgorithm(), signatureValue);
CMSSignedData originalCMSSignedData = DSSUtils.toCMSSignedData(signatureDocument);
CAdESCounterSignatureBuilder counterSignatureBuilder = new CAdESCounterSignatureBuilder(certificateVerifier);
CMSSignedDocument counterSigned = counterSignatureBuilder.addCounterSignature(originalCMSSignedData, parameters, signatureValue);
counterSigned.setName(getFinalFileName(signatureDocument, SigningOperation.COUNTER_SIGN, parameters.getSignatureLevel()));
counterSigned.setMimeType(signatureDocument.getMimeType());
return counterSigned;
}
private void assertCounterSignaturePossible(CAdESCounterSignatureParameters parameters) {
if (!SignatureLevel.CAdES_BASELINE_B.equals(parameters.getSignatureLevel())) {
throw new UnsupportedOperationException(String.format("A counter signature with a level '%s' is not supported! "
+ "Please, use CAdES-BASELINE-B", parameters.getSignatureLevel()));
}
}
}