Skip to content

Commit

Permalink
decoder: enable loading tpm2-tools context files
Browse files Browse the repository at this point in the history
  • Loading branch information
gotthardp committed Nov 5, 2023
1 parent 0d5b0d7 commit 579410a
Show file tree
Hide file tree
Showing 7 changed files with 409 additions and 18 deletions.
5 changes: 4 additions & 1 deletion Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ tpm2_la_SOURCES = \
src/tpm2-provider-pkey.h \
src/tpm2-provider-store-handle.c \
src/tpm2-provider-decoder-der.c \
src/tpm2-provider-decoder-tss2.c \
src/tpm2-provider-decoder-tss2key.c \
src/tpm2-provider-decoder-ctx.c \
src/tpm2-provider-decoder-ctx2key.c \
src/tpm2-provider-encoder.c \
src/tpm2-provider-keymgmt-rsa.c \
src/tpm2-provider-keymgmt-ec.c \
Expand Down Expand Up @@ -73,6 +75,7 @@ TESTS = $(TESTS_SHELL) $(check_PROGRAMS)
TESTS_SHELL = test/list.sh \
test/rand.sh \
test/rsa_genrsa_check.sh \
test/rsa_import_null_sign.sh \
test/rsa_genpkey_sign.sh \
test/rsa_genpkey_sign_rawin.sh \
test/rsa_genpkey_auth_parent.sh \
Expand Down
132 changes: 132 additions & 0 deletions src/tpm2-provider-decoder-ctx.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
/* SPDX-License-Identifier: BSD-3-Clause */

/*
* This implements a decoder for context objects created by the tpm2-tools.
*/

#include <string.h>

#include <openssl/core_dispatch.h>
#include <openssl/core_names.h>
#include <openssl/core_object.h>
#include <openssl/params.h>

#include "tpm2-provider-pkey.h"
#include "tpm2-provider-types.h"

typedef struct tpm2_ctx_decoder_ctx_st TPM2_CTX_DECODER_CTX;

struct tpm2_ctx_decoder_ctx_st {
const OSSL_CORE_HANDLE *core;
OSSL_LIB_CTX *libctx;
ESYS_CONTEXT *esys_ctx;
};

static OSSL_FUNC_decoder_newctx_fn tpm2_ctx_decoder_newctx;
static OSSL_FUNC_decoder_freectx_fn tpm2_ctx_decoder_freectx;
static OSSL_FUNC_decoder_decode_fn tpm2_ctx_decoder_decode;

static void *
tpm2_ctx_decoder_newctx(void *provctx)
{
TPM2_PROVIDER_CTX *cprov = provctx;
TPM2_CTX_DECODER_CTX *cctx = OPENSSL_zalloc(sizeof(TPM2_CTX_DECODER_CTX));

if (cctx == NULL)
return NULL;

cctx->core = cprov->core;
cctx->libctx = cprov->libctx;
cctx->esys_ctx = cprov->esys_ctx;
return cctx;
}

static void
tpm2_ctx_decoder_freectx(void *ctx)
{
TPM2_CTX_DECODER_CTX *cctx = ctx;

OPENSSL_clear_free(cctx, sizeof(TPM2_CTX_DECODER_CTX));
}

/* the file format is defined in tpm2-tools/lib/files.c */
static const uint32_t MAGIC = 0xBADCC0DE;
#define CONTEXT_VERSION 1

#define DEFINE_BIO_READ(size) \
static int \
BIO_read_uint##size(BIO *b, uint##size##_t *val) \
{ \
uint##size##_t v; \
if (BIO_read(b, &v, sizeof(uint##size##_t)) == sizeof(uint##size##_t)) { \
*val = be##size##toh(v); \
return 1; \
} \
return 0; \
}

DEFINE_BIO_READ(16)
DEFINE_BIO_READ(32)
DEFINE_BIO_READ(64)

static int
read_context(BIO *bin, TPMS_CONTEXT *context)
{
uint32_t magic, version;

if (!BIO_read_uint32(bin, &magic) || magic != MAGIC
|| !BIO_read_uint32(bin, &version) || version != CONTEXT_VERSION
|| !BIO_read_uint32(bin, &context->hierarchy)
|| !BIO_read_uint32(bin, &context->savedHandle)
|| !BIO_read_uint64(bin, &context->sequence)
|| !BIO_read_uint16(bin, &context->contextBlob.size)
|| context->contextBlob.size > sizeof(context->contextBlob.buffer)
|| BIO_read(bin, context->contextBlob.buffer, context->contextBlob.size)
!= context->contextBlob.size) {
/* this is not our file */
return 0;
}

DBG("CTX DECODER loaded\n");
return 1;
}

static int
tpm2_ctx_decoder_decode(void *ctx, OSSL_CORE_BIO *cin, int selection,
OSSL_CALLBACK *object_cb, void *object_cbarg,
OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg)
{
TPM2_CTX_DECODER_CTX *cctx = ctx;
BIO *bin;
TPMS_CONTEXT context;
OSSL_PARAM params[3];
int res = 0;

DBG("CTX DECODER DECODE\n");
if ((bin = BIO_new_from_core_bio(cctx->libctx, cin)) == NULL)
return 0;

if (read_context(bin, &context)) {
params[0] = OSSL_PARAM_construct_octet_string(OSSL_OBJECT_PARAM_DATA,
&context, sizeof(TPMS_CONTEXT));
params[1] = OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_STRUCTURE,
"TPMS_CONTEXT", 0);
params[2] = OSSL_PARAM_construct_end();

res = object_cb(params, object_cbarg);
} else {
/* We return "empty handed". This is not an error. */
res = 1;
}

BIO_free(bin);
return res;
}

const OSSL_DISPATCH tpm2_ctx_decoder_functions[] = {
{ OSSL_FUNC_DECODER_NEWCTX, (void (*)(void))tpm2_ctx_decoder_newctx },
{ OSSL_FUNC_DECODER_FREECTX, (void (*)(void))tpm2_ctx_decoder_freectx },
{ OSSL_FUNC_DECODER_DECODE, (void (*)(void))tpm2_ctx_decoder_decode },
{ 0, NULL }
};

220 changes: 220 additions & 0 deletions src/tpm2-provider-decoder-ctx2key.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
/* SPDX-License-Identifier: BSD-3-Clause */

/*
* This implements a decoder for context objects created by the tpm2-tools.
*/

#include <string.h>

#include <openssl/core_dispatch.h>
#include <openssl/core_names.h>
#include <openssl/core_object.h>
#include <openssl/params.h>

#include "tpm2-provider-pkey.h"
#include "tpm2-provider-types.h"

typedef struct tpm2_ctx_decoder_ctx_st TPM2_CTX_DECODER_CTX;

struct tpm2_ctx_decoder_ctx_st {
const OSSL_CORE_HANDLE *core;
OSSL_LIB_CTX *libctx;
ESYS_CONTEXT *esys_ctx;
TPM2_CAPABILITY capability;
TPM2B_DIGEST parentAuth;
};

static OSSL_FUNC_decoder_newctx_fn tpm2_ctx_decoder_newctx;
static OSSL_FUNC_decoder_freectx_fn tpm2_ctx_decoder_freectx;
static OSSL_FUNC_decoder_decode_fn tpm2_ctx_decoder_decode_rsa;
static OSSL_FUNC_decoder_decode_fn tpm2_ctx_decoder_decode_ec;
static OSSL_FUNC_decoder_export_object_fn tpm2_ctx_decoder_export_object;

static void *
tpm2_ctx_decoder_newctx(void *provctx)
{
TPM2_PROVIDER_CTX *cprov = provctx;
TPM2_CTX_DECODER_CTX *cctx = OPENSSL_zalloc(sizeof(TPM2_CTX_DECODER_CTX));

if (cctx == NULL)
return NULL;

cctx->core = cprov->core;
cctx->libctx = cprov->libctx;
cctx->esys_ctx = cprov->esys_ctx;
cctx->capability = cprov->capability;
return cctx;
}

static void
tpm2_ctx_decoder_freectx(void *ctx)
{
TPM2_CTX_DECODER_CTX *cctx = ctx;

OPENSSL_clear_free(cctx, sizeof(TPM2_CTX_DECODER_CTX));
}

static const char *
decode_privkey(TPM2_CTX_DECODER_CTX *cctx, TPM2_PKEY *pkey,
BIO *bin, OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg)
{
TPMS_CONTEXT context;
TPM2B_PUBLIC *out_public = NULL;
TPM2B_DIGEST userauth;
size_t plen = 0;
const char *keytype;
TSS2_RC r = 0;

if (BIO_read(bin, &context, sizeof(context)) != sizeof(context))
return NULL;

r = Esys_ContextLoad(cctx->esys_ctx, &context, &pkey->object);
TPM2_CHECK_RC(cctx->core, r, TPM2_ERR_CANNOT_LOAD_KEY, goto error1);

r = Esys_ReadPublic(cctx->esys_ctx, pkey->object,
ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE,
&out_public, NULL, NULL);
TPM2_CHECK_RC(cctx->core, r, TPM2_ERR_CANNOT_LOAD_KEY, goto error2);

pkey->data.pub = *out_public;
pkey->data.privatetype = KEY_TYPE_HANDLE;

r = Esys_TR_GetTpmHandle(cctx->esys_ctx, pkey->object, &pkey->data.handle);
free(out_public);
TPM2_CHECK_RC(cctx->core, r, TPM2_ERR_CANNOT_LOAD_KEY, goto error2);

/* request password; this might open an interactive user prompt */
if (!pw_cb((char *)userauth.buffer, sizeof(TPMU_HA), &plen, NULL, pw_cbarg)) {
TPM2_ERROR_raise(cctx->core, TPM2_ERR_AUTHORIZATION_FAILURE);
goto error2;
}
userauth.size = plen;

r = Esys_TR_SetAuth(cctx->esys_ctx, pkey->object, &userauth);
TPM2_CHECK_RC(cctx->core, r, TPM2_ERR_CANNOT_LOAD_KEY, goto error2);

if ((keytype = tpm2_openssl_type(&pkey->data)) == NULL) {
TPM2_ERROR_raise(cctx->core, TPM2_ERR_UNKNOWN_ALGORITHM);
goto error2;
}

return keytype;
error2:
if (pkey->object != ESYS_TR_NONE)
Esys_FlushContext(pkey->esys_ctx, pkey->object);
error1:
return NULL;
}

static int
tpm2_ctx_decoder_decode(void *ctx, OSSL_CORE_BIO *cin, int selection,
int expected_type,
OSSL_CALLBACK *object_cb, void *object_cbarg,
OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg)
{
TPM2_CTX_DECODER_CTX *cctx = ctx;
TPM2_PKEY *pkey;
BIO *bin;
const char *keytype = NULL;
OSSL_PARAM params[4];
int object_type;
int res = 0;

DBG("CTX-KEY DECODER DECODE 0x%x\n", selection);
if ((pkey = OPENSSL_zalloc(sizeof(TPM2_PKEY))) == NULL)
return 0;

if ((bin = BIO_new_from_core_bio(cctx->libctx, cin)) == NULL)
goto error1;

pkey->core = cctx->core;
pkey->esys_ctx = cctx->esys_ctx;
pkey->capability = cctx->capability;
pkey->object = ESYS_TR_NONE;

if (selection == 0 || (selection & OSSL_KEYMGMT_SELECT_ALL) != 0)
keytype = decode_privkey(cctx, pkey, bin, pw_cb, pw_cbarg);

if (pkey->data.pub.publicArea.type == expected_type) {
object_type = OSSL_OBJECT_PKEY;
params[0] = OSSL_PARAM_construct_int(OSSL_OBJECT_PARAM_TYPE, &object_type);

DBG("CTX-KEY DECODER DECODE found %s\n", keytype);
params[1] = OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_TYPE,
(char *)keytype, 0);
/* The address of the key becomes the octet string */
params[2] = OSSL_PARAM_construct_octet_string(OSSL_OBJECT_PARAM_REFERENCE,
&pkey, sizeof(pkey));
params[3] = OSSL_PARAM_construct_end();

if (object_cb(params, object_cbarg)) {
BIO_free(bin);
return 1;
}
} else {
/* We return "empty handed". This is not an error. */
res = 1;
}

BIO_free(bin);
error1:
OPENSSL_clear_free(pkey, sizeof(TPM2_PKEY));
return res;
}

static int
tpm2_ctx_decoder_decode_rsa(void *ctx, OSSL_CORE_BIO *cin, int selection,
OSSL_CALLBACK *object_cb, void *object_cbarg,
OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg)
{
return tpm2_ctx_decoder_decode(ctx, cin, selection, TPM2_ALG_RSA,
object_cb, object_cbarg, pw_cb, pw_cbarg);
}

static int
tpm2_ctx_decoder_decode_ec(void *ctx, OSSL_CORE_BIO *cin, int selection,
OSSL_CALLBACK *object_cb, void *object_cbarg,
OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg)
{
return tpm2_ctx_decoder_decode(ctx, cin, selection, TPM2_ALG_ECC,
object_cb, object_cbarg, pw_cb, pw_cbarg);
}

static int
tpm2_ctx_decoder_export_object(void *ctx, const void *objref, size_t objref_sz,
OSSL_CALLBACK *export_cb, void *export_cbarg)
{
TPM2_PKEY *keydata;

DBG("CTX-KEY DECODER EXPORT_OBJECT\n");
if (objref_sz == sizeof(keydata)) {
/* The contents of the reference is the address to our object */
keydata = *(TPM2_PKEY **)objref;

if (keydata->data.pub.publicArea.type == TPM2_ALG_RSA)
return tpm2_rsa_keymgmt_export(keydata, OSSL_KEYMGMT_SELECT_ALL,
export_cb, export_cbarg);
else if (keydata->data.pub.publicArea.type == TPM2_ALG_ECC)
return tpm2_ec_keymgmt_export(keydata, OSSL_KEYMGMT_SELECT_ALL,
export_cb, export_cbarg);
}

return 0;
}

const OSSL_DISPATCH tpm2_ctx_to_rsa_decoder_functions[] = {
{ OSSL_FUNC_DECODER_NEWCTX, (void (*)(void))tpm2_ctx_decoder_newctx },
{ OSSL_FUNC_DECODER_FREECTX, (void (*)(void))tpm2_ctx_decoder_freectx },
{ OSSL_FUNC_DECODER_DECODE, (void (*)(void))tpm2_ctx_decoder_decode_rsa },
{ OSSL_FUNC_DECODER_EXPORT_OBJECT, (void (*)(void))tpm2_ctx_decoder_export_object },
{ 0, NULL }
};

const OSSL_DISPATCH tpm2_ctx_to_ec_decoder_functions[] = {
{ OSSL_FUNC_DECODER_NEWCTX, (void (*)(void))tpm2_ctx_decoder_newctx },
{ OSSL_FUNC_DECODER_FREECTX, (void (*)(void))tpm2_ctx_decoder_freectx },
{ OSSL_FUNC_DECODER_DECODE, (void (*)(void))tpm2_ctx_decoder_decode_ec },
{ OSSL_FUNC_DECODER_EXPORT_OBJECT, (void (*)(void))tpm2_ctx_decoder_export_object },
{ 0, NULL }
};

Loading

0 comments on commit 579410a

Please sign in to comment.