Sign a signed-PDF with it's hash value

New Here ,
Apr 12, 2021 Apr 12, 2021

Copy link to clipboard

Copied

I have to do the followingto an existing PDF document,  programatically using PDFBox::

 

1. Open the existing document (as a PDDocument object)

1. Create a Signature object.

2. Set the Name, Location, Reason and SignDate properties.

3. Add the Signature to tee document.

4. Save as Signed PDF docuument.

5. Get the Hash value of the Signed PDF document.

6. Sign the Signed PDF docuument.with the Hash value.

All works fine except when I open in Acrobat, T get the error 'At least one signature is invalid''. If I expaind the  errror, I get:
 - Signature is invalid.

    - Document has been altered or corrupted since last it was signed.

    - Signer's identity is valid.

    - Signin ttime is from the clock ...

The signatures are validd if I do (6) above using thee contents of the Signed PDF instead on iit's Hasd value.

Wham am I doing wrong?

Is 'Signing' the document using a Hash value supported?

 

Many thanks in advance.

 

TOPICS
Create PDFs, Security digital signatures and esignatures

Views

532

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Apr 12, 2021 Apr 12, 2021

Copy link to clipboard

Copied

I'm not quite sure what you are trying to do. If you apply a digital signature to a document, you are signing the hash value of the document (technically, the hash of everything except the signature itself, since you can't hash that becsuse you don't know what the signature bytes will be until after you generate them). Why would you then need to take another hash of the document? Checking a signature involves taking a hash of all of the bytes of the document except for the signature. If you use a different value for your "hash" then the signature will be invalid.

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
New Here ,
Apr 13, 2021 Apr 13, 2021

Copy link to clipboard

Copied

[deleted per user’s request]

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Contributor ,
Apr 13, 2021 Apr 13, 2021

Copy link to clipboard

Copied

LATEST
quote

This my requirements "The function getDocumentHash is returning the pdf content and not a hash of the pdf content - needs to return hash - (can potentially digest the content using SHA-256), and then sign that and embed it in the PDF"

"and then sign that" in particular means that you have to also adapt the `sign` method, see below. That's merely standard BouncyCastle usage.

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Contributor ,
Apr 13, 2021 Apr 13, 2021

Copy link to clipboard

Copied

In your question title you say you want to "Sign a signed-PDF". Does that mean the PDF you want to sign already has an integrated digital signature? If that is the case, you have to first check whether adding another signature is allowed at all (the previous signatures may forbid that), and then you have to make sure you save your changes as an incremental update (PDDocument has saveIncremental methods for that task; beware, they require marking or collecting the changed COS objects).

 

Two further remarks:

 

5. Get the Hash value of the Signed PDF document.

I hope you mean that you hash the signed byte ranges, not the whole document...

 

6. Sign the Signed PDF docuument.with the Hash value.The signatures are validd if I do (6) above using thee contents of the Signed PDF instead on iit's Hasd value.

Wham am I doing wrong?

Is 'Signing' the document using a Hash value supported?

Signing digitally always involves hashing. But maybe the signing API method you use in your step 6 also does calculate a hash. In that case you indeed have to call that method for the whole prepared PDF and let that method calculate the hash, or you have to switch to a different signing method (of the same or of a different API) that expects a hash value as input.

 

Without your code and without details of the signing API you use, we can only guess.

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
New Here ,
Apr 13, 2021 Apr 13, 2021

Copy link to clipboard

Copied

Many thanks for your replies. Here are the main portions of my code.

public class PdfBoxLTV implements SignatureInterface {

public static void main(String[] args) throws Exception {
try {
String certificatePass = "123456";
String certificateFilePath = "C:\\pathToCertificate\\certificate.p12";
String pdfFilePath = "C:\\pathToPDF\\file.pdf";
String cryptographic = "SHA-256"; //"SHA-256";

initialise(certificatePass, certificateFilePath, pdfFilePath);

scanAndSetSignature();

InputStream documentHash = getDocumentHash(cryptographic);

signSignature(documentHash);

AddValidationInformation.setLTV(signedFile);
} catch (FileNotFoundException fex) {
fex.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}

....


public static void signSignature(InputStream documentHash) throws Exception {
PdfBoxLTV detachedPkcs7 = new PdfBoxLTV();

// get the pdf document hash, and apply signature to pdf
byte[] cmsSignature = detachedPkcs7.sign(documentHash);

// apply signature to the pdf using the returned signed bytes
externalSigning.setSignature(cmsSignature);
}

 

private static void scanAndSetSignature() {
int accessPermissions = SigUtils.getMDPPermission(document);
if (accessPermissions == 1) {
throw new IllegalStateException("No changes to the document are permitted due to DocMDP transform parameters dictionary");
}

System.out.println("ENTER NAME: ");
Scanner s = new Scanner(System.in);
final String mName = s.nextLine();
System.out.println("ENTER LOCATION: ");
final String mLocation = s.nextLine();
System.out.println("ENTER REASON: ");
final String mReason = s.nextLine();
s.close();

System.out.println("You entered : \nNAME : " + mName + "\nLOCATION : " + mLocation + "\nREASON : " + mReason);
System.out.println("Signing...");

// sign a PDF with an existing empty signature, as created by the CreateEmptySignatureForm example.
signature = findExistingSignature(document, null);

if (signature == null) {
// create signature dictionary
signature = new PDSignature();
}

signature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE);
signature.setSubFilter(PDSignature.SUBFILTER_ADBE_PKCS7_DETACHED);
signature.setName(mName);
signature.setLocation(mLocation);
signature.setReason(mReason);

Calendar date = Calendar.getInstance();
signature.setSignDate(date);
}
public static InputStream getDocumentHash(String cryptographic) throws Exception {
document.addSignature(signature);

externalSigning = document.saveIncrementalForExternalSigning(signedOutputStream);

if (cryptographic.length() == 0) {
return externalSigning.getContent();
}

byte[] contentBytes = externalSigning.getContent().readAllBytes();
byte[] hashBytes = MessageDigest.getInstance(cryptographic, new BouncyCastleProvider()).digest(contentBytes);
InputStream hashedInputStream = new ByteArrayInputStream(hashBytes);

return hashedInputStream;
//return externalSigning.getContent();
}

 

[reply edited by moderator]

 

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Contributor ,
Apr 13, 2021 Apr 13, 2021

Copy link to clipboard

Copied

(You really should have used the option to insert a well-formatted code sample here, that would have made reading your code much much easier...)
As already assumed in my previous message, your implementation of the `sign` method calculates a digest of the data from its `InputStream` parameter. Thus, you have to feed it the prepared PDF except the placeholder for the signature to inject, not its hash.

That actually is what the `SignatureInterface` you implement is designed for: It is called by the respective PDFBox `COSWriter` or `CreateSignature` example with an `InputStream` covering the (to-be-)signed byte ranges of the prepared PDF.

If you want to calculate the hash value separately, you have to adapt your `sign` method accordingly. And then it doesn't make sense anymore to implement that `SignatureInterface` as you don't honor its contract anymore.

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Apr 13, 2021 Apr 13, 2021

Copy link to clipboard

Copied

You seem to be modifying the document after signing, which will break the signature, by design. However, I look at the PDFBox API it says "AddValidationInformation...An example for adding Validation Information to a signed PDF, inspired by ETSI TS 102 778-4 V1.1.2 (2009-12), Part 4: PAdES Long Term - PAdES-LTV Profile. This procedure appends the Validation Information of the last signature (more precise its signer(s)) to a copy of the document. The signature and the signed data will not be touched and stay valid."  

 

Since you are using an API which claims to do want you want, but doesn't seem to be doing that, you need to contact the support for PDFBox. 

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Contributor ,
Apr 13, 2021 Apr 13, 2021

Copy link to clipboard

Copied

quote

Since you are using an API which claims to do want you want, but doesn't seem to be doing that, you need to contact the support for PDFBox. 

Well, actually he feeds the API other data than the API is designed for (a hash where the to-be signed byte ranges are expected), so that wouldn't be a support call but a request for a different feature...

 

 

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
New Here ,
Apr 13, 2021 Apr 13, 2021

Copy link to clipboard

Copied

Many Thanks for this confirmation!

Just to confirm regarding your comment "You seem to be modifying the document after signing, which will break the signature, by design.":

Is the comment in the context of my:
1. signSignature() function, and consequently the sign() function of the SignatureInterface; or,
2. AddValidationInformation.setLTV() function call?

Many Thanks

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Adobe Community Professional ,
Apr 13, 2021 Apr 13, 2021

Copy link to clipboard

Copied

I recommend you ask in the PDFBox mailing list: [users at pdfbox.apache.org]

Likes

Translate

Translate

Report

Report
Community Guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines