.. hsm2-ksp-windows-guide.rst .. _hsm2-ksp-windows-guide-label: ================================================ 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. :Step 1: Obtain your PFX file. :Step 2: Split the certificate from the PFX file using ``certutil``. .. code-block:: bash PS1> certutil -split -dump This creates a file named ``.crt``. :Step 3: 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. .. code-block:: bash PS1> certutil -key :Step 4: Locate the key that corresponds with the CA. It may look something like this: .. code-block:: bash Microsoft Software Key Storage Provider: EXAMPLE-CA abcdef1234fedcba4321abcdef123456_9cfc1053-1b5a-44d7- 8a7e-3a8a1c0d0db0 RSA AT_KEYEXCHANGE :Step 5: To delete this example private key. .. code-block:: bash 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 :ref:`hsm2-cmd-put-asymmetric-key-label` via ``yubihsm-shell``, import the target private key file to your YubiHSM 2. :Step 1: 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. :Step 2: Export the private key. .. code-block:: bash PS1> openssl pkcs12 -in -nocerts -out ca.key -nodes :Step 3: To remove the passphrase from the private key. .. code-block:: bash PS1> openssl rsa -in ca.key -out ca.key Restore the Target Certificate =============================== :Step 1: Move the target certificate file (``.crt``) to the target machine. :Step 2: 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 of ``certutil`` to re-associate the certificate to the private key. :Step 3: Make sure that the target private key is visible via the YubiHSM KSP. .. code-block:: bash 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. :Step 4: Open an elevated prompt and execute the command. .. code-block:: bash PS1> certutil -repairstore MY :Step 5: Verify that the certificate has been associated with the YubiHSM KSP and has the correct ``Key Container`` property value. .. code-block:: bash PS1> certutil -store My :Step 6: 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. :Step 7: Update the KSP name for the local certificate service. * Open an elevated prompt and execute the commands. .. code-block:: bash 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\\[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. .. table:: +---------------------------+----------------------+-------------------------+ | Libyubihsm Error Code | Description | Windows CNG Translation | +===========================+======================+=========================+ | YHR_BUFFER_TOO_SMALL || Not enough space | NTE_BUFFER_TOO_SMALL | | || to store data | | +---------------------------+----------------------+-------------------------+ | YHR_CONNECTION_ERROR || Transport Backend | NTE_DEVICE_NOT_READY | | || error | | +---------------------------+----------------------+-------------------------+ | YHR_CONNECTOR_ERROR || Connector | NTE_DEVICE_NOT_READY | | || operation Failed | | +---------------------------+----------------------+-------------------------+ | YHR_CONNECTOR_NOT_FOUND || Unable to find a | NTE_DEVICE_NOT_READY | | || suitable connector | | +---------------------------+----------------------+-------------------------+ | YHR_CRYPTOGRAM_MISMATCH || Unable to verify | NTE_BAD_SIGNATURE | | || cryptogram | | +---------------------------+----------------------+-------------------------+ || YHR_DEVICE_AUTHENTICATION|| Message encryption /|| NTE_INCORRECT_PASSWORD | || _FAILED || verification failed || | +---------------------------+----------------------+-------------------------+ || YHR_DEVICE_COMMAND || The HSM attempted to| NTE_SYS_ERR | || _UNEXECUTED || 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 | | +---------------------------+----------------------+-------------------------+ || YHR_DEVICE_DEMO_MODE || Demo mode, power | NTE_DEVICE_NOT_READY | || || cycle device | | +---------------------------+----------------------+-------------------------+ || YHR_DEVICE_INSUFFICIENT || Wrong permissions | NTE_PERM | || _PERMISSIONS || for operation | | +---------------------------+----------------------+-------------------------+ || YHR_DEVICE_INVALID | Invalid command | NTE_NOT_SUPPORTED | || _COMMAND | | | +---------------------------+----------------------+-------------------------+ | YHR_DEVICE_INVALID_DATA || Malformed command / | NTE_INVALID_PARAMETER | | || invalid data | | +---------------------------+----------------------+-------------------------+ | YHR_DEVICE_INVALID_ID || Illegal ID used | NTE_INVALID_PARAMETER[] | +---------------------------+----------------------+-------------------------+ | YHR_DEVICE_INVALID_OTP || Invalid OTP | NTE_INCORRECT_PASSWORD | +---------------------------+----------------------+-------------------------+ || YHR_DEVICE_INVALID | Invalid session | NTE_DEVICE_NOT_READY | || _SESSION | | | +---------------------------+----------------------+-------------------------+ || YHR_DEVICE_LOG_FULL || Log buffer is full | NTE_DEVICE_NOT_READY | || || and forced audit is | | || || set | | +---------------------------+----------------------+-------------------------+ | YHR_DEVICE_OBJECT_EXISTS || An object with the | NTE_EXISTS | | || specified ID already| | | || exists | | +---------------------------+----------------------+-------------------------+ || YHR_DEVICE_OBJECT | Object not found | NTE_NOT_FOUND | || _NOT_FOUND | | | +---------------------------+----------------------+-------------------------+ | YHR_DEVICE_OK | No error | NTE_OP_OK | +---------------------------+----------------------+-------------------------+ | YHR_DEVICE_SESSION_FAILED || Session creation | NTE_DEVICE_NOT_READY | | || failed | | +---------------------------+----------------------+-------------------------+ | YHR_DEVICE_SESSIONS_FULL || All sessions are | NTE_DEVICE_NOT_READY | | || allocated | | +---------------------------+----------------------+-------------------------+ | 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| NTE_PROVIDER_DLL_FAIL | | || libyubihsm | | +---------------------------+----------------------+-------------------------+ | YHR_INVALID_PARAMETERS || Invalid argument to | NTE_INVALID_PARAMETER | | || a function | | +---------------------------+----------------------+-------------------------+ || YHR_MAC_MISMATCH || Unable to verify MAC|| NTE_BAD_SIGNATURE | +---------------------------+----------------------+-------------------------+ || YHR_MEMORY_ERROR || The YubiHSM or || NTE_NO_MEMORY | | || software library was| | | || not able to allocate| | | || memory to perform | | | || the requested | | | || operation | | +---------------------------+----------------------+-------------------------+ || YHR_SESSION || Unable to | NTE_INCORRECT_PASSWORD | || _AUTHENTICATION_FAILED || authenticate session| | +---------------------------+----------------------+-------------------------+ | YHR_SUCCESS || The operation | ERROR_SUCCESS | | || completed | | | || Successfully | | +---------------------------+----------------------+-------------------------+ | YHR_WRONG_LENGTH || This error may occur| NTE_BAD_LEN | | || if there is a | | | || mismatch between the| | | || YubiHSM firmware | | | || version and | | | || libyubihsm library | | | || version | | +---------------------------+----------------------+-------------------------+ .. _hsm2-ksp-windows-code-signing-cert-ksp-label: 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. .. code-block:: bash 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** .. code-block:: bash [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: .. code-block:: bash certreq -new sign.inf sign.req Sign the Certificate Request ----------------------------- In the above example, the certificate request was written to ``sign.req``. :Step 1: Take this file and submit its contents to your CA for signature. :Step 2: Open the resulting file (for example, ``sign.crt``) and install the certificate to your personal store. Sign using Signtool --------------------- :Step 1: Open a prompt with ``signtool`` in the path. :Step 2: Sign your binary. .. code-block:: bash > signtool sign :Step 3: 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 the ``sha1`` hash of the certificate: .. code-block:: bash > signtool sign /sha1 :Step 4: 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. .. code-block:: bash > certutil -repairstore my 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. .. code-block:: bash > signtool sign /v /debug 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. .. code-block:: bash > certutil -verifystore my ================ Certificate 0 ================ Serial Number: 029fe48291dd587c1e6f42bca341291 ... Certificate is valid * Use ``certutil`` to check whether the KSP has been installed correctly. You should see ``Provider Name: YubiHSM Key Storage Provider`` as one of the entries with no errors. .. code-block:: bash > 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. .. code-block:: bash > 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 that ``certutil -repairstore`` hasn’t yet been performed. .. code-block:: bash > certutil -store my ================ 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: 1. Open the Certificate Manager snap-in. 2. Select the Personal/Certificates store. 3. Right click and select **All Tasks > Advanced Operations > Create Custom Request**.