eu.europa.esig.dss.validation.SignedDocumentValidator 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;
import eu.europa.esig.dss.diagnostic.DiagnosticData;
import eu.europa.esig.dss.diagnostic.jaxb.XmlDiagnosticData;
import eu.europa.esig.dss.enumerations.DigestAlgorithm;
import eu.europa.esig.dss.enumerations.TimestampedObjectType;
import eu.europa.esig.dss.enumerations.TokenExtractionStrategy;
import eu.europa.esig.dss.exception.IllegalInputException;
import eu.europa.esig.dss.model.DSSDocument;
import eu.europa.esig.dss.model.DSSException;
import eu.europa.esig.dss.model.ManifestFile;
import eu.europa.esig.dss.model.identifier.TokenIdentifierProvider;
import eu.europa.esig.dss.model.scope.SignatureScope;
import eu.europa.esig.dss.policy.EtsiValidationPolicy;
import eu.europa.esig.dss.policy.ValidationPolicy;
import eu.europa.esig.dss.policy.ValidationPolicyFacade;
import eu.europa.esig.dss.policy.jaxb.ConstraintsParameters;
import eu.europa.esig.dss.spi.DSSSecurityProvider;
import eu.europa.esig.dss.spi.DSSUtils;
import eu.europa.esig.dss.spi.client.http.NativeHTTPDataLoader;
import eu.europa.esig.dss.spi.x509.CertificateSource;
import eu.europa.esig.dss.spi.x509.tsp.TimestampToken;
import eu.europa.esig.dss.spi.x509.tsp.TimestampedReference;
import eu.europa.esig.dss.utils.Utils;
import eu.europa.esig.dss.validation.evidencerecord.EvidenceRecord;
import eu.europa.esig.dss.validation.evidencerecord.EvidenceRecordValidator;
import eu.europa.esig.dss.validation.executor.DocumentProcessExecutor;
import eu.europa.esig.dss.validation.executor.ValidationLevel;
import eu.europa.esig.dss.validation.executor.signature.DefaultSignatureProcessExecutor;
import eu.europa.esig.dss.validation.policy.DefaultSignaturePolicyValidatorLoader;
import eu.europa.esig.dss.validation.policy.SignaturePolicyValidatorLoader;
import eu.europa.esig.dss.validation.reports.Reports;
import eu.europa.esig.dss.validation.scope.EvidenceRecordScopeFinder;
import eu.europa.esig.dss.validation.scope.SignatureScopeFinder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.security.Security;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.ServiceLoader;
/**
* Validates a signed document. The content of the document is determined
* automatically. It can be: XML, CAdES(p7m), PDF or ASiC(zip).
* SignatureScopeFinder can be set using the appropriate setter (ex.
* setCadesSignatureScopeFinder). By default, this class will use the default
* SignatureScopeFinder as defined by
* eu.europa.esig.dss.validation.scope.SignatureScopeFinderFactory
*/
public abstract class SignedDocumentValidator implements DocumentValidator {
private static final Logger LOG = LoggerFactory.getLogger(SignedDocumentValidator.class);
static {
Security.addProvider(DSSSecurityProvider.getSecurityProvider());
}
/**
* This variable can hold a specific {@code DocumentProcessExecutor}
*/
protected DocumentProcessExecutor processExecutor = null;
/**
* The document to be validated (with the signature(s) or timestamp(s))
*/
protected DSSDocument document;
/**
* In case of a detached signature this {@code List} contains the signed
* documents.
*/
protected List detachedContents = new ArrayList<>();
/**
* Contains a list of evidence record documents detached from the signature
*/
protected List detachedEvidenceRecordDocuments = new ArrayList<>();
/**
* In case of an ASiC signature this {@code List} of container documents.
*/
protected List containerContents;
/**
* A related {@link ManifestFile} to the provided {@code document}
*/
protected ManifestFile manifestFile;
/**
* Certificate source to find signing certificate
*/
protected CertificateSource signingCertificateSource;
/**
* A time to validate the document against
*/
private Date validationTime;
/**
* The reference to the certificate verifier. The current DSS implementation
* proposes {@link eu.europa.esig.dss.validation.CommonCertificateVerifier}.
* This verifier encapsulates the references to different sources used in the
* signature validation process.
*/
protected CertificateVerifier certificateVerifier;
/**
* The used token extraction strategy to define tokens representation in DiagnosticData
*/
private TokenExtractionStrategy tokenExtractionStrategy = TokenExtractionStrategy.NONE;
/**
* The implementation to be used for identifiers generation
*/
private TokenIdentifierProvider tokenIdentifierProvider = new OriginalIdentifierProvider();
/**
* This variable allows to include the semantics for Indication / SubIndication
*/
private boolean includeSemantics = false;
/**
* Provides methods to extract a policy content by its identifier
*/
private SignaturePolicyProvider signaturePolicyProvider;
/**
* The expected validation level
*
* Default: ValidationLevel.ARCHIVAL_DATA (the highest level)
*/
private ValidationLevel validationLevel = ValidationLevel.ARCHIVAL_DATA;
/**
* Locale to use for reports generation
* By default a Locale from OS is used
*/
private Locale locale = Locale.getDefault();
/**
* Defines if the ETSI Validation report shall be produced
*
* Default: true
*/
private boolean enableEtsiValidationReport = true;
/**
* Defines if the validation context processing shall be skipped
* (Disable certificate chain building, revocation data collection,...)
*
* Default: false
*/
protected boolean skipValidationContextExecution = false;
/**
* Cached list of signatures extracted from the document
*/
private List signatures;
/**
* Cached list of detached timestamps extracted from the document
*/
private List detachedTimestamps;
/**
* Cached list of detached evidence records extracted from the document
*/
private List evidenceRecords;
/**
* The constructor with a null {@code signatureScopeFinder}
*/
protected SignedDocumentValidator() {
// empty
}
/**
* The default constructor
*
* @param signatureScopeFinder {@link SignatureScopeFinder}
* @deprecated since DSS 5.13.
*/
@Deprecated
protected SignedDocumentValidator(SignatureScopeFinder> signatureScopeFinder) {
// empty
}
/**
* This method guesses the document format and returns an appropriate
* document validator.
*
* @param dssDocument
* The instance of {@code DSSDocument} to validate
* @return returns the specific instance of SignedDocumentValidator in terms
* of the document type
*/
public static SignedDocumentValidator fromDocument(final DSSDocument dssDocument) {
Objects.requireNonNull(dssDocument, "DSSDocument is null");
ServiceLoader serviceLoaders = ServiceLoader.load(DocumentValidatorFactory.class);
for (DocumentValidatorFactory factory : serviceLoaders) {
if (factory.isSupported(dssDocument)) {
return factory.create(dssDocument);
}
}
throw new UnsupportedOperationException("Document format not recognized/handled");
}
/**
* Checks if the document is supported by the current validator
*
* @param dssDocument {@link DSSDocument} to check
* @return TRUE if the document is supported, FALSE otherwise
*/
public abstract boolean isSupported(DSSDocument dssDocument);
@Override
public void setSigningCertificateSource(CertificateSource signingCertificateSource) {
this.signingCertificateSource = signingCertificateSource;
}
/**
* To carry out the validation process of the signature(s) some external sources
* of certificates and of revocation data can be needed. The certificate
* verifier is used to pass these values. Note that once this setter is called
* any change in the content of the CommonTrustedCertificateSource
* or in adjunct certificate source is not taken into account.
*
* @param certificateVerifier {@link CertificateVerifier}
*/
@Override
public void setCertificateVerifier(final CertificateVerifier certificateVerifier) {
Objects.requireNonNull(certificateVerifier);
this.certificateVerifier = certificateVerifier;
}
@Override
public void setTokenExtractionStrategy(TokenExtractionStrategy tokenExtractionStrategy) {
Objects.requireNonNull(tokenExtractionStrategy);
this.tokenExtractionStrategy = tokenExtractionStrategy;
}
/**
* Gets {@code TokenIdentifierProvider}
*
* @return {@link TokenIdentifierProvider}
*/
protected TokenIdentifierProvider getTokenIdentifierProvider() {
return tokenIdentifierProvider;
}
@Override
public void setTokenIdentifierProvider(TokenIdentifierProvider tokenIdentifierProvider) {
Objects.requireNonNull(tokenIdentifierProvider);
this.tokenIdentifierProvider = tokenIdentifierProvider;
}
@Override
public void setIncludeSemantics(boolean include) {
this.includeSemantics = include;
}
@Override
public void setDetachedContents(final List detachedContents) {
this.detachedContents = detachedContents;
}
@Override
public void setDetachedEvidenceRecordDocuments(final List detachedEvidenceRecordDocuments) {
this.detachedEvidenceRecordDocuments = detachedEvidenceRecordDocuments;
}
@Override
public void setContainerContents(List containerContents) {
this.containerContents = containerContents;
}
@Override
public void setManifestFile(ManifestFile manifestFile) {
this.manifestFile = manifestFile;
}
/**
* Returns a default digest algorithm defined for a digest calculation
*
* @return {@link DigestAlgorithm}
*/
protected DigestAlgorithm getDefaultDigestAlgorithm() {
return certificateVerifier.getDefaultDigestAlgorithm();
}
/**
* Allows to define a custom validation time
*
* @param validationTime {@link Date}
*/
@Override
public void setValidationTime(Date validationTime) {
this.validationTime = validationTime;
}
/**
* Returns validation time In case if the validation time is not provided,
* initialize the current time value from the system
*
* @return {@link Date} validation time
*/
protected Date getValidationTime() {
if (validationTime == null) {
validationTime = new Date();
}
return validationTime;
}
@Override
public void setValidationLevel(ValidationLevel validationLevel) {
this.validationLevel = validationLevel;
}
@Override
public void setEnableEtsiValidationReport(boolean enableEtsiValidationReport) {
this.enableEtsiValidationReport = enableEtsiValidationReport;
}
@Override
public Reports validateDocument() {
return validateDocument((InputStream) null);
}
@Override
public Reports validateDocument(final URL validationPolicyURL) {
if (validationPolicyURL == null) {
return validateDocument((InputStream) null);
}
try (InputStream is = validationPolicyURL.openStream()) {
return validateDocument(is);
} catch (IOException e) {
throw new IllegalInputException(String.format("Unable to load policy with URL '%s'. Reason : %s",
validationPolicyURL, e.getMessage()), e);
}
}
@Override
public Reports validateDocument(final String policyResourcePath) {
if (policyResourcePath == null) {
return validateDocument((InputStream) null);
}
try (InputStream is = getClass().getResourceAsStream(policyResourcePath)) {
return validateDocument(is);
} catch (IOException e) {
throw new IllegalInputException(String.format("Unable to load policy from path '%s'. Reason : %s",
policyResourcePath, e.getMessage()), e);
}
}
@Override
public Reports validateDocument(final File policyFile) {
if ((policyFile == null) || !policyFile.exists()) {
return validateDocument((InputStream) null);
}
try (InputStream is = DSSUtils.toByteArrayInputStream(policyFile)) {
return validateDocument(is);
} catch (IOException e) {
throw new IllegalInputException(String.format("Unable to load policy from file '%s'. Reason : %s",
policyFile, e.getMessage()), e);
}
}
@Override
public Reports validateDocument(DSSDocument policyDocument) {
try (InputStream is = policyDocument.openStream()) {
return validateDocument(is);
} catch (IOException e) {
throw new DSSException(String.format("Unable to read policy file: %s", e.getMessage()), e);
}
}
/**
* Validates the document and all its signatures. The policyDataStream contains
* the constraint file. If null or empty the default file is used.
*
* @param policyDataStream the {@code InputStream} with the validation policy
* @return the validation reports
*/
@Override
public Reports validateDocument(final InputStream policyDataStream) {
ValidationPolicy validationPolicy;
try {
if (policyDataStream == null) {
LOG.debug("No provided validation policy : use the default policy");
validationPolicy = ValidationPolicyFacade.newFacade().getDefaultValidationPolicy();
} else {
validationPolicy = ValidationPolicyFacade.newFacade().getValidationPolicy(policyDataStream);
}
} catch (Exception e) {
throw new IllegalInputException("Unable to load the policy", e);
}
return validateDocument(validationPolicy);
}
/**
* Validates the document and all its signatures. The
* {@code validationPolicyDom} contains the constraint file. If null or empty
* the default file is used.
*
* @param validationPolicyJaxb the {@code ConstraintsParameters} to use in the
* validation process
* @return the validation reports
*/
@Override
public Reports validateDocument(final ConstraintsParameters validationPolicyJaxb) {
final ValidationPolicy validationPolicy = new EtsiValidationPolicy(validationPolicyJaxb);
return validateDocument(validationPolicy);
}
/**
* Validates the document and all its signatures. The
* {@code validationPolicyDom} contains the constraint file. If null or empty
* the default file is used.
*
* @param validationPolicy the {@code ValidationPolicy} to use in the validation
* process
* @return the validation reports
*/
@Override
public Reports validateDocument(final ValidationPolicy validationPolicy) {
LOG.info("Document validation...");
assertConfigurationValid();
final XmlDiagnosticData diagnosticData = getDiagnosticData();
return processValidationPolicy(diagnosticData, validationPolicy);
}
/**
* Checks if the Validator configuration is valid
*/
protected void assertConfigurationValid() {
Objects.requireNonNull(certificateVerifier, "CertificateVerifier is not defined");
Objects.requireNonNull(document, "Document is not provided to the validator");
}
/**
* This method retrieves {@code XmlDiagnosticData} containing all information relevant
* for the validation process, including the certificate and revocation tokens obtained
* from online resources, e.g. AIA, CRL, OCSP (when applicable).
*
* @return {@link XmlDiagnosticData}
*/
public final XmlDiagnosticData getDiagnosticData() {
return prepareDiagnosticDataBuilder().build();
}
/**
* Creates a {@code DiagnosticDataBuilder}
*
* @return {@link DiagnosticDataBuilder}
*/
protected DiagnosticDataBuilder prepareDiagnosticDataBuilder() {
List allSignatures = getAllSignatures();
List detachedTimestamps = getDetachedTimestamps();
List detachedEvidenceRecords = getDetachedEvidenceRecords();
final CertificateVerifier certificateVerifierForValidation =
new CertificateVerifierBuilder(certificateVerifier).buildCompleteCopyForValidation();
final ValidationContext validationContext = prepareValidationContext(
allSignatures, detachedTimestamps, detachedEvidenceRecords, certificateVerifierForValidation);
if (!skipValidationContextExecution) {
validateContext(validationContext);
}
return createDiagnosticDataBuilder(validationContext, allSignatures, detachedEvidenceRecords);
}
/**
* Initializes and fills {@code ValidationContext} with necessary data sources
*
* @param {@link AdvancedSignature} implementation
* @param signatures a collection of {@link AdvancedSignature}s
* @param detachedTimestamps a collection of detached {@link TimestampToken}s
* @param certificateVerifier {@link CertificateVerifier} to be used for the validation
* @return {@link ValidationContext}
* @deprecated since DSS 5.13. Use
* {@code #prepareValidationContext(signatures, detachedTimestamps, detachedEvidenceRecords, certificateVerifier}}
*/
@Deprecated
protected ValidationContext prepareValidationContext(
final Collection signatures, final Collection detachedTimestamps,
final CertificateVerifier certificateVerifier) {
return prepareValidationContext(signatures, detachedTimestamps, Collections.emptyList(), certificateVerifier);
}
/**
* Initializes and fills {@code ValidationContext} with necessary data sources
*
* @param {@link AdvancedSignature} implementation
* @param signatures a collection of {@link AdvancedSignature}s
* @param detachedTimestamps a collection of detached {@link TimestampToken}s
* @param detachedEvidenceRecords a collection of detached {@link EvidenceRecord}s
* @param certificateVerifier {@link CertificateVerifier} to be used for the validation
* @return {@link ValidationContext}
*/
protected ValidationContext prepareValidationContext(
final Collection signatures, final Collection detachedTimestamps,
final Collection detachedEvidenceRecords,
final CertificateVerifier certificateVerifier) {
ValidationContext validationContext = new SignatureValidationContext();
validationContext.initialize(certificateVerifier);
prepareSignatureValidationContext(validationContext, signatures);
prepareDetachedTimestampValidationContext(validationContext, detachedTimestamps);
prepareDetachedEvidenceRecordValidationContext(validationContext, detachedEvidenceRecords);
return validationContext;
}
/**
* Initializes a relevant {@code DiagnosticDataBuilder} for the given
* implementation
*
* @return {@link SignedDocumentDiagnosticDataBuilder}
*/
protected SignedDocumentDiagnosticDataBuilder initializeDiagnosticDataBuilder() {
return new SignedDocumentDiagnosticDataBuilder(); // by default
}
@Override
public ValidationDataContainer getValidationData(Collection signatures) {
return getValidationData(signatures, Collections.emptyList());
}
@Override
public ValidationDataContainer getValidationData(Collection signatures,
Collection detachedTimestamps) {
if (Utils.isCollectionEmpty(signatures) && Utils.isCollectionEmpty(detachedTimestamps)) {
throw new DSSException("At least one signature or a timestamp shall be provided to extract the validation data!");
}
ValidationContext validationContext = prepareValidationContext(signatures, detachedTimestamps, certificateVerifier);
validateContext(validationContext);
assertSignaturesValid(signatures, validationContext);
ValidationDataContainer validationDataContainer = instantiateValidationDataContainer();
for (AdvancedSignature signature : signatures) {
ValidationData signatureValidationData = validationContext.getValidationData(signature);
validationDataContainer.addValidationData(signature, signatureValidationData);
for (TimestampToken timestampToken : signature.getAllTimestamps()) {
ValidationData timestampValidationData = validationContext.getValidationData(timestampToken);
validationDataContainer.addValidationData(timestampToken, timestampValidationData);
}
for (AdvancedSignature counterSignature : signature.getCounterSignatures()) {
ValidationData counterSignatureValidationData = validationContext.getValidationData(counterSignature);
validationDataContainer.addValidationData(counterSignature, counterSignatureValidationData);
}
}
for (TimestampToken detachedTimestamp : detachedTimestamps) {
ValidationData timestampValidationData = validationContext.getValidationData(detachedTimestamp);
validationDataContainer.addValidationData(detachedTimestamp, timestampValidationData);
}
return validationDataContainer;
}
/**
* Creates a new instance of {@code ValidationDataContainer}
*
* @return {@link ValidationDataContainer}
*/
protected ValidationDataContainer instantiateValidationDataContainer() {
return new ValidationDataContainer();
}
private void assertSignaturesValid(Collection signatures,
ValidationContext validationContext) {
validationContext.checkAllTimestampsValid();
validationContext.checkAllRequiredRevocationDataPresent();
validationContext.checkAllPOECoveredByRevocationData();
for (final AdvancedSignature signature : signatures) {
validationContext.checkSignatureNotExpired(signature);
validationContext.checkCertificatesNotRevoked(signature);
validationContext.checkAtLeastOneRevocationDataPresentAfterBestSignatureTime(signature);
}
}
/**
* Creates and fills the {@code DiagnosticDataBuilder} with a relevant data
*
* @param validationContext {@link ValidationContext} used for the validation
* @param signatures a list of {@link AdvancedSignature}s to be validated
* @return filled {@link DiagnosticDataBuilder}
* @deprecated since DSS 5.13. Use {@code #createDiagnosticDataBuilder(validationContext, signatures, evidenceRecords)}
*/
@Deprecated
protected DiagnosticDataBuilder createDiagnosticDataBuilder(final ValidationContext validationContext,
final List signatures) {
return createDiagnosticDataBuilder(validationContext, signatures, Collections.emptyList());
}
/**
* Creates and fills the {@code DiagnosticDataBuilder} with a relevant data
*
* @param validationContext {@link ValidationContext} used for the validation
* @param signatures a list of {@link AdvancedSignature}s to be validated
* @param detachedEvidenceRecords a list of detached {@link EvidenceRecord}s to be validated
* @return filled {@link DiagnosticDataBuilder}
*/
protected DiagnosticDataBuilder createDiagnosticDataBuilder(final ValidationContext validationContext,
final List signatures,
final List detachedEvidenceRecords) {
return initializeDiagnosticDataBuilder().document(document)
.foundSignatures(signatures)
.usedTimestamps(validationContext.getProcessedTimestamps())
.foundEvidenceRecords(getAllEvidenceRecords(signatures, detachedEvidenceRecords))
.allCertificateSources(validationContext.getAllCertificateSources())
.documentCertificateSource(validationContext.getDocumentCertificateSource())
.documentCRLSource(validationContext.getDocumentCRLSource())
.documentOCSPSource(validationContext.getDocumentOCSPSource())
.signaturePolicyProvider(getSignaturePolicyProvider())
.signaturePolicyValidatorLoader(getSignaturePolicyValidatorLoader())
.usedCertificates(validationContext.getProcessedCertificates())
.usedRevocations(validationContext.getProcessedRevocations())
.defaultDigestAlgorithm(certificateVerifier.getDefaultDigestAlgorithm())
.tokenExtractionStrategy(tokenExtractionStrategy)
.tokenIdentifierProvider(tokenIdentifierProvider)
.validationDate(getValidationTime());
}
private List getAllEvidenceRecords(final List signatures,
final List detachedEvidenceRecords) {
List result = new ArrayList<>();
for (AdvancedSignature signature : signatures) {
result.addAll(signature.getEmbeddedEvidenceRecords());
}
result.addAll(detachedEvidenceRecords);
return result;
}
/**
* Prepares the {@code validationContext} for signature validation process
*
* @param
* {@link AdvancedSignature} implementation
* @param validationContext
* {@link ValidationContext}
* @param allSignatures
* a collection of all {@link AdvancedSignature}s to be
* validated
*/
protected void prepareSignatureValidationContext(
final ValidationContext validationContext, final Collection allSignatures) {
prepareSignatureForVerification(validationContext, allSignatures);
processSignaturesValidation(allSignatures);
}
/**
* This method prepares a {@code SignatureValidationContext} for signatures validation
*
* @param
* {@link AdvancedSignature} implementation
* @param allSignatureList {@code Collection} of {@code AdvancedSignature}s to
* validate including the countersignatures
* @param validationContext {@code ValidationContext} is the implementation of
* the validators for: certificates, timestamps and
* revocation data.
*/
protected void prepareSignatureForVerification(
final ValidationContext validationContext, final Collection allSignatureList) {
for (final AdvancedSignature signature : allSignatureList) {
validationContext.addSignatureForVerification(signature);
}
}
/**
* Prepares the {@code validationContext} for a timestamp validation process
*
* @param validationContext
* {@link ValidationContext}
* @param timestamps
* a collection of detached timestamps
*/
protected void prepareDetachedTimestampValidationContext(
final ValidationContext validationContext, Collection timestamps) {
for (TimestampToken timestampToken : timestamps) {
validationContext.addTimestampTokenForVerification(timestampToken);
}
}
/**
* Prepares the {@code validationContext} for the evidence record validation process
*
* @param validationContext
* {@link ValidationContext}
* @param evidenceRecords
* a collection of detached evidence records
*/
protected void prepareDetachedEvidenceRecordValidationContext(
final ValidationContext validationContext, Collection evidenceRecords) {
for (EvidenceRecord evidenceRecord : evidenceRecords) {
validationContext.addEvidenceRecordForVerification(evidenceRecord);
}
}
/**
* Process the validation
*
* @param validationContext {@link ValidationContext} to process
*/
protected void validateContext(final ValidationContext validationContext) {
validationContext.validate();
}
@Override
public void setSignaturePolicyProvider(SignaturePolicyProvider signaturePolicyProvider) {
this.signaturePolicyProvider = signaturePolicyProvider;
}
/**
* Returns a signaturePolicyProvider If not defined, returns a default provider
*
* @return {@link SignaturePolicyProvider}
*/
protected SignaturePolicyProvider getSignaturePolicyProvider() {
if (signaturePolicyProvider == null) {
LOG.info("Default SignaturePolicyProvider instantiated with NativeHTTPDataLoader.");
signaturePolicyProvider = new SignaturePolicyProvider();
signaturePolicyProvider.setDataLoader(new NativeHTTPDataLoader());
}
return signaturePolicyProvider;
}
/**
* Returns an instance of a corresponding to the format {@code SignaturePolicyValidatorLoader}
*
* @return {@link SignaturePolicyValidatorLoader}
*/
public SignaturePolicyValidatorLoader getSignaturePolicyValidatorLoader() {
return new DefaultSignaturePolicyValidatorLoader();
}
@Override
public void setProcessExecutor(final DocumentProcessExecutor processExecutor) {
this.processExecutor = processExecutor;
}
/**
* This method returns the process executor. If the instance of this class is
* not yet instantiated then the new instance is created.
*
* @return {@code SignatureProcessExecutor}
*/
protected DocumentProcessExecutor provideProcessExecutorInstance() {
if (processExecutor == null) {
processExecutor = getDefaultProcessExecutor();
}
return processExecutor;
}
@Override
public DocumentProcessExecutor getDefaultProcessExecutor() {
return new DefaultSignatureProcessExecutor();
}
/**
* Executes the validation regarding the given {@code validationPolicy}
*
* @param diagnosticData {@link DiagnosticData} contained a data to be
* validated
* @param validationPolicy {@link ValidationPolicy}
* @return validation {@link Reports}
*/
protected final Reports processValidationPolicy(XmlDiagnosticData diagnosticData, ValidationPolicy validationPolicy) {
final DocumentProcessExecutor executor = provideProcessExecutorInstance();
executor.setValidationPolicy(validationPolicy);
executor.setValidationLevel(validationLevel);
executor.setDiagnosticData(diagnosticData);
executor.setIncludeSemantics(includeSemantics);
executor.setEnableEtsiValidationReport(enableEtsiValidationReport);
executor.setLocale(locale);
executor.setCurrentTime(getValidationTime());
return executor.execute();
}
/**
* Returns a list of all signatures from the validating document
*
* @return a list of {@link AdvancedSignature}s
*/
protected List getAllSignatures() {
final List allSignatureList = new ArrayList<>();
for (final AdvancedSignature signature : getSignatures()) {
allSignatureList.add(signature);
appendCounterSignatures(allSignatureList, signature);
}
appendExternalEvidenceRecords(allSignatureList);
return allSignatureList;
}
/**
* The util method to link counter signatures with the related master signatures
*
* @param allSignatureList a list of {@link AdvancedSignature}s
* @param signature current {@link AdvancedSignature}
*/
protected void appendCounterSignatures(final List allSignatureList,
final AdvancedSignature signature) {
for (AdvancedSignature counterSignature : signature.getCounterSignatures()) {
counterSignature.prepareOfflineCertificateVerifier(certificateVerifier);
allSignatureList.add(counterSignature);
appendCounterSignatures(allSignatureList, counterSignature);
}
}
/**
* Appends detached evidence record provided to the validator to
* the corresponding signatures covering by the evidence record document
*
* @param allSignatureList a list of {@link AdvancedSignature}s
*/
protected void appendExternalEvidenceRecords(List allSignatureList) {
List detachedEvidenceRecords = getDetachedEvidenceRecords();
if (Utils.isCollectionNotEmpty(detachedEvidenceRecords) && Utils.isCollectionNotEmpty(allSignatureList)) {
for (AdvancedSignature signature : allSignatureList) {
for (EvidenceRecord evidenceRecord : detachedEvidenceRecords) {
if (coversSignature(signature, evidenceRecord)) {
signature.addExternalEvidenceRecord(evidenceRecord);
}
}
}
}
}
/**
* Verifies whether an {@code evidenceRecord} covers the {@code signature}
*
* @param signature {@link AdvancedSignature}
* @param evidenceRecord {@link EvidenceRecord}
* @return TRUE if the evidence record covers the signature file, FALSE otherwise
*/
protected boolean coversSignature(AdvancedSignature signature, EvidenceRecord evidenceRecord) {
// return true by default
return true;
}
@Override
public List getSignatures() {
if (signatures == null) {
signatures = buildSignatures();
}
// delegated in CommonSignatureValidator
return signatures;
}
/**
* This method build a list of signatures to be extracted from a document
*
* @return a list of {@link AdvancedSignature}s
*/
protected List buildSignatures() {
// not implemented by default
return Collections.emptyList();
}
@Override
public List getDetachedTimestamps() {
if (detachedTimestamps == null) {
detachedTimestamps = buildDetachedTimestamps();
}
return detachedTimestamps;
}
/**
* Builds a list of detached {@code TimestampToken}s extracted from the document
*
* @return a list of {@code TimestampToken}s
*/
protected List buildDetachedTimestamps() {
return Collections.emptyList();
}
@Override
public List getDetachedEvidenceRecords() {
if (evidenceRecords == null) {
evidenceRecords = buildDetachedEvidenceRecords();
}
return evidenceRecords;
}
/**
* Builds a list of detached {@code EvidenceRecord}s extracted from the document
*
* @return a list of {@code EvidenceRecord}s
*/
protected List buildDetachedEvidenceRecords() {
if (Utils.isCollectionNotEmpty(detachedEvidenceRecordDocuments)) {
List result = new ArrayList<>();
for (DSSDocument evidenceRecordDocument : detachedEvidenceRecordDocuments) {
EvidenceRecord evidenceRecord = buildEvidenceRecord(evidenceRecordDocument);
if (evidenceRecord != null) {
result.add(evidenceRecord);
}
}
return result;
}
return Collections.emptyList();
}
/**
* Builds an evidence record from the given {@code DSSDocument}
*
* @param evidenceRecordDocument {@link DSSDocument} containing an evidence record
* @return {@link EvidenceRecord}
*/
protected EvidenceRecord buildEvidenceRecord(DSSDocument evidenceRecordDocument) {
try {
try {
EvidenceRecordValidator evidenceRecordValidator = EvidenceRecordValidator.fromDocument(evidenceRecordDocument);
evidenceRecordValidator.setDetachedContents(getSignatureEvidenceRecordDetachedContents());
evidenceRecordValidator.setCertificateVerifier(certificateVerifier);
return getEvidenceRecord(evidenceRecordValidator);
} catch (UnsupportedOperationException e) {
LOG.warn("An error occurred on attempt to read an evidence record document with name '{}' : {}" +
"Please ensure the corresponding module is loaded.", evidenceRecordDocument.getName(), e.getMessage());
}
} catch (Exception e) {
LOG.warn("An error occurred on attempt to read an evidence record document with name '{}' : {}",
evidenceRecordDocument.getName(), e.getMessage(), e);
}
return null;
}
private List getSignatureEvidenceRecordDetachedContents() {
List erDetachedContents = new ArrayList<>();
erDetachedContents.add(document);
if (Utils.isCollectionNotEmpty(detachedContents)) {
erDetachedContents.addAll(detachedContents);
}
return erDetachedContents;
}
/**
* Gets an evidence record from a {@code evidenceRecordValidator}
*
* @param evidenceRecordValidator {@link EvidenceRecordValidator}
* @return {@link EvidenceRecord}
*/
protected EvidenceRecord getEvidenceRecord(EvidenceRecordValidator evidenceRecordValidator) {
EvidenceRecord evidenceRecord = evidenceRecordValidator.getEvidenceRecord();
if (evidenceRecord != null) {
List evidenceRecordScopes = getEvidenceRecordScopes(evidenceRecord);
evidenceRecord.setEvidenceRecordScopes(evidenceRecordScopes);
evidenceRecord.setTimestampedReferences(getTimestampedReferences(evidenceRecordScopes));
return evidenceRecord;
}
return null;
}
/**
* Finds evidence record scopes
*
* @param evidenceRecord {@link EvidenceRecord}
* @return a list of {@link SignatureScope}s
*/
protected List getEvidenceRecordScopes(EvidenceRecord evidenceRecord) {
return new EvidenceRecordScopeFinder(evidenceRecord).findEvidenceRecordScope();
}
@Override
public void processSignaturesValidation(Collection allSignatureList) {
for (final AdvancedSignature signature : allSignatureList) {
signature.checkSignatureIntegrity();
}
}
@Deprecated
@Override
public void findSignatureScopes(Collection currentValidatorSignatures) {
LOG.warn("Use of deprecated method! Use eu.europa.esig.dss.validation.AdvancedSignature.getSignatureScopes() method instead.");
}
/**
* Returns a list of timestamped references from the given list of {@code SignatureScope}s
*
* @param signatureScopes a list of {@link SignatureScope}s
* @return a list of {@link TimestampedReference}s
*/
protected List getTimestampedReferences(List signatureScopes) {
List timestampedReferences = new ArrayList<>();
if (Utils.isCollectionNotEmpty(signatureScopes)) {
for (SignatureScope signatureScope : signatureScopes) {
if (addReference(signatureScope)) {
timestampedReferences.add(new TimestampedReference(
signatureScope.getDSSIdAsString(), TimestampedObjectType.SIGNED_DATA));
}
}
}
return timestampedReferences;
}
/**
* Checks if the signature scope shall be added as a timestamped reference
* NOTE: used to avoid duplicates in ASiC with CAdES validator, due to covered signature/timestamp files
*
* @param signatureScope {@link SignatureScope} to check
* @return TRUE if the timestamped reference shall be created for the given {@link SignatureScope}, FALSE otherwise
*/
protected boolean addReference(SignatureScope signatureScope) {
// accept all by default
return true;
}
/**
* Sets if the validation context execution shall be skipped
* (skips certificate chain building, revocation requests, ...)
*
* @param skipValidationContextExecution if the context validation shall be skipped
*/
public void setSkipValidationContextExecution(boolean skipValidationContextExecution) {
this.skipValidationContextExecution = skipValidationContextExecution;
}
/**
* Sets Locale for report messages generation
*
* @param locale {@link Locale}
*/
public void setLocale(Locale locale) {
this.locale = locale;
}
@Override
public List getOriginalDocuments(String signatureId) {
AdvancedSignature advancedSignature = getSignatureById(signatureId);
if (advancedSignature != null) {
return getOriginalDocuments(advancedSignature);
}
return Collections.emptyList();
}
/**
* Returns the signature with the given id. Processes custom {@code TokenIdentifierProvider} and counter signatures
*
* @param signatureId {@link String} id of a signature to be extracted
* @return {@link AdvancedSignature} with the given id if found, NULL otherwise
*/
public AdvancedSignature getSignatureById(String signatureId) {
Objects.requireNonNull(signatureId, "Signature Id cannot be null!");
for (AdvancedSignature advancedSignature : getSignatures()) {
AdvancedSignature signature = findSignatureRecursively(advancedSignature, signatureId);
if (signature != null) {
return signature;
}
}
return null;
}
private AdvancedSignature findSignatureRecursively(AdvancedSignature signature, String signatureId) {
if (doesIdMatch(signature, signatureId)) {
return signature;
}
for (AdvancedSignature counterSignature : signature.getCounterSignatures()) {
AdvancedSignature advancedSignature = findSignatureRecursively(counterSignature, signatureId);
if (advancedSignature != null) {
return advancedSignature;
}
}
return null;
}
private boolean doesIdMatch(AdvancedSignature signature, String signatureId) {
return signatureId.equals(signature.getId()) || signatureId.equals(signature.getDAIdentifier()) ||
signatureId.equals(tokenIdentifierProvider.getIdAsString(signature));
}
}