/* 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; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.List; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.digidoc4j.Configuration; import org.digidoc4j.Container; import org.digidoc4j.DataFile; import org.digidoc4j.DigestAlgorithm; import org.digidoc4j.Signature; import org.digidoc4j.SignatureBuilder; import org.digidoc4j.SignatureParameters; import org.digidoc4j.SignatureProfile; import org.digidoc4j.SignatureToken; import org.digidoc4j.SignedInfo; import org.digidoc4j.ValidationResult; import org.digidoc4j.exceptions.DigiDoc4JException; import org.digidoc4j.exceptions.DuplicateDataFileException; import org.digidoc4j.exceptions.InvalidSignatureException; import org.digidoc4j.exceptions.NotSupportedException; import org.digidoc4j.exceptions.RemovingDataFileException; import org.digidoc4j.exceptions.TechnicalException; import org.digidoc4j.impl.bdoc.asic.AsicContainerCreator; import org.digidoc4j.impl.bdoc.asic.DetachedContentCreator; import org.digidoc4j.impl.bdoc.xades.SignatureExtender; import org.digidoc4j.utils.Helper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import eu.europa.esig.dss.DSSDocument; public abstract class BDocContainer implements Container { private static final Logger logger = LoggerFactory.getLogger(BDocContainer.class); private Configuration configuration; private ValidationResult validationResult; public BDocContainer() { logger.debug("Instantiating BDoc container"); configuration = Configuration.getInstance(); } public BDocContainer(Configuration configuration) { logger.debug("Instantiating BDoc container with configuration"); this.configuration = configuration; } protected abstract ValidationResult validateContainer(); protected abstract void writeAsicContainer(AsicContainerCreator zipCreator); @Override public String getType() { return "BDOC"; } @Override public ValidationResult validate() { if (validationResult == null) { validationResult = validateContainer(); } return validationResult; } @Override public File saveAsFile(String filePath) { logger.debug("Saving container to file: " + filePath); File file = new File(filePath); AsicContainerCreator zipCreator = new AsicContainerCreator(file); writeAsicContainer(zipCreator); logger.info("Container was saved to file " + filePath); return file; } @Override public InputStream saveAsStream() { logger.debug("Saving container as stream"); AsicContainerCreator zipCreator = new AsicContainerCreator(); writeAsicContainer(zipCreator); InputStream inputStream = zipCreator.fetchInputStreamOfFinalizedContainer(); logger.info("Container was saved to stream"); return inputStream; } public Configuration getConfiguration() { return configuration; } protected List<Signature> parseSignatureFiles(List<DSSDocument> signatureFiles, List<DSSDocument> detachedContents) { Configuration configuration = getConfiguration(); BDocSignatureOpener signatureOpener = new BDocSignatureOpener(detachedContents, configuration); List<Signature> signatures = new ArrayList<>(signatureFiles.size()); for (DSSDocument signatureFile : signatureFiles) { List<BDocSignature> bDocSignatures = signatureOpener.parse(signatureFile); signatures.addAll(bDocSignatures); } return signatures; } protected void validateIncomingSignature(Signature signature) { if (!(signature instanceof BDocSignature)) { throw new TechnicalException("BDoc signature must be an instance of BDocSignature"); } } protected List<Signature> extendAllSignaturesProfile(SignatureProfile profile, List<Signature> signatures, List<DataFile> dataFiles) { logger.info("Extending all signatures' profile to " + profile.name()); DetachedContentCreator detachedContentCreator = new DetachedContentCreator().populate(dataFiles); DSSDocument firstDetachedContent = detachedContentCreator.getFirstDetachedContent(); List<DSSDocument> detachedContentList = detachedContentCreator.getDetachedContentList(); SignatureExtender signatureExtender = new SignatureExtender(getConfiguration(), firstDetachedContent); List<DSSDocument> extendedSignatureDocuments = signatureExtender.extend(signatures, profile); List<Signature> extendedSignatures = parseSignatureFiles(extendedSignatureDocuments, detachedContentList); logger.debug("Finished extending all signatures"); return extendedSignatures; } protected String createUserAgent() { if(!getSignatures().isEmpty()) { SignatureProfile profile = getSignatures().get(0).getProfile(); return Helper.createBDocUserAgent(profile); } return Helper.createBDocUserAgent(); } protected void validateDataFilesRemoval() { if (!getSignatures().isEmpty()) { logger.error("Datafiles cannot be removed from an already signed container"); throw new RemovingDataFileException(); } } protected void verifyIfAllowedToAddDataFile(String fileName) { if (getSignatures().size() > 0) { String errorMessage = "Datafiles cannot be added to an already signed container"; logger.error(errorMessage); throw new DigiDoc4JException(errorMessage); } checkForDuplicateDataFile(fileName); } private void checkForDuplicateDataFile(String fileName) { logger.debug(""); for (DataFile dataFile : getDataFiles()) { String dataFileName = dataFile.getName(); if (StringUtils.equals(dataFileName, fileName)) { String errorMessage = "Data file " + fileName + " already exists"; logger.error(errorMessage); throw new DuplicateDataFileException(errorMessage); } } } @Override @Deprecated public void save(OutputStream out) { try { InputStream inputStream = saveAsStream(); IOUtils.copy(inputStream, out); } catch (IOException e) { logger.error("Error saving container input stream to output stream: " + e.getMessage()); throw new TechnicalException("Error saving container input stream to output stream", e); } } @Override @Deprecated public void addRawSignature(byte[] signatureDocument) { logger.info("Adding raw signature"); Signature signature = SignatureBuilder. aSignature(this). openAdESSignature(signatureDocument); addSignature(signature); } @Override @Deprecated public void addRawSignature(InputStream signatureStream) { try { byte[] bytes = IOUtils.toByteArray(signatureStream); addRawSignature(bytes); } catch (IOException e) { logger.error("Failed to read signature stream: " + e.getMessage()); throw new InvalidSignatureException(); } } @Override @Deprecated public int countDataFiles() { return getDataFiles().size(); } @Override @Deprecated public int countSignatures() { return getSignatures().size(); } @Override @Deprecated public DocumentType getDocumentType() { return Container.DocumentType.BDOC; } @Override @Deprecated public String getVersion() { return null; } @Override @Deprecated public void extendTo(SignatureProfile profile) { extendSignatureProfile(profile); } @Override @Deprecated public void save(String path) { saveAsFile(path); } @Override @Deprecated public DataFile getDataFile(int index) { return getDataFiles().get(index); } @Override @Deprecated public Signature getSignature(int index) { return getSignatures().get(index); } @Override @Deprecated public SignedInfo prepareSigning(X509Certificate signerCert) { throw new NotSupportedException("Prepare signing method is not supported by BDoc container"); } @Override @Deprecated public String getSignatureProfile() { throw new NotSupportedException("Getting signature profile method is not supported by BDoc container"); } @Override @Deprecated public void setSignatureParameters(SignatureParameters signatureParameters) { throw new NotSupportedException("Setting signature parameters method is not supported by BDoc container"); } @Override @Deprecated public DigestAlgorithm getDigestAlgorithm() { throw new NotSupportedException("Getting digest algorithm method is not supported by BDoc container"); } @Override @Deprecated public Signature sign(SignatureToken signatureToken) { throw new NotSupportedException("Sign method is not supported by BDoc container"); } @Override @Deprecated public Signature signRaw(byte[] rawSignature) { throw new NotSupportedException("Sign raw method is not supported by BDoc container"); } @Override @Deprecated public void setSignatureProfile(SignatureProfile profile) { throw new NotSupportedException("Setting signature profile method is not supported by BDoc container"); } }