vbuch / node-signpdf

Simple signing of PDFs in node.
MIT License
719 stars 178 forks source link

Problem signing more than once on some PDF files. #75

Closed therpobinski closed 4 years ago

therpobinski commented 4 years ago

Hi guys, I hope you can help me. I have a pdf that I want to sign more than once. When I sign the first time, it usually does, but when I sign the second time, I have an error signing. I thought the error was somewhat similar to before when we added links, but I think the error is another. I hope you can help me. This is the pdf signed and with error.

therpobinski commented 4 years ago

I have reviewed the signed trailer twice and I really can't find the problem. Can anyone help me find the error?

<< 
/Size 11
/Info 10 0 R
/Root 2 0 R
>>
startxref
19125
%%EOF
12 0 obj
<<
/Type /Sig
/Filter /Adobe.PPKLite
/SubFilter /adbe.pkcs7.detached
/ByteRange [0 19575 24739 848]                    
/Contents <3082063406092a864886f70d010702a082062530820621020101310f300d06096086480165030402010500300b06092a864886f70d010701a08203d5308203d1308202b9a003020102020900ae9142f187059c8c300d06092a864886f70d0101050500307f310b3009060355040613024247310e300c06035504080c05536f666961310e300c06035504070c05536f66696131153013060355040a0c0c6e6f64652d7369676e7064663110300e06035504030c075369676e5064663127302506092a864886f70d01090116186e6f64652d7369676e706466406578616d706c652e636f6d301e170d3138303932353135323434335a170d3138313032353135323434335a307f310b3009060355040613024247310e300c06035504080c05536f666961310e300c06035504070c05536f66696131153013060355040a0c0c6e6f64652d7369676e7064663110300e06035504030c075369676e5064663127302506092a864886f70d01090116186e6f64652d7369676e706466406578616d706c652e636f6d30820122300d06092a864886f70d01010105000382010f003082010a02820101009d36edaf2f5c7c0bfc62b35aff43be0b6b3c44c389b351ee69d516b62e969e7c6c3c2453e115123690e996363066ff4168af36627b7dbd1878e934b3b4402f6cab6b03a33669841220a49ed598a554553bc8a676707af847efed91857792c7de73cf1f1c78f16281ddcda6dac68c427d125f3b26504ba3785a99cb6e2090a58f98a9db72eb2a178bdeca52685fb491be5a71d52a8927b9574de93714379e8feb37115fea86accb199fd6eaa93cbe80b50a3166e0e5f3b5331a68905067e8e2c510d00117d343c8080b60424de8dfdd1865a2fe35dfd1aebbba126c8cd9ecf4f4ffaa9f95af1254be33f60f76888a0adc33025ab419ceafa9d05f7358614c08410203010001a350304e301d0603551d0e04160414cca979107f2430a51a3e0195fe8993dea7759c81301f0603551d23041830168014cca979107f2430a51a3e0195fe8993dea7759c81300c0603551d13040530030101ff300d06092a864886f70d010105050003820101008c116c5362c7717204d6b2b9c035f874433c48645bb05eed2e23e6216975769495496bb7cb7d4b7f2daec77e8de486c5d6c0014cd13f381e0d04ff28eed3050ab310d99d444e9d4ec22d1c88b8a52331ded8ea91572b1003129421cb6134aebc2cf7f2ec56011ae310367bc2c8261350189dee30bed525163577c181a4dad0d47b4e67f3679c61c4b0e59420e13dd153fe67c11026b56b024495a5a78dadde2afe0429c76c197bbb775d327066925b6fda02c3f7e88425ce6eb85196066d48a65735bb55922f6242b6150a76d742550b3fd6b5b8305abd93fdfe16d6b7ab86be1c08eb01bd565161610b8ca13732dcd0a99b90687959f84da4ae0bd1109cbcf8318202233082021f02010130818c307f310b3009060355040613024247310e300c06035504080c05536f666961310e300c06035504070c05536f66696131153013060355040a0c0c6e6f64652d7369676e7064663110300e06035504030c075369676e5064663127302506092a864886f70d01090116186e6f64652d7369676e706466406578616d706c652e636f6d020900ae9142f187059c8c300d06096086480165030402010500a069301806092a864886f70d010903310b06092a864886f70d010701302f06092a864886f70d01090431220420dcb453eb587f3b55000029d02cab83a7a1d27e993fa5c2d33ddd741a1cf1650b301c06092a864886f70d010905310f170d3230303530323138353833365a300d06092a864886f70d0101010500048201006eaff16cc04d02c9612d3683484ce929b8071c295cf404409e9ff838b162ea11a353e76a3800ea1144960ae2a3650ddf67ad421af15f1e7c62b90820a35d133d1534d7349b23f335c4e8eca9d9a83683bc4904ebb0db45807992fc8cff0840d01ac51e9fcee654144afce04745c961c2fcb849ad72e076393a6530b3e7b229218a9774d6a5559a3bb35d1689e9e795cc1cc06bffdf4bebe86fa9461374c326cbb402381d7dda338d0ec538536511ac2ca867da068c95592a8b1340facff35bf7f7f525125efa7fc7b85ef02e5ea8de221cf1d568b55bb13c7a00588678fa2c9093db9b45c5d7f7a3bbc4ce8f294db1c64172a0bd73c02a27c3011f24c6a07f8f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000>
/Reason (first)
/M (D:20200502185836Z)
/ContactInfo (emailfromp1289@gmail.com)
/Name (Name from p12)
/Location (Location from p12)
>>
endobj

13 0 obj
<<
/Type /Annot
/Subtype /Widget
/FT /Sig
/Rect [0 0 0 0]
/V 12 0 R
/T (Signature1)
/F 4
/P 4 0 R
>>
endobj

14 0 obj
<<
/Type /AcroForm
/SigFlags 3
/Fields [13 0 R]
>>
endobj

2 0 obj
<<

/Type /Catalog
/Pages 3 0 R

/AcroForm 14 0 R
>>
endobj

4 0 obj
<<

/Type /Page
/Resources << 
/Font << 
/F1 5 0 R
>>
/ProcSet [/PDF /Text /ImageC]
>>
/Contents 1 0 R
/MediaBox [0 0 594 841]
/Parent 3 0 R
/Annots [ 13 0 R]

>>
endobj

xref
0 1
0000000000 65535 f 
2 1
0000025068 00000 n 
4 1
0000025141 00000 n 
12 1
0000019436 00000 n 
13 1
0000024882 00000 n 
14 1
0000025000 00000 n 
trailer
<<
/Size 15
/Prev 19125
/Root 2 0 R
>>
startxref
19125
/Info 15 0 R
>>
startxref
25331
%%EOF
15 0 obj
<<
/Type /Sig
/Filter /Adobe.PPKLite
/SubFilter /adbe.pkcs7.detached
/ByteRange [0 25727 30891 769]                    
/Contents <3082063406092a864886f70d010702a082062530820621020101310f300d06096086480165030402010500300b06092a864886f70d010701a08203d5308203d1308202b9a003020102020900ae9142f187059c8c300d06092a864886f70d0101050500307f310b3009060355040613024247310e300c06035504080c05536f666961310e300c06035504070c05536f66696131153013060355040a0c0c6e6f64652d7369676e7064663110300e06035504030c075369676e5064663127302506092a864886f70d01090116186e6f64652d7369676e706466406578616d706c652e636f6d301e170d3138303932353135323434335a170d3138313032353135323434335a307f310b3009060355040613024247310e300c06035504080c05536f666961310e300c06035504070c05536f66696131153013060355040a0c0c6e6f64652d7369676e7064663110300e06035504030c075369676e5064663127302506092a864886f70d01090116186e6f64652d7369676e706466406578616d706c652e636f6d30820122300d06092a864886f70d01010105000382010f003082010a02820101009d36edaf2f5c7c0bfc62b35aff43be0b6b3c44c389b351ee69d516b62e969e7c6c3c2453e115123690e996363066ff4168af36627b7dbd1878e934b3b4402f6cab6b03a33669841220a49ed598a554553bc8a676707af847efed91857792c7de73cf1f1c78f16281ddcda6dac68c427d125f3b26504ba3785a99cb6e2090a58f98a9db72eb2a178bdeca52685fb491be5a71d52a8927b9574de93714379e8feb37115fea86accb199fd6eaa93cbe80b50a3166e0e5f3b5331a68905067e8e2c510d00117d343c8080b60424de8dfdd1865a2fe35dfd1aebbba126c8cd9ecf4f4ffaa9f95af1254be33f60f76888a0adc33025ab419ceafa9d05f7358614c08410203010001a350304e301d0603551d0e04160414cca979107f2430a51a3e0195fe8993dea7759c81301f0603551d23041830168014cca979107f2430a51a3e0195fe8993dea7759c81300c0603551d13040530030101ff300d06092a864886f70d010105050003820101008c116c5362c7717204d6b2b9c035f874433c48645bb05eed2e23e6216975769495496bb7cb7d4b7f2daec77e8de486c5d6c0014cd13f381e0d04ff28eed3050ab310d99d444e9d4ec22d1c88b8a52331ded8ea91572b1003129421cb6134aebc2cf7f2ec56011ae310367bc2c8261350189dee30bed525163577c181a4dad0d47b4e67f3679c61c4b0e59420e13dd153fe67c11026b56b024495a5a78dadde2afe0429c76c197bbb775d327066925b6fda02c3f7e88425ce6eb85196066d48a65735bb55922f6242b6150a76d742550b3fd6b5b8305abd93fdfe16d6b7ab86be1c08eb01bd565161610b8ca13732dcd0a99b90687959f84da4ae0bd1109cbcf8318202233082021f02010130818c307f310b3009060355040613024247310e300c06035504080c05536f666961310e300c06035504070c05536f66696131153013060355040a0c0c6e6f64652d7369676e7064663110300e06035504030c075369676e5064663127302506092a864886f70d01090116186e6f64652d7369676e706466406578616d706c652e636f6d020900ae9142f187059c8c300d06096086480165030402010500a069301806092a864886f70d010903310b06092a864886f70d010701302f06092a864886f70d01090431220420a3abb7233ae7083f0a5f511789340754a2582152827a543924d7babc9072289a301c06092a864886f70d010905310f170d3230303530323138353833375a300d06092a864886f70d0101010500048201000a19515c8104bebdad99e358a3b9f5cda43c1cdf64d7045b2e0fe662eb362c43b93b0cb856480379996dc18dec4357a7592e2fb67b31a20e3695df14dbb156f23857a64febfd6fd955d01d5859fd880a8eccf37c8b84d4e056752022bf438088d43414a3e9bbe887883919782e115d6bf74302c7a462d2f550d249b03629433d439447454dfed7193d8fed47e889cb9d60981d3750f20ed14f96f110b354aafacfcded93a7c6c580ccb41fd22c608dc58a5d642aa5c6a8fe94730e782c249ab17b45ba40c50c044fdb13829b7faad4c5d38fc1944e5b3b258060df804464901b4f25e0ca26e4fda18973694212c3995c3597485630ef75fed76dbf9265fc79500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000>
/Reason (second)
/M (D:20200502185837Z)
/ContactInfo (emailfromp1289@gmail.com)
/Name (Name from p12)
/Location (Location from p12)
>>
endobj

16 0 obj
<<
/Type /Annot
/Subtype /Widget
/FT /Sig
/Rect [0 0 0 0]
/V 15 0 R
/T (Signature2)
/F 4
/P 4 0 R
>>
endobj

14 0 obj
<<
/Type /AcroForm
/SigFlags 3
/Fields [13 0 R 16 0 R]
>>
endobj

4 0 obj
<<

/Type /Page
/Resources << 
/Font << 
/F1 5 0 R
>>
/ProcSet [/PDF /Text /ImageC]
>>
/Contents 1 0 R
/MediaBox [0 0 594 841]
/Parent 3 0 R
/Annots [ 13 0 R 16 0 R]

>>
endobj

xref
0 1
0000000000 65535 f 
4 1
0000031228 00000 n 
14 1
0000031153 00000 n 
15 1
0000025588 00000 n 
16 1
0000031035 00000 n 
trailer
<<
/Size 18
/Prev 25331
/Root 2 0 R
>>
startxref
19125
/Info 15 0 R
>>
startxref
31428
%%EOF
vbuch commented 4 years ago

Did you try debugging with https://github.com/ninja-labs-tech/verify-pdf ?

therpobinski commented 4 years ago

I've finished testing it with the library you recommend, but from what I see, I only get the first signature to verify, not all. I did tests with correctly signed PDFs and others with error and it only takes the first signature, not all. I also think the problem is due to some 'ByteRange'. When I sign the first time, everything is correct, but when I sign it the second time, the first signature is damaged and the second is correct. In the PDF viewer it shows me the following message:

Signature is invalid: There are errors in the formatting or information contained in the signature (The signature byte range is invalid)

therpobinski commented 4 years ago

In some cases I use large PDF files, it cuts the pages and replaces them on blank pages.

therpobinski commented 4 years ago

In the library, there is a readRefTable document, this document gets all the references from the PDF, I have noticed that when you sign a second time, the references skip, that is, they are not sequential.

Before the first signature, the document gets this extract.

177 => 1564668, 178 => 1564884, 179 => 1582503, 180 => 1583111, 181 => 1583234, 182 => 1583324, 183 => 1583447, 184 => 1583537, 185 => 1583660, 186 => 1583750, -1 => 0 } }

At the time of getting the references before signing for the second time, there is a jump:

178 => 1564884, 179 => 1582503, 180 => 1583111, 181 => 1583234, 182 => 1583324, 183 => 1583447, 184 => 1583537, 185 => 1583660, 186 => 1583750, 188 => 1587768, 189 => 1604485, 190 => 1604606, -1 => 0 } }

If we see, there is no reference 187, and the same thing happens after signing a second time. Do you think this is why the error occurred? I realize that when I sign the first time there is no problem, until I sign the second time! I still don't know what the problem is. I hope you can help me. Thanks!

therpobinski commented 4 years ago

I found something that seems to be the problem. Every time you add the placeholder for the second signature, it will already corrupt the PDF. Looking for a problem, I noticed that according to the PDF spec, there should only be one startxref for each trailer, that is, for each signature, here I found that 2 startxref were added in a trailer and even plus closes the object without being open with >>.

Here the image of what I explain. On the right side we find the image with a single startxref, and the PDF files that are properly signed only have a startxref for each trailer, but for some reason an additional startxref was added to the image of a the left and closing this with >>.

imagen

Now my question is where can you find the function that this startxref adds? and in which cases add new ones? To solve the problem. I think with this concern you can help me @vbuch Thanks!

vbuch commented 4 years ago

It is great that you found and fixed the issue. That's what the repo is all about. I've written a comment in the related PR #76

therpobinski commented 4 years ago

The issue regarding startxref has been fixed, but now there is another issue!

imagen The second signature cannot be verified and worse, it leaves the first sheet blank.

But when I check the Buffer, I see that if the signature exists and there is no more than one startxref for each trailer. Now what do you think is the problem? imagen

@vbuch, You think you can keep this issue open until you fix it.

therpobinski commented 4 years ago

Hi guys, the bug has been fixed. The problem is that the library was looking for the AcroForm assuming that PDFs would always have a maximum of 99 objects, that is, they would have up to 2 digits, but the problem occurred when it was necessary to sign larger PDFs that have objects with more digits In my case, PDF files had up to 3 digits the first number of the object (eg 390 0 obj).

This can be seen in this line of your code @vbuch lineError

In this line of code, you will see that once the AcromForm is found, it goes back 12 spaces, which means that if the object has more digits than 2, it doesn't take the full id. For this, with the help of @mgyugcha we were able to solve the problem. We use regular expressions to get the acroformId and thefields. To continue with your code. In this commit is the solution.

@vbuch, you can check it to do pull-request? Thanks

vbuch commented 4 years ago

Nice find. I was wondering how magical this 12 was when I was first reviewing it. Well, itbwas not magical enough obviously. The problem with such a regex is that it is executed on a potentially large amount of content. Thats why i would prefer not to have a regex directly but first try to find a smaller portion of relevant content. Extracting the dictionary and then regexing on top of it. It would be really nice if you can find a way to do this. This piece of code is in the pdfkit helper which is a bit of an error but thats just unfortunate. Dont waste too much time on it. It needs some refactoring either way. I guess ill do it when i split the packages. I will accept it with the regex. Give it a quick try just in case you can think of something more performant.

therpobinski commented 4 years ago

You are right to make a regular expression in a smaller section. But I am with a late project that does not leave me much time. I hope to solve it later! On the other hand, I did a pull of its develop branch and two unit tests appeared that have an error. It would be nice if you corrected it, these errors do not intervene at all in the operation, rather they are errors that were expected, I think. I'm going to do the 'merge request' like this. One of the ideas for this search for the refex, I intend to search from the last startxref to the end of the document, and there the `regex' is applied. Until you can correct those errors, I can correct this search.

therpobinski commented 4 years ago

Done, I've already uploaded this update. It's in the last commit of the pull request. I think with this solution we could close this issue. Thanks!

mcalcano commented 4 years ago

Hi @therpobinski I downloaded your repository but i still have the same issue. Only the last signature remains valid. Also, with your repository, it empties the first page and just leave an empty or blank page. image

Have you come across a solution for this? Thanks for your help!

therpobinski commented 4 years ago

Mmmmm is very very strange! In the last changes made at my branch, no problem! You should see your PDF and find the error. Or, do you have the String of the 'buffer' to verify it?

mcalcano commented 4 years ago

Hi @therpobinski, thank you for helping. Yes, that's exactly the branch i'm using!

I have the buffer before and after signing it, i'm attaching them both.

Also, i tried with 4 other files but encountered the same problem!

pdfBuffer_before.txt pdfBuffer_signed.txt

therpobinski commented 4 years ago

You can supply the PDF files or the buffer.string. Something like this starts the Buffer.string:

%PDF-1.7
%    
1 0 obj
<<
/Creator (Chromium)
/Producer
................................
mcalcano commented 4 years ago

@therpobinski thanks again!

I'm attaching 3 files:

Seems like the signature is changing the document somehow. These are new files i just created.

signTest_original.pdf signTest_1 signature.pdf signTest_2 signatures.pdf

therpobinski commented 4 years ago

Ok, so I check it out! I think it's something from cross-referencing.

mcalcano commented 4 years ago

@therpobinski thanks again! any idea how I can fix it or what should I look for? Have a good day

therpobinski commented 4 years ago

Not yet, I am honest, I am very busy at my work, I will review it during the weekend and I tell you some news.

stale[bot] commented 4 years ago

This issue has been automatically marked as stale because it has not had activity in the past 90 days. It will be closed if no further activity occurs. Thank you for your contributions.