package eu.europa.esig.dss.validation.process.vpfswatsp.checks.pcv;
import java.util.Date;
import java.util.List;
import eu.europa.esig.dss.jaxb.detailedreport.XmlBasicBuildingBlocks;
import eu.europa.esig.dss.jaxb.detailedreport.XmlPCV;
import eu.europa.esig.dss.jaxb.detailedreport.XmlVTS;
import eu.europa.esig.dss.jaxb.diagnostic.XmlChainItem;
import eu.europa.esig.dss.utils.Utils;
import eu.europa.esig.dss.validation.policy.Context;
import eu.europa.esig.dss.validation.policy.SubContext;
import eu.europa.esig.dss.validation.policy.ValidationPolicy;
import eu.europa.esig.dss.validation.process.Chain;
import eu.europa.esig.dss.validation.process.ChainItem;
import eu.europa.esig.dss.validation.process.bbb.sav.checks.CryptographicCheck;
import eu.europa.esig.dss.validation.process.bbb.xcv.sub.checks.CertificateSignatureValidCheck;
import eu.europa.esig.dss.validation.process.vpfswatsp.POEExtraction;
import eu.europa.esig.dss.validation.process.vpfswatsp.checks.pcv.checks.ProspectiveCertificateChainCheck;
import eu.europa.esig.dss.validation.process.vpfswatsp.checks.pcv.checks.ValidationTimeSlidingCheck;
import eu.europa.esig.dss.validation.process.vpfswatsp.checks.vts.ValidationTimeSliding;
import eu.europa.esig.dss.validation.reports.wrapper.CertificateWrapper;
import eu.europa.esig.dss.validation.reports.wrapper.DiagnosticData;
import eu.europa.esig.dss.validation.reports.wrapper.TokenProxy;
import eu.europa.esig.jaxb.policy.CryptographicConstraint;
import eu.europa.esig.jaxb.policy.LevelConstraint;
public class PastCertificateValidation extends Chain<XmlPCV> {
private final TokenProxy token;
private final DiagnosticData diagnosticData;
private final XmlBasicBuildingBlocks bbb;
private final POEExtraction poe;
private final Date currentTime;
private final ValidationPolicy policy;
private final Context context;
private Date controlTime;
public PastCertificateValidation(TokenProxy token, DiagnosticData diagnosticData, XmlBasicBuildingBlocks bbb, POEExtraction poe, Date currentTime,
ValidationPolicy policy, Context context) {
super(new XmlPCV());
this.token = token;
this.diagnosticData = diagnosticData;
this.bbb = bbb;
this.poe = poe;
this.currentTime = currentTime;
this.policy = policy;
this.context = context;
}
@Override
protected void initChain() {
String signingCertificateId = token.getSigningCertificateId();
/*
* 9.2.1.4 Processing The following steps shall be performed: 1) Build a
* new prospective certificate chain that has not yet been evaluated.
* The chain shall satisfy the conditions of a prospective certificate
* chain as stated in [4], clause 6.1, using one of the trust anchors
* provided in the inputs: a) If no new chain can be built, abort the
* processing with the current status and the last chain built or, if no
* chain was built, with INDETERMINATE/NO_CERTIFICATE_CHAIN_FOUND. b)
* Otherwise, go to the next step.
*/
ChainItem<XmlPCV> item = firstItem = prospectiveCertificateChain();
/*
* 2) The building block shall run the Certification Path Validation of
* IETF RFC 5280 [1], clause 6.1, with the following inputs: the
* prospective chain built in the previous step, the trust anchor used
* in the previous step, the X.509 parameters provided in the inputs and
* a date from the intersection of the validity intervals of all the
* certificates in the prospective chain. The validation shall not
* include revocation checking for the signing certificate: a) If the
* certificate path validation returns PASSED, the building block shall
* go to the next step. b) If the certificate path validation returns a
* failure indication because an intermediate CA has been determined to
* be revoked, the building block shall set the current status to
* INDETERMINATE/REVOKED_CA_NO_POE and shall go to step 1. c) If the
* certificate path validation returns a failure indication with any
* other reason, the building block shall set the current status to
* INDETERMINATE/CERTIFICATE_CHAIN_GENERAL_FAILURE and shall go to step
* 1. Or d) If the certificate path validation returns any other failure
* indication, the building block shall go to step 1.
*
* ==> Simplified because DSS only uses one certificate chain
*/
Date intervalNotBefore = null;
Date intervalNotAfter = null;
List<XmlChainItem> certificateChain = token.getCertificateChain();
for (XmlChainItem certChainItem : certificateChain) {
CertificateWrapper certificate = diagnosticData.getUsedCertificateById(certChainItem.getId());
if (certificate.isTrusted()) {
// There is not need to check for the trusted certificate
continue;
}
SubContext subContext = SubContext.CA_CERTIFICATE;
if (Utils.areStringsEqual(signingCertificateId, certChainItem.getId())) {
subContext = SubContext.SIGNING_CERT;
}
if (intervalNotBefore == null || intervalNotBefore.before(certificate.getNotBefore())) {
intervalNotBefore = certificate.getNotBefore();
}
if (intervalNotAfter == null || intervalNotAfter.after(certificate.getNotAfter())) {
intervalNotAfter = certificate.getNotAfter();
}
if (SubContext.CA_CERTIFICATE.equals(subContext) && certificate.isRevoked()) {
Date caRevocationDate = certificate.getLatestRevocationData().getRevocationDate();
if (caRevocationDate != null && intervalNotAfter.after(caRevocationDate)) {
intervalNotAfter = caRevocationDate;
}
// TODO REVOKED_CA_NO_POE
}
item = item.setNextItem(certificateSignatureValid(certificate, subContext));
}
/*
* 3) The building block shall perform the validation time sliding
* process as per clause 5.6.2.2 with the following inputs: the
* prospective chain, the set of POEs and the cryptographic constraints.
* If it outputs a success indication, the building block shall go to
* the next step. Otherwise, the building block shall set the current
* status to the returned indication and sub-indication and shall go
* back to step 1.
*/
item = item.setNextItem(validationTimeSliding());
/*
* 4) The building block shall apply the chain constraints to the chain.
* If the chain does not match these constraints, the building block
* shall set the current status to FAILED/CHAIN_CONSTRAINTS_FAILURE and
* shall go to step 1.
*/
if (controlTime != null) {
certificateChain = token.getCertificateChain();
for (XmlChainItem certChainItem : certificateChain) {
CertificateWrapper certificate = diagnosticData.getUsedCertificateById(certChainItem.getId());
if (certificate.isTrusted()) {
// There is not need to check for the trusted certificate
continue;
}
SubContext subContext = SubContext.CA_CERTIFICATE;
if (Utils.areStringsEqual(signingCertificateId, certChainItem.getId())) {
subContext = SubContext.SIGNING_CERT;
}
item = item.setNextItem(cryptographicCheck(result, certificate, controlTime, subContext));
}
}
/*
* 5) The building block shall return the current status . If the
* current status is PASSED, the building block shall also return the
* certificate chain as well as the calculated validation time returned
* in step 3.
*/
}
private ChainItem<XmlPCV> prospectiveCertificateChain() {
LevelConstraint constraint = policy.getProspectiveCertificateChainConstraint(context);
return new ProspectiveCertificateChainCheck(result, token, diagnosticData, constraint);
}
private ChainItem<XmlPCV> certificateSignatureValid(CertificateWrapper certificate, SubContext subContext) {
LevelConstraint constraint = policy.getCertificateSignatureConstraint(context, subContext);
return new CertificateSignatureValidCheck<XmlPCV>(result, certificate, constraint);
}
private ChainItem<XmlPCV> validationTimeSliding() {
ValidationTimeSliding validationTimeSliding = new ValidationTimeSliding(diagnosticData, token, currentTime, context, poe, policy);
XmlVTS vts = validationTimeSliding.execute();
bbb.setVTS(vts);
controlTime = vts.getControlTime();
return new ValidationTimeSlidingCheck(result, vts, getFailLevelConstraint());
}
private ChainItem<XmlPCV> cryptographicCheck(XmlPCV result, CertificateWrapper certificate, Date validationTime, SubContext subContext) {
CryptographicConstraint constraint = policy.getCertificateCryptographicConstraint(context, subContext);
return new CryptographicCheck<XmlPCV>(result, certificate, validationTime, constraint);
}
@Override
protected void addAdditionalInfo() {
result.setControlTime(controlTime); // can be null
}
}