Search code examples
c#encryptionitextbouncycastlehsm

Signing using iTextSharp on the Luna HSM


Environment:

C# 4.5, Windows Server 2008 R2, iTextSharp v5.5.1, Luna SA HSM hosted by GlobalSign.

Problem:

Whenever I try to sign a PDF I get the following exception:

Invalid provider type specified.
   at System.Security.Cryptography.Utils.CreateProvHandle(CspParameters parameters, Boolean randomKeyContainer)
   at System.Security.Cryptography.Utils.GetKeyPairHelper(CspAlgorithmType keyType, CspParameters parameters, Boolean randomKeyContainer, Int32 dwKeySize, SafeProvHandle& safeProvHandle, SafeKeyHandle& safeKeyHandle)
   at System.Security.Cryptography.RSACryptoServiceProvider.GetKeyPair()
   at System.Security.Cryptography.RSACryptoServiceProvider..ctor(Int32 dwKeySize, CspParameters parameters, Boolean useDefaultKeySize)
   at System.Security.Cryptography.X509Certificates.X509Certificate2.get_PrivateKey()
   at iTextSharp.text.pdf.security.X509Certificate2Signature..ctor(X509Certificate2 certificate, String hashAlgorithm)

Code:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using iTextSharp.text;
using iTextSharp.text.pdf;
using iTextSharp.text.pdf.security;
using Org.BouncyCastle.Security;
using X509Certificate = Org.BouncyCastle.X509.X509Certificate;

namespace SignWithHsm
{
    public class Sign
    {
    private const string _reason = "Test seal by eSignatur";
    private const string _location = "Copenhagen, Denmark";
    private const int _estimatedSize = 0;
    private readonly X509Certificate2 _certificate;
    private readonly ICollection<X509Certificate> _chain;
    private readonly IOcspClient _ocspClient;
    private readonly ICollection<ICrlClient> _crlList;
    private readonly ITSAClient _tsaClient;

    public Sign(X509Certificate2 certificate)
    {
        _certificate = certificate;
        _chain = GetChain();
        _ocspClient = new OcspClientBouncyCastle();
        _crlList = new List<ICrlClient> {new CrlClientOnline(_chain)};
        _tsaClient = GetTsaClient(_chain);
    }

    private ICollection<X509Certificate> GetChain()
    {
        var x509Store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
        x509Store.Open(OpenFlags.ReadOnly);

        var x509Chain = new X509Chain();
        x509Chain.Build(_certificate);

        var chain = (from X509ChainElement x509ChainElement in x509Chain.ChainElements
            select DotNetUtilities.FromX509Certificate(x509ChainElement.Certificate)).ToList();

        x509Store.Close();
        return chain;
    }

    private ITSAClient GetTsaClient(IEnumerable<X509Certificate> chain)
    {
        return (from cert in chain
            select CertificateUtil.GetTSAURL(cert)
            into tsaUrl
            where tsaUrl != null
            select new TSAClientBouncyCastle(tsaUrl)).FirstOrDefault();
    }

    public void Execute(string src, string dest)
    {
        using (var reader = new PdfReader(src))
        {
            using (var os = new FileStream(dest, FileMode.Create))
            {
                using (var stamper = PdfStamper.CreateSignature(reader, os, '\0'))
                {
                    var appearance = stamper.SignatureAppearance;
                    appearance.Reason = _reason;
                    appearance.Location = _location;
                    appearance.SetVisibleSignature(new Rectangle(0, 0, 0, 0), 1, string.Format("seal-{0}", DateTime.Now));
                    var pks = new X509Certificate2Signature(_certificate, DigestAlgorithms.SHA256);
                    MakeSignature.SignDetached(appearance, pks, _chain, _crlList, _ocspClient, _tsaClient, _estimatedSize, CryptoStandard.CMS);
                }
            }
        }
     }
   }
}

Connection to the HSM has been verified. The certificate to the Sign class is the certificate I got from GlobalSign. It is not the certificate stored on the HSM.

Why do I get the exception? What am I missing?


Solution

  • Problem solved. Instead of storing the certificate in the KSP it is placed in the CSP. Then we can use the SignDetached method.