Using Key Storage Provider (KSP) - Windows Only
If the target private key is managed by the Microsoft Software Key Storage Provider, another software provider, or any other KSP that allows export via PKCS#12 PFX, it is possible to move your key to the YubiHSM 2, but results may vary.
This process relies on using the -repairstore
functionality of the certutil
command, so the private key must only be present via the YubiHSM Key Storage Provider when performing this step. Please refer to the source storage provider documentation for how to cleanly and completely delete a private key.
Because KSP implementations differ, we recommend testing this procedure using your existing provider before affecting a live system.
Export your Existing Private Key and Certificate
Refer to your current KSP documentation on how to obtain a PKCS#12 PFX export of your certificate and private key.
Obtain your PFX file.
Split the certificate from the PFX file using
certutil
.PS1> certutil -split -dump <pfx file> This creates a file named ``<Cert Hash>.crt``.
If you are moving the key to the YubiHSM 2 on the same machine, you must delete the original private key in your current provider.
PS1> certutil -key
Locate the key that corresponds with the CA. It may look something like this:
Microsoft Software Key Storage Provider: EXAMPLE-CA abcdef1234fedcba4321abcdef123456_9cfc1053-1b5a-44d7- 8a7e-3a8a1c0d0db0 RSA AT_KEYEXCHANGE
To delete this example private key.
PS1> certutil -delkey -csp "Microsoft Software Key Storage Provider" "abcdef1234fedcba4321abcdef123456_9cfc1053-1b5a-44d7-8a7e-3 a8a1c0d0db0"
Import the Target Private Key
Using the instructions for importing a PFX private key, see PUT ASYMMETRIC KEY Command via yubihsm-shell
, import the target private key file to your YubiHSM 2.
Record the
Label
property of your imported key.Important
The
certutil
utility does not provide an easy way to split a key exported from the Software KSP into an unencrypted PEM file. It may be necessary to use another tool like OpenSSL to convert the key file to an unencrypted format for import into the HSM.Export the private key.
PS1> openssl pkcs12 -in <pfx file> -nocerts -out ca.key -nodes
To remove the passphrase from the private key.
PS1> openssl rsa -in ca.key -out ca.key
Restore the Target Certificate
Move the target certificate file (
<Cert Hash>.crt
) to the target machine.Import the certificate to the LocalMachine “My” store via your favorite method.
At this point, the certificate does not have an associated private key. We use the
-repairstore
functionality ofcertutil
to re-associate the certificate to the private key.Make sure that the target private key is visible via the YubiHSM KSP.
PS1> certutil -key -csp "YubiHSM Key Storage Provider" This command lists all private keys visible to the current Authentication Key. It also lists the private keys corresponding container names - which are equal to the :ref:`hsm2-concepts-label-label` property in the YubiHSM 2.
Open an elevated prompt and execute the command.
PS1> certutil -repairstore MY <Cert Hash>
Verify that the certificate has been associated with the YubiHSM KSP and has the correct
Key Container
property value.PS1> certutil -store My
Inspect the Key Container and Provider properties.
Warning
If you are moving your CA key to the YubiHSM 2 on the same machine, Windows Certificate Services (CertSvc) on the local machine writes the name of the KSP to its configuration section in the registry. When signing requests, the certificate service will fail if the KSP name does not match the name in the registry.
Update the KSP name for the local certificate service.
Open an elevated prompt and execute the commands.
PS1> certutil -setreg CA\CSP\Provider "YubiHSM Key Storage Provider" PS1> certutil -setreg CA\EncryptionCSP\Provider "YubiHSM Key Storage Provider"
Optionally, if you have multiple CAs on the same machine, or prefer to edit the registry directly. These settings are located at:
HKLM\System\CurrentControlSet\Services\CertSVC\Configuration\<CAName>\[CSP | EncryptionCSP]
Status Codes Reference
The YubiHSM software components have a standard set of status codes to report the status of an HSM operation. To comply with the expectations of specific platforms, these status codes are converted to the appropriate API status code.
Currently, this translation is only performed for the Windows Key Storage Provider. The error codes, their meanings and translated values are as follows.
Libyubihsm Error Code | Description | Windows CNG Translation |
---|---|---|
YHR_BUFFER_TOO_SMALL | Not enough space
to store data
|
NTE_BUFFER_TOO_SMALL |
YHR_CONNECTION_ERROR | Transport Backend
error
|
NTE_DEVICE_NOT_READY |
YHR_CONNECTOR_ERROR | Connector
operation Failed
|
NTE_DEVICE_NOT_READY |
YHR_CONNECTOR_NOT_FOUND | Unable to find a
suitable connector
|
NTE_DEVICE_NOT_READY |
YHR_CRYPTOGRAM_MISMATCH | Unable to verify
cryptogram
|
NTE_BAD_SIGNATURE |
YHR_DEVICE_AUTHENTICATION
_FAILED
|
Message encryption /
verification failed
|
NTE_INCORRECT_PASSWORD
|
YHR_DEVICE_COMMAND
_UNEXECUTED
|
The HSM attempted to
execute a command,
but it did not
complete in allotted
time. The command
has not terminated,
and the current
state of the session
is unavailable
|
NTE_SYS_ERR |
YHR_DEVICE_DEMO_MODE
|
Demo mode, power
cycle device
|
NTE_DEVICE_NOT_READY |
YHR_DEVICE_INSUFFICIENT
_PERMISSIONS
|
Wrong permissions
for operation
|
NTE_PERM |
YHR_DEVICE_INVALID
_COMMAND
|
Invalid command | NTE_NOT_SUPPORTED |
YHR_DEVICE_INVALID_DATA | Malformed command /
invalid data
|
NTE_INVALID_PARAMETER |
YHR_DEVICE_INVALID_ID | Illegal ID used
|
NTE_INVALID_PARAMETER[] |
YHR_DEVICE_INVALID_OTP | Invalid OTP
|
NTE_INCORRECT_PASSWORD |
YHR_DEVICE_INVALID
_SESSION
|
Invalid session | NTE_DEVICE_NOT_READY |
YHR_DEVICE_LOG_FULL
|
Log buffer is full
and forced audit is
set
|
NTE_DEVICE_NOT_READY |
YHR_DEVICE_OBJECT_EXISTS | An object with the
specified ID already
exists
|
NTE_EXISTS |
YHR_DEVICE_OBJECT
_NOT_FOUND
|
Object not found | NTE_NOT_FOUND |
YHR_DEVICE_OK | No error | NTE_OP_OK |
YHR_DEVICE_SESSION_FAILED | Session creation
failed
|
NTE_DEVICE_NOT_READY |
YHR_DEVICE_SESSIONS_FULL | All sessions are
allocated
|
NTE_DEVICE_NOT_READY |
YHR_DEVICE_STORAGE_FAILED | Storage failure | NTE_TOKEN_KEYSET
_STORAGE_FULL
|
YHR_DEVICE_WRONG_LENGTH | Wrong length | NTE_BAD_LEN |
YHR_GENERIC_ERROR | Generic error | NTE_FAIL |
YHR_INIT_ERROR | Unable to initialize
libyubihsm
|
NTE_PROVIDER_DLL_FAIL |
YHR_INVALID_PARAMETERS | Invalid argument to
a function
|
NTE_INVALID_PARAMETER |
YHR_MAC_MISMATCH
|
Unable to verify MAC
|
NTE_BAD_SIGNATURE
|
YHR_MEMORY_ERROR
|
The YubiHSM or
software library was
not able to allocate
memory to perform
the requested
operation
|
NTE_NO_MEMORY
|
YHR_SESSION
_AUTHENTICATION_FAILED
|
Unable to
authenticate session
|
NTE_INCORRECT_PASSWORD |
YHR_SUCCESS | The operation
completed
Successfully
|
ERROR_SUCCESS |
YHR_WRONG_LENGTH | This error may occur
if there is a
mismatch between the
YubiHSM firmware
version and
libyubihsm library
version
|
NTE_BAD_LEN |
Example: Creating a Code-Signing Certificate using the Key Storage Provider
This example will show you how to create a code-signing certificate request using a key generated and stored in the YubiHSM 2 via the Key Storage Provider (KSP). This type of code-signing certificate is appropriate for use with the Microsoft signtool
utility for digitally signing Windows binaries.
In this example, we use the command line certreq
utility. All procedures documented here are available in the Certificate Manager (certmgr.msc
) MMC snap-in if you prefer to use a GUI.
Note
For operations that take input data (from command line or file), releases prior to and including the current yubihsm2-sdk release have a size limit - 4kb in interactive mode, or 8kb in non-interactive mode.
Configure the Key Storage Provider
By default, the KSP will use the factory authentication key in slot 1. If the factory authentication key no longer exists or a different authentication key is desired, the KSP must first be configured with the desired key ID and password.
Note
The configured authentication key must at a minimum have the capabilities generate-asymmetric-key
, sign-pkcs
, and delegated capability sign-pkcs
. If you want the generated key to be exportable, then add the exportable-under-wrap
delegated capability.
Authentication Key Example
Create a new Authentication Key capable of generating exportable asymmetric keys through KSP.
yubihsm> put authkey 0 0 "GenerateKey" 1 generate-asymmetric-key,
sign-pkcs sign-pkcs,exportable-under-wrap password
Stored Authentication key 0x0e32
Create the Certificate Request Configuration File
To specify your request, the certreq
utility requires an .inf
file as input. An example file is supplied here.
Sample sign.inf
[Version]
Signature="$Windows NT$"
[NewRequest]
Subject = "CN=My Publisher" ; Entity name (dns name/upn for other cert types)
HashAlgorithm = sha256 ; Request uses sha256 hash
KeyAlgorithm = RSA ; Key pair generated using RSA algorithm
Exportable = FALSE ; Private key is not exportable
ExportableEncrypted = FALSE ; Private key is not exportable encrypted
KeyLength = 2048 ; YubiHSM KSP key sizes: 2048, 3072, 4096
KeySpec = 2 ; 1 = AT_KEYEXCHANGE, 2 = AT_SIGNATURE
KeyUsage = 0x80
; 80 = Digital Signature, 20 = Key Encipherment (bitmask)
MachineKeySet = FALSE
; True: cert belongs the local computer, False: current user
KeyUsageProperty = NCRYPT_ALLOW_SIGNING_FLAG
; Private key only used for signing, not decryption
UseExistingKeySet = FALSE ; Do not use an existing key pair
ProviderName = "YubiHSM Key Storage Provider"
ProviderType = 1
SMIME = FALSE ; No secure email function
UseExistingKeySet = FALSE ; Do not use an existing key pair
RequestType = PKCS10 ; Can be CMC, PKCS10, PKCS7 or Cert (self-signed)
[Strings]
szOID_ENHANCED_KEY_USAGE = "2.5.29.37"
szOID_CODE_SIGN = "1.3.6.1.5.5.7.3.3"
szOID_BASIC_CONSTRAINTS = "2.5.29.19"
[Extensions]
%szOID_ENHANCED_KEY_USAGE% = "{text}%szOID_CODE_SIGN%"
%szOID_BASIC_CONSTRAINTS% = "{text}ca=0&pathlength=0"
; If you are using ADCS with certificate templates, you may add
; a specific template under [RequestAttributes]
; [RequestAttributes]
; CertificateTemplate= CodeSigning
Create the Certificate Request
Once you have created the certificate request configuration file, pass it to certreq
as the input file argument. For example:
certreq -new sign.inf sign.req
Sign the Certificate Request
In the above example, the certificate request was written to sign.req
.
- Take this file and submit its contents to your CA for signature.
- Open the resulting file (for example,
sign.crt
) and install the certificate to your personal store.
Sign using Signtool
Open a prompt with
signtool
in the path.Sign your binary.
> signtool sign <binary name>
Identify your signing certificate by hash, if you have multiple certificates available for code signing.
signtool
shows you a list of valid certificates. Re-run sign tool with thesha1
hash of the certificate:> signtool sign /sha1 <certificate hash> <binary name>
Associate the YubiHSM private key to the certificate.
When importing the certificate for the first time on a new computer, you need to manually bind the certificate to the private key. This is needed because 1) the key is not stored with the certificate and 2) Windows doesn’t automatically create an association between the private key and the certificate.
After you import the certificate to your personal store, use the
certutil
utility provided by Windows.> certutil -repairstore my <certificate hash>
Troubleshooting
The error messages returned from signtool
are often unhelpful in diagnosing why a signing operation failed. In these situations there are a few commands you can use to track down the root cause.
When using signtool
, use the /v
and /debug
flags to get more detailed output.
The example below shows a response you might receive if the certificate is installed but the YubiHSM is not connected or is misconfigured.
> signtool sign /v /debug <binary name> After EKU filter, 1 certs were left. After expiry filter, 1 certs were left. After Hash filter, 1 certs were left. After Private Key filter, 0 certs were left. SignTool Error: No certificates were found that met all the given criteria.
Use
certutil
to check the validity of the imported certificate.> certutil -verifystore my <certificate hash> ================ Certificate 0 ================ Serial Number: 029fe48291dd587c1e6f42bca341291 ... Certificate is valid
Use
certutil
to check whether the KSP has been installed correctly. You should seeProvider Name: YubiHSM Key Storage Provider
as one of the entries with no errors.> certutil -csplist ... Provider Name: YubiHSM Key Storage Provider ...
Use
certutil
to check if the key is accessible through the storage provider. You can also add the-v
flag to get additional details.> certutil -csp "YubiHSM Key Storage Provider" -key YubiHSM Key Storage Provider: tq-75c94c4b-5e40-4e44-bcd2-ee3330d4942f RSA AT_SIGNATURE
Use
certutil
to dump certificate information.If the command shows
Cannot find the certificate and private key for decryption.
when using a new computer, it might indicate thatcertutil -repairstore
hasn’t yet been performed.> certutil -store my <certificate hash> ================ Certificate 0 ================ Serial Number: 029fe48291dd587c1e6f42bca341291 ... Private key is NOT exportable Signature test passed
For a detailed explanation of all options available in the request .inf
file, see the documentation for the certreq utility.
To generate a similar request using the Certificate Manager:
- Open the Certificate Manager snap-in.
- Select the Personal/Certificates store.
- Right click and select All Tasks > Advanced Operations > Create Custom Request.