0

Problem: I want to sign PDF documents with iText and a PKCS11 provider (In C#, Java works too). This works, but the signed PDF lacks several signed attributes:

  • Issuer
  • Serial Number
  • Signing Time

So after a comment of @mkl I implemented a custom IExternalSignatureContainer, but the signature doesn't look valid My current code:

try
{
    using (var signature = new Pkcs11Signature(libraryPath, slotId, pin, "SHA256")) // My custom PKCS11 provider
    using (var pdfReader = new PdfReader(inputFile))
    using (var result = File.Create(outputFile))
    {
        var stampingProperties = new StampingProperties();
        stampingProperties.UseAppendMode();

        // Sign the document
        var pdfSigner = new PdfSigner(pdfReader, result, stampingProperties);
        pdfSigner.SignExternalContainer(new ExternalSignature(signature), 8192);

    }
}
catch (Exception exception)
{
    throw new Exception("Unable to sign PDF file: " + exception.Message);
}
using iText.Kernel.Pdf;
using iText.Signatures;
using Org.BouncyCastle.Crypto.Digests;

namespace acme;

public class ExternalSignature : IExternalSignatureContainer
{
    private Pkcs11Signature pkcs11Signature;

    public ExternalSignature(Pkcs11Signature pkcs11Signature)
    {
        this.pkcs11Signature = pkcs11Signature;
    }

    public byte[] Sign(Stream data)
    {
        // Get the certificate chain via PKCS11
        var chain = pkcs11Signature.GetChain();

        // Create the PKCS7 container
        var pdfPkcS7 = new PdfPKCS7(null, chain, pkcs11Signature.GetHashAlgorithm(), false);
        var secondDigest = DigestAlgorithms.Digest(data, new Sha256Digest());
        var authenticatedAttributeBytes = pdfPkcS7.GetAuthenticatedAttributeBytes(secondDigest, PdfSigner.CryptoStandard.CMS, null, null);

        // Dump the authenticated attributes so we can check them via ASN1 parsing
        //File.WriteAllBytes("messageex.bin", authenticatedAttributeBytes);

        // Sign the message
        var digest = pkcs11Signature.Sign(authenticatedAttributeBytes);

        // Set the digest
        pdfPkcS7.SetExternalDigest(digest, null, pkcs11Signature.GetEncryptionAlgorithm());
        var encodedPkcS7 = pdfPkcS7.GetEncodedPKCS7(secondDigest, PdfSigner.CryptoStandard.CMS, null, null, null);

        return encodedPkcS7;
    }

    public void ModifySigningDictionary(PdfDictionary signDic)
    {
        //throw new NotImplementedException();
    }
}
swaechter
  • 1,357
  • 3
  • 22
  • 46
  • You use `pdfSigner.SignDetached`. This makes itext create the signature container itself according to its own standards. If you use `pdfSigner.SignExternalContainer` instead you can build a signature container just like you want to. – mkl Jan 08 '22 at 22:56
  • @mkl Thanks a lot for the comment (and of course all your great example code and work for iText! Really helpful to study the code). I copied some code of the `SignDetached` method to build a custom external container, but the PDF signature is not valid. Do you see a problem? Falling back to the regular `SignDetached` generates a valid PDF signature – swaechter Jan 09 '22 at 14:36
  • Well, first off, if you want custom attributes in your cms signature container, do not use the iText `PdfPKCS7` class - that class has hard coded attribute sets. You can use BouncyCastle classes instead. – mkl Jan 09 '22 at 18:33

0 Answers0