diff options
author | James Bottomley <James.Bottomley@HansenPartnership.com> | 2019-12-27 18:30:01 -0800 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2019-12-27 18:30:01 -0800 |
commit | 06f566c36e4910655e8eeb18ccb668afa5ee9f15 (patch) | |
tree | ec06c2c9a8028ecd44a427b8c42b9fa32ebccf5c | |
parent | fb970cfc1031c814f8c83467e8e8c3cfe513fd3f (diff) | |
download | openssl_tpm2_engine-06f566c36e4910655e8eeb18ccb668afa5ee9f15.tar.gz |
tpm2-common: extract file and TPM loading functions
The functions needed to load the key file and load a key into the TPM
are extracted from create_tpm2_key in preparation for re-used in
load_tpm2_key.
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
-rw-r--r-- | e_tpm2-ecc.c | 2 | ||||
-rw-r--r-- | e_tpm2-rsa.c | 2 | ||||
-rw-r--r-- | e_tpm2.c | 429 | ||||
-rw-r--r-- | e_tpm2.h | 23 | ||||
-rw-r--r-- | tpm2-asn.h | 41 | ||||
-rw-r--r-- | tpm2-common.c | 467 | ||||
-rw-r--r-- | tpm2-common.h | 27 |
7 files changed, 510 insertions, 481 deletions
diff --git a/e_tpm2-ecc.c b/e_tpm2-ecc.c index 21a636c..89e3762 100644 --- a/e_tpm2-ecc.c +++ b/e_tpm2-ecc.c @@ -87,7 +87,7 @@ static TPM_HANDLE tpm2_load_key_from_ecc(const EC_KEY *eck, *num_commands = app_data->num_commands; *nameAlg = app_data->name_alg; - return tpm2_load_key(tssContext, app_data); + return tpm2_load_key(tssContext, app_data, srk_auth); } void tpm2_bind_key_to_engine_ecc(EVP_PKEY *pkey, void *data) diff --git a/e_tpm2-rsa.c b/e_tpm2-rsa.c index fe82bc6..85be4a8 100644 --- a/e_tpm2-rsa.c +++ b/e_tpm2-rsa.c @@ -119,7 +119,7 @@ static TPM_HANDLE tpm2_load_key_from_rsa(RSA *rsa, TSS_CONTEXT **tssContext, *num_commands = app_data->num_commands; *nameAlg = app_data->name_alg; - return tpm2_load_key(tssContext, app_data); + return tpm2_load_key(tssContext, app_data, srk_auth); } void tpm2_bind_key_to_engine_rsa(EVP_PKEY *pkey, void *data) @@ -22,11 +22,10 @@ #include TSSINCLUDE(tssresponsecode.h) #include TSSINCLUDE(Unmarshal_fp.h) -#include "tpm2-asn.h" #include "tpm2-common.h" #include "e_tpm2.h" -static char *srk_auth; +char *srk_auth = NULL; static char *nvprefix; static int tpm2_engine_init(ENGINE * e) @@ -99,73 +98,6 @@ static const ENGINE_CMD_DEFN tpm2_cmd_defns[] = { {0, NULL, NULL, 0} }; -static char *tpm2_get_auth_ui(UI_METHOD *ui_method, char *prompt, void *cb_data) -{ - UI *ui = UI_new(); - /* Max auth size is name algorithm hash length, so this - * is way bigger than necessary */ - char auth[256], *ret = NULL; - int len; - - if (ui_method) - UI_set_method(ui, ui_method); - - UI_add_user_data(ui, cb_data); - - if (UI_add_input_string(ui, prompt, UI_INPUT_FLAG_DEFAULT_PWD, - auth, 0, sizeof(auth)) == 0) { - fprintf(stderr, "UI_add_input_string failed\n"); - goto out; - } - - if (UI_process(ui)) { - fprintf(stderr, "UI_process failed\n"); - goto out; - } - - len = strlen(auth); - ret = OPENSSL_malloc(len + 1); - if (!ret) - goto out; - - strcpy(ret, auth); - - out: - UI_free(ui); - - return ret; -} - -static char *tpm2_get_auth_pem(char *input_string, void *cb_data) -{ - char auth[256], *ret; - int len; - - EVP_set_pw_prompt(input_string); - - PEM_def_callback(auth, sizeof(auth), 0, cb_data); - EVP_set_pw_prompt(NULL); - - len = strlen(auth); - ret = OPENSSL_malloc(len + 1); - if (!ret) - goto out; - - strcpy(ret, auth); - - out: - return ret; -} - -static char *tpm2_get_auth(UI_METHOD *ui, char *input_string, - void *cb_data) -{ - if (ui) - return tpm2_get_auth_ui(ui, input_string, cb_data); - else - return tpm2_get_auth_pem(input_string, cb_data); -} - void tpm2_bind_key_to_engine(EVP_PKEY *pkey, void *data) { switch (EVP_PKEY_id(pkey)) { @@ -263,67 +195,14 @@ static int tpm2_engine_load_nvkey(ENGINE *e, EVP_PKEY **ppkey, return 0; } -static int tpm2_engine_load_key_policy(struct app_data *app_data, - STACK_OF(TSSOPTPOLICY) *st_policy) -{ - struct policy_command *command; - TSSOPTPOLICY *policy; - int i, commands_len; - - app_data->num_commands = sk_TSSOPTPOLICY_num(st_policy); - if (app_data->num_commands <= 0) - return 1; - - commands_len = sizeof(struct policy_command) * app_data->num_commands; - app_data->commands = OPENSSL_malloc(commands_len); - if (!app_data->commands) - return 0; - - for (i = 0; i < app_data->num_commands; i++) { - policy = sk_TSSOPTPOLICY_value(st_policy, i); - if (!policy) - return 0; - - command = app_data->commands + i; - command->code = ASN1_INTEGER_get(policy->CommandCode); - command->size = policy->CommandPolicy->length; - command->policy = NULL; - - if (!command->size) - continue; - - command->policy = OPENSSL_malloc(command->size); - if (!command->policy) - return 0; - - memcpy(command->policy, policy->CommandPolicy->data, - command->size); - } - - return 1; -} - static int tpm2_engine_load_key_core(ENGINE *e, EVP_PKEY **ppkey, const char *key_id, UI_METHOD *ui, void *cb_data) { EVP_PKEY *pkey; - BIO *bf; - TSSLOADABLE *tssl = NULL; - TSSPRIVKEY *tpk = NULL; - BYTE *buffer; - INT32 size; - struct app_data *app_data; - char oid[128]; - int empty_auth, version = 0; const int nvkey_len = strlen(nvprefix); - ASN1_OBJECT *type; - ASN1_INTEGER *parent; - ASN1_OCTET_STRING *pubkey; - STACK_OF(TSSOPTPOLICY) *policy; - ASN1_OCTET_STRING *privkey; - ASN1_OCTET_STRING *secret = NULL; - Import_In iin; + struct app_data *app_data; + int rc; if (!key_id) { fprintf(stderr, "key_id is NULL\n"); @@ -341,221 +220,16 @@ static int tpm2_engine_load_key_core(ENGINE *e, EVP_PKEY **ppkey, return tpm2_engine_load_nvkey(e, ppkey, key, ui, cb_data); } - bf = BIO_new_file(key_id, "r"); - if (!bf) { - fprintf(stderr, "File %s does not exist or cannot be read\n", key_id); + rc = tpm2_load_engine_file(key_id, &app_data, &pkey, ui, cb_data, + srk_auth); + if (!rc) return 0; - } - - tpk = PEM_read_bio_TSSPRIVKEY(bf, NULL, NULL, NULL); - if (tpk) { - version = 1; - type = tpk->type; - empty_auth = tpk->emptyAuth; - parent = tpk->parent; - pubkey = tpk->pubkey; - privkey = tpk->privkey; - policy = tpk->policy; - secret = tpk->secret; - } else { - BIO_seek(bf, 0); - tssl = PEM_read_bio_TSSLOADABLE(bf, NULL, NULL, NULL); - if (!tssl) { - BIO_free(bf); - if (ppkey) - fprintf(stderr, "Failed to parse file %s\n", key_id); - return 0; - } - - /* have error from failed TSSPRIVKEY load */ - ERR_clear_error(); - type = tssl->type; - empty_auth = tssl->emptyAuth; - parent = tssl->parent; - pubkey = tssl->pubkey; - privkey = tssl->privkey; - policy = tssl->policy; - } - - BIO_free(bf); - - if (!ppkey) { - TSSLOADABLE_free(tssl); - TSSPRIVKEY_free(tpk); - return 1; - } - - if (OBJ_obj2txt(oid, sizeof(oid), type, 1) == 0) { - fprintf(stderr, "Failed to parse object type\n"); - goto err; - } - - if (strcmp(OID_loadableKey, oid) == 0) { - if (version != 1) { - fprintf(stderr, "New type found in old format key\n"); - goto err; - } - } else if (strcmp(OID_OldloadableKey, oid) == 0) { - if (version != 0) { - fprintf(stderr, "Old type found in new format key\n"); - goto err; - } - } else if (strcmp(OID_importableKey, oid) == 0) { - if (!secret) { - fprintf(stderr, "Importable keys require an encrypted secret\n"); - goto err; - } - } else { - fprintf(stderr, "Unrecognised object type\n"); - goto err; - } - - app_data = OPENSSL_malloc(sizeof(*app_data)); - - if (!app_data) { - fprintf(stderr, "Failed to allocate app_data\n"); - goto err; - } - memset(app_data, 0, sizeof(*app_data)); - - app_data->version = version; - app_data->dir = tpm2_set_unique_tssdir(); - - if (parent) - app_data->parent = ASN1_INTEGER_get(parent); - else - /* older keys have absent parent */ - app_data->parent = TPM_RH_OWNER; - - app_data->pub = OPENSSL_malloc(pubkey->length); - if (!app_data->pub) - goto err_free; - app_data->pub_len = pubkey->length; - memcpy(app_data->pub, pubkey->data, app_data->pub_len); - - buffer = app_data->pub; - size = app_data->pub_len; - TPM2B_PUBLIC_Unmarshal(&iin.objectPublic, &buffer, &size, FALSE); - app_data->name_alg = iin.objectPublic.publicArea.nameAlg; - - if (strcmp(OID_importableKey, oid) == 0) { - TPM_HANDLE session; - TSS_CONTEXT *tssContext; - TPM_RC rc; - const char *reason; - TPM2B_PRIVATE priv_2b; - BYTE *buf; - UINT16 written; - INT32 size; - Import_Out iout; - - rc = tpm2_create(&tssContext, app_data->dir); - if (rc) { - reason="tpm2_create"; - goto import_err; - } - - if ((app_data->parent & 0xff000000) == 0x40000000) { - tpm2_load_srk(tssContext, &iin.parentHandle, - srk_auth, NULL, app_data->parent, 1); - } else { - iin.parentHandle = app_data->parent; - } - rc = tpm2_get_session_handle(tssContext, &session, - iin.parentHandle, - TPM_SE_HMAC, - iin.objectPublic.publicArea.nameAlg); - if (rc) { - reason="tpm2_get_session_handle"; - goto import_err; - } - - /* no inner encryption */ - iin.encryptionKey.t.size = 0; - iin.symmetricAlg.algorithm = TPM_ALG_NULL; - - /* for importable keys the private key is actually the - * outer wrapped duplicate structure */ - buffer = privkey->data; - size = privkey->length; - TPM2B_PRIVATE_Unmarshal(&iin.duplicate, &buffer, &size); - - buffer = secret->data; - size = secret->length; - TPM2B_ENCRYPTED_SECRET_Unmarshal(&iin.inSymSeed, &buffer, &size); - rc = TSS_Execute(tssContext, - (RESPONSE_PARAMETERS *)&iout, - (COMMAND_PARAMETERS *)&iin, - NULL, - TPM_CC_Import, - session, srk_auth, 0, - TPM_RH_NULL, NULL, 0); - if (rc) - tpm2_flush_handle(tssContext, session); - reason = "TPM2_Import"; - - import_err: - tpm2_flush_srk(tssContext, iin.parentHandle); - TSS_Delete(tssContext); - if (rc) { - tpm2_error(rc, reason); - goto err_free; - } - buf = priv_2b.t.buffer; - size = sizeof(priv_2b.t.buffer); - written = 0; - TSS_TPM2B_PRIVATE_Marshal(&iout.outPrivate, &written, - &buf, &size); - app_data->priv = OPENSSL_malloc(written); - if (!app_data->priv) - goto err_free; - app_data->priv_len = written; - memcpy(app_data->priv, priv_2b.t.buffer, written); - } else { - app_data->priv = OPENSSL_malloc(privkey->length); - if (!app_data->priv) - goto err_free; - - app_data->priv_len = privkey->length; - memcpy(app_data->priv, privkey->data, app_data->priv_len); - } - - /* create the new objects to return */ - pkey = tpm2_to_openssl_public(&iin.objectPublic.publicArea); - if (!pkey) { - fprintf(stderr, "Failed to allocate a new EVP_KEY\n"); - goto err_free; - } - - if (empty_auth == 0) { - app_data->auth = tpm2_get_auth(ui, "TPM Key Password: ", cb_data); - if (!app_data->auth) - goto err_free_key; - } - - if (!(iin.objectPublic.publicArea.objectAttributes.val & - TPMA_OBJECT_USERWITHAUTH)) - app_data->req_policy_session = 1; - - if (!tpm2_engine_load_key_policy(app_data, policy)) - goto err_free_key; - - TSSLOADABLE_free(tssl); - TSSPRIVKEY_free(tpk); tpm2_bind_key_to_engine(pkey, app_data); *ppkey = pkey; return 1; - err_free_key: - EVP_PKEY_free(pkey); - err_free: - tpm2_delete(app_data); - err: - TSSLOADABLE_free(tssl); - - return 0; } static EVP_PKEY *tpm2_engine_load_key(ENGINE *e, const char *key_id, @@ -611,96 +285,5 @@ static int tpm2_bind_fn(ENGINE * e, const char *id) return 1; } -TPM_HANDLE tpm2_load_key(TSS_CONTEXT **tsscp, struct app_data *app_data) -{ - TSS_CONTEXT *tssContext; - Load_In in; - Load_Out out; - TPM_HANDLE key = 0; - TPM_RC rc; - BYTE *buffer; - INT32 size; - TPM_HANDLE session; - - rc = tpm2_create(&tssContext, app_data->dir); - if (rc) - return 0; - - if (app_data->key) { - key = app_data->key; - goto out; - } - - buffer = app_data->priv; - size = app_data->priv_len; - TPM2B_PRIVATE_Unmarshal(&in.inPrivate, &buffer, &size); - - buffer = app_data->pub; - size = app_data->pub_len; - TPM2B_PUBLIC_Unmarshal(&in.inPublic, &buffer, &size, FALSE); - - if ((app_data->parent & 0xff000000) == 0x81000000) { - in.parentHandle = app_data->parent; - } else { - rc = tpm2_load_srk(tssContext, &in.parentHandle, srk_auth, NULL, app_data->parent, app_data->version); - if (rc) - goto out; - } - rc = tpm2_get_session_handle(tssContext, &session, in.parentHandle, - TPM_SE_HMAC, app_data->name_alg); - if (rc) - goto out_flush_srk; - rc = TSS_Execute(tssContext, - (RESPONSE_PARAMETERS *)&out, - (COMMAND_PARAMETERS *)&in, - NULL, - TPM_CC_Load, - session, srk_auth, 0, - TPM_RH_NULL, NULL, 0); - if (rc) { - tpm2_error(rc, "TPM2_Load"); - tpm2_flush_handle(tssContext, session); - } - else - key = out.objectHandle; - - out_flush_srk: - tpm2_flush_srk(tssContext, in.parentHandle); - out: - if (!key) - TSS_Delete(tssContext); - else - *tsscp = tssContext; - return key; -} - -void tpm2_unload_key(TSS_CONTEXT *tssContext, TPM_HANDLE key) -{ - tpm2_flush_handle(tssContext, key); - - TSS_Delete(tssContext); -} - -void tpm2_delete(struct app_data *app_data) -{ - int i; - - for (i = 0; i < app_data->num_commands; i++) - OPENSSL_free(app_data->commands[i].policy); - - OPENSSL_free(app_data->commands); - OPENSSL_free(app_data->priv); - OPENSSL_free(app_data->pub); - - tpm2_rm_keyfile(app_data->dir, app_data->parent); - /* if key was nv key, flush may not have removed file */ - tpm2_rm_keyfile(app_data->dir, app_data->key); - tpm2_rm_tssdir(app_data->dir); - - OPENSSL_free((void *)app_data->dir); - - OPENSSL_free(app_data); -} - IMPLEMENT_DYNAMIC_CHECK_FN() IMPLEMENT_DYNAMIC_BIND_FN(tpm2_bind_fn) @@ -6,27 +6,6 @@ #define TPM2_ENGINE_EX_DATA_UNINIT -1 -/* structure pointed to by the RSA object's app_data pointer */ -struct app_data { - int version; - TPM_HANDLE parent; - /* if key is in NV memory */ - TPM_HANDLE key; - /* otherwise key is specified by blobs */ - void *priv; - int priv_len; - void *pub; - int pub_len; - char *auth; - const char *dir; - int req_policy_session; - int num_commands; - unsigned int name_alg; - struct policy_command *commands; -}; - -TPM_HANDLE tpm2_load_key(TSS_CONTEXT **tsscp, struct app_data *app_data); -void tpm2_unload_key(TSS_CONTEXT *tssContext, TPM_HANDLE key); -void tpm2_delete(struct app_data *app_data); +extern char *srk_auth; #endif @@ -24,13 +24,6 @@ typedef struct { ASN1_OCTET_STRING *CommandPolicy; } TSSOPTPOLICY; -ASN1_SEQUENCE(TSSOPTPOLICY) = { - ASN1_EXP(TSSOPTPOLICY, CommandCode, ASN1_INTEGER, 0), - ASN1_EXP(TSSOPTPOLICY, CommandPolicy, ASN1_OCTET_STRING, 1) -} ASN1_SEQUENCE_END(TSSOPTPOLICY) - -IMPLEMENT_ASN1_FUNCTIONS(TSSOPTPOLICY); - #if OPENSSL_VERSION_NUMBER < 0x10100000 #define sk_TSSOPTPOLICY_new_null() SKM_sk_new_null(TSSOPTPOLICY) #define sk_TSSOPTPOLICY_push(sk, policy) SKM_sk_push(TSSOPTPOLICY, sk, policy) @@ -107,36 +100,16 @@ typedef struct { #define OID_importableKey "2.23.133.10.1.4" -ASN1_SEQUENCE(TSSLOADABLE) = { - ASN1_SIMPLE(TSSLOADABLE, type, ASN1_OBJECT), - ASN1_EXP_OPT(TSSLOADABLE, emptyAuth, ASN1_BOOLEAN, 0), - ASN1_EXP_OPT(TSSLOADABLE, parent, ASN1_INTEGER, 1), - ASN1_EXP_OPT(TSSLOADABLE, pubkey, ASN1_OCTET_STRING, 2), - ASN1_EXP_SEQUENCE_OF_OPT(TSSLOADABLE, policy, TSSOPTPOLICY, 3), - ASN1_SIMPLE(TSSLOADABLE, privkey, ASN1_OCTET_STRING) -} ASN1_SEQUENCE_END(TSSLOADABLE) - -IMPLEMENT_ASN1_FUNCTIONS(TSSLOADABLE); - -ASN1_SEQUENCE(TSSPRIVKEY) = { - ASN1_SIMPLE(TSSPRIVKEY, type, ASN1_OBJECT), - ASN1_EXP_OPT(TSSPRIVKEY, emptyAuth, ASN1_BOOLEAN, 0), - ASN1_EXP_SEQUENCE_OF_OPT(TSSPRIVKEY, policy, TSSOPTPOLICY, 1), - ASN1_EXP_OPT(TSSPRIVKEY, secret, ASN1_OCTET_STRING, 2), - ASN1_SIMPLE(TSSPRIVKEY, parent, ASN1_INTEGER), - ASN1_SIMPLE(TSSPRIVKEY, pubkey, ASN1_OCTET_STRING), - ASN1_SIMPLE(TSSPRIVKEY, privkey, ASN1_OCTET_STRING) -} ASN1_SEQUENCE_END(TSSPRIVKEY) - -IMPLEMENT_ASN1_FUNCTIONS(TSSPRIVKEY); - /* This is the PEM guard tag */ #define TSSLOADABLE_PEM_STRING "TSS2 KEY BLOB" #define TSSPRIVKEY_PEM_STRING "TSS2 PRIVATE KEY" -static IMPLEMENT_PEM_write_bio(TSSLOADABLE, TSSLOADABLE, TSSLOADABLE_PEM_STRING, TSSLOADABLE) -static IMPLEMENT_PEM_read_bio(TSSLOADABLE, TSSLOADABLE, TSSLOADABLE_PEM_STRING, TSSLOADABLE) -static IMPLEMENT_PEM_write_bio(TSSPRIVKEY, TSSPRIVKEY, TSSPRIVKEY_PEM_STRING, TSSPRIVKEY) -static IMPLEMENT_PEM_read_bio(TSSPRIVKEY, TSSPRIVKEY, TSSPRIVKEY_PEM_STRING, TSSPRIVKEY) +DECLARE_ASN1_FUNCTIONS(TSSOPTPOLICY); +DECLARE_ASN1_FUNCTIONS(TSSLOADABLE); +DECLARE_ASN1_FUNCTIONS(TSSPRIVKEY); +DECLARE_PEM_write_bio(TSSLOADABLE, TSSLOADABLE); +DECLARE_PEM_read_bio(TSSLOADABLE, TSSLOADABLE); +DECLARE_PEM_write_bio(TSSPRIVKEY, TSSPRIVKEY); +DECLARE_PEM_read_bio(TSSPRIVKEY, TSSPRIVKEY); #endif diff --git a/tpm2-common.c b/tpm2-common.c index 1152777..a585b6a 100644 --- a/tpm2-common.c +++ b/tpm2-common.c @@ -11,6 +11,9 @@ #include <openssl/evp.h> #include <openssl/rsa.h> #include <openssl/ec.h> +#include <openssl/pem.h> +#include <openssl/err.h> +#include <openssl/ui.h> #define TSSINCLUDE(x) < TSS_INCLUDE/x > #include TSSINCLUDE(tss.h) @@ -20,6 +23,7 @@ #include TSSINCLUDE(Unmarshal_fp.h) #include "tpm2-common.h" +#include "tpm2-asn.h" struct myTPM2B { UINT16 s; @@ -913,3 +917,466 @@ int tpm2_get_public_point(TPM2B_ECC_POINT *tpmpt, const EC_GROUP *group, return len; } + +static char *tpm2_get_auth_ui(UI_METHOD *ui_method, char *prompt, void *cb_data) +{ + UI *ui = UI_new(); + /* Max auth size is name algorithm hash length, so this + * is way bigger than necessary */ + char auth[256], *ret = NULL; + int len; + + if (ui_method) + UI_set_method(ui, ui_method); + + UI_add_user_data(ui, cb_data); + + if (UI_add_input_string(ui, prompt, UI_INPUT_FLAG_DEFAULT_PWD, + auth, 0, sizeof(auth)) == 0) { + fprintf(stderr, "UI_add_input_string failed\n"); + goto out; + } + + if (UI_process(ui)) { + fprintf(stderr, "UI_process failed\n"); + goto out; + } + + len = strlen(auth); + ret = OPENSSL_malloc(len + 1); + if (!ret) + goto out; + + strcpy(ret, auth); + + out: + UI_free(ui); + + return ret; +} + +static char *tpm2_get_auth_pem(char *input_string, void *cb_data) +{ + char auth[256], *ret; + int len; + + EVP_set_pw_prompt(input_string); + + PEM_def_callback(auth, sizeof(auth), 0, cb_data); + EVP_set_pw_prompt(NULL); + + len = strlen(auth); + ret = OPENSSL_malloc(len + 1); + if (!ret) + goto out; + + strcpy(ret, auth); + + out: + return ret; +} + +char *tpm2_get_auth(UI_METHOD *ui, char *input_string, void *cb_data) +{ + if (ui) + return tpm2_get_auth_ui(ui, input_string, cb_data); + else + return tpm2_get_auth_pem(input_string, cb_data); +} + +static int tpm2_engine_load_key_policy(struct app_data *app_data, + STACK_OF(TSSOPTPOLICY) *st_policy) +{ + struct policy_command *command; + TSSOPTPOLICY *policy; + int i, commands_len; + + app_data->num_commands = sk_TSSOPTPOLICY_num(st_policy); + if (app_data->num_commands <= 0) + return 1; + + commands_len = sizeof(struct policy_command) * app_data->num_commands; + app_data->commands = OPENSSL_malloc(commands_len); + if (!app_data->commands) + return 0; + + for (i = 0; i < app_data->num_commands; i++) { + policy = sk_TSSOPTPOLICY_value(st_policy, i); + if (!policy) + return 0; + + command = app_data->commands + i; + command->code = ASN1_INTEGER_get(policy->CommandCode); + command->size = policy->CommandPolicy->length; + command->policy = NULL; + + if (!command->size) + continue; + + command->policy = OPENSSL_malloc(command->size); + if (!command->policy) + return 0; + + memcpy(command->policy, policy->CommandPolicy->data, + command->size); + } + + return 1; +} + +int tpm2_load_engine_file(const char *filename, struct app_data **app_data, + EVP_PKEY **ppkey, UI_METHOD *ui, void *cb_data, + const char *srk_auth) +{ + BIO *bf; + TSSLOADABLE *tssl = NULL; + TSSPRIVKEY *tpk = NULL; + BYTE *buffer; + INT32 size; + struct app_data *ad; + char oid[128]; + int empty_auth, version = 0; + ASN1_OBJECT *type; + ASN1_INTEGER *parent; + ASN1_OCTET_STRING *pubkey; + STACK_OF(TSSOPTPOLICY) *policy; + ASN1_OCTET_STRING *privkey; + ASN1_OCTET_STRING *secret = NULL; + Import_In iin; + + bf = BIO_new_file(filename, "r"); + if (!bf) { + fprintf(stderr, "File %s does not exist or cannot be read\n", + filename); + return 0; + } + + tpk = PEM_read_bio_TSSPRIVKEY(bf, NULL, NULL, NULL); + if (tpk) { + version = 1; + type = tpk->type; + empty_auth = tpk->emptyAuth; + parent = tpk->parent; + pubkey = tpk->pubkey; + privkey = tpk->privkey; + policy = tpk->policy; + secret = tpk->secret; + } else { + BIO_seek(bf, 0); + tssl = PEM_read_bio_TSSLOADABLE(bf, NULL, NULL, NULL); + if (!tssl) { + BIO_free(bf); + fprintf(stderr, "Failed to parse file %s\n", filename); + return 0; + } + + /* have error from failed TSSPRIVKEY load */ + ERR_clear_error(); + type = tssl->type; + empty_auth = tssl->emptyAuth; + parent = tssl->parent; + pubkey = tssl->pubkey; + privkey = tssl->privkey; + policy = tssl->policy; + } + + BIO_free(bf); + + if (OBJ_obj2txt(oid, sizeof(oid), type, 1) == 0) { + fprintf(stderr, "Failed to parse object type\n"); + goto err; + } + + if (strcmp(OID_loadableKey, oid) == 0) { + if (version != 1) { + fprintf(stderr, "New type found in old format key\n"); + goto err; + } + } else if (strcmp(OID_OldloadableKey, oid) == 0) { + if (version != 0) { + fprintf(stderr, "Old type found in new format key\n"); + goto err; + } + } else if (strcmp(OID_importableKey, oid) == 0) { + if (!secret) { + fprintf(stderr, "Importable keys require an encrypted secret\n"); + goto err; + } + } else { + fprintf(stderr, "Unrecognised object type\n"); + goto err; + } + + ad = OPENSSL_malloc(sizeof(*ad)); + + if (!ad) { + fprintf(stderr, "Failed to allocate app_data\n"); + goto err; + } + memset(ad, 0, sizeof(*ad)); + + *app_data = ad; + + ad->version = version; + ad->dir = tpm2_set_unique_tssdir(); + + if (parent) + ad->parent = ASN1_INTEGER_get(parent); + else + /* older keys have absent parent */ + ad->parent = TPM_RH_OWNER; + + ad->pub = OPENSSL_malloc(pubkey->length); + if (!ad->pub) + goto err_free; + ad->pub_len = pubkey->length; + memcpy(ad->pub, pubkey->data, ad->pub_len); + + buffer = ad->pub; + size = ad->pub_len; + TPM2B_PUBLIC_Unmarshal(&iin.objectPublic, &buffer, &size, FALSE); + ad->name_alg = iin.objectPublic.publicArea.nameAlg; + + if (strcmp(OID_importableKey, oid) == 0) { + TPM_HANDLE session; + TSS_CONTEXT *tssContext; + TPM_RC rc; + const char *reason; + TPM2B_PRIVATE priv_2b; + BYTE *buf; + UINT16 written; + INT32 size; + Import_Out iout; + + rc = tpm2_create(&tssContext, ad->dir); + if (rc) { + reason="tpm2_create"; + goto import_err; + } + + if ((ad->parent & 0xff000000) == 0x40000000) { + tpm2_load_srk(tssContext, &iin.parentHandle, + srk_auth, NULL, ad->parent, 1); + } else { + iin.parentHandle = ad->parent; + } + rc = tpm2_get_session_handle(tssContext, &session, + iin.parentHandle, + TPM_SE_HMAC, + iin.objectPublic.publicArea.nameAlg); + if (rc) { + reason="tpm2_get_session_handle"; + goto import_err; + } + + /* no inner encryption */ + iin.encryptionKey.t.size = 0; + iin.symmetricAlg.algorithm = TPM_ALG_NULL; + + /* for importable keys the private key is actually the + * outer wrapped duplicate structure */ + buffer = privkey->data; + size = privkey->length; + TPM2B_PRIVATE_Unmarshal(&iin.duplicate, &buffer, &size); + + buffer = secret->data; + size = secret->length; + TPM2B_ENCRYPTED_SECRET_Unmarshal(&iin.inSymSeed, &buffer, &size); + rc = TSS_Execute(tssContext, + (RESPONSE_PARAMETERS *)&iout, + (COMMAND_PARAMETERS *)&iin, + NULL, + TPM_CC_Import, + session, srk_auth, 0, + TPM_RH_NULL, NULL, 0); + if (rc) + tpm2_flush_handle(tssContext, session); + reason = "TPM2_Import"; + + import_err: + tpm2_flush_srk(tssContext, iin.parentHandle); + TSS_Delete(tssContext); + if (rc) { + tpm2_error(rc, reason); + goto err_free; + } + buf = priv_2b.t.buffer; + size = sizeof(priv_2b.t.buffer); + written = 0; + TSS_TPM2B_PRIVATE_Marshal(&iout.outPrivate, &written, + &buf, &size); + ad->priv = OPENSSL_malloc(written); + if (!ad->priv) + goto err_free; + ad->priv_len = written; + memcpy(ad->priv, priv_2b.t.buffer, written); + } else { + ad->priv = OPENSSL_malloc(privkey->length); + if (!ad->priv) + goto err_free; + + ad->priv_len = privkey->length; + memcpy(ad->priv, privkey->data, ad->priv_len); + } + + /* create the new objects to return */ + *ppkey = tpm2_to_openssl_public(&iin.objectPublic.publicArea); + if (!*ppkey) { + fprintf(stderr, "Failed to allocate a new EVP_KEY\n"); + goto err_free; + } + + if (empty_auth == 0) { + ad->auth = tpm2_get_auth(ui, "TPM Key Password: ", cb_data); + if (!ad->auth) + goto err_free_key; + } + + if (!(iin.objectPublic.publicArea.objectAttributes.val & + TPMA_OBJECT_USERWITHAUTH)) + ad->req_policy_session = 1; + + if (!tpm2_engine_load_key_policy(ad, policy)) + goto err_free_key; + + TSSLOADABLE_free(tssl); + TSSPRIVKEY_free(tpk); + + return 1; + err_free_key: + EVP_PKEY_free(*ppkey); + err_free: + *ppkey = NULL; + + tpm2_delete(ad); + err: + TSSLOADABLE_free(tssl); + TSSPRIVKEY_free(tpk); + + return 0; +} + +void tpm2_delete(struct app_data *app_data) +{ + int i; + + for (i = 0; i < app_data->num_commands; i++) + OPENSSL_free(app_data->commands[i].policy); + + OPENSSL_free(app_data->commands); + OPENSSL_free(app_data->priv); + OPENSSL_free(app_data->pub); + + tpm2_rm_keyfile(app_data->dir, app_data->parent); + /* if key was nv key, flush may not have removed file */ + tpm2_rm_keyfile(app_data->dir, app_data->key); + tpm2_rm_tssdir(app_data->dir); + + OPENSSL_free((void *)app_data->dir); + + OPENSSL_free(app_data); +} + +TPM_HANDLE tpm2_load_key(TSS_CONTEXT **tsscp, struct app_data *app_data, + const char *srk_auth) +{ + TSS_CONTEXT *tssContext; + Load_In in; + Load_Out out; + TPM_HANDLE key = 0; + TPM_RC rc; + BYTE *buffer; + INT32 size; + TPM_HANDLE session; + + rc = tpm2_create(&tssContext, app_data->dir); + if (rc) + return 0; + + if (app_data->key) { + key = app_data->key; + goto out; + } + + buffer = app_data->priv; + size = app_data->priv_len; + TPM2B_PRIVATE_Unmarshal(&in.inPrivate, &buffer, &size); + + buffer = app_data->pub; + size = app_data->pub_len; + TPM2B_PUBLIC_Unmarshal(&in.inPublic, &buffer, &size, FALSE); + + if ((app_data->parent & 0xff000000) == 0x81000000) { + in.parentHandle = app_data->parent; + } else { + rc = tpm2_load_srk(tssContext, &in.parentHandle, srk_auth, NULL, app_data->parent, app_data->version); + if (rc) + goto out; + } + rc = tpm2_get_session_handle(tssContext, &session, in.parentHandle, + TPM_SE_HMAC, app_data->name_alg); + if (rc) + goto out_flush_srk; + rc = TSS_Execute(tssContext, + (RESPONSE_PARAMETERS *)&out, + (COMMAND_PARAMETERS *)&in, + NULL, + TPM_CC_Load, + session, srk_auth, 0, + TPM_RH_NULL, NULL, 0); + if (rc) { + tpm2_error(rc, "TPM2_Load"); + tpm2_flush_handle(tssContext, session); + } + else + key = out.objectHandle; + + out_flush_srk: + tpm2_flush_srk(tssContext, in.parentHandle); + out: + if (!key) + TSS_Delete(tssContext); + else + *tsscp = tssContext; + return key; +} + +void tpm2_unload_key(TSS_CONTEXT *tssContext, TPM_HANDLE key) +{ + tpm2_flush_handle(tssContext, key); + + TSS_Delete(tssContext); +} + +IMPLEMENT_ASN1_FUNCTIONS(TSSOPTPOLICY) +IMPLEMENT_ASN1_FUNCTIONS(TSSLOADABLE) +IMPLEMENT_ASN1_FUNCTIONS(TSSPRIVKEY) +IMPLEMENT_PEM_write_bio(TSSLOADABLE, TSSLOADABLE, TSSLOADABLE_PEM_STRING, TSSLOADABLE) +IMPLEMENT_PEM_read_bio(TSSLOADABLE, TSSLOADABLE, TSSLOADABLE_PEM_STRING, TSSLOADABLE) +IMPLEMENT_PEM_write_bio(TSSPRIVKEY, TSSPRIVKEY, TSSPRIVKEY_PEM_STRING, TSSPRIVKEY) +IMPLEMENT_PEM_read_bio(TSSPRIVKEY, TSSPRIVKEY, TSSPRIVKEY_PEM_STRING, TSSPRIVKEY) + +ASN1_SEQUENCE(TSSOPTPOLICY) = { + ASN1_EXP(TSSOPTPOLICY, CommandCode, ASN1_INTEGER, 0), + ASN1_EXP(TSSOPTPOLICY, CommandPolicy, ASN1_OCTET_STRING, 1) +} ASN1_SEQUENCE_END(TSSOPTPOLICY) + +ASN1_SEQUENCE(TSSLOADABLE) = { + ASN1_SIMPLE(TSSLOADABLE, type, ASN1_OBJECT), + ASN1_EXP_OPT(TSSLOADABLE, emptyAuth, ASN1_BOOLEAN, 0), + ASN1_EXP_OPT(TSSLOADABLE, parent, ASN1_INTEGER, 1), + ASN1_EXP_OPT(TSSLOADABLE, pubkey, ASN1_OCTET_STRING, 2), + ASN1_EXP_SEQUENCE_OF_OPT(TSSLOADABLE, policy, TSSOPTPOLICY, 3), + ASN1_SIMPLE(TSSLOADABLE, privkey, ASN1_OCTET_STRING) +} ASN1_SEQUENCE_END(TSSLOADABLE) + +ASN1_SEQUENCE(TSSPRIVKEY) = { + ASN1_SIMPLE(TSSPRIVKEY, type, ASN1_OBJECT), + ASN1_EXP_OPT(TSSPRIVKEY, emptyAuth, ASN1_BOOLEAN, 0), + ASN1_EXP_SEQUENCE_OF_OPT(TSSPRIVKEY, policy, TSSOPTPOLICY, 1), + ASN1_EXP_OPT(TSSPRIVKEY, secret, ASN1_OCTET_STRING, 2), + ASN1_SIMPLE(TSSPRIVKEY, parent, ASN1_INTEGER), + ASN1_SIMPLE(TSSPRIVKEY, pubkey, ASN1_OCTET_STRING), + ASN1_SIMPLE(TSSPRIVKEY, privkey, ASN1_OCTET_STRING) +} ASN1_SEQUENCE_END(TSSPRIVKEY) + diff --git a/tpm2-common.h b/tpm2-common.h index f22422b..264fc8e 100644 --- a/tpm2-common.h +++ b/tpm2-common.h @@ -10,6 +10,25 @@ struct policy_command { BYTE *policy; }; +/* structure pointed to by the RSA object's app_data pointer */ +struct app_data { + int version; + TPM_HANDLE parent; + /* if key is in NV memory */ + TPM_HANDLE key; + /* otherwise key is specified by blobs */ + void *priv; + int priv_len; + void *pub; + int pub_len; + char *auth; + const char *dir; + int req_policy_session; + int num_commands; + unsigned int name_alg; + struct policy_command *commands; +}; + void tpm2_error(TPM_RC rc, const char *reason); TPM_RC tpm2_load_srk(TSS_CONTEXT *tssContext, TPM_HANDLE *h, const char *auth, TPM2B_PUBLIC *pub, TPM_HANDLE handle, int version); void tpm2_flush_handle(TSS_CONTEXT *tssContext, TPM_HANDLE h); @@ -36,4 +55,12 @@ void tpm2_rm_tssdir(const char *dir); void tpm2_rm_keyfile(const char *dir, TPM_HANDLE key); int tpm2_get_public_point(TPM2B_ECC_POINT *tpmpt, const EC_GROUP *group, const EC_POINT *pt); +int tpm2_load_engine_file(const char *filename, struct app_data **app_data, + EVP_PKEY **ppkey, UI_METHOD *ui, void *cb_data, + const char *srk_auth); +TPM_HANDLE tpm2_load_key(TSS_CONTEXT **tsscp, struct app_data *app_data, + const char *srk_auth); +void tpm2_unload_key(TSS_CONTEXT *tssContext, TPM_HANDLE key); +void tpm2_delete(struct app_data *app_data); +char *tpm2_get_auth(UI_METHOD *ui, char *input_string, void *cb_data); #endif |