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 <juergen_repp@web.de>
  • Loading branch information
JuergenReppSIT committed Feb 12, 2025
1 parent e12d9d3 commit fc16488
Show file tree
Hide file tree
Showing 4 changed files with 236 additions and 8 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
179 changes: 179 additions & 0 deletions src/tss2-fapi/ifapi_verify_cert_chain.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
/* SPDX-License-Identifier: BSD-2-Clause */
#ifdef HAVE_CONFIG_H
#include "config.h" // for HAVE_CURL_URL_STRERROR
#endif

#include <curl/curl.h> // for curl_easy_strerror, CURLE_OK, curl_ea...
#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 <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_helpers.h"

#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. */
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;
}

TSS2_RC
construct_cert_chain(NODE_OBJECT_T *cert_list, X509 *ek_cert, STACK_OF(X509) *chain) {
NODE_OBJECT_T *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) {
// XXX add crl to store
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 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();

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;

}

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);
r = construct_cert_chain(cert_list, ek_cert, chain);
goto_if_error(r, "Failed to construct cert chain.", error);

store = X509_STORE_new();
goto_if_null(store, "Out of memory", TSS2_FAPI_RC_MEMORY, 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);
}

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. */
sk_X509_free(chain);
X509_STORE_CTX_free(store_ctx);
X509_STORE_free(store);
return TSS2_RC_SUCCESS;
}
goto_error(r, TSS2_FAPI_RC_GENERAL_FAILURE,
"EK verification failed.", error);

error:
if (chain) {
sk_X509_free(chain);
}
if (store_ctx) {
X509_STORE_CTX_free(store_ctx);
}
if (store) {
X509_STORE_free(store);
}
if (bio) {
BIO_free(bio);
}
ifapi_free_object_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 fc16488

Please sign in to comment.