/* DigiDoc4J library
*
* This software is released under either the GNU Library General Public
* License (see LICENSE.LGPL).
*
* Note that the only valid version of the LGPL license as far as this
* project is concerned is the original GNU Library General Public License
* Version 2.1, February 1999
*/
package org.digidoc4j.impl.bdoc.xades;
import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
import static org.digidoc4j.SignatureProfile.B_BES;
import static org.digidoc4j.SignatureProfile.B_EPES;
import static org.digidoc4j.SignatureProfile.LT;
import static org.digidoc4j.SignatureProfile.LTA;
import static org.digidoc4j.SignatureProfile.LT_TM;
import static org.digidoc4j.impl.bdoc.ocsp.OcspSourceBuilder.anOcspSource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.digidoc4j.Configuration;
import org.digidoc4j.Signature;
import org.digidoc4j.SignatureProfile;
import org.digidoc4j.exceptions.NotSupportedException;
import org.digidoc4j.impl.bdoc.BDocSignature;
import org.digidoc4j.impl.bdoc.BDocSignatureBuilder;
import org.digidoc4j.impl.bdoc.SkDataLoader;
import org.digidoc4j.impl.bdoc.ocsp.SKOnlineOCSPSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import eu.europa.esig.dss.DSSDocument;
import eu.europa.esig.dss.Policy;
import eu.europa.esig.dss.SignatureLevel;
import eu.europa.esig.dss.client.tsp.OnlineTSPSource;
import eu.europa.esig.dss.x509.ocsp.OCSPSource;
public class SignatureExtender {
private static final Logger logger = LoggerFactory.getLogger(SignatureExtender.class);
private static final Map<SignatureProfile, Set<SignatureProfile>> possibleExtensions = new HashMap<>(5);
private Configuration configuration;
private DSSDocument detachedContent;
private XadesSigningDssFacade extendingFacade;
static {
possibleExtensions.put(B_BES, new HashSet<>(asList(LT, LTA)));
possibleExtensions.put(B_EPES, new HashSet<>(singletonList(LT_TM)));
possibleExtensions.put(LT, new HashSet<>(singletonList(LTA)));
possibleExtensions.put(LT_TM, Collections.<SignatureProfile>emptySet());
possibleExtensions.put(LTA, Collections.<SignatureProfile>emptySet());
}
public SignatureExtender(Configuration configuration, DSSDocument detachedContent) {
this.configuration = configuration;
this.detachedContent = detachedContent;
extendingFacade = new XadesSigningDssFacade();
}
public List<DSSDocument> extend(List<Signature> signaturesToExtend, SignatureProfile profile) {
logger.debug("Extending signatures to " + profile);
validatePossibilityToExtendTo(signaturesToExtend, profile);
prepareExtendingFacade(profile);
List<DSSDocument> extendedSignatures = new ArrayList<>();
for (Signature signature : signaturesToExtend) {
DSSDocument extendedSignature = extendSignature((BDocSignature) signature, profile);
extendedSignatures.add(extendedSignature);
}
logger.debug("Finished extending signatures");
return extendedSignatures;
}
private void prepareExtendingFacade(SignatureProfile profile) {
extendingFacade.setCertificateSource(configuration.getTSL());
OnlineTSPSource tspSource = createTimeStampProviderSource(profile);
extendingFacade.setTspSource(tspSource);
SignatureLevel signatureLevel = getSignatureLevel(profile);
extendingFacade.setSignatureLevel(signatureLevel);
setSignaturePolicy(profile);
}
private DSSDocument extendSignature(BDocSignature signature, SignatureProfile profile) {
OCSPSource ocspSource = createOcspSource(profile, signature.getOrigin().getSignatureValue());
extendingFacade.setOcspSource(ocspSource);
DSSDocument signatureDocument = signature.getSignatureDocument();
return extendingFacade.extendSignature(signatureDocument, detachedContent);
}
private OCSPSource createOcspSource(SignatureProfile profile, byte[] signatureValue) {
SKOnlineOCSPSource ocspSource = anOcspSource().
withSignatureProfile(profile).
withSignatureValue(signatureValue).
withConfiguration(configuration).
build();
return ocspSource;
}
private OnlineTSPSource createTimeStampProviderSource(SignatureProfile profile) {
OnlineTSPSource tspSource = new OnlineTSPSource(configuration.getTspSource());
SkDataLoader dataLoader = SkDataLoader.createTimestampDataLoader(configuration);
dataLoader.setUserAgentSignatureProfile(profile);
tspSource.setDataLoader(dataLoader);
return tspSource;
}
private SignatureLevel getSignatureLevel(SignatureProfile profile) {
if (profile == SignatureProfile.LT || profile == SignatureProfile.LT_TM) {
return SignatureLevel.XAdES_BASELINE_LT;
}
if (profile == SignatureProfile.LTA) {
return SignatureLevel.XAdES_BASELINE_LTA;
}
logger.error("Extending signature to " + profile + " is not supported");
throw new NotSupportedException("Extending signature to " + profile + " is not supported");
}
private void setSignaturePolicy(SignatureProfile profile) {
if (profile == LT_TM) {
Policy signaturePolicy = BDocSignatureBuilder.createBDocSignaturePolicy();
extendingFacade.setSignaturePolicy(signaturePolicy);
}
}
private void validatePossibilityToExtendTo(List<Signature> signatures, SignatureProfile profile) {
logger.debug("Validating if it's possible to extend all the signatures to " + profile);
for (Signature signature : signatures) {
if (!canExtendSignatureToProfile(signature, profile)) {
String message = "It is not possible to extend " + signature.getProfile() + " signature to " + signature.getProfile() + ".";
logger.error(message);
throw new NotSupportedException(message);
}
}
}
private boolean canExtendSignatureToProfile(Signature signature, SignatureProfile profile) {
return possibleExtensions.get(signature.getProfile()).contains(profile);
}
}