/* * 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.DSSUtils; 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.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.xades.XPathQueryHolder; 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_ICS_AIDNASNE; import static eu.europa.ec.markt.dss.validation102853.rules.MessageTag.BBB_ICS_AIDNASNE_ANS; import static eu.europa.ec.markt.dss.validation102853.rules.MessageTag.BBB_ICS_ICDVV; import static eu.europa.ec.markt.dss.validation102853.rules.MessageTag.BBB_ICS_ICDVV_ANS; import static eu.europa.ec.markt.dss.validation102853.rules.MessageTag.BBB_ICS_ISACDP; import static eu.europa.ec.markt.dss.validation102853.rules.MessageTag.BBB_ICS_ISACDP_ANS; import static eu.europa.ec.markt.dss.validation102853.rules.MessageTag.BBB_ICS_ISASCP; import static eu.europa.ec.markt.dss.validation102853.rules.MessageTag.BBB_ICS_ISASCP_ANS; import static eu.europa.ec.markt.dss.validation102853.rules.MessageTag.BBB_ICS_ISCI; import static eu.europa.ec.markt.dss.validation102853.rules.MessageTag.BBB_ICS_ISCI_ANS; import static eu.europa.ec.markt.dss.validation102853.rules.MessageTag.BBB_ICS_ISCS; import static eu.europa.ec.markt.dss.validation102853.rules.MessageTag.BBB_ICS_ISCS_ANS; /** * 5.1 Identification of the Signer's Certificate (ISC) * <p/> * 5.1.1 Description * This process consists in identifying the signer's certificate that will be used to validate the signature. * 5.1.2 Inputs * Table 3: Inputs to the ISC process * - Input Requirement * - Signature Mandatory * - Signer's Certificate Optional * 5.1.3 Outputs * • In case of success, i.e. the signer's certificate can be identified, the output shall be the signer's certificate. * • In case of failure, i.e. the signer's certificate cannot be identified, the output shall be the indication INDETERMINATE and the sub indication NO_SIGNER_CERTIFICATE_FOUND. * NOTE: If the signature is compliant with the CD 2011/130/EU, this process will never return INDETERMINATE, since the signer's certificate is present in the signature. * <p/> * DISCLAIMER: Project owner DG-MARKT. * * @author <a href="mailto:dgmarkt.Project-DSS@arhs-developments.com">ARHS Developments</a> * @version $Revision: 1016 $ - $Date: 2011-06-17 15:30:45 +0200 (Fri, 17 Jun 2011) $ */ public class IdentificationOfTheSignersCertificate implements Indication, SubIndication, NodeName, NodeValue, AttributeName, AttributeValue, ExceptionMessage { /** * The following variables are used only in order to simplify the writing of the rules! */ private ProcessParameters params = null; /** * See {@link ProcessParameters#getDiagnosticData()} */ private XmlDom diagnosticData; /** * // TODO: (Bob: 2014 Mar 12) */ private String contextName; /** * See {@link ProcessParameters#getContextElement()} */ private XmlDom contextElement; /** * This node is used to add the constraint nodes. */ private XmlNode validationDataXmlNode; private void prepareParameters() { this.diagnosticData = params.getDiagnosticData(); this.contextElement = params.getContextElement(); isInitialised(); } private void isInitialised() { if (params.getCurrentValidationPolicy() == null) { throw new DSSException(String.format(EXCEPTION_TCOPPNTBI, getClass().getSimpleName(), "validationPolicy")); } if (diagnosticData == null) { throw new DSSException(String.format(EXCEPTION_TCOPPNTBI, getClass().getSimpleName(), "diagnosticData")); } if (contextElement == null) { throw new DSSException(String.format(EXCEPTION_TCOPPNTBI, getClass().getSimpleName(), "contextElement")); } } /** * This method prepares the execution of the ISC process. * * @param params validation process parameters * @return the {@code Conclusion} which indicates the result of the process */ public Conclusion run(final ProcessParameters params, final String contextName) { this.params = params; this.contextName = contextName; prepareParameters(); /** * 5.1 Identification of the signer's certificate (ISC) */ validationDataXmlNode = new XmlNode(ISC); validationDataXmlNode.setNameSpace(XmlDom.NAMESPACE); final Conclusion conclusion = process(params); conclusion.setValidationData(validationDataXmlNode); return conclusion; } /** * This method implements ISC process. * <p/> * 5.1.4 Processing * The common way to unambiguously identify the signer's certificate is by using a property/attribute of the signature * containing a reference to it, which includes the digest computed over the certificates encoded value. The certificate or a * reference to the certificate can either be found in the signature or it can be obtained using external sources. The signer's * certificate may also be provided by the DA. If the certificate cannot be retrieved, the indication INDETERMINATE will * be the result. * Clauses 5.1.4.1 to 5.1.4.3 provide specific processing details for each AdES signature type (i.e. XAdES, CAdES or * PAdES), once the certificate has been retrieved. * * @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(); // The signing certificate Id and the signing certificate are reset. params.setSigningCertificateId(null); params.setSigningCertificate(null); final String signingCertificateId = contextElement.getValue("./SigningCertificate/@Id"); final XmlDom signingCertificateXmlDom = params.getCertificate(signingCertificateId); final boolean signingCertificateRecognised = signingCertificateXmlDom != null; if (!checkRecognitionConstraint(conclusion, signingCertificateRecognised, signingCertificateId)) { return conclusion; } /** * The signing certificate Id and the signing certificate are saved for further use. */ params.setSigningCertificateId(signingCertificateId); params.setSigningCertificate(signingCertificateXmlDom); Constraint constraint = null; final String signedElement = contextElement.getValue("./SigningCertificate/Signed/text()"); if (DSSUtils.isNotEmpty(signedElement)) { constraint = params.getCurrentValidationPolicy().getSigningCertificateSignedConstraint(contextName); if (constraint != null) { if (!checkSignedSigningCertificateConstraint(constraint, conclusion, signedElement)) { return conclusion; } } } if (constraint == null) { if (!checkSigningCertificateAttributePresentConstraint(conclusion)) { return conclusion; } if (!checkDigestValuePresentConstraint(conclusion)) { return conclusion; } if (!checkDigestValueMatchConstraint(conclusion)) { return conclusion; } if (!checkIssuerSerialMatchConstraint(conclusion)) { return conclusion; } } // This validation process returns VALID conclusion.setIndication(VALID); return conclusion; } /** * @param conclusion the conclusion to use to add the result of the check. * @param signingCertificateRecognised indicates if the signing certificate was recognised. * @param signingCertificateId * @return false if the check failed and the process should stop, true otherwise. */ private boolean checkRecognitionConstraint(final Conclusion conclusion, final boolean signingCertificateRecognised, String signingCertificateId) { final Constraint constraint = params.getCurrentValidationPolicy().getSigningCertificateRecognitionConstraint(contextName); if (constraint == null) { return true; } constraint.create(validationDataXmlNode, BBB_ICS_ISCI); constraint.setValue(signingCertificateRecognised); if (DSSUtils.isNotBlank(signingCertificateId) && !signingCertificateId.equals("0")) { constraint.setAttribute(CERTIFICATE_ID, signingCertificateId); } constraint.setIndications(INDETERMINATE, NO_SIGNER_CERTIFICATE_FOUND, BBB_ICS_ISCI_ANS); constraint.setConclusionReceiver(conclusion); return constraint.check(); } private boolean checkSignedSigningCertificateConstraint(final Constraint constraint, final Conclusion conclusion, final String signedElement) { constraint.create(validationDataXmlNode, BBB_ICS_ISCS); final boolean signed = XPathQueryHolder.XMLE_X509CERTIFICATE.equals(signedElement) || XPathQueryHolder.XMLE_X509DATA.equals(signedElement) || XPathQueryHolder.XMLE_KEYINFO .equals(signedElement); constraint.setValue(signed); constraint.setIndications(INVALID, FORMAT_FAILURE, BBB_ICS_ISCS_ANS); constraint.setConclusionReceiver(conclusion); return constraint.check(); } private boolean checkSigningCertificateAttributePresentConstraint(final Conclusion conclusion) { final Constraint constraint = params.getCurrentValidationPolicy().getSigningCertificateAttributePresentConstraint(contextName); if (constraint == null) { return true; } constraint.create(validationDataXmlNode, BBB_ICS_ISASCP); final boolean digestValueMatch = contextElement.getBoolValue("./SigningCertificate/AttributePresent/text()"); constraint.setValue(digestValueMatch); constraint.setIndications(INVALID, FORMAT_FAILURE, BBB_ICS_ISASCP_ANS); constraint.setConclusionReceiver(conclusion); return constraint.check(); } /** * This method checks if the digest value of the signing certificate is within the signature * * @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 checkDigestValuePresentConstraint(final Conclusion conclusion) { final Constraint constraint = params.getCurrentValidationPolicy().getSigningCertificateDigestValuePresentConstraint(contextName); if (constraint == null) { return true; } constraint.create(validationDataXmlNode, BBB_ICS_ISACDP); final boolean digestValueMatch = contextElement.getBoolValue("./SigningCertificate/DigestValuePresent/text()"); constraint.setValue(digestValueMatch); constraint.setIndications(INVALID, FORMAT_FAILURE, BBB_ICS_ISACDP_ANS); constraint.setConclusionReceiver(conclusion); return constraint.check(); } /** * 5.1.4.1 XAdES processing / 5.1.4.2 CAdES processing / 5.1.4.3 PAdES processing<br/> * <br/> * For XAdES:<br/> * The signing certificate shall be checked against all references present in the ds:SigningCertificate property, * if present, since one of these references shall be a reference to the signing certificate [1]. The following * steps shall be performed:<br/> * <br/> * 1) Take the first child of the property and check that the content of ds:DigestValue matches the result of * digesting the signing certificate with the algorithm indicated in ds:DigestMethod. If they do not match, take * the next child and repeat this step until a matching child element has been found or all children of the * element have been checked. If they do match, continue with step 2. If the last element is reached without * finding any match, the validation of this property shall be taken as failed and INVALID/FORMAT_FAILURE is * returned.<br/> * <br/> * For CAdES:<br/> * The signing certificate shall be checked against the references present in one of the following attributes: * ESS-signing-certificate, ESS-signing-certificate-v2 or Other-signing-certificate, since one of these attributes shall * contain a reference to the signing certificate. For doing this, the following tasks shall be performed: * 1) Take the first element of the attribute and check that the content of the field containing the digest value * matches the result of digesting the signing certificate with the algorithm implicitly or explicitly indicated in the * reference attribute. If they match, continue with step 2. Otherwise the validation of this attribute shall be taken * as failed and INVALID/FORMAT_FAILURE is returned.<br/> * <br/> * For PAdES:<br/> * The signing certificate shall be checked against the references present in one of the following attributes: * ESS-signing-certificate or ESS-signing-certificate-v2, since one of these attributes shall contain a reference to the * signing certificate. For doing this, follow the same steps as for CAdES (see clause 5.1.4.2). * * @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 checkDigestValueMatchConstraint(final Conclusion conclusion) { final Constraint constraint = params.getCurrentValidationPolicy().getSigningCertificateDigestValueMatchConstraint(contextName); if (constraint == null) { return true; } constraint.create(validationDataXmlNode, BBB_ICS_ICDVV); final boolean digestValueMatch = contextElement.getBoolValue("./SigningCertificate/DigestValueMatch/text()"); constraint.setValue(digestValueMatch); constraint.setIndications(INVALID, FORMAT_FAILURE, BBB_ICS_ICDVV_ANS); constraint.setConclusionReceiver(conclusion); return constraint.check(); } /** * 5.1.4.1 XAdES processing / 5.1.4.2 CAdES processing / 5.1.4.3 PAdES processing<br/> * ...<p/> * For XAdES:<br/> * 2) If the ds:KeyInfo contains the ds:X509IssuerSerial element, check that the issuer and the serial * number indicated in that element and IssuerSerial from SigningCertificate are the same. If they do * not match, the validation of this property shall be taken as failed and INDETERMINATE is returned.<br/> * <p/> * For CAdES:<br/> * 2) Compare the details of the issuer's name and the serial number of the certificate with those indicated in the * reference. If any of them does not match, the validation of this attribute shall be taken as failed and * INDETERMINATE is returned.<br/> * <p/> * For PAdES:<br/> * The signing certificate shall be checked against the references present in one of the following attributes: * ESS-signing-certificate or ESS-signing-certificate-v2, since one of these attributes shall contain a reference to the * signing certificate. For doing this, follow the same steps as for CAdES (see clause 5.1.4.2). * * @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 checkIssuerSerialMatchConstraint(final Conclusion conclusion) { final Constraint constraint = params.getCurrentValidationPolicy().getSigningCertificateIssuerSerialMatchConstraint(contextName); if (constraint == null) { return true; } constraint.create(validationDataXmlNode, BBB_ICS_AIDNASNE); final boolean issuerSerialMatch = contextElement.getBoolValue("./SigningCertificate/IssuerSerialMatch/text()"); constraint.setValue(issuerSerialMatch); constraint.setIndications(INDETERMINATE, NO_SIGNER_CERTIFICATE_FOUND, BBB_ICS_AIDNASNE_ANS); constraint.setConclusionReceiver(conclusion); return constraint.check(); } }