I'm having problems signing pdf's with pdfbox. The idea is the same as used with itext ( Java IText7 PDF Sign Problem - Document has been altered or corrupted since it was signed ). Get bytearray from a pdf with empty signature, send byte array to an external entity that returns a hash-signature, and embed that hash in pdf with empty signature.
PDF error: Invalid signature There are errors in formatting or in the information contained in this signature.
The java code (small resume) that i use are:
//GET External signing content
PDDocument doc = PDDocument.load(inputPDF);
PDSignature signature = new PDSignature();
signature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE); // default filter
signature.setSubFilter(PDSignature.SUBFILTER_ADBE_PKCS7_DETACHED);
signature.setReason(sigReason);
signature.setLocation(sigLocation);
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
Calendar cal = Calendar.getInstance();
cal.setTime(sdf.parse(sdf.format(forcedDate)));
signature.setSignDate(cal);
SignatureOptions signatureOptions = new SignatureOptions();
signatureOptions.setPreferredSignatureSize(SignatureOptions.DEFAULT_SIGNATURE_SIZE * 8);
doc.addSignature(signature,signatureOptions);
ExternalSigningSupport externalSigningSupport = doc.saveIncrementalForExternalSigning(null);
byte[] content = IOUtils.toByteArray(externalSigningSupport.getContent());
MessageDigest md = MessageDigest.getInstance("SHA256", new BouncyCastleProvider());
hashtosign = md.digest(content); // this is sent to client
return hashtosign;
// CALL AMA(entity - external client webservice) TO GET SIGNATURE-HASH (signatureHash)
String hashToSendAMA = SafePdfHelper.getHashtoSign(hashtosign);
String signatureHash_B64 = SafeAmaHelper.getAssinat(token,hashToSendAMA,"tst_nunommc",credentialID).getSignatures().get(0);
// SIGNATURE-HASH
byte[] signatureHash = Base64.getDecoder().decode(String.valueOf(signatureHash_B64.toCharArray()));
//InsertHash SIGNATURE-HASH in PDF
#code
ExternalSigningSupport externalSigningSupport = doc.saveIncrementalForExternalSigning(fosSigned);
externalSigningSupport.setSignature(signatureHash);
doc.save("C:/INTEGRACOES/Ama/omitf/tst_signed.pdf");
return "Signed";
Base64 format of the signature (AMA) is: PMPk04d/sj5OxRZpZfGSJlrQthryaWjmj6tNs3a7g3CgOB02c/a9omVaZD1Upl87XI/FvVMBMoKlGcm7MRO+ENgKApr9O1/joKN5dnucm11OXL8rxov/EAV8cQOLqCVTNvsDDylDy1L7LdYSBCDzvqCKmR8OF7955wyZJeTDiCcYDm3gGN9IDQ82fwMKPuiIt7e1ToZdm7qzLBLTr38K2eM784NUNCFMI152QdtZIxQHl03qXk6IrNoWxW0axh9YcJmbBWlkUo75wm6BjuJzkPOYgaT4/CWTyjuCKtYg748gQQmh89xbBswmtZxw7NRVRXl4DtWE9ceRClKZx0JrIawzkWNhJt42+u62ntNs/Z4a/LRNg8rfmru2C9mhqZ5h6jfIJzk9bX219csIekM46pXofEizAnnMTjDZLWYedHFWojJGybdA76fVlBQx+9nTA7xD/gqDY9NUKW0bjfF9j+diHxNZklZ+0+RzUMF9l3Pq9Hlg2InaZM08yUyhdSYl
Can anyone help please?
-sorry for the bad formatting post
I already found a solution. The key was to create a CMS signature container with BouncyCastle.
public static byte[] createSignature(InputStream content, Certificate [] chain, String fileName) throws Exception {
//BufferedInputStream bis = new BufferedInputStream(content);
List<Certificate> certList = new ArrayList<>();
for (Certificate cert: chain){
certList.add(cert);
}
Store certs = new JcaCertStore(certList);
CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
gen.addCertificates(certs);
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte [] hashBytes = digest.digest(content.readAllBytes());
String hashToSign = SafePdfHelper.getHashtoSign(hashBytes);
String signatureHash_B64 = SafeAmaHelper.getAssinat(token,hashToSign,fileName,credentialID).getSignatures().get(0); //GET SIGNHASH WITH A EXTERNAL ENTITY
byte[] signedHash = Base64.getDecoder().decode(String.valueOf(signatureHash_B64.toCharArray()));
ContentSigner nonSigner = new ContentSigner() {
@Override
public byte[] getSignature() {
return signedHash;
}
@Override
public OutputStream getOutputStream() {
return new ByteArrayOutputStream();
}
@Override
public AlgorithmIdentifier getAlgorithmIdentifier() {
return new DefaultSignatureAlgorithmIdentifierFinder().find("SHA256WithRSA");
}
};
JcaSignerInfoGeneratorBuilder sigb = new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().build());
sigb.setDirectSignature(true);
for (Certificate cert: chain){
//Certificate x = cert;
org.bouncycastle.asn1.x509.Certificate certx509 = org.bouncycastle.asn1.x509.Certificate.getInstance(ASN1Primitive.fromByteArray(cert.getEncoded()));
gen.addSignerInfoGenerator(sigb.build(nonSigner, new X509CertificateHolder(certx509)));
}
CMSTypedData msg = new CMSProcessableInputStream(new ByteArrayInputStream("not used".getBytes()));
CMSSignedData signedData = gen.generate(msg, false);
byte[] signature = signedData.getEncoded();
return signature;
}
thanks @mkl
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.