'How to set private key to CmsSigner in .net 4.7

I have a program with .net 4.7 and we used a CMSSign class, it fail when try to compute sign, actually we convert the class from .Net Core and private property missed, the below code is from .net core

CmsSigner signer = new CmsSigner(xcert);
signer.PrivateKey = privateKey; // missed in .net 4.7 

and here full code from from 4.7 and it's not working as expected :

 Pkcs11InteropFactories factories = new Pkcs11InteropFactories();
        using (var lib = factories.Pkcs11LibraryFactory.LoadPkcs11Library(factories, dllPath, AppType.MultiThreaded))
        {
            ISlot slot = lib.GetSlotList(SlotsType.WithTokenPresent).First();
            if (slot is null)
            {
                return "No slots found";
            }

            ITokenInfo tokenInfo = slot.GetTokenInfo();
            using (ISession session = slot.OpenSession(SessionType.ReadOnly))
            {
                session.Login(CKU.CKU_USER, Encoding.UTF8.GetBytes("123456"));
                List<IObjectAttribute> certificateSearchAttributes = new List<IObjectAttribute>
                {
                    session.Factories.ObjectAttributeFactory.Create(CKA.CKA_CLASS, CKO.CKO_CERTIFICATE),
                    session.Factories.ObjectAttributeFactory.Create(CKA.CKA_TOKEN, true),
                    session.Factories.ObjectAttributeFactory.Create(CKA.CKA_CERTIFICATE_TYPE, CKC.CKC_X_509)
                };
                IObjectHandle certificate = session.FindAllObjects(certificateSearchAttributes).FirstOrDefault();
                if (certificate is null)
                {
                    return "Certificate not found";
                }

                var attributeValues = session.GetAttributeValue(certificate, new List<CKA>
                {
                    CKA.CKA_VALUE
                });


                var searchAttribute = new List<IObjectAttribute>()
                {
                    session.Factories.ObjectAttributeFactory.Create(CKA.CKA_CLASS, CKO.CKO_PRIVATE_KEY),
                    session.Factories.ObjectAttributeFactory.Create(CKA.CKA_KEY_TYPE, CKK.CKK_RSA)
                };

                IObjectHandle privateKeyHandler = session.FindAllObjects(searchAttribute).FirstOrDefault();

                var xcert = new X509Certificate2(attributeValues[0].GetValueAsByteArray());
                RSA privateKey = new TokenRSA(xcert, session, slot, privateKeyHandler);


                string serializedDocument = "Text To sign";
                byte[] data = Encoding.UTF8.GetBytes(serializedDocument);
                ContentInfo content = new ContentInfo(new Oid("1.2.840.113549.1.7.5"), data);
                SignedCms cms = new SignedCms(content, detached: true);
                CmsSigner signer = new CmsSigner(xcert);
                EssCertIDv2 bouncyCertificate = new EssCertIDv2(new Org.BouncyCastle.Asn1.X509.AlgorithmIdentifier(new DerObjectIdentifier("1.2.840.113549.1.9.16.2.47")), HashBytes(xcert.RawData));
                SigningCertificateV2 signerCertificateV2 = new SigningCertificateV2(new EssCertIDv2[1] { bouncyCertificate });
                signer.DigestAlgorithm = new Oid("2.16.840.1.101.3.4.2.1");
                signer.SignedAttributes.Add(new Pkcs9SigningTime(DateTime.UtcNow));
                signer.SignedAttributes.Add(new AsnEncodedData(new Oid("1.2.840.113549.1.9.16.2.47"), signerCertificateV2.GetEncoded()));
                cms.ComputeSignature(signer);
                byte[] output = cms.Encode();
                return Convert.ToBase64String(output, Base64FormattingOptions.None);
            }
        }


Solution 1:[1]

The .NET Framework version of CmsSigner only works when the certificate object is already coupled to its private key (cert.HasPrivateKey is true).

On .NET Framework 4.7 that pretty well requires putting the cert and private key together in a PFX, or having already had them associated in a cert that's in a cert store.

If privateKey is already just assigned something like cert.GetRSAPrivateKey() then you shouldn't need to assign signer.PrivateKey.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 bartonjs