/* * 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.signature.xades; import java.util.List; import org.apache.xml.security.Init; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Element; import org.w3c.dom.Node; import eu.europa.ec.markt.dss.DSSUtils; import eu.europa.ec.markt.dss.DSSXMLUtils; import eu.europa.ec.markt.dss.DigestAlgorithm; import eu.europa.ec.markt.dss.exception.DSSException; import eu.europa.ec.markt.dss.exception.DSSNullException; import eu.europa.ec.markt.dss.parameter.SignatureParameters; import eu.europa.ec.markt.dss.signature.AbstractSignatureService; import eu.europa.ec.markt.dss.signature.DSSDocument; import eu.europa.ec.markt.dss.signature.ProfileParameters; import eu.europa.ec.markt.dss.signature.ProfileParameters.Operation; import eu.europa.ec.markt.dss.signature.SignatureExtension; import eu.europa.ec.markt.dss.signature.SignatureLevel; import eu.europa.ec.markt.dss.signature.SignaturePackaging; import eu.europa.ec.markt.dss.signature.token.DSSPrivateKeyEntry; import eu.europa.ec.markt.dss.signature.token.SignatureTokenConnection; import eu.europa.ec.markt.dss.validation102853.AdvancedSignature; import eu.europa.ec.markt.dss.validation102853.CertificateVerifier; import eu.europa.ec.markt.dss.validation102853.SignedDocumentValidator; import eu.europa.ec.markt.dss.validation102853.xades.XAdESSignature; import eu.europa.ec.markt.dss.validation102853.xades.XMLDocumentValidator; /** * XAdES implementation of DocumentSignatureService * * @version $Revision$ - $Date$ */ public class XAdESService extends AbstractSignatureService { static { Init.init(); } private static final Logger LOG = LoggerFactory.getLogger(XAdESService.class); /** * This is the constructor to create an instance of the {@code XAdESService}. A certificate verifier must be provided. * * @param certificateVerifier {@code CertificateVerifier} provides information on the sources to be used in the validation process in the context of a signature. */ public XAdESService(final CertificateVerifier certificateVerifier) { super(certificateVerifier); LOG.debug("+ XAdESService created"); } @Override public byte[] getDataToSign(final DSSDocument toSignDocument, final SignatureParameters parameters) throws DSSException { assertSigningDateInCertificateValidityRange(parameters); final XAdESLevelBaselineB levelBaselineB = new XAdESLevelBaselineB(certificateVerifier); final byte[] dataToSign = levelBaselineB.getDataToSign(toSignDocument, parameters); parameters.getContext().setProfile(levelBaselineB); return dataToSign; } @Override public DSSDocument signDocument(final DSSDocument toSignDocument, final SignatureParameters parameters, final byte[] signatureValue) throws DSSException { if (parameters.getSignatureLevel() == null) { throw new DSSNullException(SignatureLevel.class); } assertSigningDateInCertificateValidityRange(parameters); parameters.getContext().setOperationKind(Operation.SIGNING); final XAdESLevelBaselineB profile; final ProfileParameters context = parameters.getContext(); if (context.getProfile() != null) { profile = context.getProfile(); } else { profile = new XAdESLevelBaselineB(certificateVerifier); } final DSSDocument signedDoc = profile.signDocument(toSignDocument, parameters, signatureValue); final SignatureExtension extension = getExtensionProfile(parameters); if (extension != null) { if (SignaturePackaging.DETACHED.equals(parameters.getSignaturePackaging())) { parameters.setDetachedContent(toSignDocument); } final DSSDocument dssExtendedDocument = extension.extendSignatures(signedDoc, parameters); // The deterministic id is reset between two consecutive signing operations. It prevents having two signatures with the same Id within the same document. parameters.setDeterministicId(null); return dssExtendedDocument; } parameters.setDeterministicId(null); return signedDoc; } @Override public DSSDocument signDocument(final DSSDocument toSignDocument, final SignatureParameters parameters) throws DSSException { if (parameters.getSignatureLevel() == null) { throw new DSSNullException(SignatureLevel.class); } final SignatureTokenConnection signingToken = parameters.getSigningToken(); if (signingToken == null) { throw new DSSNullException(SignatureTokenConnection.class); } parameters.getContext().setOperationKind(Operation.SIGNING); final XAdESLevelBaselineB profile = new XAdESLevelBaselineB(certificateVerifier); final byte[] dataToSign = profile.getDataToSign(toSignDocument, parameters); parameters.getContext().setProfile(profile); final DigestAlgorithm digestAlgorithm = parameters.getDigestAlgorithm(); final DSSPrivateKeyEntry dssPrivateKeyEntry = parameters.getPrivateKeyEntry(); final byte[] signatureValue = signingToken.sign(dataToSign, digestAlgorithm, dssPrivateKeyEntry); final DSSDocument dssDocument = signDocument(toSignDocument, parameters, signatureValue); return dssDocument; } @Override public DSSDocument extendDocument(final DSSDocument toExtendDocument, final SignatureParameters parameters) throws DSSException { parameters.getContext().setOperationKind(Operation.EXTENDING); final SignatureExtension extension = getExtensionProfile(parameters); if (extension != null) { final DSSDocument dssDocument = extension.extendSignatures(toExtendDocument, parameters); return dssDocument; } throw new DSSException("Cannot extend to " + parameters.getSignatureLevel().name()); } public DSSDocument counterSignDocument(final DSSDocument toCounterSignDocument, final SignatureParameters parameters) throws DSSException { if (toCounterSignDocument == null) { throw new DSSNullException(DSSDocument.class, "toCounterSignDocument"); } if (parameters == null) { throw new DSSNullException(SignatureParameters.class); } if (parameters.getSignatureLevel() == null) { throw new DSSNullException(SignatureLevel.class); } final SignatureTokenConnection signingToken = parameters.getSigningToken(); if (signingToken == null) { throw new DSSNullException(SignatureTokenConnection.class); } final String toCounterSignSignatureId = parameters.getToCounterSignSignatureId(); if (DSSUtils.isBlank(toCounterSignSignatureId)) { throw new DSSException("There is no provided signature id to countersign!"); } final XAdESSignature xadesSignature = getToCountersignSignature(toCounterSignDocument, toCounterSignSignatureId); if (xadesSignature == null) { throw new DSSException("The signature to countersign not found!"); } final Node signatureValueNode = xadesSignature.getSignatureValue(); if (signatureValueNode == null) { throw new DSSNullException(Node.class, "signature-value"); } final String signatureValueId = DSSXMLUtils.getIDIdentifier((Element) signatureValueNode); if (DSSUtils.isBlank(toCounterSignSignatureId)) { throw new DSSException("There is no signature-value id to countersign!"); } parameters.setToCounterSignSignatureValueId(signatureValueId); final CounterSignatureBuilder counterSignatureBuilder = new CounterSignatureBuilder(toCounterSignDocument, xadesSignature, parameters, certificateVerifier); final byte[] dataToSign = counterSignatureBuilder.build(); final DigestAlgorithm digestAlgorithm = parameters.getDigestAlgorithm(); final DSSPrivateKeyEntry dssPrivateKeyEntry = parameters.getPrivateKeyEntry(); byte[] counterSignatureValue = signingToken.sign(dataToSign, digestAlgorithm, dssPrivateKeyEntry); final DSSDocument counterSignedDocument = counterSignatureBuilder.signDocument(counterSignatureValue); // final XMLDocumentValidator xmlDocumentValidator = (XMLDocumentValidator) validator; // final Document rootElement = xmlDocumentValidator.getRootElement(); // final byte[] bytes = DSSXMLUtils.transformDomToByteArray(rootElement); // final InMemoryDocument inMemoryDocument = new InMemoryDocument(bytes); return counterSignedDocument; } private XAdESSignature getToCountersignSignature(final DSSDocument toCounterSignDocument, final String toCounterSignSignatureId) { final SignedDocumentValidator validator = SignedDocumentValidator.fromDocument(toCounterSignDocument); if (!(validator instanceof XMLDocumentValidator)) { throw new DSSException("Incompatible signature form!"); } final List<AdvancedSignature> signatures = validator.getSignatures(); XAdESSignature xadesSignature = null; for (final AdvancedSignature signature_ : signatures) { final String id = signature_.getId(); if (toCounterSignSignatureId.equals(id)) { xadesSignature = (XAdESSignature) signature_; break; } } return xadesSignature; } /** * The choice of profile according to the passed parameter. * * @param parameters * @return */ private SignatureExtension getExtensionProfile(final SignatureParameters parameters) { switch (parameters.getSignatureLevel()) { case XAdES_BASELINE_B: return null; case XAdES_BASELINE_T: final XAdESLevelBaselineT extensionT = new XAdESLevelBaselineT(certificateVerifier); extensionT.setTspSource(tspSource); return extensionT; case XAdES_C: final XAdESLevelC extensionC = new XAdESLevelC(certificateVerifier); extensionC.setTspSource(tspSource); return extensionC; case XAdES_X: final XAdESLevelX extensionX = new XAdESLevelX(certificateVerifier); extensionX.setTspSource(tspSource); return extensionX; case XAdES_XL: final XAdESLevelXL extensionXL = new XAdESLevelXL(certificateVerifier); extensionXL.setTspSource(tspSource); return extensionXL; case XAdES_A: final XAdESLevelA extensionA = new XAdESLevelA(certificateVerifier); extensionA.setTspSource(tspSource); return extensionA; case XAdES_BASELINE_LT: final XAdESLevelBaselineLT extensionLT = new XAdESLevelBaselineLT(certificateVerifier); extensionLT.setTspSource(tspSource); return extensionLT; case XAdES_BASELINE_LTA: final XAdESLevelBaselineLTA extensionLTA = new XAdESLevelBaselineLTA(certificateVerifier); extensionLTA.setTspSource(tspSource); return extensionLTA; default: throw new DSSException("Unsupported signature format " + parameters.getSignatureLevel()); } } }