0

I am using a smart card that is signing a SHA-1 hash of a document, and compute a 256 bytes digital signature.

I am using the code posted on this question - iText signing PDF using external signature with smart card.

My problem is that I get the error:" The document has been altered or corrupted since the signature was applied".

I am using a GUI to create the hash and then send the signed 256 bytes that is computed on the card to the signing functions .

Here is my code:

hash creating code of filepath pdf document:

SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider(); 
SHA256 sha2 = SHA256.Create(); 
//sha2.ComputeHash 
byte[] pdfBytes = System.IO.File.ReadAllBytes(filePath); 
byte[] hash = null; 
hash=  sha1.ComputeHash(pdfBytes); 

the above code is used in one of the GUI functions to create the hash of the document

namespace EIDSmartCardSign
{
    class PdfSignature
    {
        private string outputPdfPath;
        private string certPath;
        byte[] messageDigest;

        private string inputPdfPath;
        public PdfSignature(byte[] messageDigest, string inputPdfPath,string outputPdfPath)
        {
            this.messageDigest = messageDigest;
            this.outputPdfPath = outputPdfPath;
            this.inputPdfPath = inputPdfPath;
        }

        public void setCertPath(string certPath)
        {
            this.certPath = certPath;
        }

        public void signPdf()
        {
            X509Certificate2 cert = new X509Certificate2();

            cert.Import(certPath); // .cer file certificate obtained from smart card

            X509CertificateParser certParse = new Org.BouncyCastle.X509.X509CertificateParser();
                       Org.BouncyCastle.X509.X509Certificate[] chain = new Org.BouncyCastle.X509.X509Certificate[1] ;
            chain[0] = certParse.ReadCertificate(cert.RawData);

            X509Certificate2[] certs;

            PdfReader reader  = new PdfReader(inputPdfPath);
            FileStream fout = new FileStream(outputPdfPath,FileMode.Create);
            PdfStamper stamper = PdfStamper.CreateSignature(reader, fout, '\0',null,true);

            PdfSignatureAppearance appearance = stamper.SignatureAppearance;
            appearance.SignatureCreator = "Me";
            appearance.Reason = "Testing iText";
            appearance.Location = "On my Laptop";
            iTextSharp.text.Rectangle rec = new iTextSharp.text.Rectangle(50, 50, 250, 100);
            appearance.SetVisibleSignature(rec, 1, "Signature");
            IExternalSignature extSignature= new MyExternalSignature("SHA-1",this.messageDigest);


            MakeSignature.SignDetached(appearance, extSignature, chain, null, null, null, 0, CryptoStandard.CMS);
            //MakeSignature.
        }
    }
}
Community
  • 1
  • 1
GLC
  • 3
  • 3

1 Answers1

2

Your hash creating function

SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider(); 
SHA256 sha2 = SHA256.Create(); 
//sha2.ComputeHash 
byte[] pdfBytes = System.IO.File.ReadAllBytes(filePath); 
byte[] hash = null; 
hash = sha1.ComputeHash(pdfBytes);

calculates the wrong hash value.

Have a look at this answer on Information Security Stack Exchange, in particular the sketch

sketch of how PDF signatures are integrated

shows that to get the document bytes to sign you do not take the original PDF but instead have to prepare it for integrating the signature container (add signature field, field value with some space reserved for the signature container, and field visualization) and then hash all the bytes except the space reserved for the signature container.

Furthermore, even this naked hash is not the data to sign. Instead a set of attributes is built, one of them containing the document hash calculated as above, other ones containing references to the signer certificate etc., and these attributes are to be signed.

Thus, instead do what you already claimed to be doing:

I am using the code posted on this question - iText signing PDF using external signature with smart card.

In particular the code there does not sign the hash of the whole file but instead uses the data the method Sign of the IExternalSignature implementation receives as parameter which is constructed as explained above.

More details

In a comment the OP said

The card I am working with expects a 20 bytes hash.

20 bytes would be typical for a naked hash generated by either SHA1 or RIPEMD-160. According to your question text, I assume the former algorithm is used. (This by the way indicates that the context does not require a high security level as SHA1 effectively is already phased out or in the process of being phased out for such use cases.)

What steps are needed to further create this hash After hashing the contents of the pdf?

Simply do as in the IExternalSignature implementation in the question you referenced:

public virtual byte[] Sign(byte[] message) {

    byte[] hash = null;
    using (SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider())
    {
        hash = sha1.ComputeHash(message);
    }

    byte[] sig = MySC.GetSignature(hash);

    return sig;
}

(Obviously chances are that your smart card signing routine is not called MySC.GetSignature and you have to replace that call accordingly...)

As your card appears to expect a naked hash value in contrast to the card of the OP of the referenced question, this should work for you.

Where can I find examples of creating the aformentioned integrated signature container?

In the examples to the iText white paper Digital Signatures for PDF Documents.

After the signature process, I have 256 bytes signed data, 3 .cer certificates exported from the card.

256 bytes signed data sounds like a naked signature generated using RSA or RSASSA-PSS with a 2048 bit key size.

That been said, you need the signer certificate before signing: In most relevant profiles the signed attributes have to contain a reference to the signer certificate. In the code in the question you referenced that signer certificate is handled here

public void StartTest(){
    X509Certificate2 cert = new X509Certificate2();
    cert.Import("cert.cer"); // certificate obtained from smart card

    X509CertificateParser certParse = new Org.BouncyCastle.X509.X509CertificateParser();

    Org.BouncyCastle.X509.X509Certificate[] chain = new Org.BouncyCastle.X509.X509Certificate[] { certParse.ReadCertificate(cert.RawData) };

    [...]

    MyMakeSignature.SignDetached(appearance, externalSignature, chain, null, null, tsc, 0, CryptoStandard.CADES);

In particular you have to identify the correct signer certificate among those three certificate your card returns; otherwise you might have the same issue as the OP in the referenced question.

How do I create the Contents object when I have all of this data?

Considering what you said about your use case, chances are good that you really merely have to use the code posted of the question iText signing PDF using external signature with smart card with minor adaptions.

Community
  • 1
  • 1
mkl
  • 90,588
  • 15
  • 125
  • 265
  • I understand the first part of hash procedure you have described. The card I am working with expects a 20 bytes hash. What steps are needed to further create this hash After hashing the contents of the pdf? Where can I find examples of creating the aformentioned integrated signature container? After the signature process, I have 256 bytes signed data, 3 .cer certificates exported from the card. How do I create the Contents object when I have all of this data? – GLC May 15 '17 at 11:31
  • 1
    @GLC Great! In that case please accept the answer (click the tick at its upper left). – mkl May 15 '17 at 14:25