/*
* DSS - Digital Signature Services
*
* Copyright (C) 2013 European Commission, Directorate-General Internal Market and Services (DG MARKT), B-1049 Bruxelles/Brussel
*
* Developed by: 2013 ARHS Developments S.A. (rue Nicolas Bové 2B, L-1253 Luxembourg) http://www.arhs-developments.com
*
* This file is part of the "DSS - Digital Signature Services" project.
*
* "DSS - Digital Signature Services" 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.
*
* DSS 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
* "DSS - Digital Signature Services". If not, see <http://www.gnu.org/licenses/>.
*/
package eu.europa.ec.markt.dss.validation102853.processes.subprocesses;
import eu.europa.ec.markt.dss.exception.DSSException;
import eu.europa.ec.markt.dss.validation102853.policy.Constraint;
import eu.europa.ec.markt.dss.validation102853.policy.ProcessParameters;
import eu.europa.ec.markt.dss.validation102853.policy.ValidationPolicy;
import eu.europa.ec.markt.dss.validation102853.processes.ValidationXPathQueryHolder;
import eu.europa.ec.markt.dss.validation102853.report.Conclusion;
import eu.europa.ec.markt.dss.validation102853.rules.AttributeName;
import eu.europa.ec.markt.dss.validation102853.rules.AttributeValue;
import eu.europa.ec.markt.dss.validation102853.rules.ExceptionMessage;
import eu.europa.ec.markt.dss.validation102853.rules.Indication;
import eu.europa.ec.markt.dss.validation102853.rules.NodeName;
import eu.europa.ec.markt.dss.validation102853.rules.NodeValue;
import eu.europa.ec.markt.dss.validation102853.rules.SubIndication;
import eu.europa.ec.markt.dss.validation102853.xml.XmlDom;
import eu.europa.ec.markt.dss.validation102853.xml.XmlNode;
import static eu.europa.ec.markt.dss.validation102853.rules.MessageTag.BBB_CV_IRDOF;
import static eu.europa.ec.markt.dss.validation102853.rules.MessageTag.BBB_CV_IRDOF_ANS;
import static eu.europa.ec.markt.dss.validation102853.rules.MessageTag.BBB_CV_IRDOI;
import static eu.europa.ec.markt.dss.validation102853.rules.MessageTag.BBB_CV_IRDOI_ANS;
import static eu.europa.ec.markt.dss.validation102853.rules.MessageTag.BBB_CV_ISI;
import static eu.europa.ec.markt.dss.validation102853.rules.MessageTag.BBB_CV_ISI_ANS;
/**
* This class executes the cryptographic signature verification. It can be for the document signatures or timestamp
* signatures...
* <p/>
* 5.4 Cryptographic Verification (CV)<br/>
* <br/>
* 5.4.1 Description<br/>
* This process consists in verifying the integrity of the signed data by performing the cryptographic verifications.<br/>
* 5.4.2 Inputs<br/>
* Table 8: Inputs to the CV process<br/>
* - Input Requirement<br/>
* - Signature Mandatory<br/>
* - Signer Certificate Mandatory<br/>
* - Validated certificate chain Optional<br/>
* - Signed data object(s) Optional<br/>
* NOTE: In most cases, the cryptographic verification requires only the signer's certificate and not the entire validated chain. However, for some algorithms the full chain may
* be required (e.g. the case of DSS/DSA public keys which inherit their parameters from the issuer certificate).<br/>
* 5.4.3 Outputs<br/>
* The process outputs one of the following indications together with the associated validation report data:<br/>
* Table 9: Outputs of the CV process<br/>
* - Indication: VALID<br/>
* - Description: The signature passed the cryptographic verification.<br/>
* - Additional data items:<br/>
* <br/>
* - Indication: INVALID HASH_FAILURE<br/>
* - Description: The hash of at least one of the signed data items does not match the corresponding hash value in the signature.<br/>
* - Additional data items: The process should output:<br/>
* - • The identifier (s) (e.g. an URI) of the signed data that caused the failure.<br/>
* <br/>
* - Indication: INVALID SIG_CRYPTO_FAILURE<br/>
* - Description: The cryptographic verification of the signature value failed.<br/>
* <br/>
* - Indication: INDETERMINATE SIGNED_DATA_NOT_FOUND<br/>
* - Description: Cannot obtain signed data.<br/>
* - Additional data items: The process should output:<br/>
* - • The identifier (s) (e.g. an URI) of the signed data that caused the failure.<br/>
*
* @author bielecro
*/
public class CryptographicVerification implements Indication, SubIndication, NodeName, NodeValue, AttributeName, AttributeValue, ExceptionMessage, ValidationXPathQueryHolder {
/**
* See {@link ProcessParameters#getCurrentValidationPolicy()}
*/
private ValidationPolicy constraintData;
private XmlDom contextElement;
/**
* This node is used to add the constraint nodes.
*/
private XmlNode subProcessNode;
private void prepareParameters(final ProcessParameters params) {
this.constraintData = params.getCurrentValidationPolicy();
this.contextElement = params.getContextElement();
isInitialised();
}
private void isInitialised() {
if (constraintData == null) {
throw new DSSException(String.format(EXCEPTION_TCOPPNTBI, getClass().getSimpleName(), "validationPolicy"));
}
if (contextElement == null) {
throw new DSSException(String.format(EXCEPTION_TCOPPNTBI, getClass().getSimpleName(), "signature"));
}
}
/**
* 5.4.4 Processing<br>
* The first and second steps as well as the Data To Be Signed depend on the signature type. The technical details on
* how to do this correctly are out of scope for the present document. See [10], [16], [12], [13], [14] and [15] for
* details:
*
* @param params validation process parameters
* @param processNode the parent process {@code XmlNode} to use to include the validation information
* @return the {@code Conclusion} which indicates the result of the process
*/
public Conclusion run(final ProcessParameters params, final XmlNode processNode) {
if (processNode == null) {
throw new DSSException(String.format(EXCEPTION_TCOPPNTBI, getClass().getSimpleName(), "processNode"));
}
prepareParameters(params);
subProcessNode = processNode.addChild(CV);
final Conclusion conclusion = process(params);
final XmlNode conclusionXmlNode = conclusion.toXmlNode();
subProcessNode.addChild(conclusionXmlNode);
return conclusion;
}
/**
* This method implement CV process.
*
* @param params validation process parameters
* @return the {@code Conclusion} which indicates the result of the process
*/
private Conclusion process(final ProcessParameters params) {
final Conclusion conclusion = new Conclusion();
if (!checkReferenceDataExistenceConstraint(conclusion)) {
return conclusion;
}
if (!checkReferenceDataIntactConstraint(conclusion)) {
return conclusion;
}
if (!checkSignatureIntactConstraint(conclusion)) {
return conclusion;
}
// This validation process returns VALID
conclusion.setIndication(VALID);
return conclusion;
}
/**
* 1) Obtain the signed data objects(s) if not provided in the inputs (e.g. by dereferencing an URI present in the
* signature). If the signed data object (s) cannot be obtained, abort with the indication
* INDETERMINATE/SIGNED_DATA_NOT_FOUND.
*
* @param conclusion the conclusion to use to add the result of the check.
* @return false if the check failed and the process should stop, true otherwise.
*/
private boolean checkReferenceDataExistenceConstraint(Conclusion conclusion) {
final Constraint constraint = constraintData.getReferenceDataExistenceConstraint();
if (constraint == null) {
return true;
}
constraint.create(subProcessNode, BBB_CV_IRDOF);
final boolean referenceDataFound = contextElement.getBoolValue(XP_REFERENCE_DATA_FOUND);
constraint.setValue(referenceDataFound);
constraint.setIndications(INDETERMINATE, SIGNED_DATA_NOT_FOUND, BBB_CV_IRDOF_ANS);
constraint.setConclusionReceiver(conclusion);
return constraint.check();
}
/**
* 2) Check the integrity of the signed data objects. In case of failure, abort the signature validation process
* with INVALID/HASH_FAILURE.
*
* @param conclusion the conclusion to use to add the result of the check.
* @return false if the check failed and the process should stop, true otherwise.
*/
private boolean checkReferenceDataIntactConstraint(Conclusion conclusion) {
final Constraint constraint = constraintData.getReferenceDataIntactConstraint();
if (constraint == null) {
return true;
}
constraint.create(subProcessNode, BBB_CV_IRDOI);
final boolean referenceDataIntact = contextElement.getBoolValue(XP_REFERENCE_DATA_INTACT);
constraint.setValue(referenceDataIntact);
constraint.setIndications(INVALID, HASH_FAILURE, BBB_CV_IRDOI_ANS);
constraint.setConclusionReceiver(conclusion);
return constraint.check();
}
/**
* 3) Verify the cryptographic signature using the public key extracted from the signer's certificate in the
* chain, the signature value and the signature algorithm extracted from the signature. If this cryptographic
* verification outputs a success indication, terminate with VALID. Otherwise, terminate with
* INVALID/SIG_CRYPTO_FAILURE.
*
* @param conclusion the conclusion to use to add the result of the check.
* @return false if the check failed and the process should stop, true otherwise.
*/
private boolean checkSignatureIntactConstraint(Conclusion conclusion) {
final Constraint constraint = constraintData.getSignatureIntactConstraint();
if (constraint == null) {
return true;
}
constraint.create(subProcessNode, BBB_CV_ISI);
final boolean signatureIntact = contextElement.getBoolValue(XP_SIGNATURE_INTACT);
constraint.setValue(signatureIntact);
constraint.setIndications(INVALID, SIG_CRYPTO_FAILURE, BBB_CV_ISI_ANS);
constraint.setConclusionReceiver(conclusion);
return constraint.check();
}
}