1

So we have this C# code that uses the itext7 library to sign pdf's:

public static void SignPDFDocument(string src, string dest, string thumbprint)
    {
        GetStoreCertificates("MY", StoreLocation.CurrentUser);
        cert = GetCertificateFromCollection(thumbprint);

        var privateKey = Org.BouncyCastle.Security  //I think this part needs "exportable" cert
            .DotNetUtilities
            .GetKeyPair(cert.GetRSAPrivateKey())
            .Private;

        var boucyCertParsed = new Org.BouncyCastle.X509
            .X509CertificateParser()
            .ReadCertificate(cert.GetRawCertData());

        Org.BouncyCastle.X509
            .X509Certificate[] bouncyCert = { boucyCertParsed };

        PdfReader reader = new PdfReader(src);
        StampingProperties stampProp = new StampingProperties();
        stampProp.PreserveEncryption();
        PdfSigner signer = new PdfSigner(
            reader,
            new FileStream(dest, FileMode.Create),
            stampProp);

        string digestAlgorithm = DigestAlgorithms.SHA256;
        IExternalSignature signature = new PrivateKeySignature(privateKey, digestAlgorithm);

        signer.SignDetached(signature, bouncyCert, null, null, null, 0, CryptoStandard.CADES);

        reader.Close();
    }

The only problem I have with this, is that the user, needs to have the certificate installed and marked as exportable for this to work. Is there any workaround?

Jack Casas
  • 914
  • 18
  • 37

1 Answers1

0

In iTextSharp 5 this would work for WCS certificate with non-exportable PK:

    Org.BouncyCastle.X509.X509Certificate[] chain;
    IExternalSignature es;

    System.Security.Cryptography.X509Certificates.X509Certificate2 cer = null;
    System.Security.Cryptography.X509Certificates.StoreLocation certStoreLocation = System.Security.Cryptography.X509Certificates.StoreLocation.LocalMachine;
    if (store.Equals("CurrentUser", StringComparison.OrdinalIgnoreCase))
        certStoreLocation = System.Security.Cryptography.X509Certificates.StoreLocation.CurrentUser;
    System.Security.Cryptography.X509Certificates.X509Store certStore = 
        new System.Security.Cryptography.X509Certificates.X509Store(certStoreLocation);
    certStore.Open(System.Security.Cryptography.X509Certificates.OpenFlags.ReadOnly);
    System.Security.Cryptography.X509Certificates.X509Certificate2Collection certs =
        certStore.Certificates.Find(System.Security.Cryptography.X509Certificates.X509FindType.FindByThumbprint, thumbprint, false);
    if (certs.Count > 0)
    {
        cer = certs[0];
    } else
    {
        throw new InvalidOperationException("Not found");
    }
    System.Security.Cryptography.X509Certificates.X509Chain x509chain = new System.Security.Cryptography.X509Certificates.X509Chain();
    x509chain.ChainPolicy.RevocationMode = System.Security.Cryptography.X509Certificates.X509RevocationMode.NoCheck;
    x509chain.Build(cer);

    // convert the chain to BouncyCastle format
    Org.BouncyCastle.X509.X509Certificate[] bouncyCastleChain = new Org.BouncyCastle.X509.X509Certificate[x509chain.ChainElements.Count];
    for (int i = 0; i < x509chain.ChainElements.Count; i++)
    {
        X509Certificate2 element = x509chain.ChainElements[i].Certificate;
        bouncyCastleChain[i] = new Org.BouncyCastle.X509.X509CertificateParser().ReadCertificate(element.RawData);
    }
    chain = bouncyCastleChain;
    es = new X509Certificate2Signature(cer, "SHA-1");

// Skipped code to prepare PsfStamper and PsfSignatureAppearance

MakeSignature.SignDetached(sap,
                           es,
                           chain,
                           null,
                           null,
                           tsa,
                           0,
                           CryptoStandard.CMS);
Vojtěch Dohnal
  • 7,867
  • 3
  • 43
  • 105