/* * 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; import java.security.cert.X509CRL; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import org.bouncycastle.cert.ocsp.BasicOCSPResp; import eu.europa.ec.markt.dss.DSSRevocationUtils; import eu.europa.ec.markt.dss.exception.DSSException; import eu.europa.ec.markt.dss.signature.DSSDocument; import eu.europa.ec.markt.dss.signature.SignatureLevel; import eu.europa.ec.markt.dss.validation102853.bean.CandidatesForSigningCertificate; import eu.europa.ec.markt.dss.validation102853.bean.CertificateValidity; import eu.europa.ec.markt.dss.validation102853.bean.SignatureCryptographicVerification; import eu.europa.ec.markt.dss.validation102853.crl.CRLToken; import eu.europa.ec.markt.dss.validation102853.crl.ListCRLSource; import eu.europa.ec.markt.dss.validation102853.crl.OfflineCRLSource; import eu.europa.ec.markt.dss.validation102853.ocsp.ListOCSPSource; import eu.europa.ec.markt.dss.validation102853.ocsp.OfflineOCSPSource; /** * TODO <p/> <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 abstract class DefaultAdvancedSignature implements AdvancedSignature { /** * This is the reference to the global (external) pool of certificates. All encapsulated certificates in the signature are added to this pool. See {@link * eu.europa.ec.markt.dss.validation102853.CertificatePool} */ protected final CertificatePool certPool; /** * In the case of a non AdES signature the signing certificate is not mandatory within the signature and can be provided by the driving application. */ protected CertificateToken providedSigningCertificateToken; /** * In case of a detached signature this is the signed document. */ protected List<DSSDocument> detachedContents; /** * This variable contains the result of the signature mathematical validation. It is initialised when the method {@code checkSignatureIntegrity} is called. */ protected SignatureCryptographicVerification signatureCryptographicVerification; /** * The reference to the object containing all candidates to the signing certificate. */ protected CandidatesForSigningCertificate candidatesForSigningCertificate; // Enclosed content timestamps. protected List<TimestampToken> contentTimestamps; // Enclosed signature timestamps. protected transient List<TimestampToken> signatureTimestamps; // Enclosed SignAndRefs timestamps. protected List<TimestampToken> sigAndRefsTimestamps; // Enclosed RefsOnly timestamps. protected List<TimestampToken> refsOnlyTimestamps; // This variable contains the list of enclosed archive signature timestamps. protected List<TimestampToken> archiveTimestamps; // Cached {@code OfflineCRLSource} protected OfflineCRLSource offlineCRLSource; // Cached {@code OfflineOCSPSource} protected OfflineOCSPSource offlineOCSPSource; private AdvancedSignature masterSignature; /** * @param certPool can be null */ protected DefaultAdvancedSignature(final CertificatePool certPool) { this.certPool = certPool; } @Override public List<DSSDocument> getDetachedContents() { return detachedContents; } @Override public void setDetachedContents(final DSSDocument... detachedContents) { for (final DSSDocument detachedContent : detachedContents) { if (detachedContent != null) { if (this.detachedContents == null) { this.detachedContents = new ArrayList<DSSDocument>(); } this.detachedContents.add(detachedContent); } } } @Override public void setDetachedContents(final List<DSSDocument> detachedContents) { this.detachedContents = detachedContents; } /** * @return the upper level for which data have been found. Doesn't mean any validity of the data found. Null if unknown. */ @Override public SignatureLevel getDataFoundUpToLevel() { final SignatureLevel[] signatureLevels = getSignatureLevels(); final SignatureLevel dataFoundUpToProfile = getDataFoundUpToProfile(signatureLevels); return dataFoundUpToProfile; } /** * This method returns the {@code SignatureLevel} which was reached. * * @param signatureLevels the array of the all levels associated with the given signature type * @return {@code SignatureLevel} */ private SignatureLevel getDataFoundUpToProfile(final SignatureLevel... signatureLevels) { for (int ii = signatureLevels.length - 1; ii >= 0; ii--) { final SignatureLevel signatureLevel = signatureLevels[ii]; if (isDataForSignatureLevelPresent(signatureLevel)) { return signatureLevel; } } return null; } /** * This method validates the signing certificate and all timestamps. * * @return signature validation context containing all certificates and revocation data used during the validation process. */ public ValidationContext getSignatureValidationContext(final CertificateVerifier certificateVerifier) { final CertificatePool validationPool = certificateVerifier.createValidationPool(); final ValidationContext validationContext = new SignatureValidationContext(certificateVerifier, validationPool); final List<CertificateToken> certificates = getCertificates(); for (final CertificateToken certificate : certificates) { validationContext.addCertificateTokenForVerification(certificate); } final List<TimestampToken> timestampTokenList = prepareTimestamps(); for (final TimestampToken timestampToken : timestampTokenList) { validationContext.addTimestampTokenForVerification(timestampToken); } certificateVerifier.setSignatureCRLSource(new ListCRLSource(getCRLSource())); certificateVerifier.setSignatureOCSPSource(new ListOCSPSource(getOCSPSource())); // certificateVerifier.setAdjunctCertSource(getCertificateSource()); validationContext.validate(); return validationContext; } /** * This method returns all certificates used during the validation process. If a certificate is already present within the signature then it is ignored. * * @param validationContext validation context containing all information about the validation process of the signing certificate and time-stamps * @return set of certificates not yet present within the signature */ public Set<CertificateToken> getCertificatesForInclusion(final ValidationContext validationContext) { final Set<CertificateToken> certificates = new HashSet<CertificateToken>(); final List<CertificateToken> certWithinSignatures = getCertificatesWithinSignatureAndTimestamps(); for (final CertificateToken certificateToken : validationContext.getProcessedCertificates()) { if (certWithinSignatures.contains(certificateToken)) { continue; } certificates.add(certificateToken); } return certificates; } public List<CertificateToken> getCertificatesWithinSignatureAndTimestamps() { final List<CertificateToken> certWithinSignatures = new ArrayList<CertificateToken>(); certWithinSignatures.addAll(getCertificates()); for (final TimestampToken timestampToken : getSignatureTimestamps()) { certWithinSignatures.addAll(timestampToken.getCertificates()); } for (final TimestampToken timestampToken : getArchiveTimestamps()) { certWithinSignatures.addAll(timestampToken.getCertificates()); } for (final TimestampToken timestampToken : getContentTimestamps()) { certWithinSignatures.addAll(timestampToken.getCertificates()); } for (final TimestampToken timestampToken : getTimestampsX1()) { certWithinSignatures.addAll(timestampToken.getCertificates()); } for (final TimestampToken timestampToken : getTimestampsX2()) { certWithinSignatures.addAll(timestampToken.getCertificates()); } return certWithinSignatures; } /** * This method returns revocation values (ocsp and crl) that will be included in the LT profile. * * @param validationContext {@code ValidationContext} contains all the revocation data retrieved during the validation process. * @return {@code RevocationDataForInclusion} */ public RevocationDataForInclusion getRevocationDataForInclusion(final ValidationContext validationContext) { //TODO: to be checked: there can be also CRL and OCSP in TimestampToken CMS data final Set<RevocationToken> revocationTokens = validationContext.getProcessedRevocations(); final OfflineCRLSource crlSource = getCRLSource(); final List<X509CRL> containedX509CRLs = crlSource.getContainedX509CRLs(); final OfflineOCSPSource ocspSource = getOCSPSource(); final List<BasicOCSPResp> containedBasicOCSPResponses = ocspSource.getContainedOCSPResponses(); final List<CRLToken> crlTokens = new ArrayList<CRLToken>(); final List<OCSPToken> ocspTokens = new ArrayList<OCSPToken>(); for (final RevocationToken revocationToken : revocationTokens) { if (revocationToken instanceof CRLToken) { final CRLToken crlToken = (CRLToken) revocationToken; final X509CRL x509crl = crlToken.getX509crl(); final boolean tokenIn = containedX509CRLs.contains(x509crl); if (!tokenIn) { crlTokens.add(crlToken); } } else if (revocationToken instanceof OCSPToken) { final boolean tokenIn = DSSRevocationUtils.isTokenIn(revocationToken, containedBasicOCSPResponses); if (!tokenIn) { final OCSPToken ocspToken = (OCSPToken) revocationToken; ocspTokens.add(ocspToken); } } else { throw new DSSException("Unknown type for revocationToken: " + revocationToken.getClass().getName()); } } return new RevocationDataForInclusion(crlTokens, ocspTokens); } @Override public void setMasterSignature(final AdvancedSignature masterSignature) { this.masterSignature = masterSignature; } @Override public AdvancedSignature getMasterSignature() { return masterSignature; } public static class RevocationDataForInclusion { public final List<CRLToken> crlTokens; public final List<OCSPToken> ocspTokens; public RevocationDataForInclusion(final List<CRLToken> crlTokens, final List<OCSPToken> ocspTokens) { this.crlTokens = crlTokens; this.ocspTokens = ocspTokens; } public boolean isEmpty() { return crlTokens.isEmpty() && ocspTokens.isEmpty(); } } @Override public CertificateToken getProvidedSigningCertificateToken() { return providedSigningCertificateToken; } @Override public void setProvidedSigningCertificateToken(final CertificateToken certificateToken) { this.providedSigningCertificateToken = certificateToken; } @Override public CertificateToken getSigningCertificateToken() { // This ensures that the variable candidatesForSigningCertificate has been initialized candidatesForSigningCertificate = getCandidatesForSigningCertificate(); // This ensures that the variable signatureCryptographicVerification has been initialized signatureCryptographicVerification = checkSignatureIntegrity(); final CertificateValidity theCertificateValidity = candidatesForSigningCertificate.getTheCertificateValidity(); if (theCertificateValidity != null) { if (theCertificateValidity.isValid()) { final CertificateToken signingCertificateToken = theCertificateValidity.getCertificateToken(); return signingCertificateToken; } } final CertificateValidity theBestCandidate = candidatesForSigningCertificate.getTheBestCandidate(); return theBestCandidate == null ? null : theBestCandidate.getCertificateToken(); } /** * @return the {@code List} of all {@code TimestampToken} present within the signature */ @Override public List<TimestampToken> prepareTimestamps() { final List<TimestampToken> timestampTokenList = new ArrayList<TimestampToken>(); /* * This validates the signature timestamp tokens present in the signature. */ for (final TimestampToken timestampToken : getContentTimestamps()) { timestampTokenList.add(timestampToken); } /* * This validates the signature timestamp tokens present in the signature. */ for (final TimestampToken timestampToken : getSignatureTimestamps()) { timestampTokenList.add(timestampToken); } /* * This validates the SigAndRefs timestamp tokens present in the signature. */ for (final TimestampToken timestampToken : getTimestampsX1()) { timestampTokenList.add(timestampToken); } /* * This validates the RefsOnly timestamp tokens present in the signature. */ for (final TimestampToken timestampToken : getTimestampsX2()) { timestampTokenList.add(timestampToken); } /* * This validates the archive timestamp tokens present in the signature. */ for (final TimestampToken timestampToken : getArchiveTimestamps()) { timestampTokenList.add(timestampToken); } return timestampTokenList; } /** * This method adds all timestamps to be validated. */ @Override public void validateTimestamps() { /* * This validates the content-timestamp tokensToProcess present in the signature. */ for (final TimestampToken timestampToken : getContentTimestamps()) { final byte[] timestampBytes = getContentTimestampData(timestampToken); timestampToken.matchData(timestampBytes); } /* * This validates the signature timestamp tokensToProcess present in the signature. */ for (final TimestampToken timestampToken : getSignatureTimestamps()) { final byte[] timestampBytes = getSignatureTimestampData(timestampToken, null); timestampToken.matchData(timestampBytes); } /* * This validates the SigAndRefs timestamp tokensToProcess present in the signature. */ for (final TimestampToken timestampToken : getTimestampsX1()) { final byte[] timestampBytes = getTimestampX1Data(timestampToken, null); timestampToken.matchData(timestampBytes); } /* * This validates the RefsOnly timestamp tokensToProcess present in the signature. */ for (final TimestampToken timestampToken : getTimestampsX2()) { final byte[] timestampBytes = getTimestampX2Data(timestampToken, null); timestampToken.matchData(timestampBytes); } /* * This validates the archive timestamp tokensToProcess present in the signature. */ for (final TimestampToken timestampToken : getArchiveTimestamps()) { final byte[] timestampData = getArchiveTimestampData(timestampToken, null); timestampToken.matchData(timestampData); } } @Override public String validateStructure() { return null; } }