All Downloads are FREE. Search and download functionalities are using the official Maven repository.

eu.europa.esig.dss.asic.signature.AbstractASiCSignatureService Maven / Gradle / Ivy

package eu.europa.esig.dss.asic.signature;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
import java.util.zip.CRC32;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

import eu.europa.esig.dss.AbstractSignatureParameters;
import eu.europa.esig.dss.DSSDocument;
import eu.europa.esig.dss.DSSException;
import eu.europa.esig.dss.DSSUnsupportedOperationException;
import eu.europa.esig.dss.InMemoryDocument;
import eu.europa.esig.dss.SignatureValue;
import eu.europa.esig.dss.ToBeSigned;
import eu.europa.esig.dss.asic.ASiCExtractResult;
import eu.europa.esig.dss.asic.ASiCParameters;
import eu.europa.esig.dss.asic.ASiCUtils;
import eu.europa.esig.dss.asic.AbstractASiCContainerExtractor;
import eu.europa.esig.dss.signature.AbstractSignatureService;
import eu.europa.esig.dss.signature.MultipleDocumentsSignatureService;
import eu.europa.esig.dss.utils.Utils;
import eu.europa.esig.dss.validation.CertificateVerifier;

public abstract class AbstractASiCSignatureService extends AbstractSignatureService
		implements MultipleDocumentsSignatureService {

	private static final long serialVersionUID = 243114076381526665L;

	private static final String ZIP_ENTRY_DETACHED_FILE = "detached-file";
	private static final String ZIP_ENTRY_MIMETYPE = "mimetype";

	private ASiCExtractResult archiveContent = new ASiCExtractResult();

	protected AbstractASiCSignatureService(CertificateVerifier certificateVerifier) {
		super(certificateVerifier);
	}

	protected void assertCanBeSign(List documents, final ASiCParameters asicParameters) {
		if (!canBeSigned(documents, asicParameters)) { // First verify if the file can be signed
			throw new DSSUnsupportedOperationException("You only can sign an ASiC container by using the same type of container and of signature");
		}
	}

	private boolean canBeSigned(List documents, ASiCParameters asicParameters) {
		boolean isMimetypeCorrect = true;
		boolean isSignatureTypeCorrect = true;
		if (ASiCUtils.isArchive(documents)) {
			DSSDocument archive = documents.get(0);
			String expectedMimeType = archive.getMimeType().getMimeTypeString();
			String mimeTypeFromParameter = ASiCUtils.getMimeTypeString(asicParameters);
			isMimetypeCorrect = Utils.areStringsEqualIgnoreCase(expectedMimeType, mimeTypeFromParameter);
			if (isMimetypeCorrect) {
				isSignatureTypeCorrect = ASiCUtils.isArchiveContainsCorrectSignatureExtension(archive, getExpectedSignatureExtension());
			}
		}
		return isMimetypeCorrect && isSignatureTypeCorrect;
	}

	abstract String getExpectedSignatureExtension();

	@Override
	public ToBeSigned getDataToSign(DSSDocument toSignDocument, SP parameters) throws DSSException {
		return getDataToSign(Arrays.asList(toSignDocument), parameters);
	}

	@Override
	public DSSDocument signDocument(DSSDocument toSignDocument, SP parameters, SignatureValue signatureValue) throws DSSException {
		return signDocument(Arrays.asList(toSignDocument), parameters, signatureValue);
	}

	protected void extractCurrentArchive(DSSDocument archive) {
		AbstractASiCContainerExtractor extractor = getArchiveExtractor(archive);
		archiveContent = extractor.extract();
	}

	abstract AbstractASiCContainerExtractor getArchiveExtractor(DSSDocument archive);

	protected List getEmbeddedSignatures() {
		return archiveContent.getSignatureDocuments();
	}

	protected List getEmbeddedManifests() {
		return archiveContent.getManifestDocuments();
	}

	protected List getEmbeddedArchiveManifests() {
		return archiveContent.getArchiveManifestDocuments();
	}

	protected List getEmbeddedTimestamps() {
		return archiveContent.getTimestampDocuments();
	}

	protected List getEmbeddedSignedDocuments() {
		return archiveContent.getSignedDocuments();
	}

	protected DSSDocument getEmbeddedMimetype() {
		return archiveContent.getMimeTypeDocument();
	}

	protected DSSDocument mergeArchiveAndExtendedSignatures(DSSDocument archiveDocument, List signaturesToAdd) {
		try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); ZipOutputStream zos = new ZipOutputStream(baos)) {
			copyArchiveContentWithoutSignatures(archiveDocument, zos);
			storeDocuments(signaturesToAdd, zos);

			zos.finish();

			return new InMemoryDocument(baos.toByteArray(), null, archiveDocument.getMimeType());
		} catch (IOException e) {
			throw new DSSException("Unable to extend the ASiC container", e);
		}
	}

	private void copyArchiveContentWithoutSignatures(DSSDocument archiveDocument, ZipOutputStream zos) throws IOException {
		try (InputStream is = archiveDocument.openStream(); ZipInputStream zis = new ZipInputStream(is)) {
			ZipEntry entry;
			while ((entry = zis.getNextEntry()) != null) {
				final String name = entry.getName();
				final ZipEntry newEntry = new ZipEntry(name);
				if (!isSignatureFilename(name)) {
					zos.putNextEntry(newEntry);
					Utils.copy(zis, zos);
				}
			}
		}
	}

	abstract boolean isSignatureFilename(String name);

	protected DSSDocument buildASiCContainer(List documentsToBeSigned, List signatures, List manifestDocuments,
			ASiCParameters asicParameters) {

		try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); ZipOutputStream zos = new ZipOutputStream(baos)) {
			if (ASiCUtils.isASiCE(asicParameters)) {
				storeDocuments(manifestDocuments, zos);
			}

			storeDocuments(signatures, zos);
			storeSignedFiles(documentsToBeSigned, zos);
			storeMimetype(asicParameters, zos);
			storeZipComment(asicParameters, zos);

			zos.finish();

			return new InMemoryDocument(baos.toByteArray(), null, ASiCUtils.getMimeType(asicParameters));
		} catch (IOException e) {
			throw new DSSException("Unable to build the ASiC Container", e);
		}
	}

	private void storeDocuments(List documents, ZipOutputStream zos) throws IOException {
		for (DSSDocument doc : documents) {
			final ZipEntry entrySignature = new ZipEntry(doc.getName());
			zos.putNextEntry(entrySignature);
			doc.writeTo(zos);
		}
	}

	private void storeSignedFiles(final List detachedDocuments, final ZipOutputStream zos) throws IOException {
		for (DSSDocument detachedDocument : detachedDocuments) {
			try (InputStream is = detachedDocument.openStream()) {
				final String detachedDocumentName = detachedDocument.getName();
				final String name = detachedDocumentName != null ? detachedDocumentName : ZIP_ENTRY_DETACHED_FILE;
				final ZipEntry entryDocument = new ZipEntry(name);

				zos.setLevel(ZipEntry.DEFLATED);
				zos.putNextEntry(entryDocument);
				Utils.copy(is, zos);
			}
		}
	}

	private void storeMimetype(final ASiCParameters asicParameters, final ZipOutputStream zos) throws IOException {
		final byte[] mimeTypeBytes = ASiCUtils.getMimeTypeString(asicParameters).getBytes("UTF-8");
		final ZipEntry entryMimetype = getZipEntryMimeType(mimeTypeBytes);
		zos.putNextEntry(entryMimetype);
		Utils.write(mimeTypeBytes, zos);
	}

	private ZipEntry getZipEntryMimeType(final byte[] mimeTypeBytes) {
		final ZipEntry entryMimetype = new ZipEntry(ZIP_ENTRY_MIMETYPE);
		entryMimetype.setMethod(ZipEntry.STORED);
		entryMimetype.setSize(mimeTypeBytes.length);
		entryMimetype.setCompressedSize(mimeTypeBytes.length);
		final CRC32 crc = new CRC32();
		crc.update(mimeTypeBytes);
		entryMimetype.setCrc(crc.getValue());
		return entryMimetype;
	}

	protected void storeZipComment(final ASiCParameters asicParameters, final ZipOutputStream zos) {
		if (asicParameters.isZipComment()) {
			zos.setComment(ASiCUtils.MIME_TYPE_COMMENT + ASiCUtils.getMimeTypeString(asicParameters));
		}
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy