There are some errors in your signature and an uncommon structure which in the context of digital signatures may result in rejection by a validator.
Incorrect Signed Hash Value Inside Signature Container
Signing in CMS signature containers with signed attributes makes use of two hash values:
- the hash value of the signed byte ranges of the PDF; that value is correct in your example files;
- the hash value of the signed attributes in the
SignerInfo
of the signature container; that value is not correct in your example files.
PS: Looking into the mismatch once again, it turns out that your signed attributes are not DER encoded: The DER encoding in particular sorts the elements of a SET in a specific order, and in your case the attribute order is not the DER order. The specification requires the signed attributes to be DER encoded, though.
PPS: In a comment you argued
I just checked the order of the SET and I can not find anything that is wrong with it. Here is my reasoning, let me know what part is incorrect. The items should be order according to the 'key' which in my case is an Oid.
First of all, this reasoning is flawed: The type in question is a set type (more exactly an ASN.1 SET OF), not some map type; and the DER encoding rule set only knows the ASN.1 base types. Thus, that OID (which just is an arbitrary part of the attribute structure) cannot be the generic ordering key.
And indeed, a quick glance at the specification shows:
11.6 Set-of components
The encodings of the component values of a set-of value shall appear in ascending order, the encodings being compared
as octet strings with the shorter components being padded at their trailing end with 0-octets.
NOTE – The padding octets are for comparison purposes only and do not appear in the encodings.
(ISO/IEC 8825-1 / ITU-T Rec. X.690, section 11 "Restrictions on BER employed by both CER and DER")
Thus, in case of the signed attributes essentially you first DER encode the attribute elements and then sort the resulting byte arrays as described above.
As an aside, this issue of your signature merely causes problems in probably half the validators around. Some validators do not check or DER re-encode the signed attributes, so they get the same hash as you get. Others either check the encoding up front (and, therefore, throw an error because of the issue) or simply re-encode the attributes in DER (and, therefore, get a different hash than you get).
Problematic Extended Key Usage of Signer Certificate
Your signer certificate has an extended key usage value 1.3.6.1.4.1.311.80.1 (Microsoft's OID for Document Encryption) and only that. Adobe validation used to only support certificates with either no extended key usage or one or more of the following:
- emailProtection
- codeSigning
- anyExtendedKeyUsage
- 1.2.840.113583.1.1.5 (Adobe Authentic Documents Trust)
See Enterprise Toolkit » Digital Signatures Guide for IT » A: Changes Across Releases.
Incorrect Incremental Updates
You sign in an incremental update to the original PDF. This in general is a good idea as it allows to extract the unsigned original document.
But one needs to add the incremental update correctly, and in case of result2_invalid_byte_range_no_image.pdf and result2_invalid_byte_range_with_image.pdf it is done incorrectly: The original revision there is created using cross reference tables but your incremental updates use pure cross reference streams. This is incorrect, you have to continue with the same kind of cross references.
When opening documents with a mix of cross reference tables and pure cross reference streams, Adobe Acrobat internally repairs this which in particular relocates signatures and so makes byte ranges incorrect.
Uncommon Signature Field Structure
You use an uncommon signature field structure in your example PDFs, you separate the widget from the field and only update the field, not the widget, in signing.
While this strictly speaking is ok, I would implement the common structures while making the code work at all, and deviate only thereafter.
PS: In a comment you asked whether I could elaborate on this.
Your signing implementation in a first step adds an incremental update with an empty signature field and a widget as indirectly referenced kid, e.g.:
16 0 obj
<<
/Type /Annot
/F 4
/Subtype /Widget
/BS << /Type /Border /S /S /W 0 >>
/Parent 17 0 R
/P 2 0 R
/Rect [141.75 664.89 276.75 702.39]
/AP << /N 18 0 R >>
/MK << /BC [.1882353 .1882353 .1882353] /BG [1.00 1.00 1.00] /R 0 >>
/DA (/TiRo 0 Tf 0 0 0 rg\r
)
>>
endobj
17 0 obj
<<
/Kids [16 0 R]
/FT /Sig
/T (eyJ1c2VySWQiOiIyNzIifQ==)
>>
In another incremental update you then sign the field with a direct signature value but don't change the widget, e.g.:
17 0 obj
<<
/Kids [16 0 R]
/FT /Sig
/T (eyJ1c2VySWQiOiIyNzIifQ==)
/V << /Type/Sig ... >>
>>
This is uncommon in some ways:
- Usually for signatures the option to merge field and widget is used.
- Usually for signatures (except for usage right signatures) the signature dictionary is not a direct but an indirect value of the key V.
- Usually the appearance of a signature field is updated together with the signature dictionary if there is an appearance at all.
Also, unless other form fill-ins shall happen between adding an empty signature field and signing it, fields usually are added and filled in the same document update.
Thus, more common would be a single incremental update (or even full re-save) containing something like this:
92 0 obj
<<
/AP << /N 94 0 R >>
/DA (/MyriadPro-Regular 0 Tf 0 Tz 0 g)
/F 132
/FT /Sig
/MK <<>>
/P 1 0 R
/Rect [117.575 499.561 515.968 520.938]
/Subtype /Widget
/T (Signature3)
/Type /Annot
/V 93 0 R
>>
endobj
93 0 obj
<<
/ByteRange [ 0 3227714 5751810 2789]
...
>>
As said above, though, your structure strictly speaking is ok, too. But the "Bad parameter" only occurs when validating from the widget in the document or from the signature panel, but it does not occur when validating your signature using the "Validate Signature" button of the "Signature Properties" dialog. Because of that I think it's possible that Adobe is iritated by an uncommon structure.