简体   繁体   中英

Java PdfBox - PDF Sign Problem -External Signature -Invalid signature There are errors in formatting or in the information contained in this signature

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM