
br.com.esec.icpm.libs.signature.helper.attach.PdfAttachSignatureHelper Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of certillion-client-library Show documentation
Show all versions of certillion-client-library Show documentation
This library is used to make integration with Certillion server, so our Clients can easily ask for signatures or generate certificates.
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