Create a TPM backed certificate request (on windows)

Security in IT is around everywhere and within the recent years certificates have become the standard on connection security on the web but also on VPN connections like when using openvpn.

The most secure way to store a certificate - or rather the private key - is to generate it directly in the TPM and just derive a certificate signing request (CSR) from it. Using this way, the secret never leaves hardware security, not during creation, not during usage.

Creating the CSR

In order to create the signing request, you will need to use certreq and a configuration file.

The configuration ini file looks like this

[NewRequest]
Subject = "CN=MYTPMBASEDCERT"
FriendlyName = MYTPMBASEDCERT
HashAlgorithm = SHA256
KeyAlgorithm = ECDSA_P384
KeyLength = 384
MachineKeySet = TRUE
Exportable = FALSE
MachineKeySet = TRUE
ProviderName = "Microsoft Platform Crypto Provider"
request.inf

The next step will be to request the certificate:

certreq -new request.inf request.csr
Create csr

As a result you will get a file containing the request that you can pass on to the CA to get it signed.

The output will look somehow similar to this:

PS C:\temp> certreq -new .\request.inf .\request.csr

CertReq: Request Created
PS C:\temp> cat .\request.csr
-----BEGIN NEW CERTIFICATE REQUEST-----
MIICFDCCAZsCAQAwGTEXMBUGA1UEAwwOTVlUUE1CQVNFRENFUlQwdjAQBgcqhkjO
PQIBBgUrgQQAIgNiAARaqxQM3ohGiQe/ZjvdAwXJId5TxglCtlvrKIDs6wkDQGIV
JNseOCX6debNNSGTTsrfEiYt2XJOOosWKcvZcyBv8EjvsZZrrH7Tb40wra4BLMv7
d6UCXNtfORoqTkR2Nr6gggEBMBwGCisGAQQBgjcNAgMxDhYMMTAuMC4yMjYyMS4y
MC4GCSqGSIb3DQEJDjEhMB8wHQYDVR0OBBYEFOkuKFeBNVceshIKcjbPbOihp1D1
MFMGCSsGAQQBgjcVFDFGMEQCAQkMGjgwMzhGQkYyQjRBOC5kYy5udXZvdGV4LmRl
DBY4MDM4RkJGMkI0QThcbXJnb29kY2F0DAtjZXJ0cmVxLmV4ZTBcBgorBgEEAYI3
DQICMU4wTAIBAB5EAE0AaQBjAHIAbwBzAG8AZgB0ACAAUABsAGEAdABmAG8AcgBt
ACAAQwByAHkAcAB0AG8AIABQAHIAbwB2AGkAZABlAHIDAQAwCgYIKoZIzj0EAwID
ZwAwZAIwHvPeMxsbXul8IW+xeDAZTj6PZ/zPSaRphw4u54R0+TTOsMgJlDBLE95g
0a/XXLnpAjBTnjpNHvPVtgOIWkAtOtMgaAdzldH49JUVJUSPYtPDQTkj97zcYHos
jjmAAY80BlU=
-----END NEW CERTIFICATE REQUEST-----
CSR creation

Importing the certificate

Having completed the certificate request and received the certificate itself, it's time to import it.

# if it's a machine cert
certreq -accept -machine certificate.crt

# if it's a user cert
certreq -accept certificate.crt
import certificate
CA trust requiredIf you are importing from an untrusted CA (which is for example mostly the case when you create an openvpn certificate with CAs specific to the destination) you need to temporary import the CA as trusted and remove it afterwards from the trusted root CAs (to avoid abuse potential in case of a compromised CA).

Nifty issues

Creating TPM based certificates has quite some sneaky issues, like it requires you to carefully select the algorithm, if you don't do this well, you are receiving errors like: The requested operation is not supported. 0x80090029 (-2146893783 NTE_NOT_SUPPORTED)

This indicates that the selected algorithm (ECDH_P384 in this example) is not supported by the crypto provider and the creation failed.

How to get information about supported algorithms?

For this you can use certutil and list all algorithms for a specific (or all) crypto store provider.

certutil -csp "Microsoft Platform Crypto Provider" -csptest
List information about crypto provider

A shortened example output from my machine looks like this:

certutil -csp "Microsoft Platform Crypto Provider" -csptest

Provider Name: Microsoft Platform Crypto Provider
  Name: Microsoft Platform Crypto Provider
  Impl Type: 1 (0x1)
    NCRYPT_IMPL_HARDWARE_FLAG -- 1

  Version: 65536 (0x10000)
  Pass

  Provider Module:
      UM(1): PCPKsp.dll
      0(1): 10001, 0
        0: KEY_STORAGE

  Asymmetric Encryption Algorithms:
   RSA
    BCRYPT_ASYMMETRIC_ENCRYPTION_INTERFACE -- 3
    NCRYPT_ASYMMETRIC_ENCRYPTION_OPERATION -- 4
    NCRYPT_SIGNATURE_OPERATION -- 10 (16)

[...]

  Pass

   ECDH_P384
    BCRYPT_SECRET_AGREEMENT_INTERFACE -- 4
    NCRYPT_SECRET_AGREEMENT_OPERATION -- 8

    NCryptCreatePersistedKey(Microsoft Platform Crypto Provider, ECDH_P384)
  Algorithm Group: ECDH
  Algorithm Name: ECDH
  ECCCurveName: nistP384
  Length: 0 (0x0)
  Lengths:
    dwMinLength = 384 (0x180)
    dwMaxLength = 384 (0x180)
    dwIncrement = 0 (0x0)
    dwDefaultLength = 384 (0x180)
  Block Length: 96 (0x60)
  Export Policy: 0 (0x0)

  HWND Handle:Binary:
0000    00 00 00 00 00 00 00 00                            ........
  Key Usage: 1 (0x1)
    NCRYPT_ALLOW_DECRYPT_FLAG -- 1

  PCP_KEY_USAGE_POLICY: 65538 (0x10002)
    NCRYPT_TPM12_PROVIDER -- 10000 (65536)
    NCRYPT_PCP_ENCRYPTION_KEY -- 2

  Pass

   HMAC-SHA256
    BCRYPT_SIGNATURE_INTERFACE -- 5
    NCRYPT_SIGNATURE_OPERATION -- 10 (16)
    0x40 (64)

    NCryptCreatePersistedKey(Microsoft Platform Crypto Provider, HMAC-SHA256)
  Algorithm Name: HMAC-SHA256
  Length: 0 (0x0)
  Export Policy: 0 (0x0)

  HWND Handle:Binary:
0000    00 00 00 00 00 00 00 00                            ........
  Key Usage: 3 (0x3)
    NCRYPT_ALLOW_DECRYPT_FLAG -- 1
    NCRYPT_ALLOW_SIGNING_FLAG -- 2

  PCP_KEY_USAGE_POLICY: 65539 (0x10003)
    NCRYPT_TPM12_PROVIDER -- 10000 (65536)
    NCRYPT_PCP_SIGNATURE_KEY -- 1
    NCRYPT_PCP_ENCRYPTION_KEY -- 2
    NCRYPT_PCP_GENERIC_KEY -- 3

  Pass


BCryptEnumAlgorithms:
  Hash Algorithms:
    SHA256
    SHA384
    SHA512
    SHA1
    MD5
    MD4
    MD2
    AES-GMAC
    AES-CMAC

  Asymmetric Encryption Algorithms:
    RSA

  Secret Agreement Algorithms:
    DH
    ECDH_P256
    ECDH_P384
    ECDH_P521
    ECDH

  Signature Algorithms:
    RSA_SIGN
    ECDSA_P256
    ECDSA_P384
    ECDSA_P521
    ECDSA
    DSA

  Cipher Algorithms:
    AES
      dwMinLength=128 dwMaxLength=256 dwIncrement=64
    [...]
    CHACHA20_POLY1305
      dwMinLength=256 dwMaxLength=256 dwIncrement=0

  RNG Algorithms:
    RNG
    FIPS186DSARNG
    DUALECRNG

  Asymmetric Algorithms:
    RSA
    DH
    ECDH_P256
    ECDH_P384
    ECDH_P521
    ECDH
    RSA_SIGN
    ECDSA_P256
    ECDSA_P384
    ECDSA_P521
    ECDSA
    DSA

  All Algorithms:
    AES
      dwMinLength=128 dwMaxLength=256 dwIncrement=64
    3DES
      dwMinLength=192 dwMaxLength=192 dwIncrement=0
    3DES_112
      dwMinLength=128 dwMaxLength=128 dwIncrement=0
    XTS-AES
	[...]
    DUALECRNG
    SP800_108_CTR_HMAC
    SP800_56A_CONCAT
    PBKDF2
    CAPI_KDF
    TLS1_1_KDF
    TLS1_2_KDF
    HKDF

CertUtil: -csptest command completed successfully.

So, now you have some glimpse information about how to create TPM based certificate (requests) - time to get your hands dirty on it! :-)