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;
}
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.