Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
806 views
in Technique[技术] by (71.8m points)

c# - Signature is Invalid for PDF File with iText

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, '');
            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 = "[email protected]";
            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(@"mypathsigned_cert.p7s");

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

what am I missing or doing wrong?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...