Skip to content

Commit

Permalink
FAPI: Enable importing of private OSSL keys.
Browse files Browse the repository at this point in the history
A private OSSL PEM key now can be imported under a parent key in
the FAPI keystore.

Signed-off-by: Juergen Repp <[email protected]>
  • Loading branch information
JuergenReppSIT committed Dec 5, 2023
1 parent 182b027 commit 2e33d70
Show file tree
Hide file tree
Showing 4 changed files with 273 additions and 10 deletions.
79 changes: 70 additions & 9 deletions src/tss2-fapi/api/Fapi_Import.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "fapi_int.h"
#include "fapi_util.h"
#include "tss2_esys.h"
#include "tss2_mu.h"
#include "ifapi_json_deserialize.h"
#include "ifapi_policy_json_deserialize.h"
#include "tpm_json_deserialize.h"
Expand Down Expand Up @@ -148,6 +149,7 @@ Fapi_Import_Async(
json_object *jso2;
size_t pos = 0;
TPMS_POLICY policy = { 0 };
TPMA_OBJECT *attributes;

/* Check for NULL parameters */
check_not_null(context);
Expand Down Expand Up @@ -202,8 +204,31 @@ Fapi_Import_Async(

context->state = IMPORT_KEY_WRITE_OBJECT_PREPARE;

} else if (strcmp(importData, IFAPI_PEM_PRIVATE_KEY) == 0) {
goto_error(r, TSS2_FAPI_RC_BAD_VALUE, "Invalid importData.", cleanup_error);
} else if (strncmp(importData, IFAPI_PEM_PRIVATE_KEY,
sizeof(IFAPI_PEM_PRIVATE_KEY) - 1) == 0 ||
strncmp(importData, IFAPI_PEM_ECC_PRIVATE_KEY,
sizeof(IFAPI_PEM_ECC_PRIVATE_KEY) - 1) == 0 ||
strncmp(importData, IFAPI_PEM_RSA_PRIVATE_KEY,
sizeof(IFAPI_PEM_RSA_PRIVATE_KEY) - 1) == 0) {
attributes = &context->cmd.ImportKey.public_templ.public.publicArea.objectAttributes;
r = ifapi_profiles_get(&context->profiles, path, &context->cmd.ImportKey.profile);
goto_if_error2(r, "Get profile for path: %s", cleanup_error, path);

r = ifapi_merge_profile_into_template(context->cmd.ImportKey.profile,
&context->cmd.ImportKey.public_templ);
goto_if_error(r, "Merge profile", cleanup_error);

*attributes = TPMA_OBJECT_SIGN_ENCRYPT | TPMA_OBJECT_DECRYPT | TPMA_OBJECT_USERWITHAUTH;
context->cmd.ImportKey.ossl_priv = importData;

/* Create session for key loading. */
r = ifapi_get_sessions_async(context,
IFAPI_SESSION_GEN_SRK | IFAPI_SESSION1,
TPMA_SESSION_DECRYPT, 0);
goto_if_error_reset_state(r, "Create sessions", cleanup_error);

context->state = IMPORT_WAIT_FOR_SESSION;
return TSS2_RC_SUCCESS;

} else {
r = ifapi_non_tpm_mode_init(context);
Expand Down Expand Up @@ -368,6 +393,8 @@ Fapi_Import_Finish(

TSS2_RC r;
ESYS_TR session;
size_t marshalled_sensitive_size = 0;
size_t marshalled_length = 0;

/* Check for NULL parameters */
check_not_null(context);
Expand Down Expand Up @@ -413,6 +440,38 @@ Fapi_Import_Finish(
goto_if_error(r, "LoadKey finish", error_cleanup);

context->loadKey.auth_object = *auth_object;

/* Copy private OSSL PEM key to key tree. */
if (command->ossl_priv) {
command->parent_object = &context->loadKey.auth_object;
command->public_templ.public.publicArea.nameAlg =
command->parent_object->misc.key.public.publicArea.nameAlg;
r = ifapi_openssl_load_private(command->ossl_priv,
NULL,
NULL,
&context->cmd.ImportKey.public_templ.public,
&keyTree->public,
&command->sensitive);

goto_if_error(r, "Fapi load OSSL Key.", error_cleanup);


r = Tss2_MU_TPMT_SENSITIVE_Marshal(&command->sensitive.sensitiveArea,
&keyTree->duplicate.buffer[sizeof(uint16_t)],
TPM2_MAX_DIGEST_BUFFER,
&marshalled_sensitive_size);
goto_if_error(r, "Fapi marshalling sensitive data of OSSL key failed.");

r = Tss2_MU_UINT16_Marshal(marshalled_sensitive_size,
&keyTree->duplicate.buffer[0], sizeof(uint16_t),
&marshalled_length);
goto_if_error(r, "Fapi marshalling size of sensitive date failed.");

keyTree->duplicate.size = marshalled_sensitive_size + sizeof(uint16_t);
context->state = IMPORT_KEY_AUTHORIZE_PARENT;
return TSS2_FAPI_RC_TRY_AGAIN;
}

fallthrough;

statecase(context->state, IMPORT_WAIT_FOR_AUTHORIZATION);
Expand Down Expand Up @@ -550,14 +609,16 @@ Fapi_Import_Finish(
r = Esys_Import_Finish(context->esys, &command->private);
try_again_or_error_goto(r, "Import", error_cleanup);

/* Concatenate keyname and parent path */
char* ipath = NULL;
r = ifapi_asprintf(&ipath, "%s%s%s", command->parent_path,
IFAPI_FILE_DELIM, command->out_path);
goto_if_error(r, "Out of memory.", error_cleanup);
if (!command->ossl_priv) {
/* Concatenate keyname and parent path */
char* ipath = NULL;
r = ifapi_asprintf(&ipath, "%s%s%s", command->parent_path,
IFAPI_FILE_DELIM, command->out_path);
goto_if_error(r, "Out of memory.", error_cleanup);

SAFE_FREE(command->out_path);
command->out_path = ipath;
SAFE_FREE(command->out_path);
command->out_path = ipath;
}

context->state = IMPORT_KEY_WAIT_FOR_FLUSH;
fallthrough;
Expand Down
188 changes: 188 additions & 0 deletions src/tss2-fapi/fapi_crypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -2201,3 +2201,191 @@ ifapi_rsa_encrypt(const char *pem_key,
OSSL_FREE(ctx, EVP_PKEY_CTX);
return r;
}

static bool
load_private_RSA_from_key(EVP_PKEY *key,
TPM2B_SENSITIVE *priv) {

bool result = false;
#if OPENSSL_VERSION_NUMBER < 0x30000000L
const BIGNUM *p = NULL; /* the private key exponent */

RSA *k = EVP_PKEY_get0_RSA(key);
if (!k) {
LOG_ERROR("Could not retrieve RSA key");
goto out;
}
RSA_get0_factors(k, &p, NULL);
#else
BIGNUM *p = NULL; /* the private key exponent */

int rc = EVP_PKEY_get_bn_param(key, OSSL_PKEY_PARAM_RSA_FACTOR1, &p);
if (!rc) {
LOG_ERROR("Could not read private key");
goto out;
}
#endif

TPMT_SENSITIVE *sa = &priv->sensitiveArea;

sa->sensitiveType = TPM2_ALG_RSA;

TPM2B_PRIVATE_KEY_RSA *pkr = &sa->sensitive.rsa;

unsigned priv_bytes = BN_num_bytes(p);
if (priv_bytes > sizeof(pkr->buffer)) {
LOG_ERROR("Expected prime \"d\" to be less than or equal to %zu,"
" got: %u", sizeof(pkr->buffer), priv_bytes);
goto out;
}

pkr->size = priv_bytes;

int success = BN_bn2bin(p, pkr->buffer);
if (!success) {
ERR_print_errors_fp(stderr);
LOG_ERROR("Could not copy private exponent \"d\"");
goto out;
}
result = true;
out:
#if OPENSSL_VERSION_NUMBER < 0x30000000L
/* k,p point to internal structrues and must not be freed after use */
#else
BN_free(p);
#endif
return result;
}

static TSS2_RC
load_RSA_key(EVP_PKEY *key,
TPM2B_PUBLIC *pub,
TPM2B_SENSITIVE *priv) {
TSS2_RC rc = TSS2_RC_SUCCESS;

bool loaded_priv = load_private_RSA_from_key(key, priv);
if (!loaded_priv) {
return TSS2_FAPI_RC_GENERAL_FAILURE;
}

rc = get_rsa_tpm2b_public_from_evp(key, pub);
if (rc) {
goto out;
}
out:
EVP_PKEY_free(key);
return rc;
}

static bool
load_private_ECC_from_key(EVP_PKEY *key,
TPM2B_SENSITIVE *priv) {
bool result = false;
/*
* private data
*/
priv->sensitiveArea.sensitiveType = TPM2_ALG_ECC;

TPM2B_ECC_PARAMETER *p = &priv->sensitiveArea.sensitive.ecc;

#if OPENSSL_VERSION_NUMBER < 0x30000000L
EC_KEY *k = EVP_PKEY_get0_EC_KEY(key);
if (!k) {
LOG_ERROR("Could not retrieve ECC key");
goto out;
}

const EC_GROUP *group = EC_KEY_get0_group(k);
const BIGNUM *b = EC_KEY_get0_private_key(k);
unsigned priv_bytes = (EC_GROUP_get_degree(group) + 7) / 8;
#else
BIGNUM *b = NULL; /* the private key exponent */

int rc = EVP_PKEY_get_bn_param(key, OSSL_PKEY_PARAM_PRIV_KEY, &b);
if (!rc) {
LOG_ERROR("Could not read ECC private key");
goto out;
}
unsigned priv_bytes = (EVP_PKEY_bits(key) + 7) / 8;
#endif

if (priv_bytes > sizeof(p->buffer)) {
LOG_ERROR("Expected ECC private portion to be less than or equal to %zu,"
" got: %u", sizeof(p->buffer), priv_bytes);
goto out;
}

p->size = BN_bn2binpad(b, p->buffer, priv_bytes);
if (p->size != priv_bytes) {
goto out;
}
result = true;
out:
#if OPENSSL_VERSION_NUMBER < 0x30000000L
/* k,b point to internal structrues and must not be freed after use */
#else
BN_free(b);
#endif
return result;
}

static TSS2_RC
load_ECC_key(EVP_PKEY *key,
TPM2B_PUBLIC *pub,
TPM2B_SENSITIVE *priv) {
TSS2_RC rc = TSS2_RC_SUCCESS;

if (!load_private_ECC_from_key(key, priv)) {
rc = TSS2_FAPI_RC_GENERAL_FAILURE;
goto out;
}
rc = get_ecc_tpm2b_public_from_evp(key, pub);
if (rc) {
goto out;
}
out:
EVP_PKEY_free(key);
return rc;
}

TSS2_RC
ifapi_openssl_load_private(const char *pem_key,
const char *passin,
const char *object_auth,
TPM2B_PUBLIC *template,
TPM2B_PUBLIC *pub,
TPM2B_SENSITIVE *priv) {
*pub = *template;
BIO *bio = NULL;
EVP_PKEY *key = NULL;
TSS2_RC rc = TSS2_RC_SUCCESS;
(void)object_auth;

/* Create a key from PEM string. */
bio = BIO_new_mem_buf(pem_key, -1);

if (!bio) {
LOG_ERROR("Error creating BIO.");
return TSS2_FAPI_RC_GENERAL_FAILURE;
}

key = PEM_read_bio_PrivateKey(bio,NULL,NULL, (void *) passin);

if (!key) {
LOG_ERROR("Creation of key from PEM string failed.");
return TSS2_FAPI_RC_GENERAL_FAILURE;
}

switch (template->publicArea.type) {
case TPM2_ALG_RSA:
rc = load_RSA_key(key, pub, priv);
break;
case TPM2_ALG_ECC:
rc = load_ECC_key(key, pub, priv);
break;
default:
LOG_ERROR("Cannot handle algorithm, got: 0x%x", template->publicArea.type);
rc = TSS2_FAPI_RC_GENERAL_FAILURE;
}
return rc;
}
9 changes: 9 additions & 0 deletions src/tss2-fapi/fapi_crypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,4 +132,13 @@ ifapi_rsa_encrypt(
uint8_t **cipherText,
size_t *cipherTextSize);

TSS2_RC
ifapi_openssl_load_private(
const char *pem_key,
const char *passin,
const char *object_auth,
TPM2B_PUBLIC *template,
TPM2B_PUBLIC *pub,
TPM2B_SENSITIVE *priv);

#endif /* FAPI_CRYPTO_H */
7 changes: 6 additions & 1 deletion src/tss2-fapi/fapi_int.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,9 @@ typedef UINT8 IFAPI_SESSION_TYPE;
#define IFAPI_PUB_KEY_DIR "ext"
#define IFAPI_POLICY_DIR "policy"
#define IFAPI_PEM_PUBLIC_STRING "-----BEGIN PUBLIC KEY-----"
#define IFAPI_PEM_PRIVATE_KEY "-----PRIVATE KEY-----"
#define IFAPI_PEM_PRIVATE_KEY "----BEGIN PRIVATE KEY-----"
#define IFAPI_PEM_RSA_PRIVATE_KEY "-----BEGIN RSA PRIVATE KEY-----"
#define IFAPI_PEM_ECC_PRIVATE_KEY "-----BEGIN EC PRIVATE KEY-----"
#define IFAPI_JSON_TAG_POLICY "policy"
#define IFAPI_JSON_TAG_OBJECT_TYPE "objectType"
#define IFAPI_JSON_TAG_DUPLICATE "public_parent"
Expand Down Expand Up @@ -716,6 +718,9 @@ typedef struct {
TPM2B_PRIVATE *private;
char *jso_string;
const IFAPI_PROFILE *profile;
IFAPI_KEY_TEMPLATE public_templ; /**< The template for the keys public data */
const char *ossl_priv; /**< Private OSSL PEM key to be import. */
TPM2B_SENSITIVE sensitive; /**< The sensitive part of an OSSL key. */
} IFAPI_ImportKey;


Expand Down

0 comments on commit 2e33d70

Please sign in to comment.