3

To sign a document we have to place the user signature (converted to a PNG image) on the document then digitally sign this PDF. According to PDF documentation only the first one needs "DocMDP" option. Everything looks fine until I place the second signature (Approval signature). This invalidate the first signature because the document has changed, not the data in signature byterage but due to incremental update (an image has been added).

The questions are:

how to add multiple digital signature (Approval signature) without invalidating the previous one?

How to handle the image signature during incremental update?

Below is an example of PDF structure during incremental updates. (Just an example to show the object inside.)

%PDF-1.7

1 0 obj
<</Type /Pages
/Kids [ 3 0 R]
/Count 1
/MediaBox [0 0 595.28 841.89]
>>
endobj

3 0 obj
<</Type /Page
/Parent 1 0 R
/MediaBox [0 0 595.28 841.89]
/Rotate 0
/Resources 2 0 R
/Group <</Type /Group /S /Transparency /CS /DeviceRGB>>
/Contents [4 0 R 5 0 R] >>
endobj

4 0 obj
<</Length 44>>
stream
BT /F1 24 Tf 175 720 Td (Hello World!)Tj ET
endstream
endobj

5 0 obj
<</Length 93>>
stream
q 15.00 0 0 15.00 80.00 700.00 cm /I1 Do Q
endstream
endobj

2 0 obj
<<
/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]
/Font <<
/F1 7 0 R
>>
/XObject <<
/I1 6 0 R
>>
>>
endobj

7 0 obj
<</Type /Font
/BaseFont /Helvetica
/Subtype /Type1
....
>>
endobj

6 0 obj
<</Type /XObject
/Subtype /Image
/Width 36
/Height 36
/ColorSpace /DeviceRGB
/BitsPerComponent 8
/Filter /FlateDecode
/DecodeParms <</Predictor 15 /Colors 3 /BitsPerComponent 8 /Columns 36>>
/SMask 8 0 R
/Length 273>>
stream
[.....]
endstream
endobj

8 0 obj
<</Type /XObject
/Subtype /Image
/Width 36
/Height 36
/ColorSpace /DeviceGray
/BitsPerComponent 8
/Filter /FlateDecode
/DecodeParms <</Predictor 15 /Colors 1 /BitsPerComponent 8 /Columns 36>>
/Length 273>>
stream
[.....]
endstream
endobj

5 0 obj
<<
/Producer (Test Producer)
/CreationDate (D:20180708005634)
>>
endobj

9 0 obj
<<
/Type /Catalog
/Pages 1 0 R
>>
endobj

xref
0 10
0000000000 65535 f
00000000?? 00000 n
0000000??? 00000 n
000000???? 00000 n
000000???? 00000 n
000000???? 00000 n
00000????? 00000 n
00000????? 00000 n
00000????? 00000 n
00000????? 00000 n
trailer
<<
/Size 10
/Root 9 0 R
/Info 5 0 R 
>>
startxref
123456
%%EOF

3 0 obj
<</Type /Page
/Parent 1 0 R
/MediaBox [0 0 595.28 841.89]
/Rotate 0
/Resources 2 0 R
/Annots [10 0 R]
/Group <</Type /Group /S /Transparency /CS /DeviceRGB>>
/Contents [4 0 R 5 0 R 10 0 R] >>
endobj

10 0 obj
<</Length 93>>
stream
q 15.00 0 0 15.00 180.00 700.00 cm /I2 Do Q
endstream
endobj

11 0 obj
<< /Type /Annot /Subtype /Widget /Rect [180.000000 700.000000 195.000000 780.000000] /P 3 0 R /F 4 /FT /Sig /T (Test Sig #0) /Ff 0 /V 12 0 R >>
endobj

12 0 obj
<< /Type /Sig /Filter /Adobe.PPKLite /SubFilter /adbe.pkcs7.detached /ByteRange[0 150000 160000 800]                /Contents<12321.....0000000000000> /Reference [ << /Type /SigRef /TransformMethod /DocMDP /TransformParams << /Type /TransformParams /P 2 /V /1.2 >> >> ] /Name (Stack Overflow) /Location (USA) /Reason (Testing Signature 0) /ContactInfo (https://stackoverflow.com) /M (D:20180708093628+02'00') >>
endobj

13 0 obj
<</Type /XObject
/Subtype /Image
/Width 36
/Height 36
/ColorSpace /DeviceRGB
/BitsPerComponent 8
/Filter /FlateDecode
/DecodeParms <</Predictor 15 /Colors 3 /BitsPerComponent 8 /Columns 36>>
/SMask 14 0 R
/Length 273>>
stream
[.....]
endstream
endobj

14 0 obj
<</Type /XObject
/Subtype /Image
/Width 36
/Height 36
/ColorSpace /DeviceGray
/BitsPerComponent 8
/Filter /FlateDecode
/DecodeParms <</Predictor 15 /Colors 1 /BitsPerComponent 8 /Columns 36>>
/Length 273>>
stream
[.....]
endstream
endobj


9 0 obj
<<
/Type /Catalog
/Pages 1 0 R
/AcroForm << /Fields [ 11 0 R] /NeedAppearances false /SigFlags 3 >> /Perms << /DocMDP 12 0 R >>
>>
endobj

2 0 obj
<<
/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]
/Font <<
/F1 7 0 R
>>
/XObject <<
/I1 6 0 R /I2 13 0 R
>>
>>
endobj

xref
0 1
0000000000 65535 f
2 2
0000000000 00000 n
0000000??? 00000 n
9 6
000000???? 00000 n
00000????? 00000 n
00000????? 00000 n
00000????? 00000 n
00000????? 00000 n
00000????? 00000 n
trailer
<<
/Size 15
/Root 9 0 R
/Info 5 0 R 
/Prev 123456
>>
startxref
1234567
%%EOF

3 0 obj
<</Type /Page
/Parent 1 0 R
/MediaBox [0 0 595.28 841.89]
/Rotate 0
/Resources 2 0 R
/Annots [11 0 R 16 0 R]
/Group <</Type /Group /S /Transparency /CS /DeviceRGB>>
/Contents [4 0 R 5 0 R 10 0 R 15 0 R] >>
endobj

15 0 obj
<</Length 93>>
stream
q 15.00 0 0 15.00 280.00 700.00 cm /I3 Do Q
endstream
endobj

16 0 obj
<< /Type /Annot /Subtype /Widget /Rect [280.000000 700.000000 195.000000 780.000000] /P 3 0 R /F 4 /FT /Sig /T (Test Sig #1) /Ff 0 /V 17 0 R >>
endobj

17 0 obj
<< /Type /Sig /Filter /Adobe.PPKLite /SubFilter /adbe.pkcs7.detached /ByteRange[0 150000 160000 800]                /Contents<12321.....0000000000000> /Name (Stack Overflow) /Location (USA) /Reason (Testing Signature 0) /ContactInfo (https://stackoverflow.com) /M (D:20180708093628+02'00') >>
endobj

18 0 obj
<</Type /XObject
/Subtype /Image
/Width 36
/Height 36
/ColorSpace /DeviceRGB
/BitsPerComponent 8
/Filter /FlateDecode
/DecodeParms <</Predictor 15 /Colors 3 /BitsPerComponent 8 /Columns 36>>
/SMask 14 0 R
/Length 273>>
stream
[.....]
endstream
endobj

19 0 obj
<</Type /XObject
/Subtype /Image
/Width 36
/Height 36
/ColorSpace /DeviceGray
/BitsPerComponent 8
/Filter /FlateDecode
/DecodeParms <</Predictor 15 /Colors 1 /BitsPerComponent 8 /Columns 36>>
/Length 273>>
stream
[.....]
endstream
endobj


9 0 obj
<<
/Type /Catalog
/Pages 1 0 R
/AcroForm << /Fields [11 0 R 16 0 R] /SigFlags 1 >>
>>
endobj

2 0 obj
<<
/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]
/Font <<
/F1 7 0 R
>>
/XObject <<
/I1 6 0 R /I2 13 0 R /I3 18 0 R
>>
>>
endobj

xref
0 1
0000000000 65535 f
2 2
0000000000 00000 n
0000000??? 00000 n
9 1
0000000??? 00000 n
15 5
000000???? 00000 n
00000????? 00000 n
00000????? 00000 n
00000????? 00000 n
00000????? 00000 n
trailer
<<
/Size 20
/Root 9 0 R
/Info 5 0 R 
/Prev 1234567
>>
startxref
12345678
%%EOF

UPDATE 09 JUL 2018 - Unsuccessful PDF examples

Additional PDF examples:

Original PDF

https://drive.google.com/open?id=14_raGyJHHJPv2Ze-pWOJ46SargX0JQ0N

First signature - Certified signed

https://drive.google.com/open?id=12aLqKfTczxRAqB3MjklYNBtg5h8DJJ0b

Second signature - Approval signature

https://drive.google.com/open?id=10ghpxuO9gPKRsWcNwsu-ozQH9lth6QVx

Certificate with password "a"

https://drive.google.com/open?id=1eMrjMlVURIVsIo6LLboyii7ewSWoC8xY

These are my tentative. If someone can digitally sign the first file two or more times with an image as signature appearance please share share the results.

UPDATE 11 JUL 2018 - Successful multiple signatures without appearance

In this tentative, during incremental update, I didn't cloned any page (As on previous example) but just updated "/Catalog" object (AcroForm fields). The message "Changes have been made to this document that are permitted by the certifying party" is more than reasonable.

Unsigned PDF example

https://drive.google.com/open?id=1LUQiJMEh73I11NIbL3X8b8LltKseG08a

1st signature example

https://drive.google.com/open?id=150H6SYMPpVf5inZy4uWgqSjOuqOk5hoS

2nd signature example

https://drive.google.com/open?id=1m_6ew4IywNqaOs3uh5o1QLjYKDRDtyNu

3rd signature example

https://drive.google.com/open?id=1IyZQAAwwyaON35qH1xEw_GSsa2RUBaG-

h2odev
  • 634
  • 9
  • 21
  • 2
    I am preparing an answer but as you did not provide an actual sample pdf to check, it is going to be very generic. But some issues are already visible in your pdf structure. – mkl Jul 08 '18 at 14:22
  • 1
    By the way, *"According to PDF documentation only the first one needs "DocMDP" option."* - more to the point, only the first signature *is allowed to have a **DocMDP** transform*, no other may. – mkl Jul 08 '18 at 15:27
  • Thank You for your reply, I appreciate that. I had some misguiding object naming on the example (mea culpa) so it is better to share a PDF to have a better idea. Yes, the images are placed into the page because I don't know how to use as signature visualization to belong into an appearance xobject of the signature widget :( I will upload the PDF in about 20 minutes. Thanks a lot – h2odev Jul 08 '18 at 16:15

2 Answers2

7

In general

how to add multiple digital signature (Approval signature) without invalidating the previous one?

First of all, obviously the first signature must not be a certification signature with "no changes allowed": Adding a second signature is a change and, therefore, would invalidate the original one.

Furthermore, you have to add the second signature in an incremental update.

Finally, don't add any disallowed changes in the incremental update, cf. this answer.

How this relates to your PDF structures and shared PDF files, you can find in the sections

  • In your case, original PDF structure
  • In your case, updated PDF structure
  • In your case, shared PDF files "Unsuccessful PDF examples"
  • In your case, shared PDF files "Successful multiple signatures without appearance"

How to handle the image signature during incremental update?

Here the final advice above, don't add any disallowed changes in the incremental updates, is very important. In particular: Don't add a signature visualization to the page content but use the signature widget appearance streams instead.

You find details on this in the sections

  • How to add signature visualizations
  • An example of a signature with visualization

How to add signature visualizations

In your files you have merged each of your signature fields with its respective single widget annotation (the objects are both /Type /Annot /Subtype /Widget, i.e. widget annotations, and /FT /Sig, i.e. signature fields) which is pretty common. In such a case no further reference from the field to the widget annotation is necessary. Thus, you merely have to add an appearance to the combined signature field/widget.

First of all,

AP dictionary (Optional; PDF 1.2) An appearance dictionary specifying how the annotation shall be presented visually on the page (see 12.5.5, "Appearance streams").

(ISO 32000-2, Table 166 — Entries common to all annotation dictionaries)

Thus, you need to add an appearance dictionary to your signature field and widget objects.

An annotation may define as many as three separate appearances:

  • The normal appearance shall be used when the annotation is not interacting with the user. This appearance is also used for printing the annotation.

(ISO 32000-2, Section 12.5.5 — Appearance streams)

N stream or dictionary (Required) The annotation’s normal appearance.

(ISO 32000-2, Table 170 — Entries in an appearance dictionary)

Thus, your appearance dictionary needs an entry with an /N key.

In case of signature widgets the value is a stream, it is a dictionary of streams only for multi-state annotation, e.g. checkbox form field widgets.

This stream is a form XObject, cf. ISO 32000-2 Section 8.10.2 — Form dictionaries.

An example of a signature with visualization

In the section How to add signature visualizations above I referenced the relevant ISO 32000 sections for the PDF objects to use in a signature visualization. In your comments you asked for more, so I'll show details of an example here.

Let's look into this example file from the PDFBox issue PDFBOX-3198, somewhat pretty-printed.

In there you'll find the signature field and widget combined object

77 0 obj
<<
  /FT /Sig
  /Type /Annot
  /Subtype /Widget
  /F 132
  /T (Signature1)
  /V 82 0 R
  /P 13 0 R
  /Rect [0.0 792.0 100.0 842.0]
  /AP <<
    /N 83 0 R
  >>
>> 

Your signatures use most of these entries, too, except the AP entry. This is the appearance dictionary and it contains a single entry with the N key. This references the normal appearance of the signature in object 83:

83 0 obj
<<
  /Length 171
  /Type /XObject
  /Subtype /Form
  /Resources <<
    /XObject <<
      /Im1 84 0 R
    >>
    /Font 85 0 R
  >>
  /BBox [0.0 0.0 100.0 50.0]
  /FormType 1
>>
stream
  q
    0.25 0 0 0.25 0 0 cm
    q
      200 0 0 142 0 0 cm
      /Im1 Do
    Q
  Q
  BT
    /F1 10 Tf
    10 35 Td
    15 TL
    (\(Signature line 1\)) Tj
    T*
    (\(Signature line 2\)) Tj
    T*
    (\(Signature line 3\)) Tj
  ET
endstream
endobj 

This appearance stream is a form XObject of form type 1 (cf. its Type, Subtype, and FormType entries) with its own resources, an image XObject Im1 in object 84 and fonts in object 85 (cf. its Resources entry).

It furthermore has a boundary box (cf. its BBox entry) which defines the area in which the instructions in its stream can draw an appearance. This area with everything drawn there will be displayed by a PDF viewer in the page area defined by the Rect entry of the signature widget annotation, see above.

In the stream you see instructions to draw the bitmap image resource and three lines of text.

There is nothing special about its font resources in object 85, either:

85 0 obj
<<
  /F1 86 0 R
>>
endobj
86 0 obj
<<
  /Type /Font
  /Subtype /Type1
  /BaseFont /Helvetica-Bold
  /Encoding /WinAnsiEncoding
>> 

Beware, if you happen to have to deal with documents with page rotation, be sure to

  • either not set the NoRotate annotation flag of the signature widget (the 24 summand of the F value) but add a rotation to the form XObject or its content
  • or set the NoRotate annotation flag and consider the effects thereof in your calculation of the annotation Rect values,

cf. this answer for details.

In your case, original PDF structure

In your case you use incremental updates and have a certification signature with the required changes allowed. Other than that, though, the PDF is utterly broken.

There are weirdnesses already in the incremental update with the first signature:

You add a content stream (object 10 0) to the page as content stream. Ok. But you also reference this content stream in the Annots array of your page. This does not make sense, a naked content stream is not an annotation.

Probably the image shown in this content stream is meant as signature visualization. In that case, though, both changes above would be completely wrong, a signature visualization belongs into an appearance xobject of the signature widget, not into the page content.

The incremental update for the second signature is completely weird,

  • in the resources of the page you
    • add an image xobject to the xobject resources (which may already be counted as disallowed) and
    • set the previously already existing font F1 to point to the signature field 16 0 (which clearly is destructive nonsense);
  • in the AcroForm dictionary you
    • reference object 15 0 as new field, but 15 0 only is a content stream (destructive nonsense),
    • reduce the SigFlags value from 3 to 1 (very inappropriate for a signed document), and
    • drop the Perms entry (something the document MDP signature won't find funny).

Furthermore, the cross references obviously are broken. By design when copying & pasting here? By error already in the original file? I cannot tell.

So the bottom line is that in particular the last incremental update is completely broken and cannot serve as a sensible base for a question about "Inserting multiple digital approval signatures without invalidating the previous one" because unrelated basics already are wrong.

In your case, updated PDF structure

You edited the PDF structure, and now it makes more sense. At least you don't reference the wrong objects from resources or field lists anymore, except in one case.

These obvious issues remain:

  1. As already mentioned you still reference one inappropriate object, in the revision with the certification signature the Page dictionary still references object 10 in its Annots array, but object 10 is but a content stream, no annotation. object 11, the signature field and widget, is the object you should reference.

    Actually in the final revision, the revision of the approval signature, you have corrected it. But only correcting this in the newest revision but not in the first signed revision results in a change between revisions which may or may not be allowed...

  2. You still inappropriately change the AcroForm dictionary contents in your final revision, you reduce the SigFlags value from 3 to 1 and drop the Perms entry.

    The former change is a bad idea because you so signal to upcoming PDF processors that they do not need to apply changes in incremental updates, i.e. you beg them to damage your signatures.

    The latter change is not immediately a problem but a very sensitive signature validator may consider this a suspicious change.

  3. Now your final incremental update also changes the page content and adds a new content stream to it which draws an image.

    Changing page content of a signed document is disallowed, cf. my answer already referenced above in the general section. Thus, even if the other changes don't cause Adobe Reader to claim an invalidated signature, this one will.

    In a comment to your question you actually already admit this change:

    Yes, the images are placed into the page because I don't know how to use as signature visualization to belong into an appearance xobject of the signature widget.

    On this issue have a look at the section "How to add signature visualizations" of my answer above.

In your case, shared PDF files "Unsuccessful PDF examples"

In the complete PDFs you shared the situation is similar to that in the updated PDF structure discussed above. There are some minor differences, though, and due to the completeness of the file additional issues come to light.

  1. Unused Document Information Dictionaries - in each revision you create a new Document Information Dictionary but your trailers keep referencing the dictionary of the initial revision. Harmless but surely not intended this way.

  2. Empty ToUnicode maps - each of your fonts has a ToUnicode entry which points to an empty stream. This is invalid: If there is a ToUnicode entry in a font, its value MUST be a stream containing a CMap file that maps character codes to Unicode values, and the common expectation is that the mapping is complete as far as character codes actually used in the document are concerned.

  3. Duplicate font resources - In the incremental updates you add fonts to the page resources have the same resource name as already existing fonts in the same resources, i.e. you create duplicate entries for these names. As multiple entries in the same dictionary shall not have the same key, this makes your PDF invalid.

  4. When applying your approval signature you still drop the Perms entry with the reference to the certification signature from the AcroForm dictionary. This is probably harmless as a validator will find that signature in a signature form field anyways, but a very sensitive validator might report this as suspicious change anyways.

  5. Changes to the page content - just like before (as discussed under updated PDF structure) you add a signature visualization to the page content. As before it is harmless for the first signature but it is a disallowed change in follow-up signatures.

  6. Changes to the page resources - you add new image XObjects and new fonts the the page resources.

    If they were not used in the page content, this is probably harmless but that means counting on validators checking for usage of added resources. Validators that don't check for usage will surely consider this a disallowed change.

    In your case, though, the added resources are used, so they definitively are part of a disallowed change.

Thus, Adobe completely correctly reports that there have been changes made to this document that invalidate the certification signature and displays that certification signature as invalid. If you don't want this, stop adding disallowed changes, in particular stop changing the page content stream. Instead put signature visualizations into signature widget appearance streams as described above.

Furthermore, be a bit more attentive and don't create non-conforming PDF structures.

In your case, shared PDF files "Successful multiple signatures without appearance"

By signing without visualizations you indeed got rid of items 3, 5, and 6. Furthermore no unused document information dictionaries are present anymore, resolving item 1.

You got rid of item 4 by not adding a Perms dictionary to the catalog of the revision with the certification signature to start with. While this of course is possible, I'd recommend you also make sure that your code for adding further approval signatures does not remove Perms dictionaries.

Item 2 remains, your fonts still have empty ToUnicode values. While not relevant for the issue at hand, this is invalid and it is likely to disturb some text extraction implementations.

Other than that you

  • switched the DocMDP transform P value from 2 to 3; unless you really need to allow arbitrary annotation creation, deletion, and modification, I'd recommend against this because annotations can substantially change the appearance of a document;

  • use RSA with the PKCS#1 v.1.5 signature scheme for signing; in a new signing application without a requirement for backward compatibility I'd instead recommend using the RSASSA-PSS signature scheme as defined in PKCS#1 since version 2.1 because acceptance of the PKCS#1 v.1.5 scheme is likely to dwindle in the early 2020s;

but these are items to fine-tune your code once all actual errors are wiped out.

mkl
  • 90,588
  • 15
  • 125
  • 265
  • I have uploaded 3 PDF files. Maybe this way is better for you check the problem on this case. I will analyze you reply right now. Thanks – h2odev Jul 08 '18 at 20:49
  • @h2odev I added an analysis of your shared PDFs to my answer, section "In your case, shared PDF files". The major issue remains, though: Changing the page content is disallowed in a signed file. – mkl Jul 09 '18 at 10:55
  • Thank you so much for your insistence. I'm aware for the most of the issues you noted (Because I'm rewriting the messy code developed previously). A very good help was also the mention of "appearance stream, /AP". I will share tomorrow the results (PDF file) – h2odev Jul 09 '18 at 11:33
  • 1
    I have uploaded my first tentative without visible signature but a working one. Now I'm working on signature appearance . The reason I'm insisting on this and uploading this PDF files is because has been hard for me to find a step by step example. I guess, this will be a little help to the others :) – h2odev Jul 10 '18 at 23:14
  • 1
    @h2odev I've added a section *'In your case, shared PDF files "Successful multiple signatures without appearance"'* analyzing your newest shared files and a section *'An example of a signature with visualization'* showing the internals of a signature visualization by example. – mkl Jul 11 '18 at 11:02
  • Thank You! I think with your last update we are done with PDF signature. This post will be very useful to others. Personally I had to rewrite almost everything and still are things to improve on the project I'm working on. Never trust beginners! Thank You MKL. – h2odev Jul 11 '18 at 12:37
  • 1
    @h2odev I re-organized the sections of my answer, pushing the sections of general interest to the front. This way other readers probably more easily find the information they seek. – mkl Jul 12 '18 at 09:17
0

I found this conversation very interesting and I wish I understood it well enough to implement the ideas discussed, as h20dev was able to do.

MKL is very knowledgeable about PDFs and digital signatures, as I have read a lot of his replies while researching this subject.

For anyone who is still struggling to do Multiple Digital Signatures on PDFs with incremental updates, check out this github which I have had great success using to do this task:

https://github.com/vbuch/node-signpdf