diff --git a/Makefile-test.am b/Makefile-test.am index 4a2a3c513..6eec9ea31 100644 --- a/Makefile-test.am +++ b/Makefile-test.am @@ -21,6 +21,7 @@ EXTRA_DIST += $(srcdir)/script/int-log-compiler.sh \ $(srcdir)/script/fint-log-compiler.sh \ $(srcdir)/script/int-log-compiler-common.sh \ $(srcdir)/script/ekca/create_ca.sh \ + $(srcdir)/script/ekca/init_ca.sh \ $(srcdir)/script/ekca/ek.cnf \ $(srcdir)/script/ekca/intermed-ca.cnf \ $(srcdir)/script/ekca/root-ca.cnf diff --git a/Makefile.am b/Makefile.am index 12de494fc..58119a571 100644 --- a/Makefile.am +++ b/Makefile.am @@ -54,8 +54,8 @@ GITIGNOREFILES = "" # ax_code_coverage if AUTOCONF_CODE_COVERAGE_2019_01_06 include $(top_srcdir)/aminclude_static.am -clean-local: code-coverage-clean -distclean-local: code-coverage-dist-clean +clean-local: code-coverage-clean check-hook +distclean-local: code-coverage-dist-clean check-hook else @CODE_COVERAGE_RULES@ endif @@ -971,6 +971,16 @@ uninstall-local: [ -L Tss2_TctiLdr_Initialize_Ex.3 ] && \ rm -f Tss2_TctiLdr_Initialize_Ex.3 || true +check-hook: + rm -r -f $(top_builddir)/ca + +prepare-check: +if INIT_CI + $(top_srcdir)/script/ekca/init_ca.sh $(top_builddir) +endif + +check: prepare-check + EXTRA_DIST += \ doc/doxygen.dox \ doc/coding_standard_c.md \ diff --git a/configure.ac b/configure.ac index db4e99662..b05a71a82 100644 --- a/configure.ac +++ b/configure.ac @@ -640,6 +640,8 @@ AS_IF([test "x$enable_self_generated_certificate" = xyes], [AC_DEFINE([SELF_GENERATED_CERTIFICATE], [1], [Allow usage of self generated root certificate])], [AS_IF([test "x$integration_tcti" != "xdevice"], [AC_DEFINE([FAPI_TEST_EK_CERT_LESS], [1], [Perform integration tests without EK certificate verification])])]) +AM_CONDITIONAL([INIT_CI], [test "x$enable_self_generated_certificate" == xyes]) + AS_IF([test "x$enable_integration" = "xyes" && test "x$enable_self_generated_certificate" != "xyes" && test "x$integration_tcti" != "xdevice"], [AC_MSG_WARN([Running integration tests without EK certificate verification, use --enable-self-generated-certificate for full test coverage])]) diff --git a/script/ekca/init_ca.sh b/script/ekca/init_ca.sh new file mode 100755 index 000000000..e8c94bb4e --- /dev/null +++ b/script/ekca/init_ca.sh @@ -0,0 +1,129 @@ +#!/usr/bin/env bash + +#set -x + +#set -euf +OS=$(uname) +DATE_FMT_BEFORE="" +DATE_FMT_AFTER="" +SED_CMD="" + +if [ "$OS" == "Linux" ]; then + DATE_FMT_BEFORE="+%y%m%d000000Z -u -d -1day" + DATE_FMT_AFTER="+%y%m%d000000Z -u -d +10years+1day" + SED_CMD="sed -i" +elif [ "$OS" == "FreeBSD" ]; then + DATE_FMT_BEFORE="-u -v-1d +%y%m%d000000Z" + DATE_FMT_AFTER="-u -v+10y +%y%m%d000000Z" + SED_CMD="sed -i '' -e" +fi + +EKCADIR="$(dirname $(realpath ${0}))/" +CA_DIR="$1/ca" +if test -e $CA_DIR; then + exit +fi +mkdir -p $CA_DIR + +pushd "$CA_DIR" + +mkdir root-ca +pushd root-ca + +mkdir certreqs certs crl newcerts private +touch root-ca.index +echo 00 > root-ca.crlnum +echo 1000 > root-ca.serial +echo "123456" > pass.txt + +cp "${EKCADIR}/root-ca.cnf" ./ +export OPENSSL_CONF=./root-ca.cnf +ROOT_URL="file:$ROOTCRT" +${SED_CMD} "s|ROOTCRT|$ROOT_URL|g" $OPENSSL_CONF +ROOT_URL="file:$ROOTCRL" +${SED_CMD} "s|ROOTCRL|$ROOT_URL|g" $OPENSSL_CONF +openssl req -new -out root-ca.req.pem -passout file:pass.txt + +# +# Create self signed root certificate +# + +openssl ca -selfsign \ + -in root-ca.req.pem \ + -out root-ca.cert.pem \ + -extensions root-ca_ext \ + -startdate `date ${DATE_FMT_BEFORE}` \ + -enddate `date ${DATE_FMT_AFTER}` \ + -passin file:pass.txt -batch + +openssl x509 -outform der -in root-ca.cert.pem -out root-ca.cert.crt + +openssl verify -verbose -CAfile root-ca.cert.pem \ + root-ca.cert.pem + +openssl ca -gencrl -cert root-ca.cert.pem \ + -out root-ca.cert.crl.pem -passin file:pass.txt +openssl crl -in root-ca.cert.crl.pem -outform DER -out root-ca.cert.crl + +popd #root-ca + +# +# Create intermediate certificate +# +mkdir intermed-ca +pushd intermed-ca + +mkdir certreqs certs crl newcerts private +touch intermed-ca.index +echo 00 > intermed-ca.crlnum +echo 2000 > intermed-ca.serial +echo "abcdef" > pass.txt + +cp "${EKCADIR}/intermed-ca.cnf" ./ +export OPENSSL_CONF=./intermed-ca.cnf + +# Adapt CRT URL to current test directory +${SED_CMD} "s|ROOTCRT|$ROOT_URL|g" $OPENSSL_CONF + +openssl req -new -out intermed-ca.req.pem -passout file:pass.txt + +openssl rsa -inform PEM -in private/intermed-ca.key.pem \ + -outform DER -out private/intermed-ca.key.der -passin file:pass.txt + +cp intermed-ca.req.pem \ + ../root-ca/certreqs/ + +INTERMED_URL="file:$INTERMEDCRT" +${SED_CMD} "s|INTERMEDCRT|$INTERMED_URL|g" $OPENSSL_CONF + +pushd ../root-ca +export OPENSSL_CONF=./root-ca.cnf + +openssl ca \ + -in certreqs/intermed-ca.req.pem \ + -out certs/intermed-ca.cert.pem \ + -extensions intermed-ca_ext \ + -startdate `date ${DATE_FMT_BEFORE}` \ + -enddate `date ${DATE_FMT_AFTER}` \ + -passin file:pass.txt -batch + +openssl x509 -outform der -in certs/intermed-ca.cert.pem \ + -out certs/intermed-ca.cert.crt + +openssl verify -verbose -CAfile root-ca.cert.pem \ + certs/intermed-ca.cert.pem + +cp certs/intermed-ca.cert.pem \ + ../intermed-ca + +cp certs/intermed-ca.cert.crt \ + ../intermed-ca + +popd #root-ca + +export OPENSSL_CONF=./intermed-ca.cnf +openssl ca -gencrl -cert ../root-ca/certs/intermed-ca.cert.pem \ + -out intermed-ca.crl.pem -passin file:pass.txt +openssl crl -in intermed-ca.crl.pem -outform DER -out intermed-ca.crl + +popd #intermed-ca diff --git a/test/integration/main-fapi.c b/test/integration/main-fapi.c index 9d6d8a037..8053d2fd6 100644 --- a/test/integration/main-fapi.c +++ b/test/integration/main-fapi.c @@ -14,7 +14,18 @@ #include #include #include -#include +#include +#include +#include +#if OPENSSL_VERSION_NUMBER < 0x30000000L +#include +#else +#include +#include +#include +#endif +#include +#include #include "tss2_esys.h" #include "tss2_fapi.h" @@ -28,6 +39,21 @@ #include "test-common.h" +#if OPENSSL_VERSION_NUMBER >= 0x10101000L +#define EC_POINT_set_affine_coordinates_tss(group, tpm_pub_key, bn_x, bn_y, dmy) \ + EC_POINT_set_affine_coordinates(group, tpm_pub_key, bn_x, bn_y, dmy) + +#define EC_POINT_get_affine_coordinates_tss(group, tpm_pub_key, bn_x, bn_y, dmy) \ + EC_POINT_get_affine_coordinates(group, tpm_pub_key, bn_x, bn_y, dmy) + +#else +#define EC_POINT_set_affine_coordinates_tss(group, tpm_pub_key, bn_x, bn_y, dmy) \ + EC_POINT_set_affine_coordinates_GFp(group, tpm_pub_key, bn_x, bn_y, dmy) + +#define EC_POINT_get_affine_coordinates_tss(group, tpm_pub_key, bn_x, bn_y, dmy) \ + EC_POINT_get_affine_coordinates_GFp(group, tpm_pub_key, bn_x, bn_y, dmy) +#endif /* OPENSSL_VERSION_NUMBER >= 0x10101000L */ + char *fapi_profile = NULL; TSS2_TEST_FAPI_CONTEXT *fapi_test_ctx = NULL; @@ -454,6 +480,464 @@ int init_fapi(char *profile, FAPI_CONTEXT **fapi_context) return ret; } +TSS2_RC +rsa_pub_from_tpm(const TPM2B_PUBLIC *tpmPublicKey, EVP_PKEY **evpPublicKey) +{ +#if OPENSSL_VERSION_NUMBER < 0x30000000L + RSA *rsa = NULL; +#else + OSSL_PARAM_BLD *build = NULL; + OSSL_PARAM *params = NULL; + EVP_PKEY_CTX *ctx = NULL; +#endif + + /* Check for NULL parameters */ + return_if_null(tpmPublicKey, "tpmPublicKey is NULL", TSS2_FAPI_RC_BAD_REFERENCE); + return_if_null(evpPublicKey, "evpPublicKey is NULL", TSS2_FAPI_RC_BAD_REFERENCE); + + TSS2_RC r = TSS2_RC_SUCCESS; + /* Initialize the RSA parameters */ + BIGNUM *e = NULL; + BIGNUM *n = BN_bin2bn(tpmPublicKey->publicArea.unique.rsa.buffer, + tpmPublicKey->publicArea.unique.rsa.size, NULL); + if (!n) { + goto_error(r, TSS2_FAPI_RC_MEMORY, "Out of memory", error_cleanup); + } + + uint32_t exp; + if (tpmPublicKey->publicArea.parameters.rsaDetail.exponent == 0) + exp = 65537; + else + exp = tpmPublicKey->publicArea.parameters.rsaDetail.exponent; + +#if OPENSSL_VERSION_NUMBER < 0x30000000L + if ((rsa = RSA_new()) == NULL) { + goto_error(r, TSS2_FAPI_RC_MEMORY, "Out of memory", error_cleanup); + } + + if ((e = BN_new()) == NULL) { + goto_error(r, TSS2_FAPI_RC_MEMORY, "Out of memory", error_cleanup); + } + if (1 != BN_set_word(e, exp)) { + goto_error(r, TSS2_FAPI_RC_GENERAL_FAILURE, + "Could not set exponent.", error_cleanup); + } + + if (!RSA_set0_key(rsa, n, e, NULL)) { + goto_error(r, TSS2_FAPI_RC_GENERAL_FAILURE, + "Could not set public key.", error_cleanup); + } + n = NULL; /* ownership transferred */ + e = NULL; + + *evpPublicKey = EVP_PKEY_new(); + goto_if_null2(*evpPublicKey, "Out of memory.", r, TSS2_FAPI_RC_MEMORY, error_cleanup); + + /* Assign the parameters to the key */ + if (!EVP_PKEY_assign_RSA(*evpPublicKey, rsa)) { + EVP_PKEY_free(*evpPublicKey); + goto_error(r, TSS2_FAPI_RC_GENERAL_FAILURE, "Assign rsa key", + error_cleanup); + } + rsa = NULL; /* ownership transferred */ +error_cleanup: + OSSL_FREE(rsa, RSA); +#else /* OPENSSL_VERSION_NUMBER < 0x30000000L */ + if ((build = OSSL_PARAM_BLD_new()) == NULL + || !OSSL_PARAM_BLD_push_BN(build, OSSL_PKEY_PARAM_RSA_N, n) + || !OSSL_PARAM_BLD_push_uint32(build, OSSL_PKEY_PARAM_RSA_E, exp) + || (params = OSSL_PARAM_BLD_to_param(build)) == NULL) { + goto_error(r, TSS2_FAPI_RC_GENERAL_FAILURE, "Create rsa key parameters", + error_cleanup); + } + + if ((ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL)) == NULL + || EVP_PKEY_fromdata_init(ctx) <= 0 + || EVP_PKEY_fromdata(ctx, evpPublicKey, EVP_PKEY_PUBLIC_KEY, params) <= 0) { + goto_error(r, TSS2_FAPI_RC_GENERAL_FAILURE, "Create rsa key", + error_cleanup); + } +error_cleanup: + OSSL_FREE(ctx, EVP_PKEY_CTX); + OSSL_FREE(params, OSSL_PARAM); + OSSL_FREE(build, OSSL_PARAM_BLD); +#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */ + OSSL_FREE(e, BN); + OSSL_FREE(n, BN); + return r; +} + +TSS2_RC +ecc_pub_from_tpm(const TPM2B_PUBLIC *tpmPublicKey, EVP_PKEY **evpPublicKey) +{ + /* Check for NULL parameters */ + return_if_null(tpmPublicKey, "tpmPublicKey is NULL", TSS2_FAPI_RC_BAD_REFERENCE); + return_if_null(evpPublicKey, "evpPublicKey is NULL", TSS2_FAPI_RC_BAD_REFERENCE); + + TSS2_RC r = TSS2_RC_SUCCESS; + EC_GROUP *ecgroup = NULL; + int curveId; + BIGNUM *x = NULL, *y = NULL; + EC_POINT *ecPoint = NULL; +#if OPENSSL_VERSION_NUMBER < 0x30000000L + EC_KEY *ecKey = NULL; +#else + OSSL_PARAM_BLD *build = NULL; + OSSL_PARAM *params = NULL; + EVP_PKEY_CTX *ctx = NULL; + unsigned char *puboct = NULL; + size_t bsize; +#endif + + /* Find the curve of the ECC key */ + switch (tpmPublicKey->publicArea.parameters.eccDetail.curveID) { + case TPM2_ECC_NIST_P192: + curveId = NID_X9_62_prime192v1; + break; + case TPM2_ECC_NIST_P224: + curveId = NID_secp224r1; + break; + case TPM2_ECC_NIST_P256: + curveId = NID_X9_62_prime256v1; + break; + case TPM2_ECC_NIST_P384: + curveId = NID_secp384r1; + break; + case TPM2_ECC_NIST_P521: + curveId = NID_secp521r1; + break; +#ifdef NID_sm2 + case TPM2_ECC_SM2_P256: + curveId = NID_sm2; + break; +#endif + default: + return_error(TSS2_FAPI_RC_BAD_VALUE, + "ECC curve not implemented."); + } + + /* Initialize the OpenSSL ECC key with its group */ + ecgroup = EC_GROUP_new_by_curve_name(curveId); + goto_if_null(ecgroup, "new EC group.", TSS2_FAPI_RC_GENERAL_FAILURE, + error_cleanup); + + /* Set the ECC parameters in the OpenSSL key */ + x = BN_bin2bn(tpmPublicKey->publicArea.unique.ecc.x.buffer, + tpmPublicKey->publicArea.unique.ecc.x.size, NULL); + + y = BN_bin2bn(tpmPublicKey->publicArea.unique.ecc.y.buffer, + tpmPublicKey->publicArea.unique.ecc.y.size, NULL); + + if (!x || !y) { + goto_error(r, TSS2_FAPI_RC_MEMORY, "Out of memory", error_cleanup); + } + + if ((ecPoint = EC_POINT_new(ecgroup)) == NULL + || !EC_POINT_set_affine_coordinates_tss(ecgroup, ecPoint, x, y, NULL)) { + goto_error(r, TSS2_FAPI_RC_GENERAL_FAILURE, "EC_POINT_set_affine_coordinates", + error_cleanup); + } + +#if OPENSSL_VERSION_NUMBER < 0x30000000 + ecKey = EC_KEY_new(); + return_if_null(ecKey, "Out of memory.", TSS2_FAPI_RC_MEMORY); + + if (!EC_KEY_set_group(ecKey, ecgroup)) { + goto_error(r, TSS2_FAPI_RC_GENERAL_FAILURE, "EC_KEY_set_group", + error_cleanup); + } + + if (!EC_KEY_set_public_key(ecKey, ecPoint)) { + goto_error(r, TSS2_FAPI_RC_GENERAL_FAILURE, + "EC_KEY_set_public_key", error_cleanup); + } + + *evpPublicKey = EVP_PKEY_new(); + goto_if_null2(*evpPublicKey, "Out of memory.", r, TSS2_FAPI_RC_MEMORY, error_cleanup); + + if (!EVP_PKEY_assign_EC_KEY(*evpPublicKey, ecKey)) { + EVP_PKEY_free(*evpPublicKey); + goto_error(r, TSS2_FAPI_RC_GENERAL_FAILURE, "Assign ecc key", + error_cleanup); + } + ecKey = NULL; /* ownership transferred */ +error_cleanup: + OSSL_FREE(ecKey, EC_KEY); +#else + if ((build = OSSL_PARAM_BLD_new()) == NULL + || !OSSL_PARAM_BLD_push_utf8_string(build, OSSL_PKEY_PARAM_GROUP_NAME, + (char *)OBJ_nid2sn(curveId), 0) + || (bsize = EC_POINT_point2buf(ecgroup, ecPoint, + POINT_CONVERSION_COMPRESSED, + &puboct, NULL)) == 0 + || !OSSL_PARAM_BLD_push_octet_string(build, OSSL_PKEY_PARAM_PUB_KEY, + puboct, bsize) + || (params = OSSL_PARAM_BLD_to_param(build)) == NULL) { + goto_error(r, TSS2_FAPI_RC_GENERAL_FAILURE, "Create ecc key parameters", + error_cleanup); + } + + if ((ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL)) == NULL + || EVP_PKEY_fromdata_init(ctx) <= 0 + || EVP_PKEY_fromdata(ctx, evpPublicKey, EVP_PKEY_PUBLIC_KEY, params) <= 0) { + goto_error(r, TSS2_FAPI_RC_GENERAL_FAILURE, "Create ecc key", + error_cleanup); + } +error_cleanup: + EVP_PKEY_CTX_free(ctx); + OSSL_PARAM_free(params); + OSSL_PARAM_BLD_free(build); + OPENSSL_free(puboct); +#endif + OSSL_FREE(ecPoint, EC_POINT); + OSSL_FREE(ecgroup, EC_GROUP); + OSSL_FREE(y, BN); + OSSL_FREE(x, BN); + return r; +} + +TPM2_RC +get_ek_rsa_public(TSS2_SYS_CONTEXT *sys_context, EVP_PKEY **evp_pub) +{ + TSS2_RC rc; + TSS2L_SYS_AUTH_COMMAND auth_cmd = { + .auths = {{ .sessionHandle = TPM2_RH_PW }}, + .count = 1 + }; + TPM2B_SENSITIVE_CREATE in_sensitive = { 0 }; + TPM2B_PUBLIC in_public = { + .publicArea = { + .type = TPM2_ALG_RSA, + .nameAlg = TPM2_ALG_SHA256, + .objectAttributes = ( + TPMA_OBJECT_FIXEDTPM | + TPMA_OBJECT_FIXEDPARENT | + TPMA_OBJECT_SENSITIVEDATAORIGIN | + TPMA_OBJECT_ADMINWITHPOLICY | + TPMA_OBJECT_RESTRICTED | + TPMA_OBJECT_DECRYPT + ), + .authPolicy = { + .size = 32, + .buffer = 0x83, 0x71, 0x97, 0x67, 0x44, 0x84, + 0xB3, 0xF8, 0x1A, 0x90, 0xCC, 0x8D, + 0x46, 0xA5, 0xD7, 0x24, 0xFD, 0x52, + 0xD7, 0x6E, 0x06, 0x52, 0x0B, 0x64, + 0xF2, 0xA1, 0xDA, 0x1B, 0x33, 0x14, + 0x69, 0xAA, + }, + .parameters.rsaDetail = { + .symmetric = { + .algorithm = TPM2_ALG_AES, + .keyBits.aes = 128, + .mode.aes = TPM2_ALG_CFB, + }, + .scheme = { + .scheme = TPM2_ALG_NULL, + }, + .keyBits = 2048, + .exponent = 0, + }, + .unique.rsa = { + .size = 256, + .buffer = {0}, + } + } + }; + TPML_PCR_SELECTION creation_pcr = { 0 }; + TPM2_HANDLE handle; + TPM2B_PUBLIC out_public = { 0 }; + TSS2L_SYS_AUTH_RESPONSE auth_rsp = { + .count = 0 + }; + + /* Generate the EK key */ + + rc = Tss2_Sys_CreatePrimary(sys_context, TPM2_RH_ENDORSEMENT, &auth_cmd, + &in_sensitive, &in_public, NULL, &creation_pcr, + &handle, &out_public, NULL, NULL, NULL, NULL, &auth_rsp); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR("TPM CreatePrimary FAILED: 0x%"PRIx32, rc); + return rc; + } + + rc = Tss2_Sys_FlushContext(sys_context, handle); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR("TPM FlushContext FAILED: 0x%"PRIx32, rc); + return rc; + } + + rc = rsa_pub_from_tpm(&out_public, evp_pub); + if (rc != TPM2_RC_SUCCESS) { + LOG_ERROR("Failed to create EVP key from RSA EK: 0x%"PRIx32, rc); + return rc; + } + + return TSS2_RC_SUCCESS; +} + +TSS2_RC +get_ecc_ek_public(TSS2_SYS_CONTEXT *sys_context, EVP_PKEY **evp_pub) +{ + TSS2_RC rc; + TSS2L_SYS_AUTH_COMMAND auth_cmd = { + .auths = {{ .sessionHandle = TPM2_RH_PW }}, + .count = 1 + }; + TPM2B_SENSITIVE_CREATE in_sensitive = { 0 }; + TPM2B_PUBLIC in_public = { + .publicArea = { + .type = TPM2_ALG_ECC, + .nameAlg = TPM2_ALG_SHA256, + .objectAttributes = ( + TPMA_OBJECT_FIXEDTPM | + TPMA_OBJECT_FIXEDPARENT | + TPMA_OBJECT_SENSITIVEDATAORIGIN | + TPMA_OBJECT_ADMINWITHPOLICY | + TPMA_OBJECT_RESTRICTED | + TPMA_OBJECT_DECRYPT + ), + .authPolicy = { + .size = 32, + .buffer = 0x83, 0x71, 0x97, 0x67, 0x44, 0x84, + 0xB3, 0xF8, 0x1A, 0x90, 0xCC, 0x8D, + 0x46, 0xA5, 0xD7, 0x24, 0xFD, 0x52, + 0xD7, 0x6E, 0x06, 0x52, 0x0B, 0x64, + 0xF2, 0xA1, 0xDA, 0x1B, 0x33, 0x14, + 0x69, 0xAA, + }, + .parameters.eccDetail = { + .symmetric = { + .algorithm = TPM2_ALG_AES, + .keyBits.aes = 128, + .mode.aes = TPM2_ALG_CFB, + }, + .scheme = { + .scheme = TPM2_ALG_NULL, + .details = { 0 } + }, + .curveID = TPM2_ECC_NIST_P256, + .kdf = {.scheme = TPM2_ALG_NULL, + .details = { 0 } + } + }, + .unique.ecc = { + .x = {.size = 32,.buffer = { 0 }}, + .y = {.size = 32,.buffer = { 0 }} + } + } + }; + TPML_PCR_SELECTION creation_pcr = { 0 }; + TPM2_HANDLE handle; + TPM2B_PUBLIC out_public = { 0 }; + TSS2L_SYS_AUTH_RESPONSE auth_rsp = { + .count = 0 + }; + rc = Tss2_Sys_CreatePrimary(sys_context, TPM2_RH_ENDORSEMENT, &auth_cmd, + &in_sensitive, &in_public, NULL, &creation_pcr, + &handle, &out_public, NULL, NULL, NULL, NULL, &auth_rsp); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR("TPM CreatePrimary FAILED: 0x%"PRIx32, rc); + return rc; + } + + rc = Tss2_Sys_FlushContext(sys_context, handle); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR("TPM FlushContext FAILED: 0x%"PRIx32, rc); + return rc; + } + + rc = ecc_pub_from_tpm(&out_public, evp_pub); + if (rc != TPM2_RC_SUCCESS) { + LOG_ERROR("Failed to create EVP key from ECC EK: 0x%"PRIx32, rc); + return rc; + } + + return TSS2_RC_SUCCESS; + +} + +TSS2_RC +nv_write(TSS2_SYS_CONTEXT *sys_context, TPMI_RH_NV_INDEX nvIndex, X509 *cert) +{ + TSS2_RC rc; + TSS2L_SYS_AUTH_COMMAND auth_cmd = { + .auths = {{ .sessionHandle = TPM2_RH_PW }}, + .count = 1 + }; + + if (!nvIndex) { + nvIndex = 0x01c00002; + } + + TPM2B_AUTH nv_auth = { 0 }; + TPM2B_NV_PUBLIC public_info = { + .nvPublic = { + .nameAlg = TPM2_ALG_SHA1, + .attributes = TPMA_NV_PPWRITE | TPMA_NV_AUTHREAD | TPMA_NV_OWNERREAD | + TPMA_NV_PLATFORMCREATE | TPMA_NV_NO_DA, + .dataSize = 0, + .nvIndex = nvIndex, + }, + }; + + TSS2L_SYS_AUTH_RESPONSE auth_rsp = { + .count = 0 + }; + TPM2B_MAX_NV_BUFFER buf1 = { 0 }; + TPM2B_MAX_NV_BUFFER buf2 = { 0 }; + unsigned char *cert_buf = NULL; + int cert_size; + + cert_size = i2d_X509(cert, &cert_buf); + if (cert_size < 0) { + LOG_ERROR("Certificate buffer can't be created."); + return TSS2_FAPI_RC_GENERAL_FAILURE; + } + if (buf1.size >= sizeof(buf1.buffer)) { + LOG_ERROR("Certificate to large"); + return TSS2_FAPI_RC_GENERAL_FAILURE; + } + buf1.size = cert_size; + memcpy(&buf1.buffer[0], cert_buf, cert_size); + free(cert_buf); + + /* First make sure that not EK certificate is currently loaded */ + LOG_WARNING("Cert input size is %"PRIu16, buf1.size); + public_info.nvPublic.dataSize = buf1.size; + + LOG_WARNING("Define NV cert with nv index: %x", public_info.nvPublic.nvIndex); + + rc = Tss2_Sys_NV_DefineSpace(sys_context, TPM2_RH_PLATFORM, &auth_cmd, + &nv_auth, &public_info, &auth_rsp); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR("TPM NV DefineSpace FAILED: 0x%"PRIx32, rc); + return rc; + } + + /* Split the input buffer into 2 chunks */ + buf2.size = buf1.size; + buf1.size /= 2; + buf2.size -= buf1.size; + memcpy(&buf2.buffer[0], &buf1.buffer[buf1.size], buf2.size); + + rc = Tss2_Sys_NV_Write(sys_context, TPM2_RH_PLATFORM, nvIndex, &auth_cmd, + &buf1, 0, &auth_rsp); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR("TPM NV Write FAILED: 0x%"PRIx32, rc); + return rc; + } + + rc = Tss2_Sys_NV_Write(sys_context, TPM2_RH_PLATFORM, nvIndex, &auth_cmd, + &buf2, buf1.size, &auth_rsp); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR("TPM NV Write FAILED: 0x%"PRIx32, rc); + return rc; + } + + return TSS2_RC_SUCCESS; +} + int test_fapi_setup(TSS2_TEST_FAPI_CONTEXT **test_ctx) {