Digital Signature (PKCS#7 - Deferred Signing) / Th

2019-05-22 07:18发布

问题:

I have gone through all similar questions but could not find a case where itextsharp deferred signing is applied.

Basically, my application signs pdf documents using PKCS#7 signature that is created by remote web service.

My application sends this web service the hash of the original document (hash of the signable bytes after empty signature field is added), and receives a Base64 encoded signature file.

I embed this signature to previously generated temporary pdf file which has empty signature field.

At the end my signature is not validated because Adobe Reader says that either the document is changed or it is corrupted.

Code That Adds Empty Signature Field and Gets Signable Bytes of Pdf

public static string GetBytesToSign(string unsignedPdf, string tempPdf, string signatureFieldName)
{
    if (File.Exists(tempPdf))
        File.Delete(tempPdf);

    using (PdfReader reader = new PdfReader(unsignedPdf))
    {
        using (FileStream os = File.OpenWrite(tempPdf))
        {
            PdfStamper stamper = PdfStamper.CreateSignature(reader, os, '\0');
            PdfSignatureAppearance appearance = stamper.SignatureAppearance;
            appearance.SetVisibleSignature(new Rectangle(36, 748, 250, 400), 1, signatureFieldName);

            IExternalSignatureContainer external = new ExternalBlankSignatureContainer(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);

            MakeSignature.SignExternalContainer(appearance, external, 8192);

            byte[] array = SHA256Managed.Create().ComputeHash(appearance.GetRangeStream());

            return Convert.ToBase64String(array);
        }
    }
}

As a result of this operation tempPdf is generated and I receive the hash for the signable bytes of the pdf document from this tempPdf file.

Then using the below code, I reopen this tempFile and embed the PKCS#7 signature which is Base64 encoded.

Code That Opens Temp Pdf And Embeds The Received Signature

public static void EmbedSignature(string tempPdf, string signedPdf, string signatureFieldName, string signature)
{
    byte[] signedBytes = Convert.FromBase64String(signature);

    using (PdfReader reader = new PdfReader(tempPdf))
    {
        using (FileStream os = File.OpenWrite(signedPdf))
        {
            IExternalSignatureContainer external = new MyExternalSignatureContainer(signedBytes);
            MakeSignature.SignDeferred(reader, signatureFieldName, os, external);
        }
    }
}

As a result of this operation my final signedPdf is generated. However, Adobe says that the signature is not valid due the change or corruption.

My Original File

Temporary File Generated For Signing

Final Signed File

The hash of the tempFile file that I sent to web service is:

z9qIyvtp4cRBZ1SSCQ+P0JVRinz5lvjYjXk3L7YP/IE=

The signature I received from web service is:

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

I compared the bytes of tempFile and signedFile and only the zeros of tempFile (which are used for temp signature file I think) are replaced with the actual signature in signedFile.

I am really stuck at this point. I am not sure where I should be looking next.

回答1:

In the signature you received from the web service there is:

  39   59: . . . SEQUENCE {
  41    9: . . . . OBJECT IDENTIFIER data (1 2 840 113549 1 7 1)
         : . . . . . (PKCS #7)
  52   46: . . . . [0] {
  54   44: . . . . . OCTET STRING    
         : . . . . . . 7A 39 71 49 79 76 74 70    z9qIyvtp
         : . . . . . . 34 63 52 42 5A 31 53 53    4cRBZ1SS
         : . . . . . . 43 51 2B 50 30 4A 56 52    CQ+P0JVR
         : . . . . . . 69 6E 7A 35 6C 76 6A 59    inz5lvjY
         : . . . . . . 6A 58 6B 33 4C 37 59 50    jXk3L7YP
         : . . . . . . 2F 49 45 3D                /IE=
         : . . . . . }
         : . . . . }
[...]
1955    9: . . . . . SEQUENCE {
1957    5: . . . . . . OBJECT IDENTIFIER sha1 (1 3 14 3 2 26)
         : . . . . . . . (OIW)
1964    0: . . . . . . NULL
         : . . . . . . }
1966   93: . . . . . [0] {
1968   24: . . . . . . SEQUENCE {
1970    9: . . . . . . . OBJECT IDENTIFIER contentType (1 2 840 113549 1 9 3)
         : . . . . . . . . (PKCS #9)
1981   11: . . . . . . . SET {
1983    9: . . . . . . . . OBJECT IDENTIFIER data (1 2 840 113549 1 7 1)
         : . . . . . . . . . (PKCS #7)
         : . . . . . . . . }
         : . . . . . . . }
1994   28: . . . . . . SEQUENCE {
1996    9: . . . . . . . OBJECT IDENTIFIER signingTime (1 2 840 113549 1 9 5)
         : . . . . . . . . (PKCS #9)
2007   15: . . . . . . . SET {
2009   13: . . . . . . . . UTCTime 22/09/2017 13:18:38 GMT
         : . . . . . . . . }
         : . . . . . . . }
2024   35: . . . . . . SEQUENCE {
2026    9: . . . . . . . OBJECT IDENTIFIER messageDigest (1 2 840 113549 1 9 4)
         : . . . . . . . . (PKCS #9)
2037   22: . . . . . . . SET {
2039   20: . . . . . . . . OCTET STRING    
         : . . . . . . . . . EF 37 38 3B B1 31 AB 96    .78;.1..
         : . . . . . . . . . CE FC 47 1E 32 A7 79 73    ..G.2.ys
         : . . . . . . . . . 5D 95 15 04                ]...
         : . . . . . . . . }
         : . . . . . . . }
         : . . . . . . }
2061   13: . . . . . SEQUENCE {
2063    9: . . . . . . OBJECT IDENTIFIER rsaEncryption (1 2 840 113549 1 1 1)
         : . . . . . . . (PKCS #1)
2074    0: . . . . . . NULL
         : . . . . . . }

Herein your base64 encoded hash appears as embedded signed data (offsets 56..99). Furthermore, the hashing algorithm is chosen as "SHA-1" (offsets 1955..1965) and the signed document hash is a 20 byte value which matches the size of SHA-1 hash values. Additionally RSA is used for signing as described in PKCS#1 1.5 (offsets 2061..2075).

Thus, it looks like your signing service does not use your input as base64 encoded pre-calculated document hash value but as plain data to sign using SHA1withRSA/2048.

So the error is not in your iText using code but in your signing service calling code.