具有多个签名的 iText7 PDF
iText7 PDF with multiple signatures
我正在将代码从 iText5 迁移到 iText7,目前我正在努力将一个签名附加到已经包含另一个签名的 PDF。
这些签名是用我们的国民身份证(公民卡)做的。
在 iText5 中我使用了 PdfStamper 但它在 iText7 中丢失了...
这是我目前拥有的:
package cartaocidadao;
import java.io.FileOutputStream;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Security;
import java.security.cert.Certificate;
import javax.swing.JOptionPane;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.poreid.config.POReIDConfig;
import org.poreid.crypto.POReIDProvider;
import com.itextpdf.signatures.OcspClientBouncyCastle;
import com.itextpdf.signatures.TSAClientBouncyCastle;
import java.io.IOException;
import java.util.Collection;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.signatures.BouncyCastleDigest;
import com.itextpdf.signatures.ICrlClient;
import com.itextpdf.signatures.DigestAlgorithms;
import com.itextpdf.signatures.IExternalDigest;
import com.itextpdf.signatures.IExternalSignature;
import com.itextpdf.signatures.IOcspClient;
import com.itextpdf.signatures.PdfSignatureAppearance;
import com.itextpdf.signatures.PdfSigner;
import com.itextpdf.signatures.PrivateKeySignature;
import com.itextpdf.signatures.ITSAClient;
import com.itextpdf.signatures.OCSPVerifier;
import java.security.GeneralSecurityException;
import static javax.swing.JOptionPane.ERROR_MESSAGE;
/**
*
* @author i.lourenco
*/
public class Signature {
/**
* Signs the PDF with the Citizen Card Certificate
* @param src Source file
* @param dest Destination file
* @return TRUE if the PDF was signed successfully
*/
protected static boolean signPDF(String src, String dest) {
try {
Security.addProvider(new POReIDProvider());
BouncyCastleProvider provider = new BouncyCastleProvider();
Security.addProvider(provider);
KeyStore ks = KeyStore.getInstance(POReIDConfig.POREID);
ks.load(null);
PrivateKey pk = (PrivateKey) ks.getKey(POReIDConfig.ASSINATURA, null);
Certificate[] chain = ks.getCertificateChain(POReIDConfig.ASSINATURA);
OCSPVerifier ocspVerifier = new OCSPVerifier(null, null);
IOcspClient ocspClient = new OcspClientBouncyCastle(ocspVerifier);
ITSAClient tsaClient = new TSAClientBouncyCastle("http://ts.cartaodecidadao.pt/tsa/server", "", "");
sign(src, dest, chain, pk, DigestAlgorithms.SHA256, POReIDConfig.POREID, PdfSigner.CryptoStandard.CMS, "", "", null, ocspClient, tsaClient, 0);
} catch (Exception e) {
JOptionPane.showMessageDialog(null, e.getMessage(), "Erro", ERROR_MESSAGE);
}
return true;
}
/**
* Applies the certificate, timestamp and revocation list to a PDF
* @param src Original PDF document
* @param dest Signed PDF document
* @param chain List of certificates
* @param pk Private key
* @param digestAlgorithm Encryption algorithm
* @param provider Citizen Card provider
* @param subfilter CMS
* @param reason Reason for signature
* @param location Location
* @param crlList Revocation list
* @param ocspClient Online Certification Status
* @param tsaClient Timestamp server
* @param estimatedSize
* @throws IOException
* @throws GeneralSecurityException
*/
private static void sign(String src, String dest, Certificate[] chain, PrivateKey pk, String digestAlgorithm,
String provider, PdfSigner.CryptoStandard subfilter, String reason, String location, Collection<ICrlClient> crlList,
IOcspClient ocspClient, ITSAClient tsaClient, int estimatedSize) throws IOException, GeneralSecurityException {
PdfReader reader = new PdfReader(src);
PdfSigner signer = new PdfSigner(reader, new FileOutputStream(dest), false);
PdfSignatureAppearance appearance = signer.getSignatureAppearance()
.setReason(reason)
.setLocation(location)
.setReuseAppearance(false);
Rectangle rect = new Rectangle(36, 648, 200, 100);
appearance.setPageRect(rect).setPageNumber(1);
signer.getNewSigFieldName();
IExternalSignature pks = new PrivateKeySignature(pk, digestAlgorithm, provider);
IExternalDigest digest = new BouncyCastleDigest();
signer.signDetached(digest, pks, chain, crlList, ocspClient, tsaClient, estimatedSize, subfilter);
}
}
POReID (https://github.com/poreid/poreid) 是用于与智能卡交互的库。
第一次签署文档时,它工作正常。再次签署文件时,第一个签名失效,只有最后一个有效。
PDF:
您的签名代码不是以附加模式打开PDF,因此会在第二次签名时改变内容,破坏第一次签名。
要以附加模式登录,只需更改以下行
PdfSigner signer = new PdfSigner(reader, new FileOutputStream(dest), false);
至
PdfSigner signer = new PdfSigner(reader, new FileOutputStream(dest), true);
构造函数中的第三个参数决定签名者是否以附加模式使用。
我正在将代码从 iText5 迁移到 iText7,目前我正在努力将一个签名附加到已经包含另一个签名的 PDF。 这些签名是用我们的国民身份证(公民卡)做的。
在 iText5 中我使用了 PdfStamper 但它在 iText7 中丢失了...
这是我目前拥有的:
package cartaocidadao;
import java.io.FileOutputStream;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Security;
import java.security.cert.Certificate;
import javax.swing.JOptionPane;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.poreid.config.POReIDConfig;
import org.poreid.crypto.POReIDProvider;
import com.itextpdf.signatures.OcspClientBouncyCastle;
import com.itextpdf.signatures.TSAClientBouncyCastle;
import java.io.IOException;
import java.util.Collection;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.signatures.BouncyCastleDigest;
import com.itextpdf.signatures.ICrlClient;
import com.itextpdf.signatures.DigestAlgorithms;
import com.itextpdf.signatures.IExternalDigest;
import com.itextpdf.signatures.IExternalSignature;
import com.itextpdf.signatures.IOcspClient;
import com.itextpdf.signatures.PdfSignatureAppearance;
import com.itextpdf.signatures.PdfSigner;
import com.itextpdf.signatures.PrivateKeySignature;
import com.itextpdf.signatures.ITSAClient;
import com.itextpdf.signatures.OCSPVerifier;
import java.security.GeneralSecurityException;
import static javax.swing.JOptionPane.ERROR_MESSAGE;
/**
*
* @author i.lourenco
*/
public class Signature {
/**
* Signs the PDF with the Citizen Card Certificate
* @param src Source file
* @param dest Destination file
* @return TRUE if the PDF was signed successfully
*/
protected static boolean signPDF(String src, String dest) {
try {
Security.addProvider(new POReIDProvider());
BouncyCastleProvider provider = new BouncyCastleProvider();
Security.addProvider(provider);
KeyStore ks = KeyStore.getInstance(POReIDConfig.POREID);
ks.load(null);
PrivateKey pk = (PrivateKey) ks.getKey(POReIDConfig.ASSINATURA, null);
Certificate[] chain = ks.getCertificateChain(POReIDConfig.ASSINATURA);
OCSPVerifier ocspVerifier = new OCSPVerifier(null, null);
IOcspClient ocspClient = new OcspClientBouncyCastle(ocspVerifier);
ITSAClient tsaClient = new TSAClientBouncyCastle("http://ts.cartaodecidadao.pt/tsa/server", "", "");
sign(src, dest, chain, pk, DigestAlgorithms.SHA256, POReIDConfig.POREID, PdfSigner.CryptoStandard.CMS, "", "", null, ocspClient, tsaClient, 0);
} catch (Exception e) {
JOptionPane.showMessageDialog(null, e.getMessage(), "Erro", ERROR_MESSAGE);
}
return true;
}
/**
* Applies the certificate, timestamp and revocation list to a PDF
* @param src Original PDF document
* @param dest Signed PDF document
* @param chain List of certificates
* @param pk Private key
* @param digestAlgorithm Encryption algorithm
* @param provider Citizen Card provider
* @param subfilter CMS
* @param reason Reason for signature
* @param location Location
* @param crlList Revocation list
* @param ocspClient Online Certification Status
* @param tsaClient Timestamp server
* @param estimatedSize
* @throws IOException
* @throws GeneralSecurityException
*/
private static void sign(String src, String dest, Certificate[] chain, PrivateKey pk, String digestAlgorithm,
String provider, PdfSigner.CryptoStandard subfilter, String reason, String location, Collection<ICrlClient> crlList,
IOcspClient ocspClient, ITSAClient tsaClient, int estimatedSize) throws IOException, GeneralSecurityException {
PdfReader reader = new PdfReader(src);
PdfSigner signer = new PdfSigner(reader, new FileOutputStream(dest), false);
PdfSignatureAppearance appearance = signer.getSignatureAppearance()
.setReason(reason)
.setLocation(location)
.setReuseAppearance(false);
Rectangle rect = new Rectangle(36, 648, 200, 100);
appearance.setPageRect(rect).setPageNumber(1);
signer.getNewSigFieldName();
IExternalSignature pks = new PrivateKeySignature(pk, digestAlgorithm, provider);
IExternalDigest digest = new BouncyCastleDigest();
signer.signDetached(digest, pks, chain, crlList, ocspClient, tsaClient, estimatedSize, subfilter);
}
}
POReID (https://github.com/poreid/poreid) 是用于与智能卡交互的库。
第一次签署文档时,它工作正常。再次签署文件时,第一个签名失效,只有最后一个有效。
PDF:
您的签名代码不是以附加模式打开PDF,因此会在第二次签名时改变内容,破坏第一次签名。
要以附加模式登录,只需更改以下行
PdfSigner signer = new PdfSigner(reader, new FileOutputStream(dest), false);
至
PdfSigner signer = new PdfSigner(reader, new FileOutputStream(dest), true);
构造函数中的第三个参数决定签名者是否以附加模式使用。