I have a PDF file signed and .p7s file. I need retrieve .p7s from PDF and co-sign the PDF (generating other .p7s).
After I need put again the p7s into PDF file.
I get this error when I try get p7s from PDF:
ExceptionConverter: java.security.SignatureException: object not initialized for signing
My code:
BouncyCastleProvider provider = new BouncyCastleProvider();
Security.addProvider(provider);
PdfReader pdfReader = new
PdfReader(Files.readAllBytes(inputFile.toPath()));
AcroFields acroFields = pdfReader.getAcroFields();
List<String> signatures = acroFields.getSignatureNames();
for (String name : signatures) {
PdfPKCS7 pdfPkcs7 = acroFields.verifySignature(name, "BC");
Files.write(Paths.get("~/TEST/itext/"+ name +".p7s"),
pdfPkcs7.getEncodedPKCS7());//ERROR HERE!
}
In Theory
You want to co-sign the PDF (counter-sign? parallel-sign?) by extracting an embedded CMS signature container from a PDF, adding your signature to it, and re-embedding the extended container.
This is the wrong approach, PDF signing is designed to contain a single signature only per PDF signature field and the CMS signature container we talk about essentially is the value of such a field, so each embedded signature container shall contain exactly one signature.
Strictly speaking the PDF specification allows you to use arbitrary custom signing schemes, only "interoperable signatures" are limited. Thus, your signature containers with multiple signatures could be considered valid PDF, merely not "interoperably signed", i.e. you shouldn't expect any other software to interpret the signature like you do. In particular Adobe Acrobat Reader will recognize and display only one of those signatures.
(Indeed also some large scale signing solution providers have embedded multi-signature CMS containers in PDFs. E.g. currently I have to deal with signatures generated by some such a provider who embeds arbitrary CAdES-A signature containers (in particular some with multiple signers) into PDFs and calls this signature format PDF/CAdES-A, and now I have to explain to their customers that their signatures are PDF signatures all right but not interoperable ones even though that name PDF/CAdES-A sounds like some awesome standard...)
Multiple signatures in PDFs for interoperability must be applied sequentially like visualized in this sketch:
For some backgrounds and links to more information, cf. this answer.
In practice
Your code appears to be iText 5.5.x code, in particular not yet iText 7.x code. In that case you can use the code from the Digital Signatures for PDF Documents white book by Bruno Lowagie as is.
A very simple example:
public void sign(String src, String dest, Certificate[] chain, PrivateKey pk, String digestAlgorithm,
String provider, CryptoStandard subfilter, String reason, String location)
throws GeneralSecurityException, IOException, DocumentException {
// Creating the reader and the stamper
PdfReader reader = new PdfReader(src);
FileOutputStream os = new FileOutputStream(dest);
PdfStamper stamper = PdfStamper.createSignature(reader, os, '\0');
// Creating the appearance
PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
appearance.setReason(reason);
appearance.setLocation(location);
appearance.setVisibleSignature(new Rectangle(36, 748, 144, 780), 1, "sig");
// Creating the signature
ExternalDigest digest = new BouncyCastleDigest();
ExternalSignature signature = new PrivateKeySignature(pk, digestAlgorithm, provider);
MakeSignature.signDetached(appearance, digest, signature, chain, null, null, null, 0, subfilter);
}
(Code sample 2.1: the “Hello World” of signing with iText)
As your use case involves signing an already signed document, you merely have to change the PdfStamper.createSignature
line to
PdfStamper stamper = PdfStamper.createSignature(reader, os, '\0', true);
(notice the new boolean argument at the end). This change causes the signature to be created in append mode which leaves the former revision with the original signature as is to not invalidate that signature.