OpenSSL tpm2 provider. C++ API to issue a CSR using TPM-resident private key

56 views Asked by At

Is it possible to implement the functionality shown in the bash script below from a C++ application, possibly using an OpenSSL provider obtained using:

OSSL_PROVIDER * tpm2_provider = OSSL_PROVIDER_load(NULL, "tpm2");

or by another method?

# Create CSR using TPM-resident private key
openssl req -provider tpm2 -provider default -propquery '?provider=tpm2'
    -new
    -key handle:$TPMHandle
    -config openssl.conf
    -reqexts v3_req
    -out device.csr

Can the private key remain in the TPM or is it necessary to extract the private key into the application, in order to sign the CSR in the C++ code?

I am able to create a CSR using the bash script with the openssl tpm2 provider to sign the CSR. I don't see a way to achieve the same functionality using the C or C++ APIs.

This code works but it retrieves the private key from the TPM. Can I achieve the same result without extracting the private key?

EVP_PKEY * GetPrivateKeyFromTPM(void) {

    OSSL_STORE_CTX *storeCtx = NULL;
    storeCtx = OSSL_STORE_open_ex("handle:0x81005020", tpm2_libctx,"?provider=tpm2", NULL, NULL, NULL,NULL, NULL);

    while (!OSSL_STORE_eof(storeCtx)) {
      OSSL_STORE_INFO *info = OSSL_STORE_load(storeCtx);

      switch (OSSL_STORE_INFO_get_type(info)) {
      case OSSL_STORE_INFO_PKEY:
        EVP_PKEY *TPMpkey = OSSL_STORE_INFO_get1_PKEY(info);

        if (TPMpkey) {
          OSSL_STORE_close(storeCtx);
          return TPMpkey;
        }
        break;
      }
    }

    OSSL_STORE_close(storeCtx);

    return NULL;
}
1

There are 1 answers

0
AndrewPBCN On

This C++ code can be used to get a Reference to a TPM-resident private key which can be used for crypto operations. The key itself remains in the TPM.

In my case, I wanted to create a CSR and sign it with the TPM-resident private key. The EVP_PKEY pointer returned from this code can be used to sign the CSR using other OpenSSL library calls in the normal way.

TPM_Private_Key_Handle argument is in the form 0x8000000.

EVP_PKEY* AWSCertificateMgr::GetPrivateKeyFromTPM(const std::string & TPM_Private_Key_Handle)

const std::string TPMHandle = "handle:" + TPM_Private_Key_Handle;


OSSL_STORE_CTX *storeCtx = OSSL_STORE_open_ex(TPMHandle.c_str(), tpm2_libctx, "?provider=tpm2",
                                              NULL, NULL, NULL, NULL, NULL);

if (!storeCtx) {
    LOG4CXX_ERROR(AppLogger, "Failed to open store context");
    return nullptr;
}

EVP_PKEY *TPMpkey = nullptr;
OSSL_STORE_INFO *info = nullptr;

while (!OSSL_STORE_eof(storeCtx) && (info = OSSL_STORE_load(storeCtx)) != nullptr) {
    int type = OSSL_STORE_INFO_get_type(info);

    if (type == OSSL_STORE_INFO_PKEY) {
        TPMpkey = OSSL_STORE_INFO_get1_PKEY(info);
        OSSL_STORE_INFO_free(info);

        if (TPMpkey) {
            LOG4CXX_INFO(AppLogger, "GetPrivateKeyFromTPM Succeeded");
            break; // Exit the loop since the key has been found                                                                                  
        }
    } else {
        OSSL_STORE_INFO_free(info); // Ensure info is freed if not the expected type                                                              
    }
}

OSSL_STORE_close(storeCtx);

if (!TPMpkey) {
    LOG4CXX_ERROR(AppLogger, "Failed to retrieve TPM key");
}

return TPMpkey;

}

Code Explanation

Opening a Store Context: The OSSL_STORE_open_ex function opens a store context for a specified URI, which in this case is a TPM handle. This is a reference to where the key is stored, not the key itself.

The store context is an abstraction that allows OpenSSL to access keys and other objects in a variety of locations in a uniform manner.

The "?provider=tpm2" part specifies that the TPM 2.0 provider should be used.

Reading the Key: The code then enters a loop where it attempts to load objects from the store context using OSSL_STORE_load. For each object loaded, it checks if the object is a private key (OSSL_STORE_INFO_PKEY).

Accessing the Private Key: If a private key is found, it is accessed via OSSL_STORE_INFO_get1_PKEY, which increases the reference count of the EVP_PKEY object, meaning the caller is responsible for freeing it.

This EVP_PKEY object can then be used in OpenSSL cryptographic operations, but the actual private key material remains securely within the TPM.

Closure and Cleanup: The loop exits once the key is found or there are no more objects to load. The store context is closed, and the EVP_PKEY object is returned for use in the application.