aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Bottomley <James.Bottomley@HansenPartnership.com>2023-03-16 13:47:15 -0400
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2023-03-22 22:59:44 -0400
commit184d8dda5c317536ab40ec90b008849c23c67246 (patch)
tree5b0563b586e0841fb1c4e76b5c97a88bfb4f7460
parent5fe4ac30a30bc8fa1693dbbf4ca6a3ab2b57bff6 (diff)
downloadopenssl_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.am2
-rw-r--r--src/provider/keymgmt.c2
-rw-r--r--src/provider/provider.c11
-rw-r--r--src/provider/provider.h5
-rw-r--r--src/provider/store.c184
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 }
+};