Skip to content

Commit

Permalink
FAPI: Add reading of intermediate certificates from NV ram.
Browse files Browse the repository at this point in the history
TCG's EK credential profile allows the storage of intermediate
certificates in the address range 0x01c00100 - 0x01c001ff.
The EK verification using these certificates if available is now
implemented.

Signed-off-by: Juergen Repp <[email protected]>
  • Loading branch information
JuergenReppSIT committed Feb 17, 2025
1 parent 7d2e74e commit 6c4c0c5
Show file tree
Hide file tree
Showing 6 changed files with 274 additions and 12 deletions.
46 changes: 38 additions & 8 deletions src/tss2-fapi/api/Fapi_Provision.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
#include "ifapi_helpers.h" // for ifapi_init_hierarchy_object, ifapi_c...
#include "ifapi_io.h" // for ifapi_io_read_async, ifapi_io_read_f...
#include "ifapi_keystore.h" // for IFAPI_OBJECT, IFAPI_OBJECT_UNION
#include "ifapi_macros.h" // for statecase, fallthrough, goto_if_erro...
#include "ifapi_macros.h" // for statecase, fallthrough, goto_if_erro..
#include "ifapi_verify_cert_chain.h" // for ifapi_verify_cert_chain
#include "ifapi_profiles.h" // for IFAPI_PROFILE, IFAPI_PROFILES
#include "tss2_common.h" // for TSS2_FAPI_RC_TRY_AGAIN, BYTE, TSS2_RC
#include "tss2_esys.h" // for ESYS_TR_NONE, Esys_GetCapability_Async
Expand All @@ -36,6 +37,8 @@
#include "util/log.h" // for goto_if_error, SAFE_FREE, goto_error

#define EK_CERT_RANGE (0x01c07fff)
#define EK_CERT_CHAIN_MIN 0x01c00100
#define EK_CERT_CHAIN_MAX 0x01c001ff
#define RSA_EK_NONCE_NV_INDEX 0x01c00003
#define RSA_EK_TEMPLATE_NV_INDEX 0x01c00004
#define ECC_EK_NONCE_NV_INDEX 0x01c0000b
Expand Down Expand Up @@ -784,6 +787,11 @@ Fapi_Provision_Finish(FAPI_CONTEXT *context)

/* Filter out NV handles beyond the EK cert range */
for (size_t i = 0; i < command->cert_count; i++) {
/* Check whether a cert chain exists. */
if (command->capabilityData->data.handles.handle[i] >= EK_CERT_CHAIN_MIN &&
command->capabilityData->data.handles.handle[i] <= EK_CERT_CHAIN_MAX) {
command->cert_chain_exists = true;
}
if (command->capabilityData->data.handles.handle[i] > EK_CERT_RANGE) {
command->cert_count = i;
}
Expand All @@ -796,6 +804,7 @@ Fapi_Provision_Finish(FAPI_CONTEXT *context)
context->state = PROVISION_CHECK_FOR_VENDOR_CERT;
return TSS2_FAPI_RC_TRY_AGAIN;
}

fallthrough;

statecase(context->state, PROVISION_GET_CERT_NV);
Expand Down Expand Up @@ -884,9 +893,13 @@ Fapi_Provision_Finish(FAPI_CONTEXT *context)
SAFE_FREE(certData);
goto_if_error(r, "Convert certificate to pem.", error_cleanup);

/* Check whether the EKs public key corresponds to the certificate. */
/* Check whether the EKs pifapi_cmp_public_keyublic key corresponds to the certificate. */
if (ifapi_cmp_public_key(&pkeyObject->misc.key.public, &public_key)) {
context->state = PROVISION_PREPARE_READ_ROOT_CERT;
if (command->cert_chain_exists) {
context->state = PROVISION_READ_CERT_CHAIN;
} else {
context->state = PROVISION_PREPARE_READ_ROOT_CERT;
}
return TSS2_FAPI_RC_TRY_AGAIN;
} else {
/* Certificate not appropriate for current EK key type */
Expand All @@ -902,6 +915,16 @@ Fapi_Provision_Finish(FAPI_CONTEXT *context)
goto_error(r, TSS2_FAPI_RC_NO_CERT, "No EK certificate found.",
error_cleanup);

statecase(context->state, PROVISION_READ_CERT_CHAIN);
/* Retrieve the certificate chains from the TPM's NV space . */
r = ifapi_get_certificates(context, EK_CERT_CHAIN_MIN ,
EK_CERT_CHAIN_MAX,
&command->certs,
&command->cert_list_size);
return_try_again(r);
goto_if_error(r, "Get certificates.", error_cleanup);
fallthrough;

statecase(context->state, PROVISION_PREPARE_READ_ROOT_CERT);
/* Prepare reading of root certificate. */
root_ca_file = NULL;
Expand Down Expand Up @@ -967,11 +990,18 @@ Fapi_Provision_Finish(FAPI_CONTEXT *context)
fallthrough;

statecase(context->state, PROVISION_EK_CHECK_CERT);
/* The EK certificate will be verified against the FAPI list of root certificates. */
r = ifapi_curl_verify_ek_cert(command->root_crt, command->intermed_crt, command->pem_cert);
SAFE_FREE(command->root_crt);
SAFE_FREE(command->intermed_crt);
goto_if_error2(r, "Verify EK certificate", error_cleanup);
if (command->cert_chain_exists) {
/* Verify the EK certificate with the cert chain. */
r = ifapi_verify_cert_chain(command->pem_cert, command->certs,
command->cert_list_size);
goto_if_error(r, "Failed to verify certificate chain.", error_cleanup);
} else {
/* The EK certificate will be verified against the FAPI list of root certificates. */
r = ifapi_curl_verify_ek_cert(command->root_crt, command->intermed_crt, command->pem_cert);
SAFE_FREE(command->root_crt);
SAFE_FREE(command->intermed_crt);
goto_if_error2(r, "Verify EK certificate", error_cleanup);
}

fallthrough;

Expand Down
4 changes: 4 additions & 0 deletions src/tss2-fapi/fapi_int.h
Original file line number Diff line number Diff line change
Expand Up @@ -559,6 +559,9 @@ typedef struct {
bool srk_exists;
TPM2_HANDLE template_nv_index;
TPM2_HANDLE nonce_nv_index;
bool cert_chain_exists;
uint8_t *certs;
size_t cert_list_size;
} IFAPI_Provision;

/** The data structure holding internal state of regenerate primary key.
Expand Down Expand Up @@ -858,6 +861,7 @@ enum FAPI_STATE {
PROVISION_GET_CERT_NV_FINISH,
PROVISION_GET_CERT_READ_PUBLIC,
PROVISION_READ_CERT,
PROVISION_READ_CERT_CHAIN,
PROVISION_PREPARE_READ_ROOT_CERT,
PROVISION_READ_ROOT_CERT,
PROVISION_PREPARE_READ_INT_CERT,
Expand Down
8 changes: 4 additions & 4 deletions src/tss2-fapi/ifapi_curl.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ static X509
* @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occurred.
* @retval TSS2_FAPI_RC_NO_CERT if an error did occur during certificate downloading.
*/
static TSS2_RC
get_crl_from_cert(X509 *cert, X509_CRL **crl)
TSS2_RC
ifapi_get_crl_from_cert(X509 *cert, X509_CRL **crl)
{
TSS2_RC r = TSS2_RC_SUCCESS;
unsigned char* url = NULL;
Expand Down Expand Up @@ -231,11 +231,11 @@ ifapi_curl_verify_ek_cert(
}

/* Get Certificate revocation list for Intermediate certificate */
r = get_crl_from_cert(intermed_cert, &crl_intermed);
r = ifapi_get_crl_from_cert(intermed_cert, &crl_intermed);
goto_if_error(r, "Get crl for intermediate certificate.", cleanup);

/* Get Certificate revocation list for EK certificate */
r = get_crl_from_cert(ek_cert, &crl_ek);
r = ifapi_get_crl_from_cert(ek_cert, &crl_ek);
goto_if_error(r, "Get crl for ek certificate.", cleanup);
}

Expand Down
6 changes: 6 additions & 0 deletions src/tss2-fapi/ifapi_curl.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <stddef.h> // for size_t

#include "tss2_common.h" // for TSS2_RC
#include <openssl/x509.h> // for X509 and X509_CRL

TSS2_RC
ifapi_curl_verify_ek_cert(
Expand All @@ -18,4 +19,9 @@ ifapi_get_curl_buffer(
unsigned char ** buffer,
size_t *cert_size);

TSS2_RC
ifapi_get_crl_from_cert(
X509 *cert,
X509_CRL **crl);

#endif /* IFAPI_CURL_H */
207 changes: 207 additions & 0 deletions src/tss2-fapi/ifapi_verify_cert_chain.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
/* SPDX-License-Identifier: BSD-2-Clause */
#ifdef HAVE_CONFIG_H
#include "config.h" // for HAVE_CURL_URL_STRERROR
#endif

#include <openssl/bio.h> // for BIO_free, BIO_new_mem_buf
#include <openssl/evp.h> // for X509, ASN1_IA5STRING, X509_CRL, DIST_...
#include <openssl/obj_mac.h> // for NID_crl_distribution_points, NID_info...
#include <openssl/opensslv.h> // for OPENSSL_VERSION_NUMBER
#include <openssl/pem.h> // for PEM_read_bio_X509
#include <openssl/safestack.h> // for STACK_OF
#include <openssl/x509.h> // for X509_free, X509_STORE_add_cert, X509_...
#include <openssl/x509v3.h> // for DIST_POINT_NAME, GENERAL_NAME, ACCESS...
#include <openssl/err.h> // for ERR_error_string_n, ERR_get_error
#include <stdbool.h> // for bool, false, true
#include <stdlib.h> // for free, realloc
#include <string.h> // for memcpy, strdup, strlen

#if OPENSSL_VERSION_NUMBER < 0x30000000L
#include <openssl/aes.h>
#endif

#include "fapi_certificates.h" // for root_cert_list
#include "fapi_int.h" // for OSSL_FREE
#include "ifapi_curl.h" // for ifapi_get_crl_from_cert
#include "ifapi_helpers.h" // linked lists...

#include "ifapi_macros.h" // for goto_if_null2

#define LOGMODULE fapi
#include "util/log.h" // for LOG_ERROR, goto_error, SAFE_FREE, got...

/* Function to find a certificate node by subject from issuer. */
static NODE_OBJECT_T
*find_cert_by_issuer(NODE_OBJECT_T *head, X509_NAME *issuer) {
NODE_OBJECT_T *current = head;
while (current) {
if (X509_NAME_cmp(X509_get_subject_name(current->object), issuer) == 0) {
return current;
}
current = current->next;
}
return NULL;
}

static TSS2_RC
construct_cert_chain(NODE_OBJECT_T *cert_list, X509 *ek_cert, STACK_OF(X509) *chain,
X509_STORE *store) {
TSS2_RC r;
NODE_OBJECT_T *current = NULL;
X509_CRL *ek_crl = NULL;
X509_CRL *crl = NULL;

/* Add crl for EK to store */
r = ifapi_get_crl_from_cert(ek_cert, &ek_crl);
return_if_error(r, "Get crl for EK certificate.");

if (ek_crl) {
/* Set the flags of the store to use CRLs. */
X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
if (1 != X509_STORE_add_crl(store, ek_crl)) {
return_error(TSS2_FAPI_RC_GENERAL_FAILURE,
"Failed to add EK certificate crl.");
}
}

/* Create chain of intermediate certificates from EK certificate. */
current = find_cert_by_issuer(cert_list, X509_get_issuer_name(ek_cert));
return_if_null(current, "No intermediate certificate found for EK",
TSS2_FAPI_RC_GENERAL_FAILURE);

while(current) {
/* Add crl for intermediate certificate. */
r = ifapi_get_crl_from_cert(current->object, &crl);
return_if_error(r, "Get crl for intermediate certificate.");

if (crl) {
/* Set the flags of the store to use CRLs. */
X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
if (1 != X509_STORE_add_crl(store, crl)) {
return_error(TSS2_FAPI_RC_GENERAL_FAILURE,
"Failed to add intermediate crl.");
}
}
sk_X509_push(chain, current->object);
current = find_cert_by_issuer(cert_list, X509_get_issuer_name(current->object));
}
return TSS2_RC_SUCCESS;
}

static X509
*get_X509_from_pem(const char *pem_cert)
{
if (!pem_cert) {
return NULL;
}
BIO *bufio = NULL;
X509 *cert = NULL;

/* Use BIO buffer for conversion */
size_t pem_length = strlen(pem_cert);
bufio = BIO_new_mem_buf((void *)pem_cert, (int) pem_length);
if (!bufio)
return NULL;
/* Convert the certificate */
cert = PEM_read_bio_X509(bufio, NULL, NULL, NULL);
BIO_free(bufio);
return cert;
}

/**
* Verify EK certificate read from TPM with cert list stored in NV ram.
*
* @param[in] ek_pem The ek certificate in pem format.
* @param[in] cert_buff a list of intermediate der cerficicates stored in
* NV ram.
* @param[in] cert_bu_size The size of the certificate buffer..
*
* @retval TSS2_RC_SUCCESS on success
* @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occurred.
* @retval TSS2_FAPI_RC_MEMORY if not enough memory can be allocated.
*/
TSS2_RC
ifapi_verify_cert_chain(char* ek_pem, uint8_t *cert_buf, size_t cert_buf_size) {
TSS2_RC r;
const uint8_t *current_pos = cert_buf;
size_t remaining_length = cert_buf_size;
NODE_OBJECT_T *cert_list = NULL;
X509 *ek_cert = NULL;
BIO *bio = NULL;
STACK_OF(X509) *chain = NULL;
X509_STORE *store = X509_STORE_new();
X509_STORE_CTX *store_ctx = NULL;
X509 *root_cert = NULL;
X509_STORE_CTX_new();

/* Create linked list with all X509 intermediate certificates. */
while (remaining_length > 0) {
X509 *cert = d2i_X509(NULL, &current_pos, remaining_length);
goto_if_null(cert, "Failed to convert DER certificate to X509 certificate.",
TSS2_FAPI_RC_MEMORY, error);

r = append_object_to_list(cert, &cert_list);
goto_if_error(r, "Failed to create certificate list.", error);

/* Calculate the length of the current certificate in the buffer. */
size_t cert_length = current_pos - (cert_buf + (cert_buf_size - remaining_length));
remaining_length -= cert_length;

}

/* Convert EK certificate from PEM to X509. */
bio = BIO_new_mem_buf(ek_pem, -1);
if (!bio) {
goto_error(r, TSS2_FAPI_RC_MEMORY, "Out of memory", error);
}
ek_cert = PEM_read_bio_X509(bio, NULL, NULL, NULL);
goto_if_null(ek_cert, "Failed do convert EK certificate", TSS2_FAPI_RC_GENERAL_FAILURE,
error);
BIO_free(bio);
chain = sk_X509_new_null();
goto_if_null(chain, "Out of memory", TSS2_FAPI_RC_MEMORY, error);

store = X509_STORE_new();
goto_if_null(store, "Out of memory", TSS2_FAPI_RC_MEMORY, error);

/* Add intermediate certificates to chain and crls to store. */
r = construct_cert_chain(cert_list, ek_cert, chain, store);
goto_if_error(r, "Failed to construct cert chain.", error);

/* Add stored root certificates */
for (uint i = 0; i < sizeof(root_cert_list) / sizeof(char *); i++) {
root_cert = get_X509_from_pem(root_cert_list[i]);
goto_if_null(root_cert, "Failed to convert PEM certificate to DER.",
TSS2_FAPI_RC_BAD_VALUE, error);
if (1 != X509_STORE_add_cert(store, root_cert)) {
goto_error(r, TSS2_FAPI_RC_GENERAL_FAILURE,
"Failed to add root certificate", error);
}
OSSL_FREE(root_cert, X509);
}

/* Verify the certificate chain. */
store_ctx = X509_STORE_CTX_new();
goto_if_null(store_ctx, "Out of memory", TSS2_FAPI_RC_MEMORY, error);

if (X509_STORE_CTX_init(store_ctx, store, ek_cert, chain) != 1) {
goto_error(r, TSS2_FAPI_RC_GENERAL_FAILURE,
"Failed to init X509 store", error);
} else if (X509_verify_cert(store_ctx) == 1) {
/* Verification of EK was successful. */
OSSL_FREE(chain, sk_X509);
OSSL_FREE(store_ctx, X509_STORE_CTX);
OSSL_FREE(store, X509_STORE);
return TSS2_RC_SUCCESS;
}
LOG_ERROR("EK verification failed");
r = TSS2_FAPI_RC_GENERAL_FAILURE;

error:
OSSL_FREE(chain, sk_X509);
OSSL_FREE(store_ctx, X509_STORE_CTX);
OSSL_FREE(store, X509_STORE);
OSSL_FREE(bio, BIO);
ifapi_free_node_list(cert_list);
return r;
}
15 changes: 15 additions & 0 deletions src/tss2-fapi/ifapi_verify_cert_chain.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/* SPDX-License-Identifier: BSD-2-Clause */
#ifndef IFAPI_VERIFY_CERT_CHAIN_H
#define IFAPI_VERIFY_CERT_CHAIN_H

#include <stddef.h> // for size_t
#include <openssl/evp.h> // for X509, ASN1_IA5STRING, X509_CRL, DIST_..
#include "tss2_common.h" // for TSS2_RC

TSS2_RC
ifapi_verify_cert_chain(
char* ek_pem,
uint8_t *cert_buf,
size_t cert_buf_size);

#endif /* IFAPI_VERIFY_CERT_CHAIN_H */

0 comments on commit 6c4c0c5

Please sign in to comment.