Search code examples
c#.net-corecryptographycng

Signing with CMS and RSACng in .NET Core


It seems that CNG replaces CSP in .NET Core As stated here:

This method is only supported on .NET Framework. Its use on .NET Core throws a PlatformNotSupportedException.

But CmsSigner doesn't expose any API to support CNG keys, for example, there is nothing like CngParameters, to specify the CNG key to sign with.

When I use CmsSigner(CspParameters) in .NET Framework, it creates a dummy certificate used for signing. I tried this just to see what will happen:

var signer = new CmsSigner();
signer.PrivateKey = new RSACng(CngKey.Open("rsaKey"));
signer.SignedAttributes.Add(new Pkcs9SigningTime());

var signedCms = new SignedCms(new ContentInfo(new byte[] { 1, 2, 3 }), false);
signedCms.ComputeSignature(signer);
var encodeByteBlock = signedCms.Encode();

but it threw this exception at the ComputeSignature call:

System.InvalidOperationException: 'No signer certificate was provided.'

In .NET Framework, I can do this:

var cspObj = new CspParameters()
{
    ProviderName = "provider",
    ProviderType = 1,
    KeyNumber = (int)KeyNumber.Signature,
    Flags = CspProviderFlags.UseExistingKey,
    KeyContainerName = "ContainerName"
};
var signer = new CmsSigner(cspObj)
{
    DigestAlgorithm = new Oid(_signerHashAlgorithmOid)
};

signer.SignedAttributes.Add(new Pkcs9SigningTime());

var signedCms = new SignedCms(contentInfo, true);
signedCms.ComputeSignature(signer);
var encodeByteBlock = signedCms.Encode();

Solution

  • For the .NET Core implementation you need to provide a certificate with a bound private key. If the certificate isn't important for your purposes, you can create a dummy certificate of your own. This sample uses RSA-SHA256 whereas the CspParameters version in .NET Framework uses RSA-SHA1, but otherwise it's essentially the same.

    using (CngKey cngKey = CngKey.Open(...))
    using (RSA rsa = new RSACng(cngKey))
    {
        CertificateRequest req = new CertificateRequest(
            "CN=CMS Signer Dummy Certificate",
            rsa,
            HashAlgorithmName.SHA256,
            RSASignaturePadding.Pkcs1);
    
        DateTimeOffset now = DateTimeOffset.UtcNow;
    
       using (X509Certificate2 cert = req.CreateSelfSigned(now, now.AddYears(1)))
       {
           CmsSigner signer = new CmsSigner(cert);
           ...
       }
    }