diff options
author | James Bottomley <James.Bottomley@HansenPartnership.com> | 2023-03-16 13:47:15 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2023-03-22 22:59:44 -0400 |
commit | 184d8dda5c317536ab40ec90b008849c23c67246 (patch) | |
tree | 5b0563b586e0841fb1c4e76b5c97a88bfb4f7460 | |
parent | 5fe4ac30a30bc8fa1693dbbf4ca6a3ab2b57bff6 (diff) | |
download | openssl_tpm2_engine-184d8dda5c317536ab40ec90b008849c23c67246.tar.gz |
provider: add nv key handling with store
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
-rw-r--r-- | src/provider/Makefile.am | 2 | ||||
-rw-r--r-- | src/provider/keymgmt.c | 2 | ||||
-rw-r--r-- | src/provider/provider.c | 11 | ||||
-rw-r--r-- | src/provider/provider.h | 5 | ||||
-rw-r--r-- | src/provider/store.c | 184 |
5 files changed, 200 insertions, 4 deletions
diff --git a/src/provider/Makefile.am b/src/provider/Makefile.am index fc17fef..5ff91cf 100644 --- a/src/provider/Makefile.am +++ b/src/provider/Makefile.am @@ -7,7 +7,7 @@ openssl_providerdir=@modulesdir@ libtpm2_la_LDFLAGS= -no-undefined -avoid-version libtpm2_la_LIBADD=${COMMONLIB} ${DEPS_LIBS} -libtpm2_la_SOURCES=provider.c decode_encode.c keymgmt.c signatures.c decryption.c +libtpm2_la_SOURCES=provider.c decode_encode.c keymgmt.c signatures.c decryption.c store.c libtpm2_la_CFLAGS=${DEPS_CFLAGS} -g -Werror install-data-hook: diff --git a/src/provider/keymgmt.c b/src/provider/keymgmt.c index 6b79660..aa9c120 100644 --- a/src/provider/keymgmt.c +++ b/src/provider/keymgmt.c @@ -73,7 +73,7 @@ static int tpm2_keymgmt_has(const void *ref, int selection) if (selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) return 1; if (selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) - return ad->priv != NULL; + return ad->priv != NULL || ad->key != 0; return 0; } diff --git a/src/provider/provider.c b/src/provider/provider.c index 3db944b..f913bc6 100644 --- a/src/provider/provider.c +++ b/src/provider/provider.c @@ -73,7 +73,7 @@ static struct { QOP(OSSL_OP_SIGNATURE, signatures), QOP(OSSL_OP_ASYM_CIPHER, asymciphers), QOP(OSSL_OP_KEYEXCH, keyexchs), - QOP(OSSL_OP_STORE, NULL), + QOP(OSSL_OP_STORE, stores), }; static const OSSL_ALGORITHM *p_query(void *provctx, int operation_id, @@ -102,12 +102,13 @@ int OSSL_provider_init(const OSSL_CORE_HANDLE *handle, { OSSL_LIB_CTX *libctx; const OSSL_DISPATCH *fns = in; + int i; OSSL_PARAM provider_params[] = { OSSL_PARAM_utf8_ptr("PIN", &srk_auth, 0), + OSSL_PARAM_utf8_ptr("NVPREFIX", &nvprefix, 0), OSSL_PARAM_END }; - *out = prov_fns; for (; fns->function_id != 0; fns++) { @@ -126,6 +127,12 @@ int OSSL_provider_init(const OSSL_CORE_HANDLE *handle, fprintf(stderr, "core failed to load params\n"); goto err; } + /* scheme can't have a ':' in it and the engine did have it */ + for (i = strlen(nvprefix) - 1; i > 0; --i) + if (nvprefix[i] == ':') + nvprefix[i] = 0; + + stores[0].algorithm_names = nvprefix; libctx = OSSL_LIB_CTX_new_from_dispatch(handle, in); if (libctx == NULL) { diff --git a/src/provider/provider.h b/src/provider/provider.h index bb44f9b..3eac2cf 100644 --- a/src/provider/provider.h +++ b/src/provider/provider.h @@ -16,6 +16,7 @@ #include "tpm2-common.h" extern char *srk_auth; +extern char *nvprefix; /* core context functions in provider.h */ void *tpm2_passthrough_newctx(void *ctx); @@ -42,5 +43,9 @@ extern const OSSL_ALGORITHM signatures[]; extern const OSSL_ALGORITHM asymciphers[]; extern const OSSL_ALGORITHM keyexchs[]; +/* store.c */ + +extern OSSL_ALGORITHM stores[]; + #endif diff --git a/src/provider/store.c b/src/provider/store.c new file mode 100644 index 0000000..56a39e0 --- /dev/null +++ b/src/provider/store.c @@ -0,0 +1,184 @@ +/* Copyright (C) 2023 James Bottomley <James.Bottomley@HansenPartnership.com> + * + * SPDX-License-Identifier: LGPL-2.1-only + */ + +#include <string.h> +#include <stdio.h> +#include <stdarg.h> + +#include <openssl/store.h> + +#include "provider.h" + +char *nvprefix = "//nvkey"; + +struct tpm2_store_ctx { + const char *uri; + int eof; + int expect; +}; + + +static void *tpm2_store_open(void *provctx, const char *uri) +{ + const int nvprefix_size = strlen(nvprefix); + struct tpm2_store_ctx *sctx; + + if (strncmp(nvprefix, uri, nvprefix_size) != 0) + return NULL; + + sctx = OPENSSL_zalloc(sizeof(*sctx)); + if (!sctx) + return NULL; + + sctx->uri = uri + nvprefix_size; + if (sctx->uri[0] == ':') + sctx->uri++; + + return sctx; +} + +static int tpm2_store_load(void *ctx, + OSSL_CALLBACK *data_cb, void *data_cbarg, + OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg) +{ + struct tpm2_store_ctx *sctx = ctx; + TPM_HANDLE key = strtoul(sctx->uri, NULL, 16); + struct app_data *ad; + TSS_CONTEXT *tssContext; + TPM_RC rc; + int ret = 0; + int askauth = 0; + OSSL_PARAM params[4]; + int type; + char *keytype; + + sctx->eof = 1; + if ((key >> 24) != TPM_HT_PERSISTENT) { + fprintf(stderr, "nvkey doesn't have a persistent handle\n"); + return 0; + } + + ad = tpm2_keymgmt_new(NULL); + if (!ad) + return 0; + + ad->dir = tpm2_set_unique_tssdir(); + + rc = tpm2_create(&tssContext, ad->dir); + if (rc) + goto err; + + key = tpm2_handle_int(tssContext, key); + rc = tpm2_readpublic(tssContext, key, &ad->Public.publicArea); + if (rc) + goto err_del; + + if ((sctx->expect == OSSL_STORE_INFO_PKEY)) { + ad->key = tpm2_handle_ext(tssContext, key); + + if (VAL(ad->Public.publicArea.objectAttributes) & TPMA_OBJECT_NODA) { + /* no DA implications, try an authorization + * and see if NULL is accepted */ + TPM_HANDLE session; + + rc = tpm2_get_bound_handle(tssContext, &session, key, NULL); + if (rc == TPM_RC_SUCCESS) { + rc = tpm2_ReadPublic(tssContext, key, NULL, session); + if (rc) + tpm2_flush_handle(tssContext, session); + } + if (rc != TPM_RC_SUCCESS) + askauth = 1; + } else { + /* assume since we have DA implications, we have a password */ + askauth = 1; + } + + if (askauth) { + char pass[SHA512_DIGEST_LENGTH]; + size_t len; + + if (!pw_cb(pass, sizeof(pass), &len, NULL, pw_cbarg)) + goto err_del; + ad->auth = OPENSSL_malloc(len + 1); + if (!ad->auth) + goto err_del; + memcpy(ad->auth, pass, len); + ad->auth[len] = '\0'; + OPENSSL_cleanse(pass, len); + } + } else { + tpm2_rm_keyfile(ad->dir, tpm2_handle_ext(tssContext, key)); + } + TSS_Delete(tssContext); + + type = OSSL_OBJECT_PKEY; + keytype = ad->Public.publicArea.type == TPM_ALG_RSA ? "RSA" : "EC"; + params[0] = OSSL_PARAM_construct_int(OSSL_OBJECT_PARAM_TYPE, + &type); + params[1] = OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_TYPE, + keytype, 0); + params[2] = OSSL_PARAM_construct_octet_string(OSSL_OBJECT_PARAM_REFERENCE, + &ad, sizeof(ad)); + params[3] = OSSL_PARAM_construct_end(); + + ret = data_cb(params, data_cbarg); + if (!ret) + goto err; + + return ret; + + err_del: + TSS_Delete(tssContext); + err: + tpm2_delete(ad); + return 0; +} + +static int tpm2_store_eof(void *ctx) +{ + struct tpm2_store_ctx *sctx = ctx; + + return sctx->eof; +} + +static int tpm2_store_close(void *ctx) +{ + OPENSSL_free(ctx); + return 1; +} + +static int tpm2_store_set_ctx_params(void *ctx, const OSSL_PARAM params[]) +{ + const OSSL_PARAM *p = params; + struct tpm2_store_ctx *sctx = ctx; + + p = OSSL_PARAM_locate_const(params, OSSL_STORE_PARAM_EXPECT); + if (p != NULL) { + if (p->data_type != OSSL_PARAM_INTEGER) + return 0; + OSSL_PARAM_get_int(p, &sctx->expect); + } + return 1; +} + +const OSSL_DISPATCH store_fns[] = { + { OSSL_FUNC_STORE_OPEN, (void(*)(void))tpm2_store_open }, + { OSSL_FUNC_STORE_LOAD, (void(*)(void))tpm2_store_load }, + { OSSL_FUNC_STORE_EOF, (void(*)(void))tpm2_store_eof }, + { OSSL_FUNC_STORE_CLOSE, (void(*)(void))tpm2_store_close }, + { OSSL_FUNC_STORE_SET_CTX_PARAMS, (void(*)(void))tpm2_store_set_ctx_params }, + { 0, NULL } +}; + +/* + * OpenSSL weirdness: the algorithm_name has to be set to the scheme, but + * the scheme can be modified by a config file parameter, so set it NULL here + * and then set it after we collect the parameters in OSSL_provider_init() + */ +OSSL_ALGORITHM stores[] = { + { NULL, "provider=tpm2", store_fns }, + { NULL, NULL, NULL } +}; |