Search code examples
c#.netcryptographyrsapkcs#7

How to force CmsSigner to use RSASSA-PSS (RsaPss) when signing with an X509Certificate with RSA assymetric parameters


I am creating signed & encrypted pkcs 7 data. The certificates that I use to generate signatures are issued by an external party (goverment agency).

The 'other-side' only supports signatures based on a SHA256 digest, computed using RSASSA-PSS, but CmsSigner (internally used by SignedCms) automatically chooses 'plain RSA'.

Creating an RSASSA-PSS (or RsaPss) signature would not be problem. The issue at hand is that CmsSigner seems to choose the signature algorithm, based on the certificate's key pair algorithm.

Code snippet:

public static byte[] EncryptDotNet(P12Keystore p12KeyStore, byte[] secret, params Etk[] etks)
    {
        if (etks == null || etks?.Any() == false)
        {
            throw new ArgumentNullException(nameof(etks));
        }

        var authenticationCertificate = p12KeyStore.AuthenticationCert;

        var cmsSigner = new CmsSigner(SubjectIdentifierType.IssuerAndSerialNumber, authenticationCertificate)
        {
            IncludeOption = X509IncludeOption.EndCertOnly,
            DigestAlgorithm = new Oid(oidDigestAlgoSHA256)
        };

        var content = new ContentInfo(secret);
        var innerSignedCms = new SignedCms(content);
        innerSignedCms.ComputeSignature(cmsSigner, true);

        if (innerSignedCms.SignerInfos[0].SignatureAlgorithm.Value != signatureAlgorithmRSASSAPSS)
        {
            //---> does not comply with expectation.
        }

I have tried using reflection to setting the the algorithm oid for RSASSA-PSS to the public/private key of the certificate, didn't seem to have an impact. Now I am wondering if I can take the RSA output and do the PSS padding myself? Anyhow, I am open to all suggestions...


Solution

  • This became possible in .NET 6+, with the System.Security.Cryptography.Pkcs package at version 7.0.0 (or higher):

    CmsSigner signer = new CmsSigner(...);
    signer.SignaturePadding = RSASignaturePadding.Pss;
    ...
    signedCms.ComputeSignature(signer);
    

    or you can specify the padding in a constructor overload:

    CmsSigner signer = new CmsSigner(..., signaturePadding: RSASignaturePadding.Pss);
    ...
    signedCms.ComputeSignature(signer);
    

    The support was added in https://github.com/dotnet/runtime/pull/60316/files, and you can see several examples in the tests that were added with it.