Microsoft CAPI returns NTE_BADKEYSET while using SHA256

251 views Asked by At

I have my private key in HSM and i am using Microsoft CAPI (SignerSignEx) to sign a file . If am able to generate a sha1 signature successfully ,but if i try to generate a sha256 signature using the same cert and same key on my hsm SignerSignEx() returns -2146893802 . (NTE_BAD_KEYSET) . I am not sure what is going wrong . My private key is stored in a CSP container on the HSM .

     void main(string filePath,  X509Certificate2 crossSigningCert, string timestampUrl)
      {
                UInt32 signatureAlgId =  0x0000800c //CALG_SHA_256 Signature Algorithm
                X509Certificate2 cert  = PKCSWrapper.GetCertificateFromHSM(SignCertLabel);
                uint dwFlags = 0x0;
                IntPtr pSignerCert = IntPtr.Zero;
                IntPtr pSubjectInfo = IntPtr.Zero;
                IntPtr pSignatureInfo = IntPtr.Zero;
                IntPtr pProviderInfo = IntPtr.Zero;

                    pSignerCert = CreateSignerCertStruct(cert, crossSigningCert);
                    pSubjectInfo = CreateSubjectInfoStruct(filePath);
                    pSignatureInfo = CreateSignerSignatureInfoStruct(signatureAlgId);
                    pProviderInfo = CreateProviderInfoStruct(cert);
                    SIGNER_CONTEXT signerContext;
                    int hResult = SignerSignEx(
                       dwFlags,
                       pSubjectInfo,
                       pSignerCert,
                       pSignatureInfo,
                       pProviderInfo,
                       timestampUrl,
                       IntPtr.Zero,
                       IntPtr.Zero,
                       out signerContext
                       );
    }
     private  IntPtr CreateSubjectInfoStruct(string filePath){      
        IntPtr assemblyFilePtr = Marshal.StringToHGlobalUni(filePath);
        SIGNER_FILE_INFO fileInfo = new SIGNER_FILE_INFO
        {
            cbSize = (uint)Marshal.SizeOf(typeof(SIGNER_FILE_INFO)),
            pwszFileName = assemblyFilePtr,
            hFile = IntPtr.Zero
        };
        SIGNER_SUBJECT_INFO subjectInfo = new SIGNER_SUBJECT_INFO
        {
            cbSize = (uint)Marshal.SizeOf(typeof(SIGNER_SUBJECT_INFO)),
            pdwIndex = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(uint)))
        };
        subjectInfo.Union1 = new SIGNER_SUBJECT_INFO.SubjectChoiceUnion
        {
            pSignerFileInfo = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(SIGNER_FILE_INFO)))
        };
        UInt32 SIGNER_SUBJECT_FILE = 0x1;
        var index = 0;

        Marshal.StructureToPtr(index, subjectInfo.pdwIndex, false);
        subjectInfo.dwSubjectChoice = SIGNER_SUBJECT_FILE; //SIGNER_SUBJECT_FILE
        Marshal.StructureToPtr(fileInfo, subjectInfo.Union1.pSignerFileInfo, false);
        IntPtr pSubjectInfo = Marshal.AllocHGlobal(Marshal.SizeOf(subjectInfo));
        Marshal.StructureToPtr(subjectInfo, pSubjectInfo, false);
        return pSubjectInfo;

      }
       private  IntPtr CreateProviderInfoStruct(X509Certificate2 cert){   
            ICspAsymmetricAlgorithm key = (ICspAsymmetricAlgorithm)cert.PrivateKey;
            const int PVK_TYPE_KEYCONTAINER = 2;
            const uint AT_SIGNATURE = 2;
            if (key == null){
                return IntPtr.Zero;
            }
            SIGNER_PROVIDER_INFO providerInfo = new SIGNER_PROVIDER_INFO{
                cbSize = (uint)Marshal.SizeOf(typeof(SIGNER_PROVIDER_INFO)),
                pwszProviderName = Marshal.StringToHGlobalUni(key.CspKeyContainerInfo.ProviderName),
                dwProviderType = (uint)key.CspKeyContainerInfo.ProviderType,
                dwKeySpec = AT_SIGNATURE/* AT_SIGNATURE */,
                dwPvkChoice = PVK_TYPE_KEYCONTAINER  /* The private key information is a key container.*/,
                Union1 = new SIGNER_PROVIDER_INFO.SignerProviderUnion
                {
                    pwszKeyContainer = Marshal.StringToHGlobalUni(key.CspKeyContainerInfo.KeyContainerName)
                },
            };
            IntPtr pProviderInfo = Marshal.AllocHGlobal(Marshal.SizeOf(providerInfo));
            Marshal.StructureToPtr(providerInfo, pProviderInfo, false);
            return pProviderInfo;
     }

      private  IntPtr CreateSignerSignatureInfoStruct(UInt32 signatureAlgId){
            const UInt32 ATTRIBUTES = 0x0; // SIGNER_NO_ATTR
            SIGNER_SIGNATURE_INFO signatureInfo = new SIGNER_SIGNATURE_INFO
            {
                cbSize = (uint)Marshal.SizeOf(typeof(SIGNER_SIGNATURE_INFO)),
                algidHash = signatureAlgId,
                dwAttrChoice = ATTRIBUTES,
                pAttrAuthCode = IntPtr.Zero,
                psAuthenticated = IntPtr.Zero,
                psUnauthenticated = IntPtr.Zero
            };
            IntPtr pSignatureInfo = Marshal.AllocHGlobal(Marshal.SizeOf(signatureInfo));
            Marshal.StructureToPtr(signatureInfo, pSignatureInfo, false);
            return pSignatureInfo;
        }

         private  IntPtr CreateSignerCertStruct(X509Certificate2 cert, X509Certificate2 crossCertifcate ){
            UInt32 SIGNER_CERT_STORE = 0x2;
            SIGNER_CERT signerCert = new SIGNER_CERT
            {
                cbSize = (uint)Marshal.SizeOf(typeof(SIGNER_CERT)),
                dwCertChoice = SIGNER_CERT_STORE,
                Union1 = new SIGNER_CERT.SignerCertUnion
                {
                    pCertStoreInfo = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(SIGNER_CERT_STORE_INFO)))
                },
                hwnd = IntPtr.Zero
            };
            IntPtr pCertContext = CertCreateCertificateContext(
                X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
                cert.GetRawCertData(),
                cert.GetRawCertData().Length);
            IntPtr pHCertStore = IntPtr.Zero;
            uint certPolicy = 0;
            if (crossCertifcate != null)
            {
                pHCertStore =  CreateCrossCertificateStore(crossCertifcate);
                certPolicy = (UInt32)CERT_POLICY.SIGNER_CERT_POLICY_STORE;
            }
            SIGNER_CERT_STORE_INFO certStoreInfo = new SIGNER_CERT_STORE_INFO
            {
                cbSize = (uint)Marshal.SizeOf(typeof(SIGNER_CERT_STORE_INFO)),
                pSigningCert = pCertContext,
                dwCertPolicy = (UInt32)CERT_POLICY.SIGNER_CERT_POLICY_CHAIN| certPolicy,
                hCertStore = pHCertStore
            };
            Marshal.StructureToPtr(certStoreInfo, signerCert.Union1.pCertStoreInfo, false);
            IntPtr pSignerCert = Marshal.AllocHGlobal(Marshal.SizeOf(signerCert));
            Marshal.StructureToPtr(signerCert, pSignerCert, false);
            return pSignerCert;
      }
1

There are 1 answers

0
alexrait On

You cannot create a full CMS with a SHA-256 and CSP on windows. The only way to do it, is to manually construct the CMS structure and sign the SHA-256 directly with a key. If you use RSACryptoServiceProvider instance and SHA-256 it should work.

Also, if you use a CNG provider, your code will work.