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

br.com.esec.icpm.libs.signature.helper.attach.PdfAttachSignatureHelper Maven / Gradle / Ivy

Go to download

This library is used to make integration with Certillion server, so our Clients can easily ask for signatures or generate certificates.

There is a newer version: 1.2.0
Show newest version
package br.com.esec.icpm.libs.signature.helper.attach;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.GeneralSecurityException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.text.ParseException;
import java.util.Collection;
import java.util.Date;
import java.util.Enumeration;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.time.DateUtils;
import org.bouncycastle.asn1.ASN1Set;
import org.bouncycastle.asn1.ASN1UTCTime;
import org.bouncycastle.asn1.DERSet;
import org.bouncycastle.asn1.cms.Attribute;
import org.bouncycastle.asn1.cms.CMSAttributes;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cms.CMSException;
import org.bouncycastle.cms.CMSSignedData;
import org.bouncycastle.cms.SignerInformation;
import org.bouncycastle.cms.SignerInformationStore;
import org.bouncycastle.util.Store;

import com.esec.signature.MakeExternalSignature;
import com.esec.text.DocumentException;
import com.esec.text.pdf.PdfReader;
import com.esec.text.pdf.PdfSignatureAppearance;
import com.esec.text.pdf.PdfStamper;

public class PdfAttachSignatureHelper {

	public static void attach(long transactionId, InputStream originalPdf, InputStream signature, OutputStream signedPdf) {
		try {
			attach(transactionId, originalPdf, IOUtils.toByteArray(signature), signedPdf);
		} catch (IOException e) {
			throw new IllegalStateException("Error when attach signature on original PDF.", e);
		}
	}
	
	public static void attach(long transactionId, InputStream originalPdf, byte[] signature, OutputStream signedPdf) {
		try {
			SignatureAttributes attributes = getSignatureAttributes(signature);

			CertificateFactory cf = CertificateFactory.getInstance("X.509");
			Certificate signerCert = cf.generateCertificate(new ByteArrayInputStream(attributes.getCertificateEncoded()));

			FileInputStream tempPDF = (FileInputStream) createSignedPDFStream(signerCert, originalPdf, signature, transactionId, attributes.getSignDate());

			IOUtils.copy(tempPDF, signedPdf);
		} catch (CMSException e) {
			throw new IllegalStateException("Error when attach signature on original PDF.", e);
		} catch (IOException e) {
			throw new IllegalStateException("Error when attach signature on original PDF.", e);
		} catch (CertificateException e) {
			throw new IllegalStateException("Error when attach signature on original PDF.", e);
		} catch (DocumentException e) {
			throw new IllegalStateException("Error when attach signature on original PDF.", e);
		} catch (GeneralSecurityException e) {
			throw new IllegalStateException("Error when attach signature on original PDF.", e);
		}
	}

	/**
	 * Creates an InputStream containing the PDF with the signature attached
	 * 
	 * @param signerCert
	 *            The certificate that signeds the PDF
	 * @param originalPdf
	 *            The PDF without signature
	 * @param signature
	 *            the signature
	 * @param transactionId
	 *            transactionId used to send signature request
	 * @param signingTime
	 *            the date that file was signed
	 * @return
	 * @throws IOException
	 *             if some error in read was occurred
	 * @throws DocumentException
	 *             if document is in wrong format
	 * @throws GeneralSecurityException
	 * @throws FileNotFoundException
	 */
	public static InputStream createSignedPDFStream(Certificate signerCert, InputStream originalPdf, byte[] signature, long transactionId, Date signingTime) throws IOException,
			DocumentException, GeneralSecurityException, FileNotFoundException {

		File signedDoc = File.createTempFile("signed-" + transactionId, ".pdf");

		PdfReader reader = new PdfReader(originalPdf);
		PdfStamper stamper = PdfStamper.createSignature(reader, FileUtils.openOutputStream(signedDoc), '\0', null, true);

		stamper.setDocumentId(transactionId);
		stamper.setModDate(DateUtils.toCalendar(signingTime));

		PdfSignatureAppearance appearance = generateAppearance(stamper, signingTime);
		MakeExternalSignature.attachSignature(appearance, signerCert, signature);

		return new FileInputStream(signedDoc);
	}

	/**
	 * Generates the PDF signature appearance object, that will be used to attach the signature
	 * 
	 * @param stamper
	 *            PDFStamper object
	 * @param signingTime
	 *            the date that certificate was signed
	 * @return
	 */
	protected static PdfSignatureAppearance generateAppearance(PdfStamper stamper, Date signingTime) {
		PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
		appearance.setReason("Remote PDF Signer");
		appearance.setLocation("Certillion");
		appearance.setSignDate(DateUtils.toCalendar(signingTime));
		return appearance;
	}

	/**
	 * Extract parameters from signature
	 * 
	 * @param signature
	 * @return An object that contains sign certificate and sign date
	 * @throws CMSException
	 *             if there are some error in signature, or if signature is corrupted
	 * @throws IOException
	 *             if occurs some error when extract certificate bytes
	 */
	public static SignatureAttributes getSignatureAttributes(byte[] signature) throws CMSException, IOException {
		SignatureAttributes attributes = new SignatureAttributes();
		CMSSignedData signedData = new CMSSignedData(signature);

		// Obtem signer information
		SignerInformationStore signerInfos = signedData.getSignerInfos();
		SignerInformation signerInfo = (SignerInformation) signerInfos.getSigners().iterator().next();

		if (signerInfo != null) {
			byte[] certificate = extractCertificate(signedData, signerInfo);
			Date signDate = extractDate(signerInfo);

			attributes.setCertificateEncoded(certificate);
			attributes.setSignDate(signDate);

			return attributes;
		}
		return null;

	}

	/**
	 * extract the sign certificate form given signature object
	 * 
	 * @param signedData
	 * @param signerInfo
	 * @return certificate encoded bytes, or null if no certificate was found
	 * @throws IOException
	 */
	private static byte[] extractCertificate(CMSSignedData signedData, SignerInformation signerInfo) throws IOException {

		Store certStore = signedData.getCertificates();

		@SuppressWarnings("unchecked")
		Collection certs = certStore.getMatches(signerInfo.getSID());
		for (X509CertificateHolder cert : certs) {
			return cert.getEncoded();
		}
		return null;
	}

	/**
	 * Extract the sign date from given signature object
	 * 
	 * @param signerInfo
	 * @return the sign date or null if no sign date was found in the signature
	 */
	private static Date extractDate(SignerInformation signerInfo) {
		try {

			Attribute signingTime = signerInfo.getSignedAttributes().get(CMSAttributes.signingTime);

			ASN1Set att = (DERSet) signingTime.getAttrValues();
			Enumeration atts = att.getObjects();

			while (atts.hasMoreElements()) {
				Object attribute = atts.nextElement();
				if (attribute instanceof ASN1UTCTime) {
					ASN1UTCTime time = (ASN1UTCTime) attribute;

					Date date = time.getDate();
					return date;
				}
			}
		} catch (ParseException e) {
			throw new IllegalStateException(e);
		}
		return null;
	}

	static class SignatureAttributes {
		
		private byte[] certificateEncoded;
		private Date signDate;

		public byte[] getCertificateEncoded() {
			return certificateEncoded;
		}

		public void setCertificateEncoded(byte[] certificateEncoded) {
			this.certificateEncoded = certificateEncoded;
		}

		public Date getSignDate() {
			return signDate;
		}

		public void setSignDate(Date signDate) {
			this.signDate = signDate;
		}

	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy