aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Bottomley <James.Bottomley@HansenPartnership.com>2019-12-27 18:30:01 -0800
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2019-12-27 18:30:01 -0800
commit06f566c36e4910655e8eeb18ccb668afa5ee9f15 (patch)
treeec06c2c9a8028ecd44a427b8c42b9fa32ebccf5c
parentfb970cfc1031c814f8c83467e8e8c3cfe513fd3f (diff)
downloadopenssl_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.c2
-rw-r--r--e_tpm2-rsa.c2
-rw-r--r--e_tpm2.c429
-rw-r--r--e_tpm2.h23
-rw-r--r--tpm2-asn.h41
-rw-r--r--tpm2-common.c467
-rw-r--r--tpm2-common.h27
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)
diff --git a/e_tpm2.c b/e_tpm2.c
index 1523e1f..ac0d6ba 100644
--- a/e_tpm2.c
+++ b/e_tpm2.c
@@ -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)
diff --git a/e_tpm2.h b/e_tpm2.h
index 5e843d2..a720acc 100644
--- a/e_tpm2.h
+++ b/e_tpm2.h
@@ -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
diff --git a/tpm2-asn.h b/tpm2-asn.h
index 82241be..9afa7c3 100644
--- a/tpm2-asn.h
+++ b/tpm2-asn.h
@@ -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