eu.europa.esig.dss.validation.timestamp.SignatureTimestampSource Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of dss-document Show documentation
Show all versions of dss-document Show documentation
DSS Document contains the code for the creation and validation of XAdES, CAdES, PAdES and ASiC signatures.
The 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.validation.timestamp;
import eu.europa.esig.dss.crl.CRLBinary;
import eu.europa.esig.dss.enumerations.ArchiveTimestampType;
import eu.europa.esig.dss.enumerations.DigestAlgorithm;
import eu.europa.esig.dss.enumerations.TimestampType;
import eu.europa.esig.dss.enumerations.TimestampedObjectType;
import eu.europa.esig.dss.model.DSSMessageDigest;
import eu.europa.esig.dss.model.ManifestFile;
import eu.europa.esig.dss.model.identifier.Identifier;
import eu.europa.esig.dss.model.scope.SignatureScope;
import eu.europa.esig.dss.model.x509.revocation.crl.CRL;
import eu.europa.esig.dss.model.x509.revocation.ocsp.OCSP;
import eu.europa.esig.dss.spi.SignatureCertificateSource;
import eu.europa.esig.dss.spi.x509.CertificateRef;
import eu.europa.esig.dss.spi.x509.ListCertificateSource;
import eu.europa.esig.dss.spi.x509.revocation.ListRevocationSource;
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.spi.x509.tsp.TimestampToken;
import eu.europa.esig.dss.spi.x509.tsp.TimestampTokenComparator;
import eu.europa.esig.dss.spi.x509.tsp.TimestampedReference;
import eu.europa.esig.dss.utils.Utils;
import eu.europa.esig.dss.validation.AdvancedSignature;
import eu.europa.esig.dss.validation.SignatureAttribute;
import eu.europa.esig.dss.validation.SignatureProperties;
import eu.europa.esig.dss.validation.evidencerecord.EvidenceRecord;
import eu.europa.esig.dss.validation.scope.EncapsulatedTimestampScopeFinder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
/**
* The timestamp source of a signature
*
* @param {@code AdvancedSignature} implementation
* @param the corresponding {@code SignatureAttribute}
*/
public abstract class SignatureTimestampSource
extends AbstractTimestampSource implements TimestampSource {
private static final long serialVersionUID = -6099954395130813702L;
private static final Logger LOG = LoggerFactory.getLogger(SignatureTimestampSource.class);
/**
* The signature is being validated
*/
protected final AS signature;
/**
* CRL revocation source containing merged data from signature and timestamps
*/
protected ListRevocationSource crlSource;
/**
* OCSP revocation source containing merged data from signature and timestamps
*/
protected ListRevocationSource ocspSource;
/**
* CertificateSource containing merged data from signature and timestamps
*/
protected ListCertificateSource certificateSource;
/**
* Enclosed content timestamps.
*/
protected transient List contentTimestamps;
/**
* Enclosed signature timestamps.
*/
protected transient List signatureTimestamps;
/**
* Enclosed SignAndRefs timestamps.
*/
protected transient List sigAndRefsTimestamps;
/**
* Enclosed RefsOnly timestamps.
*/
protected transient List refsOnlyTimestamps;
/**
* This variable contains the list of enclosed archive signature timestamps.
*/
protected transient List archiveTimestamps;
/**
* This variable contains the list of detached timestamp tokens (used in ASiC with CAdES).
*/
protected transient List detachedTimestamps;
/**
* This variable contains the list of evidence records embedded to the signature document.
*/
protected transient List embeddedEvidenceRecords;
/**
* This variable contains the list of evidence records detached from the signature document.
*/
protected transient List detachedEvidenceRecords;
/**
* A list of all TimestampedReferences extracted from a signature
*/
protected transient List unsignedPropertiesReferences;
/**
* A cached instance of Signed Signature Properties
*/
private SignatureProperties signedSignatureProperties;
/**
* A cached instance of Unsigned Signature Properties
*/
private SignatureProperties unsignedSignatureProperties;
/**
* Default constructor
*
* @param signature {@link AdvancedSignature} is being validated
*/
protected SignatureTimestampSource(final AS signature) {
Objects.requireNonNull(signature, "The signature cannot be null!");
this.signature = signature;
}
@Override
public List getContentTimestamps() {
if (contentTimestamps == null) {
createAndValidate();
}
return contentTimestamps;
}
@Override
public List getSignatureTimestamps() {
if (signatureTimestamps == null) {
createAndValidate();
}
return signatureTimestamps;
}
@Override
public List getTimestampsX1() {
if (sigAndRefsTimestamps == null) {
createAndValidate();
}
return sigAndRefsTimestamps;
}
@Override
public List getTimestampsX2() {
if (refsOnlyTimestamps == null) {
createAndValidate();
}
return refsOnlyTimestamps;
}
@Override
public List getArchiveTimestamps() {
if (archiveTimestamps == null) {
createAndValidate();
}
return archiveTimestamps;
}
@Override
public List getDocumentTimestamps() {
// Applicable only for PAdES
return Collections.emptyList();
}
@Override
public List getDetachedTimestamps() {
if (detachedTimestamps == null) {
createAndValidate();
}
return detachedTimestamps;
}
@Override
public List getAllTimestamps() {
List timestampTokens = new ArrayList<>();
timestampTokens.addAll(getContentTimestamps());
timestampTokens.addAll(getSignatureTimestamps());
timestampTokens.addAll(getTimestampsX1());
timestampTokens.addAll(getTimestampsX2());
timestampTokens.addAll(getArchiveTimestamps());
timestampTokens.addAll(getDetachedTimestamps());
return timestampTokens;
}
@Override
public List getEmbeddedEvidenceRecords() {
if (embeddedEvidenceRecords == null) {
createAndValidate();
}
return embeddedEvidenceRecords;
}
@Override
public List getDetachedEvidenceRecords() {
if (detachedEvidenceRecords == null) {
createAndValidate();
}
return detachedEvidenceRecords;
}
@Override
public List getAllEvidenceRecords() {
List evidenceRecords = new ArrayList<>();
evidenceRecords.addAll(getEmbeddedEvidenceRecords());
evidenceRecords.addAll(getDetachedEvidenceRecords());
return evidenceRecords;
}
@Override
public ListCertificateSource getTimestampCertificateSources() {
ListCertificateSource result = new ListCertificateSource();
for (TimestampToken timestampToken : getAllTimestamps()) {
result.add(timestampToken.getCertificateSource());
}
return result;
}
@Override
public ListCertificateSource getTimestampCertificateSourcesExceptLastArchiveTimestamp() {
ListCertificateSource result = new ListCertificateSource();
List timestampTokens = getAllTimestampsExceptLastArchiveTimestamp();
for (final TimestampToken timestampToken : timestampTokens) {
result.add(timestampToken.getCertificateSource());
}
return result;
}
@Override
public List getAllTimestampsExceptLastArchiveTimestamp() {
List timestampTokens = new ArrayList<>();
timestampTokens.addAll(getContentTimestamps());
timestampTokens.addAll(getSignatureTimestamps());
timestampTokens.addAll(getTimestampsX1());
timestampTokens.addAll(getTimestampsX2());
final List allArchiveTimestamps = new ArrayList<>();
allArchiveTimestamps.addAll(getArchiveTimestamps());
allArchiveTimestamps.addAll(getDocumentTimestamps()); // can be a document timestamp for PAdES
allArchiveTimestamps.addAll(getDetachedTimestamps()); // can be a detached timestamp for ASiC with CAdES
if (Utils.isCollectionNotEmpty(allArchiveTimestamps)) {
if (Utils.isCollectionNotEmpty(timestampTokens) || containsTimestampsCoveringOtherTimestamps(allArchiveTimestamps)) {
// exclude the last archive timestamp
allArchiveTimestamps.sort(new TimestampTokenComparator());
for (int ii = 0; ii < allArchiveTimestamps.size() - 1; ii++) {
TimestampToken timestampToken = allArchiveTimestamps.get(ii);
timestampTokens.add(timestampToken);
}
} else {
// add all timestamps for validation
timestampTokens.addAll(allArchiveTimestamps);
}
}
return timestampTokens;
}
private boolean containsTimestampsCoveringOtherTimestamps(List timestampTokens) {
for (TimestampToken timestampToken : timestampTokens) {
List timestampedReferences = timestampToken.getTimestampedReferences();
if (Utils.isCollectionNotEmpty(timestampedReferences) &&
timestampedReferences.stream().anyMatch(r -> TimestampedObjectType.TIMESTAMP.equals(r.getCategory()))) {
return true;
}
}
return false;
}
@Override
public ListRevocationSource getTimestampCRLSources() {
ListRevocationSource result = new ListRevocationSource<>();
for (TimestampToken timestampToken : getAllTimestamps()) {
result.add(timestampToken.getCRLSource());
}
return result;
}
@Override
public ListRevocationSource getTimestampOCSPSources() {
ListRevocationSource result = new ListRevocationSource<>();
for (TimestampToken timestampToken : getAllTimestamps()) {
result.add(timestampToken.getOCSPSource());
}
return result;
}
@Override
public List getUnsignedPropertiesReferences() {
if (unsignedPropertiesReferences == null) {
createAndValidate();
}
return unsignedPropertiesReferences;
}
/**
* Creates and validates all timestamps
* Must be called only once
*/
protected void createAndValidate() {
makeTimestampTokens();
validateTimestamps();
}
@Override
public void addExternalTimestamp(TimestampToken timestamp) {
// if timestamp tokens not created yet
if (detachedTimestamps == null) {
createAndValidate();
}
processExternalTimestamp(timestamp);
detachedTimestamps.add(timestamp);
}
@Override
public void addExternalEvidenceRecord(EvidenceRecord evidenceRecord) {
// if evidence records not created yet
if (detachedEvidenceRecords == null) {
createAndValidate();
}
processExternalEvidenceRecord(evidenceRecord);
detachedEvidenceRecords.add(evidenceRecord);
}
/**
* Populates all the lists by data found into the signature
*/
protected void makeTimestampTokens() {
// initialize timestamp lists
contentTimestamps = new ArrayList<>();
signatureTimestamps = new ArrayList<>();
sigAndRefsTimestamps = new ArrayList<>();
refsOnlyTimestamps = new ArrayList<>();
archiveTimestamps = new ArrayList<>();
detachedTimestamps = new ArrayList<>();
embeddedEvidenceRecords = new ArrayList<>();
detachedEvidenceRecords = new ArrayList<>();
// initialize combined revocation sources
crlSource = new ListRevocationSource<>(signature.getCRLSource());
ocspSource = new ListRevocationSource<>(signature.getOCSPSource());
certificateSource = new ListCertificateSource(signature.getCertificateSource());
// a list of all embedded references
unsignedPropertiesReferences = new ArrayList<>();
makeTimestampTokensFromSignedAttributes();
makeTimestampTokensFromUnsignedAttributes();
}
/**
* Creates TimestampTokens from all instances extracted from signed attributes
* (content TSTs)
*/
protected void makeTimestampTokensFromSignedAttributes() {
SignatureProperties signedSignatureProperties = getSignedSignatureProperties();
if (signedSignatureProperties == null || !signedSignatureProperties.isExist()) {
return;
}
for (SA signedAttribute : signedSignatureProperties.getAttributes()) {
List timestampTokens;
if (isContentTimestamp(signedAttribute)) {
timestampTokens = makeTimestampTokens(signedAttribute, TimestampType.CONTENT_TIMESTAMP, getSignerDataReferences());
} else if (isAllDataObjectsTimestamp(signedAttribute)) {
timestampTokens = makeTimestampTokens(signedAttribute, TimestampType.ALL_DATA_OBJECTS_TIMESTAMP, getSignerDataReferences());
} else if (isIndividualDataObjectsTimestamp(signedAttribute)) {
timestampTokens = makeTimestampTokens(signedAttribute, TimestampType.INDIVIDUAL_DATA_OBJECTS_TIMESTAMP);
} else {
continue;
}
if (Utils.isCollectionEmpty(timestampTokens)) {
continue;
}
populateSources(timestampTokens);
contentTimestamps.addAll(timestampTokens);
}
}
/**
* Creates TimestampTokens from found instances in unsigned properties
*/
protected void makeTimestampTokensFromUnsignedAttributes() {
final SignatureProperties unsignedSignatureProperties = getUnsignedSignatureProperties();
if (unsignedSignatureProperties == null || !unsignedSignatureProperties.isExist()) {
return;
}
final List allTimestamps = new ArrayList<>();
for (SA unsignedAttribute : unsignedSignatureProperties.getAttributes()) {
List timestampTokens;
if (isSignatureTimestamp(unsignedAttribute)) {
timestampTokens = makeTimestampTokens(unsignedAttribute, TimestampType.SIGNATURE_TIMESTAMP, getSignatureTimestampReferences());
if (Utils.isCollectionEmpty(timestampTokens)) {
continue;
}
signatureTimestamps.addAll(timestampTokens);
} else if (isCompleteCertificateRef(unsignedAttribute) || isAttributeCertificateRef(unsignedAttribute)) {
addReferences(unsignedPropertiesReferences, getTimestampedCertificateRefs(unsignedAttribute));
continue;
} else if (isCompleteRevocationRef(unsignedAttribute) || isAttributeRevocationRef(unsignedAttribute)) {
addReferences(unsignedPropertiesReferences, getTimestampedRevocationRefs(unsignedAttribute));
continue;
} else if (isRefsOnlyTimestamp(unsignedAttribute)) {
final List references = new ArrayList<>();
addReferences(references, unsignedPropertiesReferences);
timestampTokens = makeTimestampTokens(unsignedAttribute, TimestampType.VALIDATION_DATA_REFSONLY_TIMESTAMP, references);
if (Utils.isCollectionEmpty(timestampTokens)) {
continue;
}
refsOnlyTimestamps.addAll(timestampTokens);
} else if (isSigAndRefsTimestamp(unsignedAttribute)) {
final List references = new ArrayList<>();
List processedSignatureTimestamps = filterSignatureTimestamps(allTimestamps);
addReferences(references, getEncapsulatedReferencesFromTimestamps(processedSignatureTimestamps));
addReferences(references, unsignedPropertiesReferences);
timestampTokens = makeTimestampTokens(unsignedAttribute, TimestampType.VALIDATION_DATA_TIMESTAMP, references);
if (Utils.isCollectionEmpty(timestampTokens)) {
continue;
}
sigAndRefsTimestamps.addAll(timestampTokens);
} else if (isCertificateValues(unsignedAttribute) || isAttrAuthoritiesCertValues(unsignedAttribute)) {
addReferences(unsignedPropertiesReferences, getTimestampedCertificateValues(unsignedAttribute));
continue;
} else if (isRevocationValues(unsignedAttribute) || isAttributeRevocationValues(unsignedAttribute)) {
addReferences(unsignedPropertiesReferences, getTimestampedRevocationValues(unsignedAttribute));
continue;
} else if (isArchiveTimestamp(unsignedAttribute)) {
timestampTokens = makeTimestampTokens(unsignedAttribute, TimestampType.ARCHIVE_TIMESTAMP);
if (Utils.isCollectionEmpty(timestampTokens)) {
continue;
}
setArchiveTimestampType(timestampTokens, unsignedAttribute);
incorporateArchiveTimestampReferences(timestampTokens, allTimestamps);
archiveTimestamps.addAll(timestampTokens);
} else if (isTimeStampValidationData(unsignedAttribute)) {
List timestampValidationData = getTimestampValidationData(unsignedAttribute);
addReferences(unsignedPropertiesReferences, timestampValidationData);
continue;
} else if (isCounterSignature(unsignedAttribute)) {
List counterSignatures = getCounterSignatures(unsignedAttribute);
List counterSignatureReferences = getCounterSignaturesReferences(counterSignatures);
addReferences(unsignedPropertiesReferences, counterSignatureReferences);
continue;
} else if (isSignaturePolicyStore(unsignedAttribute)) {
// not processed
continue;
} else if (isEvidenceRecord(unsignedAttribute)) {
List evidenceRecords = makeEvidenceRecords(unsignedAttribute, unsignedPropertiesReferences);
if (Utils.isCollectionEmpty(evidenceRecords)) {
continue;
}
incorporateEvidenceRecordEvidenceReferences(evidenceRecords, allTimestamps);
for (EvidenceRecord evidenceRecord : evidenceRecords) {
populateSources(evidenceRecord.getTimestamps());
}
embeddedEvidenceRecords.addAll(evidenceRecords);
continue;
} else {
LOG.warn("The unsigned attribute with a name [{}] is not supported in TimestampSource processing", unsignedAttribute);
continue;
}
populateSources(timestampTokens);
allTimestamps.addAll(timestampTokens);
}
}
/**
* Returns the 'signed-signature-properties' element of the signature
*
* @return {@link SignatureProperties}
*/
protected SignatureProperties getSignedSignatureProperties() {
if (signedSignatureProperties == null) {
signedSignatureProperties = buildSignedSignatureProperties();
}
return signedSignatureProperties;
}
/**
* Creates the 'signed-signature-properties' element of the signature
*
* @return {@link SignatureProperties}
*/
protected abstract SignatureProperties buildSignedSignatureProperties();
/**
* Returns the 'unsigned-signature-properties' element of the signature
*
* @return {@link SignatureProperties}
*/
protected SignatureProperties getUnsignedSignatureProperties() {
if (unsignedSignatureProperties == null) {
unsignedSignatureProperties = buildUnsignedSignatureProperties();
}
return unsignedSignatureProperties;
}
/**
* Creates the 'unsigned-signature-properties' element of the signature
*
* @return {@link SignatureProperties}
*/
protected abstract SignatureProperties buildUnsignedSignatureProperties();
/**
* Determines if the given {@code signedAttribute} is an instance of "content-timestamp" element
* NOTE: Applicable only for CAdES
*
* @param signedAttribute {@link SignatureAttribute} to process
* @return TRUE if the {@code unsignedAttribute} is a Data Objects Timestamp, FALSE otherwise
*/
protected abstract boolean isContentTimestamp(SA signedAttribute);
/**
* Determines if the given {@code signedAttribute} is an instance of "data-objects-timestamp" element
* NOTE: Applicable only for XAdES
*
* @param signedAttribute {@link SignatureAttribute} to process
* @return TRUE if the {@code unsignedAttribute} is a Data Objects Timestamp, FALSE otherwise
*/
protected abstract boolean isAllDataObjectsTimestamp(SA signedAttribute);
/**
* Determines if the given {@code signedAttribute} is an instance of "individual-data-objects-timestamp" element
* NOTE: Applicable only for XAdES
*
* @param signedAttribute {@link SignatureAttribute} to process
* @return TRUE if the {@code unsignedAttribute} is a Data Objects Timestamp, FALSE otherwise
*/
protected abstract boolean isIndividualDataObjectsTimestamp(SA signedAttribute);
/**
* Determines if the given {@code unsignedAttribute} is an instance of "signature-timestamp" element
*
* @param unsignedAttribute {@link SignatureAttribute} to process
* @return TRUE if the {@code unsignedAttribute} is a Signature Timestamp, FALSE otherwise
*/
protected abstract boolean isSignatureTimestamp(SA unsignedAttribute);
/**
* Determines if the given {@code unsignedAttribute} is an instance of "complete-certificate-ref" element
*
* @param unsignedAttribute {@link SignatureAttribute} to process
* @return TRUE if the {@code unsignedAttribute} is a Complete Certificate Ref, FALSE otherwise
*/
protected abstract boolean isCompleteCertificateRef(SA unsignedAttribute);
/**
* Determines if the given {@code unsignedAttribute} is an instance of "attribute-certificate-ref" element
*
* @param unsignedAttribute {@link SignatureAttribute} to process
* @return TRUE if the {@code unsignedAttribute} is an Attribute Certificate Ref, FALSE otherwise
*/
protected abstract boolean isAttributeCertificateRef(SA unsignedAttribute);
/**
* Determines if the given {@code unsignedAttribute} is an instance of "complete-revocation-ref" element
*
* @param unsignedAttribute {@link SignatureAttribute} to process
* @return TRUE if the {@code unsignedAttribute} is a Complete Revocation Ref, FALSE otherwise
*/
protected abstract boolean isCompleteRevocationRef(SA unsignedAttribute);
/**
* Determines if the given {@code unsignedAttribute} is an instance of "attribute-revocation-ref" element
*
* @param unsignedAttribute {@link SignatureAttribute} to process
* @return TRUE if the {@code unsignedAttribute} is an Attribute Revocation Ref, FALSE otherwise
*/
protected abstract boolean isAttributeRevocationRef(SA unsignedAttribute);
/**
* Determines if the given {@code unsignedAttribute} is an instance of "refs-only-timestamp" element
*
* @param unsignedAttribute {@link SignatureAttribute} to process
* @return TRUE if the {@code unsignedAttribute} is a Refs Only TimeStamp, FALSE otherwise
*/
protected abstract boolean isRefsOnlyTimestamp(SA unsignedAttribute);
/**
* Determines if the given {@code unsignedAttribute} is an instance of "sig-and-refs-timestamp" element
*
* @param unsignedAttribute {@link SignatureAttribute} to process
* @return TRUE if the {@code unsignedAttribute} is a Sig And Refs TimeStamp, FALSE otherwise
*/
protected abstract boolean isSigAndRefsTimestamp(SA unsignedAttribute);
/**
* Determines if the given {@code unsignedAttribute} is an instance of "certificate-values" element
*
* @param unsignedAttribute {@link SignatureAttribute} to process
* @return TRUE if the {@code unsignedAttribute} is a Certificate Values, FALSE otherwise
*/
protected abstract boolean isCertificateValues(SA unsignedAttribute);
/**
* Determines if the given {@code unsignedAttribute} is an instance of "revocation-values" element
*
* @param unsignedAttribute {@link SignatureAttribute} to process
* @return TRUE if the {@code unsignedAttribute} is a Revocation Values, FALSE otherwise
*/
protected abstract boolean isRevocationValues(SA unsignedAttribute);
/**
* Determines if the given {@code unsignedAttribute} is an instance of "AttrAuthoritiesCertValues" element
*
* @param unsignedAttribute {@link SignatureAttribute} to process
* @return TRUE if the {@code unsignedAttribute} is an AttrAuthoritiesCertValues, FALSE otherwise
*/
protected abstract boolean isAttrAuthoritiesCertValues(SA unsignedAttribute);
/**
* Determines if the given {@code unsignedAttribute} is an instance of "AttributeRevocationValues" element
*
* @param unsignedAttribute {@link SignatureAttribute} to process
* @return TRUE if the {@code unsignedAttribute} is an AttributeRevocationValues, FALSE otherwise
*/
protected abstract boolean isAttributeRevocationValues(SA unsignedAttribute);
/**
* Determines if the given {@code unsignedAttribute} is an instance of "archive-timestamp" element
*
* @param unsignedAttribute {@link SignatureAttribute} to process
* @return TRUE if the {@code unsignedAttribute} is an Archive TimeStamp, FALSE otherwise
*/
protected abstract boolean isArchiveTimestamp(SA unsignedAttribute);
/**
* Determines if the given {@code unsignedAttribute} is an instance of
* "timestamp-validation-data" element
*
* @param unsignedAttribute {@link SA} to process
* @return TRUE if the {@code unsignedAttribute} is a TimeStamp Validation Data,
* FALSE otherwise
*/
protected abstract boolean isTimeStampValidationData(SA unsignedAttribute);
/**
* Determines if the given {@code unsignedAttribute} is an instance of
* "counter-signature" element
*
* @param unsignedAttribute {@link SA} to process
* @return TRUE if the {@code unsignedAttribute} is a Counter signature, FALSE
* otherwise
*/
protected abstract boolean isCounterSignature(SA unsignedAttribute);
/**
* Determines if the given {@code unsignedAttribute} is an instance of
* "signature-policy-store" element
*
* @param unsignedAttribute {@link SA} to process
* @return TRUE if the {@code unsignedAttribute} is a Counter signature, FALSE
* otherwise
*/
protected abstract boolean isSignaturePolicyStore(SA unsignedAttribute);
/**
* Determines if the given {@code unsignedAttribute} is an instance of
* "evidence-record" element
*
* @param unsignedAttribute {@link SA} to process
* @return TRUE if the {@code unsignedAttribute} is an evidence record, FALSE otherwise
*/
protected abstract boolean isEvidenceRecord(SA unsignedAttribute);
/**
* Creates a timestamp token from the provided {@code signatureAttribute}
*
* @param signatureAttribute {@link SignatureAttribute} to create timestamp from
* @param timestampType a target {@link TimestampType}
* @param references list of {@link TimestampedReference}s covered by the current timestamp
* @return {@link TimestampToken}
*/
protected abstract TimestampToken makeTimestampToken(SA signatureAttribute, TimestampType timestampType,
List references);
/**
* Creates timestamp tokens from the provided {@code signatureAttribute}
*
* @param signatureAttribute {@link SignatureAttribute} to create timestamp from
* @param timestampType a target {@link TimestampType}
* @return a list of {@link TimestampToken}s
*/
protected List makeTimestampTokens(SA signatureAttribute, TimestampType timestampType) {
return makeTimestampTokens(signatureAttribute, timestampType, new ArrayList<>());
}
/**
* Creates timestamp tokens from the provided {@code signatureAttribute}
* with a given list of {@code TimestampedReference}s
*
* @param signatureAttribute {@link SignatureAttribute} to create timestamp from
* @param timestampType a target {@link TimestampType}
* @param references list of {@link TimestampedReference}s covered by the current timestamp
* @return a list of {@link TimestampToken}s
*/
protected List makeTimestampTokens(SA signatureAttribute, TimestampType timestampType,
List references) {
TimestampToken timestampToken = makeTimestampToken(signatureAttribute, timestampType, references);
if (timestampToken != null) {
return Collections.singletonList(timestampToken);
}
return Collections.emptyList();
}
/**
* Creates a list of evidence records from the provided {@code signatureAttribute}
*
* @param signatureAttribute {@link SignatureAttribute} to create evidence records from
* @param references list of {@link TimestampedReference}s covered by the current evidence record(s)
* @return a list of {@link EvidenceRecord}s
*/
protected abstract List makeEvidenceRecords(SA signatureAttribute, List references);
@Override
public List getSignerDataReferences() {
return getSignerDataTimestampedReferences(signature.getSignatureScopes());
}
/**
* Returns a list of {@link TimestampedReference} for a "signature-timestamp" element
*
* @return list of {@link TimestampedReference}s
*/
protected List getSignatureTimestampReferences() {
final List references = new ArrayList<>();
addReferences(references, getEncapsulatedReferencesFromTimestamps(getContentTimestamps()));
addReferences(references, getSignerDataReferences());
addReference(references, getSignatureReference());
addReferences(references, getSigningCertificateTimestampReferences());
return references;
}
/**
* Creates a timestamped reference for the current signature
*
* @return {@link TimestampedReference}
*/
protected TimestampedReference getSignatureReference() {
return new TimestampedReference(signature.getId(), TimestampedObjectType.SIGNATURE);
}
/**
* Returns a list of TimestampedReferences for tokens encapsulated within the list of timestampTokens
*
* @param timestampTokens a list of {@link TimestampToken} to get references from
* @return a list of {@link TimestampedReference}s
*/
protected List getEncapsulatedReferencesFromTimestamps(List timestampTokens) {
final List references = new ArrayList<>();
for (TimestampToken timestampToken : timestampTokens) {
addReferences(references, getReferencesFromTimestamp(timestampToken, certificateSource, crlSource, ocspSource));
}
return references;
}
/**
* Returns a list of {@code TimestampedReference}s created from signing certificates of the signature
*
* @return list of {@link TimestampedReference}s
*/
protected List getSigningCertificateTimestampReferences() {
SignatureCertificateSource signatureCertificateSource = signature.getCertificateSource();
return createReferencesForCertificateRefs(signatureCertificateSource.getSigningCertificateRefs(),
signatureCertificateSource, certificateSource);
}
/**
* Returns references from the KeyInfo (for XAdES) encapsulated elements
*
* @return list of {@link TimestampedReference}s
*/
protected List getKeyInfoReferences() {
SignatureCertificateSource signatureCertificateSource = signature.getCertificateSource();
return createReferencesForCertificates(signatureCertificateSource.getKeyInfoCertificates());
}
/**
* Returns a list of {@link TimestampedReference} certificate refs found in the
* given {@code unsignedAttribute}
*
* @param unsignedAttribute {@link SA} to find references from
* @return list of {@link TimestampedReference}s
*/
protected List getTimestampedCertificateRefs(SA unsignedAttribute) {
return createReferencesForCertificateRefs(getCertificateRefs(unsignedAttribute),
signature.getCertificateSource(), certificateSource);
}
/**
* Returns a list of {@link CertificateRef}s from the given
* {@code unsignedAttribute}
*
* @param unsignedAttribute {@link SA} to get certRefs from
* @return list of {@link CertificateRef}s
*/
protected abstract List getCertificateRefs(SA unsignedAttribute);
/**
* Returns a list of {@link TimestampedReference} revocation refs found in the given {@code unsignedAttribute}
*
* @param unsignedAttribute {@link SA} to find references from
* @return list of {@link TimestampedReference}s
*/
protected List getTimestampedRevocationRefs(SA unsignedAttribute) {
List timestampedReferences = new ArrayList<>();
timestampedReferences.addAll(createReferencesForCRLRefs(getCRLRefs(unsignedAttribute),
signature.getCRLSource(), crlSource));
timestampedReferences.addAll(createReferencesForOCSPRefs(getOCSPRefs(unsignedAttribute),
signature.getOCSPSource(), certificateSource, ocspSource));
return timestampedReferences;
}
/**
* Returns a list of CRL revocation refs from the given
* {@code unsignedAttribute}
*
* @param unsignedAttribute {@link SA} to get CRLRef
* @return list of {@link CRLRef}s
*/
protected abstract List getCRLRefs(SA unsignedAttribute);
/**
* Returns a list of OCSP revocation refs from the given
* {@code unsignedAttribute}
*
* @param unsignedAttribute {@link SA} to get OCSPRefs from
* @return list of {@link OCSPRef}s
*/
protected abstract List getOCSPRefs(SA unsignedAttribute);
/**
* Returns a list of {@code TimestampedReference}s from the {@code unsignedAttribute} containing certificate values
*
* @param unsignedAttribute {@link SA} to extract certificate values from
* @return a list of {@link TimestampedReference}s
*/
protected List getTimestampedCertificateValues(SA unsignedAttribute) {
return createReferencesForIdentifiers(getEncapsulatedCertificateIdentifiers(unsignedAttribute), TimestampedObjectType.CERTIFICATE);
}
/**
* Returns a list of {@link Identifier}s obtained from the given {@code unsignedAttribute}
*
* @param unsignedAttribute {@link SA} to get certificate identifiers from
* @return list of {@link Identifier}s
*/
protected abstract List getEncapsulatedCertificateIdentifiers(SA unsignedAttribute);
/**
* Returns a list of timestamped revocation references extracted from the given unsigned attribute
*
* @param unsignedAttribute {@link SA} containing revocation data
* @return a list of {@link TimestampedReference}s
*/
protected List getTimestampedRevocationValues(SA unsignedAttribute) {
final List timestampedReferences = new ArrayList<>();
timestampedReferences.addAll(createReferencesForCRLBinaries(getEncapsulatedCRLIdentifiers(unsignedAttribute)));
timestampedReferences.addAll(createReferencesForOCSPBinaries(getEncapsulatedOCSPIdentifiers(unsignedAttribute), certificateSource));
return timestampedReferences;
}
/**
* Returns a list of {@link CRLBinary}s obtained from the given {@code unsignedAttribute}
*
* @param unsignedAttribute {@link SA} to get CRL identifiers from
* @return list of {@link CRLBinary}s
*/
protected abstract List getEncapsulatedCRLIdentifiers(SA unsignedAttribute);
/**
* Returns a list of {@link OCSPResponseBinary}s obtained from the given {@code unsignedAttribute}
*
* @param unsignedAttribute {@link SA} to get OCSP identifiers from
* @return list of {@link OCSPResponseBinary}s
*/
protected abstract List getEncapsulatedOCSPIdentifiers(SA unsignedAttribute);
private void incorporateArchiveTimestampReferences(List createdTimestampTokens,
List previousTimestamps) {
for (TimestampToken timestampToken : createdTimestampTokens) {
incorporateArchiveTimestampReferences(timestampToken, previousTimestamps);
}
}
/**
* The method incorporates all the timestamped references for
* the given archive {@code timestampToken}
*
* @param timestampToken {@link TimestampToken} representing an Archive TST
* to add references into
* @param previousTimestamps a list of previously created
* {@link TimestampToken}s
*/
protected void incorporateArchiveTimestampReferences(TimestampToken timestampToken,
List previousTimestamps) {
addReferences(timestampToken.getTimestampedReferences(), getArchiveTimestampReferences(previousTimestamps));
}
private void incorporateEvidenceRecordEvidenceReferences(List createdEvidenceRecords,
List previousTimestamps) {
for (EvidenceRecord evidenceRecord : createdEvidenceRecords) {
addReferences(evidenceRecord.getTimestampedReferences(), getArchiveTimestampReferences(previousTimestamps));
processEvidenceRecordTimestamps(evidenceRecord);
}
}
/**
* Returns a list of time-stamped references for an archival time-stamp
*
* @param previousTimestamps a list of previous {@link TimestampToken}s
* @return a list of {@link TimestampedReference}s
*/
protected List getArchiveTimestampReferences(List previousTimestamps) {
List timestampedReferences = new ArrayList<>();
addReferences(timestampedReferences, getSignatureTimestampReferences());
addReferences(timestampedReferences, getEncapsulatedReferencesFromTimestamps(previousTimestamps));
addReferences(timestampedReferences, unsignedPropertiesReferences);
return timestampedReferences;
}
/**
* Returns a list of all {@code TimestampedReference}s found into CMS SignedData of the signature
* NOTE: used only in ASiC-E CAdES
*
* @return list of {@link TimestampedReference}s
*/
protected List getSignatureSignedDataReferences() {
// empty by default
return new ArrayList<>();
}
/**
* Returns a list of {@link TimestampedReference}s encapsulated to the "timestamp-validation-data" {@code unsignedAttribute}
*
* @param unsignedAttribute {@link SA} to get timestamped references from
* @return list of {@link TimestampedReference}s
*/
protected List getTimestampValidationData(SA unsignedAttribute) {
final List timestampedReferences = new ArrayList<>();
addReferences(timestampedReferences, createReferencesForIdentifiers(
getEncapsulatedCertificateIdentifiers(unsignedAttribute), TimestampedObjectType.CERTIFICATE));
addReferences(timestampedReferences, createReferencesForCRLBinaries(getEncapsulatedCRLIdentifiers(unsignedAttribute)));
addReferences(timestampedReferences, createReferencesForOCSPBinaries(getEncapsulatedOCSPIdentifiers(unsignedAttribute), certificateSource));
return timestampedReferences;
}
/**
* Returns a list of {@link TimestampedReference}s encapsulated from the list of counter signatures
*
* @param counterSignatures a list of {@link AdvancedSignature} to get timestamped references from
* @return list of {@link TimestampedReference}s
*/
protected List getCounterSignaturesReferences(List counterSignatures) {
List references = new ArrayList<>();
if (Utils.isCollectionNotEmpty(counterSignatures)) {
for (AdvancedSignature counterSignature : counterSignatures) {
references.addAll(getCounterSignatureReferences(counterSignature));
}
}
return references;
}
/**
* Returns a list of references extracted from a counter signature
*
* @param counterSignature {@link AdvancedSignature} representing a counter signature
* @return a list of {@link TimestampedReference}s
*/
protected List getCounterSignatureReferences(AdvancedSignature counterSignature) {
List counterSigReferences = new ArrayList<>();
counterSigReferences.add(new TimestampedReference(counterSignature.getId(), TimestampedObjectType.SIGNATURE));
SignatureCertificateSource signatureCertificateSource = counterSignature.getCertificateSource();
addReferences(counterSigReferences, createReferencesForCertificates(signatureCertificateSource.getCertificates()));
TimestampSource counterSignatureTimestampSource = counterSignature.getTimestampSource();
addReferences(counterSigReferences, counterSignatureTimestampSource.getSignerDataReferences());
addReferences(counterSigReferences, counterSignatureTimestampSource.getUnsignedPropertiesReferences());
addReferences(counterSigReferences, getEncapsulatedReferencesFromTimestamps(
counterSignatureTimestampSource.getAllTimestamps()));
return counterSigReferences;
}
/**
* Extracts Counter Signatures from the given {@code unsignedAttribute}
*
* @param unsignedAttribute {@link SA} containing counter signatures
* @return a list of {@link AdvancedSignature} containing counter signatures
*/
protected abstract List getCounterSignatures(SA unsignedAttribute);
private List filterSignatureTimestamps(List previousTimestampedTimestamp) {
List result = new ArrayList<>();
for (TimestampToken timestampToken : previousTimestampedTimestamp) {
if (TimestampType.SIGNATURE_TIMESTAMP.equals(timestampToken.getTimeStampType())) {
result.add(timestampToken);
}
}
return result;
}
private void setArchiveTimestampType(List timestampTokens, SA unsignedAttribute) {
ArchiveTimestampType archiveTimestampType = getArchiveTimestampType(unsignedAttribute);
for (TimestampToken timestampToken : timestampTokens) {
timestampToken.setArchiveTimestampType(archiveTimestampType);
}
}
/**
* Returns {@link ArchiveTimestampType} for the given {@code unsignedAttribute}
*
* @param unsignedAttribute {@link SA} to get archive timestamp type for
* @return {@link ArchiveTimestampType}
*/
protected abstract ArchiveTimestampType getArchiveTimestampType(SA unsignedAttribute);
/**
* Validates list of all timestamps present in the source
*/
protected void validateTimestamps() {
DSSMessageDigest messageDigest = null;
/*
* This validates the content-timestamp tokensToProcess present in the signature.
*/
for (final TimestampToken timestampToken : getContentTimestamps()) {
messageDigest = getTimestampMessageImprintDigestBuilder(timestampToken).getContentTimestampMessageDigest();
timestampToken.matchData(messageDigest);
timestampToken.setTimestampScopes(getTimestampScopes(timestampToken));
}
/*
* This validates the signature timestamp tokensToProcess present in the signature.
*/
for (final TimestampToken timestampToken : getSignatureTimestamps()) {
messageDigest = getTimestampMessageImprintDigestBuilder(timestampToken).getSignatureTimestampMessageDigest();
timestampToken.matchData(messageDigest);
}
/*
* This validates the SigAndRefs timestamp tokensToProcess present in the signature.
*/
for (final TimestampToken timestampToken : getTimestampsX1()) {
messageDigest = getTimestampMessageImprintDigestBuilder(timestampToken).getTimestampX1MessageDigest();
timestampToken.matchData(messageDigest);
}
/*
* This validates the RefsOnly timestamp tokensToProcess present in the signature.
*/
for (final TimestampToken timestampToken : getTimestampsX2()) {
messageDigest = getTimestampMessageImprintDigestBuilder(timestampToken).getTimestampX2MessageDigest();
timestampToken.matchData(messageDigest);
}
/*
* This validates the archive timestamp tokensToProcess present in the signature.
*/
for (final TimestampToken timestampToken : getArchiveTimestamps()) {
if (!timestampToken.isProcessed()) {
messageDigest = getTimestampMessageImprintDigestBuilder(timestampToken).getArchiveTimestampMessageDigest();
timestampToken.matchData(messageDigest);
timestampToken.setTimestampScopes(getTimestampScopes(timestampToken));
}
}
}
/**
* Returns a {@link TimestampMessageDigestBuilder} to compute message digest
* with the provided {@code DigestAlgorithm}
*
* @param digestAlgorithm {@link DigestAlgorithm} to use for message-digest computation
* @return {@link TimestampMessageDigestBuilder}
*/
protected abstract TimestampMessageDigestBuilder getTimestampMessageImprintDigestBuilder(
DigestAlgorithm digestAlgorithm);
/**
* Returns a related {@link TimestampMessageDigestBuilder}
*
* @param timestampToken {@link TimestampToken} to get message-imprint digest builder for
* @return {@link TimestampMessageDigestBuilder}
*/
protected abstract TimestampMessageDigestBuilder getTimestampMessageImprintDigestBuilder(TimestampToken timestampToken);
/**
* Generates timestamp token scopes
*
* @param timestampToken {@link TimestampToken} to get timestamp sources for
* @return a list of {@link SignatureScope}s
*/
protected List getTimestampScopes(TimestampToken timestampToken) {
EncapsulatedTimestampScopeFinder timestampScopeFinder = new EncapsulatedTimestampScopeFinder();
timestampScopeFinder.setSignature(signature);
return timestampScopeFinder.findTimestampScope(timestampToken);
}
private void processExternalTimestamp(TimestampToken externalTimestamp) {
// add all validation data present in Signature CMS SignedData, because an external timestamp covers a whole signature file
addReferences(externalTimestamp.getTimestampedReferences(), getSignatureSignedDataReferences());
// add references from previously added timestamps
addReferences(externalTimestamp.getTimestampedReferences(), getEncapsulatedReferencesFromTimestamps(
getTimestampsCoveredByManifest(externalTimestamp.getManifestFile())));
// add existing counter signatures
addReferences(externalTimestamp.getTimestampedReferences(), getCounterSignatureReferences(signature));
// populate timestamp certificate source with values present in the timestamp
populateSources(externalTimestamp);
}
private List getTimestampsCoveredByManifest(ManifestFile manifestFile) {
List result = new ArrayList<>();
for (TimestampToken timestampToken : getAllTimestamps()) {
if (detachedTimestamps.contains(timestampToken) &&
(manifestFile == null || !manifestFile.isDocumentCovered(timestampToken.getFileName()))) {
// the detached timestamp is not covered, continue
continue;
}
result.add(timestampToken);
}
return result;
}
private void processExternalEvidenceRecord(EvidenceRecord evidenceRecord) {
final List timestampedReferences = new ArrayList<>();
addReferences(timestampedReferences, getSignatureTimestampReferences());
addReferences(timestampedReferences, getSignatureSignedDataReferences());
addReferences(timestampedReferences, getEncapsulatedReferencesFromTimestamps(getSignatureTimestamps()));
addReferences(timestampedReferences, unsignedPropertiesReferences);
addReferences(timestampedReferences, getEncapsulatedReferencesFromTimestamps(getTimestampsX1()));
addReferences(timestampedReferences, getEncapsulatedReferencesFromTimestamps(getTimestampsX2()));
addReferences(timestampedReferences, getEncapsulatedReferencesFromTimestamps(getArchiveTimestamps()));
addReferences(timestampedReferences, getEncapsulatedReferencesFromTimestamps(
getTimestampsCoveredByManifest(evidenceRecord.getManifestFile())));
addReferences(evidenceRecord.getTimestampedReferences(), timestampedReferences);
processEvidenceRecordTimestamps(evidenceRecord);
processEmbeddedEvidenceRecords(evidenceRecord);
populateSources(evidenceRecord);
}
/**
* Enriches embedded time-stamp tokens with evidence record references
*
* @param evidenceRecord {@link EvidenceRecord}
*/
private void processEvidenceRecordTimestamps(EvidenceRecord evidenceRecord) {
for (TimestampToken timestampToken : evidenceRecord.getTimestamps()) {
ensureOnlyDataTimestampReferencesPresent(timestampToken.getTimestampedReferences(), evidenceRecord.getTimestampedReferences());
addReferences(timestampToken.getTimestampedReferences(), evidenceRecord.getTimestampedReferences());
}
}
private void processEmbeddedEvidenceRecords(EvidenceRecord evidenceRecord) {
for (EvidenceRecord embeddedEvidenceRecord : evidenceRecord.getDetachedEvidenceRecords()) {
addReferences(embeddedEvidenceRecord.getTimestampedReferences(), evidenceRecord.getTimestampedReferences());
processEvidenceRecordTimestamps(embeddedEvidenceRecord);
}
}
/**
* This method is a workaround to ensure time-stamps from evidence record do not refer
* signature or time-stamp files in addition to token references
*
* @param referenceList a list of {@link TimestampedReference} from time-stamp token
* @param referencesToCheck a list of {@link TimestampedReference} from an evidence record
*/
private void ensureOnlyDataTimestampReferencesPresent(List referenceList, List referencesToCheck) {
referenceList.removeIf(timestampedReference ->
TimestampedObjectType.SIGNED_DATA.equals(timestampedReference.getCategory()) &&
referencesToCheck.stream().noneMatch(timestampedReference::equals));
}
/**
* Allows to populate all merged sources with extracted from a timestamp data
*
* @param timestampTokens a list of {@link TimestampToken}s to populate data from
*/
protected void populateSources(List timestampTokens) {
for (TimestampToken timestampToken : timestampTokens) {
populateSources(timestampToken);
}
}
/**
* Allows to populate all merged sources with extracted from a timestamp data
*
* @param timestampToken {@link TimestampToken} to populate data from
*/
protected void populateSources(TimestampToken timestampToken) {
if (timestampToken != null) {
certificateSource.add(timestampToken.getCertificateSource());
crlSource.add(timestampToken.getCRLSource());
ocspSource.add(timestampToken.getOCSPSource());
}
}
/**
* Allows to populate all sources from an external evidence record
*
* @param externalEvidenceRecord {@link EvidenceRecord} to populate data from
*/
protected void populateSources(EvidenceRecord externalEvidenceRecord) {
if (externalEvidenceRecord != null) {
// TODO : add extraction of embedded validation data
populateSources(externalEvidenceRecord.getTimestamps());
}
}
@Override
public boolean isTimestamped(String tokenId, TimestampedObjectType objectType) {
return isTimestamped(signature, tokenId, objectType);
}
private boolean isTimestamped(AdvancedSignature signature, String tokenId, TimestampedObjectType objectType) {
for (TimestampToken timestampToken : getAllTimestamps()) {
if (timestampToken.getTimestampedReferences().contains(new TimestampedReference(tokenId, objectType))) {
return true;
}
}
AdvancedSignature masterSignature = signature.getMasterSignature();
if (masterSignature != null) {
return isTimestamped(masterSignature, tokenId, objectType);
}
return false;
}
/**
* Gets position of the {@code signatureAttribute} either within signed or unsigned properties
*
* @param signatureAttribute {@link SignatureAttribute} to search for
* @return position of the attribute within properties, NULL if not found
*/
protected Integer getAttributeOrder(SA signatureAttribute) {
for (int i = 0; i < getSignedSignatureProperties().getAttributes().size(); i++) {
SA property = getSignedSignatureProperties().getAttributes().get(i);
if (signatureAttribute.equals(property)) {
return i;
}
}
for (int i = 0; i < getUnsignedSignatureProperties().getAttributes().size(); i++) {
SA property = getUnsignedSignatureProperties().getAttributes().get(i);
if (signatureAttribute.equals(property)) {
return i;
}
}
return null;
}
}