Signature is Invalid for PDF File with iText

2019-03-01 04:24发布

I am using swisscom digital signature service and we have a test account. Well the service requires the hash code the pdf file . We send it with

DIGEST_VALUE=$(openssl dgst -binary -SHA256 $FILE | openssl enc -base64 -A)

and I get a PKCS#7 response. You can decode the my signature response by using this website https://certlogik.com/decoder/ and the signature content is http://not_need_anymore

I have the same problem as follow (because we use the same code)

Digital Signature (PKCS#7 - Deferred Signing) / The document has been altered or corrupted since the signature was applied

my response has been with sha256 crypted. Well I am using iText with c# to sign the pdf file. I sign and I see some details (such as reason, location etc).

here is the method that creates a pdf file with a signature field

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);
            IExternalSignatureContainer external = new ExternalBlankSignatureContainer(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);
            PdfSignature external2 = new PdfSignature(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);//ADBE_PKCS7_SHA1);
//as pdf name I tried also PdfName.ETSI_RFC3161
//(ref => https://github.com/SCS-CBU-CED-IAM/itext-ais/blob/master/src/com/swisscom/ais/itext/PDF.java)

            appearance.Reason = "For archive";
            appearance.Location = "my loc";
            appearance.SignDate = DateTime.Now;
            appearance.Contact = "myemail@domain.ch";
            appearance.CryptoDictionary = external2;

            var level = reader.GetCertificationLevel();
            // check: at most one certification per pdf is allowed
            if (level != PdfSignatureAppearance.NOT_CERTIFIED)
                throw new Exception("Could not apply -certlevel option. At most one certification per pdf is allowed, but source pdf contained already a certification.");
            appearance.CertificationLevel = level;

            MakeSignature.SignExternalContainer(appearance, external,30000);

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

            return Convert.ToBase64String(array);
        }
    }
}

Actualls I do not use what this method returns. Because it already creates a temp pdf file with signature field.

After that,I give the hash code of this pdf file and get PKCS#7 responde. and then using the following function, I am adding the signature to a pdf (it creates another pdf file).

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);
        }
    }
}

the signature parameter in the method, I give p7s file content as follows

string signatureContent = File.ReadAllText(@"mypath\signed_cert.p7s");

signatureContent = signatureContent
                                   .Replace("-----BEGIN PKCS7-----\n", "")
                                   .Replace("-----END PKCS7-----\n","").Trim();

what am I missing or doing wrong?

1条回答
beautiful°
2楼-- · 2019-03-01 05:03

In contrast to the regular detached signatures which sign the whole signed file, integrated signatures in PDFs sign (and can only sign) everything but the space set aside for the signature itself.

enter link description here

(For more backgrounds read this answer)

Thus, when you after preparing the PDF with a placeholder to embed the signature

give the hash code of this pdf file and get PKCS#7 responde

you hash too much because your hashing included the (then empty, i.e. filled with '0' characters) placeholder for the actual signature. The method GetBytesToSign instead only returns the hash over the signed byte ranges, i.e. everything but the placeholder:

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

You have to either takes this value or similarly hash only everything but the placeholder for the signature.

查看更多
登录 后发表回答