PDFSigner.java
/*
* GovWay - A customizable API Gateway
* https://govway.org
*
* Copyright (c) 2005-2024 Link.it srl (https://link.it).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3, as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.openspcoop2.utils.pdf;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.interactive.digitalsignature.ExternalSigningSupport;
import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature;
import org.bouncycastle.cert.jcajce.JcaCertStore;
import org.bouncycastle.cms.CMSSignedData;
import org.bouncycastle.cms.CMSSignedDataGenerator;
import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
import org.openspcoop2.utils.UtilsException;
import org.openspcoop2.utils.certificate.KeyStore;
import org.openspcoop2.utils.date.DateManager;
/**
* PDFSigner
*
* @author Andrea Poli (apoli@link.it)
* @author $Author$
* @version $Rev$, $Date$
*/
public class PDFSigner extends AbstractPDFCore {
private PDSignature signature;
public PDFSigner(PDDocument doc, PDSignature signature) throws UtilsException {
super(doc);
this.signature = signature;
}
public PDFSigner(byte[] content, PDSignature signature) throws UtilsException {
super(content, false);
this.signature = signature;
}
public PDFSigner(File doc, PDSignature signature) throws UtilsException {
super(doc, false);
this.signature = signature;
}
public PDFSigner(InputStream is, PDSignature signature) throws UtilsException {
super(is, false);
this.signature = signature;
}
public PDFSigner(PDDocument doc,
String name,COSName filter,COSName subfilter, String location, String reason, String contactInfo) throws UtilsException {
super(doc);
init(name, filter, subfilter, location, reason, contactInfo);
}
public PDFSigner(byte[] content,
String name,COSName filter,COSName subfilter, String location, String reason, String contactInfo) throws UtilsException {
super(content, false);
init(name, filter, subfilter, location, reason, contactInfo);
}
public PDFSigner(File doc,
String name,COSName filter,COSName subfilter, String location, String reason, String contactInfo) throws UtilsException {
super(doc, false);
init(name, filter, subfilter, location, reason, contactInfo);
}
public PDFSigner(InputStream is,
String name,COSName filter,COSName subfilter, String location, String reason, String contactInfo) throws UtilsException {
super(is, false);
init(name, filter, subfilter, location, reason, contactInfo);
}
private void init(String name,COSName filter,COSName subfilter, String location, String reason, String contactInfo) throws UtilsException {
try {
if(name==null) {
throw new UtilsException("Name undefined");
}
this.signature = new PDSignature();
this.signature.setName(name);
this.signature.setFilter(filter);
this.signature.setSubFilter(subfilter);
this.signature.setLocation(location);
this.signature.setReason(reason);
this.signature.setContactInfo(contactInfo);
this.signature.setSignDate(DateManager.getCalendar());
}catch(Exception e) {
throw new UtilsException(e.getMessage(),e);
}
}
public void sign(KeyStore keystore, String privateKeyAlias, String privateKeyPassword, File fileOutput) throws UtilsException {
sign(keystore, privateKeyAlias, privateKeyPassword, null, fileOutput);
}
public void sign(KeyStore keystore, String privateKeyAlias, String privateKeyPassword, String algorithm, File fileOutput) throws UtilsException {
if(fileOutput==null) {
throw new UtilsException("Output file undefined");
}
try(FileOutputStream fout = new FileOutputStream(fileOutput)){
sign(keystore, privateKeyAlias, privateKeyPassword, algorithm, fout);
}catch(Exception e) {
throw new UtilsException(e.getMessage(),e);
}
}
public byte[] sign(KeyStore keystore, String privateKeyAlias, String privateKeyPassword) throws UtilsException {
String algorithm = null;
return sign(keystore, privateKeyAlias, privateKeyPassword, algorithm);
}
public byte[] sign(KeyStore keystore, String privateKeyAlias, String privateKeyPassword, String algorithm) throws UtilsException {
try(ByteArrayOutputStream bout = new ByteArrayOutputStream()){
sign(keystore, privateKeyAlias, privateKeyPassword, algorithm, bout);
bout.flush();
return bout.toByteArray();
}catch(Exception e) {
throw new UtilsException(e.getMessage(),e);
}
}
public void sign(KeyStore keystore, String privateKeyAlias, String privateKeyPassword, OutputStream output) throws UtilsException {
sign(keystore, privateKeyAlias, privateKeyPassword, null, output);
}
public void sign(KeyStore keystore, String privateKeyAlias, String privateKeyPassword, String algorithm, OutputStream output) throws UtilsException {
try {
this.document.addSignature(this.signature);
ExternalSigningSupport externalSigning = this.document.saveIncrementalForExternalSigning(output);
byte[] cmsSignature = sign(keystore, privateKeyAlias, privateKeyPassword, algorithm, externalSigning.getContent());
externalSigning.setSignature(cmsSignature);
}catch(Exception e) {
throw new UtilsException(e.getMessage(),e);
}
}
private byte[] sign(KeyStore keystore, String privateKeyAlias, String privateKeyPassword, String algorithm, InputStream content) throws UtilsException
{
if(keystore==null) {
throw new UtilsException("KeyStore undefined");
}
if(privateKeyAlias==null) {
throw new UtilsException("privateKeyAlias undefined");
}
if(privateKeyPassword==null) {
throw new UtilsException("privateKeyPassword undefined");
}
try{
Certificate[] certificateChain = keystore.getCertificateChain(privateKeyAlias);
CMSSignedDataGenerator cmsSignedDataGenerator = new CMSSignedDataGenerator();
X509Certificate cert = (X509Certificate) certificateChain[0];
if(algorithm==null) {
algorithm = "SHA256WithRSA";
}
ContentSigner signer = new JcaContentSignerBuilder(algorithm).build(keystore.getPrivateKey(privateKeyAlias, privateKeyPassword));
cmsSignedDataGenerator.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().build()).build(signer, cert));
cmsSignedDataGenerator.addCertificates(new JcaCertStore(Arrays.asList(certificateChain)));
PDFSignatureCMSTypedData signatureCMSTypedData = new PDFSignatureCMSTypedData(content, null);
CMSSignedData signedData = cmsSignedDataGenerator.generate(signatureCMSTypedData, false);
return signedData.getEncoded();
}
catch (Exception e) {
throw new UtilsException(e.getMessage(),e);
}
}
}