1
votes

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 = "[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(@"mypath\signed_cert.p7s");

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

what am I missing or doing wrong?

1
"After that,I give the hash code of this pdf file" - that is wrong: you need the hash of its signed byte ranges, not of all of it. Cf. the method GetBytesToSign the result of which you ignore, the hash is computed for appearance.GetRangeStream(), not for the whole file.mkl
@mkl thank you for your reply. I did not get it. We use a script to request the webservice and it requires the file's hash. but you said it is wrong. So then what shoud I give the webservice? should I give result of SHA256Managed.Create().ComputeHash(appearance.GetRangeStream()); As I understand this is only field's hash value, isnt it?ertan2002
@mkl my mistake.. So you are right. When I gave the hashcode of the field, it signed correctly!! Thank you so much. I was doing it from morning. You can write as an answer and i accept it as answerertan2002

1 Answers

1
votes

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.