Search code examples
encryptiondigital-signaturecryptoapirsacryptoserviceproviderhsm

Sign and decrypt data using private keys located on a HSM


I have a task to sign and decrypt data, but the private keys are located at a HSM ( Luna SA, / Safenet ). I installed all the client software and connected the Luna SA CSP to the test servers.

Using the PKCS#11 functions provided, I am able to list and export the public keys on the HSM as PCCERT_CONTEXT (CertCreateCertificateContext). When I try to acquire the private key (using CryptoAPI function CryptAcquireCertificatePrivateKey), I receive an error code CRYPT_E_NO_KEY_PROPERTY.

I am probably missing the link between the certificate data and the CSP/HSM. Has anybody done something similar and can give any hints?

EDIT


I sucessfully created CER files from all the keys located on the HSM. When i know use signtool.exe (the one that ships with Microsoft Plattform SDK) i am able to sign a dll with a key on the HSM (the tool wizard lets me choose key container, key spec, ...). I tried to use the information the tool shows me and set the private key

bool LinkPrivateKey(PCCERT_CONTEXT cert)
{
    CRYPT_KEY_PROV_INFO cryptKeyProvInfo;
    memset(&cryptKeyProvInfo, 0, sizeof(cryptKeyProvInfo));
    cryptKeyProvInfo.pwszContainerName = L"MSS";
    cryptKeyProvInfo.pwszProvName = L"Luna Cryptographic Services for Microsoft Windows";
    cryptKeyProvInfo.dwProvType = PROV_RSA_FULL;
    cryptKeyProvInfo.dwFlags = CRYPT_MACHINE_KEYSET; // CERT_SET_KEY_CONTEXT_PROP_ID | CERT_SET_KEY_PROV_HANDLE_PROP_ID;
    cryptKeyProvInfo.cProvParam = 0;
    cryptKeyProvInfo.dwKeySpec = AT_SIGNATURE;

    return CertSetCertificateContextProperty(cert, CERT_KEY_PROV_INFO_PROP_ID, 0, &cryptKeyProvInfo) != FALSE;
}

but CryptAcquirePrivateKey still gives me the same error. I believe I am missing only a small bit here, since the signtool is able to access the private key

enter image description here

Edit2


The screnshot shows KEYEXCHANGE but I chose SIGNATURE

Edit3


I changed the LinkPrivateKeyfunction a little bit, now it works

bool LinkPrivateKey(PCCERT_CONTEXT cert)
{
    CRYPT_KEY_PROV_INFO cryptKeyProvInfo;
    memset(&cryptKeyProvInfo, 0, sizeof(cryptKeyProvInfo));
    cryptKeyProvInfo.pwszContainerName = L"MSS";
    cryptKeyProvInfo.pwszProvName = L"Luna Cryptographic Services for Microsoft Windows";
    cryptKeyProvInfo.dwProvType = PROV_RSA_FULL;
    cryptKeyProvInfo.dwFlags = 1; // CERT_SET_KEY_CONTEXT_PROP_ID | CERT_SET_KEY_PROV_HANDLE_PROP_ID;
    cryptKeyProvInfo.dwKeySpec = AT_SIGNATURE;

    return CertSetCertificateContextProperty(cert, CERT_KEY_PROV_INFO_PROP_ID, 0, &cryptKeyProvInfo) != FALSE;
}

Solution

  • As stated in my post, I can link the private key using

    I changed the LinkPrivateKeyfunction a little bit, now it works

    bool LinkPrivateKey(PCCERT_CONTEXT cert)
    {
        CRYPT_KEY_PROV_INFO cryptKeyProvInfo;
        memset(&cryptKeyProvInfo, 0, sizeof(cryptKeyProvInfo));
        cryptKeyProvInfo.pwszContainerName = L"MSS";
        cryptKeyProvInfo.pwszProvName = L"Luna Cryptographic Services for Microsoft Windows";
        cryptKeyProvInfo.dwProvType = PROV_RSA_FULL;
        cryptKeyProvInfo.dwFlags = 1; // CERT_SET_KEY_CONTEXT_PROP_ID | CERT_SET_KEY_PROV_HANDLE_PROP_ID;
        cryptKeyProvInfo.dwKeySpec = AT_SIGNATURE;
    
        return CertSetCertificateContextProperty(cert, CERT_KEY_PROV_INFO_PROP_ID, 0, &cryptKeyProvInfo) != FALSE;
    }
    

    YOu have to replace L"MSS"with the key container defined on you server. LunSA provides the tool keymap.exe that is insatlled along with the LunaCSP to get the container names.