![JAR search and dependency download from the Maven repository](/logo.png)
eu.europa.esig.dss.cades.validation.CAdESTimestampSource 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.cades.validation;
import static eu.europa.esig.dss.spi.OID.attributeCertificateRefsOid;
import static eu.europa.esig.dss.spi.OID.attributeRevocationRefsOid;
import static eu.europa.esig.dss.spi.OID.id_aa_ets_archiveTimestampV2;
import static eu.europa.esig.dss.spi.OID.id_aa_ets_archiveTimestampV3;
import static org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers.id_aa_ets_certCRLTimestamp;
import static org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers.id_aa_ets_certValues;
import static org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers.id_aa_ets_certificateRefs;
import static org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers.id_aa_ets_contentTimestamp;
import static org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers.id_aa_ets_escTimeStamp;
import static org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers.id_aa_ets_revocationRefs;
import static org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers.id_aa_ets_revocationValues;
import static org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers.id_aa_signatureTimeStampToken;
import java.util.ArrayList;
import java.util.List;
import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.DERTaggedObject;
import org.bouncycastle.asn1.cms.OtherRevocationInfoFormat;
import org.bouncycastle.asn1.esf.CrlListID;
import org.bouncycastle.asn1.esf.CrlOcspRef;
import org.bouncycastle.asn1.esf.CrlValidatedID;
import org.bouncycastle.asn1.esf.OcspListID;
import org.bouncycastle.asn1.esf.OcspResponsesID;
import org.bouncycastle.asn1.esf.RevocationValues;
import org.bouncycastle.asn1.ess.OtherCertID;
import org.bouncycastle.asn1.ocsp.BasicOCSPResponse;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.Certificate;
import org.bouncycastle.asn1.x509.CertificateList;
import org.bouncycastle.cert.ocsp.BasicOCSPResp;
import org.bouncycastle.cms.CMSSignedData;
import org.bouncycastle.cms.SignerInformation;
import org.bouncycastle.tsp.TimeStampToken;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import eu.europa.esig.dss.cades.CMSUtils;
import eu.europa.esig.dss.cades.signature.CadesLevelBaselineLTATimestampExtractor;
import eu.europa.esig.dss.crl.CRLUtils;
import eu.europa.esig.dss.enumerations.ArchiveTimestampType;
import eu.europa.esig.dss.enumerations.DigestAlgorithm;
import eu.europa.esig.dss.enumerations.TimestampLocation;
import eu.europa.esig.dss.enumerations.TimestampType;
import eu.europa.esig.dss.enumerations.TimestampedObjectType;
import eu.europa.esig.dss.model.DSSDocument;
import eu.europa.esig.dss.model.DSSException;
import eu.europa.esig.dss.model.identifier.EncapsulatedRevocationTokenIdentifier;
import eu.europa.esig.dss.model.identifier.Identifier;
import eu.europa.esig.dss.model.x509.CertificateToken;
import eu.europa.esig.dss.spi.DSSASN1Utils;
import eu.europa.esig.dss.spi.DSSUtils;
import eu.europa.esig.dss.spi.x509.CertificateRef;
import eu.europa.esig.dss.spi.x509.revocation.crl.CRLRef;
import eu.europa.esig.dss.spi.x509.revocation.ocsp.OCSPRef;
import eu.europa.esig.dss.spi.x509.revocation.ocsp.OCSPResponseBinary;
import eu.europa.esig.dss.validation.CMSCRLSource;
import eu.europa.esig.dss.validation.CMSCertificateSource;
import eu.europa.esig.dss.validation.CMSOCSPSource;
import eu.europa.esig.dss.validation.SignatureProperties;
import eu.europa.esig.dss.validation.timestamp.AbstractTimestampSource;
import eu.europa.esig.dss.validation.timestamp.TimestampCRLSource;
import eu.europa.esig.dss.validation.timestamp.TimestampOCSPSource;
import eu.europa.esig.dss.validation.timestamp.TimestampToken;
import eu.europa.esig.dss.validation.timestamp.TimestampedReference;
@SuppressWarnings("serial")
public class CAdESTimestampSource extends AbstractTimestampSource {
private static final Logger LOG = LoggerFactory.getLogger(CAdESTimestampSource.class);
protected final transient SignerInformation signerInformation;
protected final transient CMSSignedData cmsSignedData;
protected final transient List detachedDocuments;
public CAdESTimestampSource(final CAdESSignature signature) {
super(signature);
this.cmsSignedData = signature.getCmsSignedData();
this.detachedDocuments = signature.getDetachedContents();
this.signerInformation = signature.getSignerInformation();
}
@Override
protected CAdESTimestampDataBuilder getTimestampDataBuilder() {
CadesLevelBaselineLTATimestampExtractor timestampExtractor = new CadesLevelBaselineLTATimestampExtractor(
cmsSignedData, certificateSource.getAllCertificateTokens());
return new CAdESTimestampDataBuilder(cmsSignedData, signerInformation, detachedDocuments, timestampExtractor);
}
@Override
protected SignatureProperties getSignedSignatureProperties() {
return CAdESSignedAttributes.build(signerInformation);
}
@Override
protected SignatureProperties getUnsignedSignatureProperties() {
return CAdESUnsignedAttributes.build(signerInformation);
}
@Override
protected boolean isContentTimestamp(CAdESAttribute signedAttribute) {
return id_aa_ets_contentTimestamp.equals(signedAttribute.getASN1Oid());
}
@Override
protected boolean isAllDataObjectsTimestamp(CAdESAttribute signedAttribute) {
// not applicable for CAdES
return false;
}
@Override
protected boolean isIndividualDataObjectsTimestamp(CAdESAttribute signedAttribute) {
// not applicable for CAdES
return false;
}
@Override
protected boolean isSignatureTimestamp(CAdESAttribute unsignedAttribute) {
return id_aa_signatureTimeStampToken.equals(unsignedAttribute.getASN1Oid());
}
@Override
protected boolean isCompleteCertificateRef(CAdESAttribute unsignedAttribute) {
return id_aa_ets_certificateRefs.equals(unsignedAttribute.getASN1Oid());
}
@Override
protected boolean isAttributeCertificateRef(CAdESAttribute unsignedAttribute) {
return attributeCertificateRefsOid.equals(unsignedAttribute.getASN1Oid());
}
@Override
protected boolean isCompleteRevocationRef(CAdESAttribute unsignedAttribute) {
return id_aa_ets_revocationRefs.equals(unsignedAttribute.getASN1Oid());
}
@Override
protected boolean isAttributeRevocationRef(CAdESAttribute unsignedAttribute) {
return attributeRevocationRefsOid.equals(unsignedAttribute.getASN1Oid());
}
@Override
protected boolean isRefsOnlyTimestamp(CAdESAttribute unsignedAttribute) {
return id_aa_ets_certCRLTimestamp.equals(unsignedAttribute.getASN1Oid());
}
@Override
protected boolean isSigAndRefsTimestamp(CAdESAttribute unsignedAttribute) {
return id_aa_ets_escTimeStamp.equals(unsignedAttribute.getASN1Oid());
}
@Override
protected boolean isCertificateValues(CAdESAttribute unsignedAttribute) {
return id_aa_ets_certValues.equals(unsignedAttribute.getASN1Oid());
}
@Override
protected boolean isRevocationValues(CAdESAttribute unsignedAttribute) {
return id_aa_ets_revocationValues.equals(unsignedAttribute.getASN1Oid());
}
@Override
protected boolean isAttrAuthoritiesCertValues(CAdESAttribute unsignedAttribute) {
// not applicable for CAdES
return false;
}
@Override
protected boolean isAttributeRevocationValues(CAdESAttribute unsignedAttribute) {
// not applicable for CAdES
return false;
}
@Override
protected boolean isArchiveTimestamp(CAdESAttribute unsignedAttribute) {
return isArchiveTimestampV2(unsignedAttribute) || isArchiveTimestampV3(unsignedAttribute);
}
private boolean isArchiveTimestampV2(CAdESAttribute unsignedAttribute) {
return id_aa_ets_archiveTimestampV2.equals(unsignedAttribute.getASN1Oid());
}
private boolean isArchiveTimestampV3(CAdESAttribute unsignedAttribute) {
return id_aa_ets_archiveTimestampV3.equals(unsignedAttribute.getASN1Oid());
}
@Override
protected boolean isTimeStampValidationData(CAdESAttribute unsignedAttribute) {
// not applicable for CAdES
return false;
}
@Override
protected TimestampToken makeTimestampToken(CAdESAttribute signatureAttribute, TimestampType timestampType,
List references) {
TimeStampToken timestamp = signatureAttribute.toTimeStampToken();
if (timestamp == null) {
return null;
}
return new TimestampToken(timestamp, timestampType, references, TimestampLocation.CAdES);
}
@Override
protected List getIndividualContentTimestampedReferences(CAdESAttribute signedAttribute) {
// not applicable for CAdES, must be not executed
throw new DSSException("Not applicable for CAdES!");
}
@Override
protected List getArchiveTimestampOtherReferences(TimestampToken timestampToken) {
return getSignedDataReferences(timestampToken);
}
protected List getSignedDataReferences(TimestampToken timestampToken) {
if (ArchiveTimestampType.CAdES_V2.equals(timestampToken.getArchiveTimestampType()) ||
ArchiveTimestampType.CAdES.equals(timestampToken.getArchiveTimestampType())) {
// in case of ArchiveTimestampV2 or another earlier form of archive timestamp
// all SignedData is covered
return getSignatureSignedDataReferences();
}
List references = new ArrayList<>();
// Compare values present in the timestamp's Hash Index Table with signature's SignedData item digests
final ASN1Sequence atsHashIndex = DSSASN1Utils.getAtsHashIndex(timestampToken.getUnsignedAttributes());
if (atsHashIndex != null) {
final DigestAlgorithm digestAlgorithm = getHashIndexDigestAlgorithm(atsHashIndex);
List certificateReferences = getSignedDataCertificateReferences(
atsHashIndex, digestAlgorithm, timestampToken.getDSSIdAsString());
references.addAll(certificateReferences);
List revocationReferences = getSignedDataRevocationReferences(atsHashIndex, digestAlgorithm, timestampToken.getDSSIdAsString());
references.addAll(revocationReferences);
}
return references;
}
private List getSignedDataCertificateReferences(final ASN1Sequence atsHashIndex, final DigestAlgorithm digestAlgorithm,
final String timestampId) {
List references = new ArrayList<>();
if (signatureCertificateSource instanceof CMSCertificateSource) {
ASN1Sequence certsHashIndex = DSSASN1Utils.getCertificatesHashIndex(atsHashIndex);
List certsHashList = DSSASN1Utils.getDEROctetStrings(certsHashIndex);
for (CertificateToken certificate : signatureCertificateSource.getSignedDataCertificates()) {
if (isDigestValuePresent(certificate.getDigest(digestAlgorithm), certsHashList)) {
addReference(references, certificate.getDSSId(), TimestampedObjectType.CERTIFICATE);
} else {
LOG.warn("The certificate with id [{}] was not included to the message imprint of timestamp with id [{}] "
+ "or was added to the CMS SignedData after this ArchiveTimestamp!",
certificate.getDSSIdAsString(), timestampId);
}
}
}
return references;
}
private List getSignedDataRevocationReferences(final ASN1Sequence atsHashIndex, final DigestAlgorithm digestAlgorithm,
final String timestampId) {
List references = new ArrayList<>();
// get CRL references
ASN1Sequence crlsHashIndex = DSSASN1Utils.getCRLHashIndex(atsHashIndex);
List crlsHashList = DSSASN1Utils.getDEROctetStrings(crlsHashIndex);
if (signatureCRLSource instanceof CMSCRLSource) {
CMSCRLSource cmsCRLSource = (CMSCRLSource) signatureCRLSource;
for (EncapsulatedRevocationTokenIdentifier token : cmsCRLSource.getCMSSignedDataRevocationBinaries()) {
if (isDigestValuePresent(token.getDigestValue(digestAlgorithm), crlsHashList)) {
addReference(references, token, TimestampedObjectType.REVOCATION);
} else {
LOG.warn("The CRL Token with id [{}] was not included to the message imprint of timestamp with id [{}] "
+ "or was added to the CMS SignedData after this ArchiveTimestamp!",
token.asXmlId(), timestampId);
}
}
}
// get OCSP references
List ocspReferences = getSignedDataOCSPReferences(crlsHashList, digestAlgorithm, timestampId);
references.addAll(ocspReferences);
return references;
}
private List getSignedDataOCSPReferences(List crlsHashList, final DigestAlgorithm digestAlgorithm,
final String timestampId) {
List references = new ArrayList<>();
if (signatureOCSPSource instanceof CMSOCSPSource) {
CMSOCSPSource cmsocspSource = (CMSOCSPSource) signatureOCSPSource;
for (EncapsulatedRevocationTokenIdentifier token : cmsocspSource.getCMSSignedDataRevocationBinaries()) {
OCSPResponseBinary binary = (OCSPResponseBinary) token;
// Compute DERTaggedObject with the same algorithm how it was created
// See: org.bouncycastle.cms.CMSUtils getOthersFromStore()
OtherRevocationInfoFormat otherRevocationInfoFormat = new OtherRevocationInfoFormat(binary.getAsn1ObjectIdentifier(),
DSSASN1Utils.toASN1Primitive(binary.getBasicOCSPRespContent()));
// false value specifies an implicit encoding method
DERTaggedObject derTaggedObject = new DERTaggedObject(false, 1, otherRevocationInfoFormat);
if (isDigestValuePresent(DSSUtils.digest(digestAlgorithm, DSSASN1Utils.getDEREncoded(derTaggedObject)), crlsHashList)) {
addReference(references, binary, TimestampedObjectType.REVOCATION);
} else {
LOG.warn("The OCSP Token with id [{}] was not included to the message imprint of timestamp with id [{}] "
+ "or was added to the CMS SignedData after this ArchiveTimestamp!",
binary.asXmlId(), timestampId);
}
}
}
return references;
}
@Override
protected List getSignatureSignedDataReferences() {
List references = new ArrayList<>();
if (signatureCertificateSource instanceof CMSCertificateSource) {
addReferences(references, createReferencesForCertificates(signatureCertificateSource.getSignedDataCertificates()));
}
if (signatureCRLSource instanceof CMSCRLSource) {
for (EncapsulatedRevocationTokenIdentifier token : ((CMSCRLSource) signatureCRLSource).getCMSSignedDataRevocationBinaries()) {
addReference(references, token, TimestampedObjectType.REVOCATION);
}
}
if (signatureOCSPSource instanceof CMSOCSPSource) {
for (EncapsulatedRevocationTokenIdentifier token : ((CMSOCSPSource) signatureOCSPSource).getCMSSignedDataRevocationBinaries()) {
addReference(references, token, TimestampedObjectType.REVOCATION);
}
}
return references;
}
private DigestAlgorithm getHashIndexDigestAlgorithm(ASN1Sequence atsHashIndex) {
AlgorithmIdentifier algorithmIdentifier = DSSASN1Utils.getAlgorithmIdentifier(atsHashIndex);
return algorithmIdentifier != null ?
DigestAlgorithm.forOID(algorithmIdentifier.getAlgorithm().getId()) : CMSUtils.DEFAULT_ARCHIVE_TIMESTAMP_HASH_ALGO;
}
private boolean isDigestValuePresent(final byte[] digestValue, final List hashList) {
return hashList.contains(new DEROctetString(digestValue));
}
@Override
protected List getCertificateRefs(CAdESAttribute unsignedAttribute) {
List certRefs = new ArrayList<>();
ASN1Sequence seq = (ASN1Sequence) unsignedAttribute.getASN1Object();
for (int ii = 0; ii < seq.size(); ii++) {
OtherCertID otherCertId = OtherCertID.getInstance(seq.getObjectAt(ii));
certRefs.add(DSSASN1Utils.getCertificateRef(otherCertId));
}
return certRefs;
}
@Override
protected List getCRLRefs(CAdESAttribute unsignedAttribute) {
List refs = new ArrayList<>();
ASN1Sequence seq = (ASN1Sequence) unsignedAttribute.getASN1Object();
for (int ii = 0; ii < seq.size(); ii++) {
final CrlOcspRef otherRefId = CrlOcspRef.getInstance(seq.getObjectAt(ii));
final CrlListID otherCrlIds = otherRefId.getCrlids();
if (otherCrlIds != null) {
for (final CrlValidatedID id : otherCrlIds.getCrls()) {
refs.add(new CRLRef(id));
}
}
}
return refs;
}
@Override
protected List getOCSPRefs(CAdESAttribute unsignedAttribute) {
List refs = new ArrayList<>();
ASN1Sequence seq = (ASN1Sequence) unsignedAttribute.getASN1Object();
for (int i = 0; i < seq.size(); i++) {
final CrlOcspRef otherCertId = CrlOcspRef.getInstance(seq.getObjectAt(i));
final OcspListID ocspListID = otherCertId.getOcspids();
if (ocspListID != null) {
for (final OcspResponsesID ocspResponsesID : ocspListID.getOcspResponses()) {
refs.add(new OCSPRef(ocspResponsesID));
}
}
}
return refs;
}
@Override
protected List getEncapsulatedCertificateIdentifiers(CAdESAttribute unsignedAttribute) {
List certificateIdentifiers = new ArrayList<>();
ASN1Sequence seq = (ASN1Sequence) unsignedAttribute.getASN1Object();
for (int ii = 0; ii < seq.size(); ii++) {
try {
final Certificate cs = Certificate.getInstance(seq.getObjectAt(ii));
CertificateToken certificateToken = DSSUtils.loadCertificate(cs.getEncoded());
certificateIdentifiers.add(certificateToken.getDSSId());
} catch (Exception e) {
String errorMessage = "Unable to parse an encapsulated certificate : {}";
if (LOG.isDebugEnabled()) {
LOG.warn(errorMessage, e.getMessage(), e);
} else {
LOG.warn(errorMessage, e.getMessage());
}
}
}
return certificateIdentifiers;
}
@Override
protected List getEncapsulatedCRLIdentifiers(CAdESAttribute unsignedAttribute) {
List crlBinaryIdentifiers = new ArrayList<>();
ASN1Encodable asn1Object = unsignedAttribute.getASN1Object();
RevocationValues revocationValues = DSSASN1Utils.getRevocationValues(asn1Object);
if (revocationValues != null) {
for (final CertificateList revValue : revocationValues.getCrlVals()) {
try {
crlBinaryIdentifiers.add(CRLUtils.buildCRLBinary(revValue.getEncoded()));
} catch (Exception e) {
String errorMessage = "Unable to parse CRL binaries : {}";
if (LOG.isDebugEnabled()) {
LOG.warn(errorMessage, e.getMessage(), e);
} else {
LOG.warn(errorMessage, e.getMessage());
}
}
}
}
return crlBinaryIdentifiers;
}
@Override
protected List getEncapsulatedOCSPIdentifiers(CAdESAttribute unsignedAttribute) {
List ocspIdentifiers = new ArrayList<>();
ASN1Encodable asn1Object = unsignedAttribute.getASN1Object();
RevocationValues revocationValues = DSSASN1Utils.getRevocationValues(asn1Object);
if (revocationValues != null) {
for (final BasicOCSPResponse basicOCSPResponse : revocationValues.getOcspVals()) {
try {
final BasicOCSPResp basicOCSPResp = new BasicOCSPResp(basicOCSPResponse);
ocspIdentifiers.add(OCSPResponseBinary.build(basicOCSPResp));
} catch (Exception e) {
String errorMessage = "Unable to parse OCSP response binaries : {}";
if (LOG.isDebugEnabled()) {
LOG.warn(errorMessage, e.getMessage(), e);
} else {
LOG.warn(errorMessage, e.getMessage());
}
}
}
}
return ocspIdentifiers;
}
@Override
protected ArchiveTimestampType getArchiveTimestampType(CAdESAttribute unsignedAttribute) {
if (id_aa_ets_archiveTimestampV2.equals(unsignedAttribute.getASN1Oid())) {
return ArchiveTimestampType.CAdES_V2;
} else if (id_aa_ets_archiveTimestampV3.equals(unsignedAttribute.getASN1Oid())) {
return ArchiveTimestampType.CAdES_V3;
}
return ArchiveTimestampType.CAdES;
}
@Override
protected void addEncapsulatedValuesFromTimestamp(List references,
TimestampToken timestampedTimestamp) {
super.addEncapsulatedValuesFromTimestamp(references, timestampedTimestamp);
TimestampCRLSource timeStampCRLSource = timestampedTimestamp.getCRLSource();
for (EncapsulatedRevocationTokenIdentifier binary : timeStampCRLSource.getAllRevocationBinaries()) {
addReference(references, binary, TimestampedObjectType.REVOCATION);
}
for (EncapsulatedRevocationTokenIdentifier binary : timeStampCRLSource.getAllReferencedRevocationBinaries()) {
addReference(references, binary, TimestampedObjectType.REVOCATION);
}
TimestampOCSPSource timeStampOCSPSource = timestampedTimestamp.getOCSPSource();
for (EncapsulatedRevocationTokenIdentifier binary : timeStampOCSPSource.getAllReferencedRevocationBinaries()) {
addReference(references, binary, TimestampedObjectType.REVOCATION);
}
for (EncapsulatedRevocationTokenIdentifier binary : timeStampOCSPSource.getAllReferencedRevocationBinaries()) {
addReference(references, binary, TimestampedObjectType.REVOCATION);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy