diff options
author | James Bottomley <James.Bottomley@HansenPartnership.com> | 2023-03-06 16:17:55 -0500 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2023-03-22 22:59:44 -0400 |
commit | 5fe4ac30a30bc8fa1693dbbf4ca6a3ab2b57bff6 (patch) | |
tree | b6874800c258b897937258637e7170bc19970fdd | |
parent | f6fae5fb6b3cba927e8cf49ad9d1f2d9a2a801da (diff) | |
download | openssl_tpm2_engine-5fe4ac30a30bc8fa1693dbbf4ca6a3ab2b57bff6.tar.gz |
provider: add decryption functions
These take different forms: RSA is a simple RSA padded decryption but
for EC it's an ECDH key derivation.
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
-rw-r--r-- | src/provider/Makefile.am | 2 | ||||
-rw-r--r-- | src/provider/decode_encode.c | 2 | ||||
-rw-r--r-- | src/provider/decryption.c | 172 | ||||
-rw-r--r-- | src/provider/keymgmt.c | 103 | ||||
-rw-r--r-- | src/provider/provider.c | 2 | ||||
-rw-r--r-- | src/provider/provider.h | 8 |
6 files changed, 282 insertions, 7 deletions
diff --git a/src/provider/Makefile.am b/src/provider/Makefile.am index 7f36726..fc17fef 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 +libtpm2_la_SOURCES=provider.c decode_encode.c keymgmt.c signatures.c decryption.c libtpm2_la_CFLAGS=${DEPS_CFLAGS} -g -Werror install-data-hook: diff --git a/src/provider/decode_encode.c b/src/provider/decode_encode.c index cbd6c7a..8b55dd9 100644 --- a/src/provider/decode_encode.c +++ b/src/provider/decode_encode.c @@ -48,7 +48,7 @@ static int tpm2_pkey_decode(void *ctx, OSSL_CORE_BIO *cin, int selection, OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg, TPM_ALG_ID alg) { - struct app_data *ad = OPENSSL_zalloc(sizeof(*ad)); + struct app_data *ad = tpm2_keymgmt_new(ctx); OSSL_LIB_CTX *libctx = ctx; BIO *in = BIO_new_from_core_bio(libctx, cin); diff --git a/src/provider/decryption.c b/src/provider/decryption.c new file mode 100644 index 0000000..47c7667 --- /dev/null +++ b/src/provider/decryption.c @@ -0,0 +1,172 @@ +/* Copyright (C) 2023 James Bottomley <James.Bottomley@HansenPartnership.com> + * + * SPDX-License-Identifier: LGPL-2.1-only + */ + +/* note: we need a reference in struct app_dir which uses gcc atomics */ +#include <stdatomic.h> + +#include "provider.h" +#include "opensslmissing.h" + +struct decryption_ctx { + struct app_data *ad; + struct app_data *peer_ad; + struct osslm_dec_ctx dctx; +}; + +static void *tpm2_decryption_newctx(void *pctx) +{ + struct decryption_ctx *ctx = OPENSSL_zalloc(sizeof(*ctx)); + OSSL_LIB_CTX *libctx = pctx; + + if (!ctx) + return NULL; + + ctx->dctx.libctx = libctx; + + return ctx; +} + +static void tpm2_decryption_freectx(void *ctx) +{ + struct decryption_ctx *dctx = ctx; + + osslm_decryption_freectx(&dctx->dctx); + OPENSSL_free(dctx); +} + +static int tpm2_decryption_init(void *ctx, void *key, const OSSL_PARAM params[]) +{ + struct decryption_ctx *dctx = ctx; + + dctx->ad = key; + + return 1; +} + +static int tpm2_decryption(void *ctx, unsigned char *out, size_t *outlen, + size_t outsize, const unsigned char *in, + size_t inlen) +{ + struct decryption_ctx *dctx = ctx; + PUBLIC_KEY_RSA_2B cipherText, outText; + int padding = dctx->dctx.padding; + int ret; + unsigned char *result; + + if (out == NULL) { + int size; + + if (!tpm2_get_sizes(dctx->ad, NULL, NULL, &size)) + return 0; + + *outlen = size; + return 1; + } + + cipherText.size = inlen; + memcpy(cipherText.buffer, in, inlen); + + if (padding == 0) + padding = RSA_PKCS1_PADDING; + + if (padding != RSA_PKCS1_PADDING) { + padding = RSA_NO_PADDING; + result = outText.buffer; + } else { + result = out; + } + + ret = tpm2_rsa_decrypt(dctx->ad, &cipherText, result, + padding, TPMA_SESSION_ENCRYPT, + srk_auth); + if (ret < 0) + return 0; + + if (dctx->dctx.padding == RSA_PKCS1_OAEP_PADDING) { + *outlen = outsize; + osslm_rsa_unpad_oaep(&dctx->dctx, out, outlen, result, ret); + } else { + *outlen = ret; + } + + return 1; +} + +static int tpm2_decryption_set_params(void *ctx, const OSSL_PARAM params[]) +{ + struct decryption_ctx *dctx = ctx; + + return osslm_decryption_set_params(&dctx->dctx, params); +} + + +static int +tpm2_keyexch_init(void *ctx, void *key, const OSSL_PARAM params[]) +{ + struct decryption_ctx *dctx = ctx; + + dctx->ad = key; + + return 1; +} + +static int +tpm2_keyexch_set_peer(void *ctx, void *peerkey) +{ + struct decryption_ctx *dctx = ctx; + + dctx->peer_ad = peerkey; + + return 1; +} + +static int +tpm2_keyexch_derive(void *ctx, unsigned char *secret, size_t *secretlen, + size_t outlen) +{ + struct decryption_ctx *dctx = ctx; + TPM2B_ECC_POINT inPoint; + + inPoint.point = dctx->peer_ad->Public.publicArea.unique.ecc; + *secretlen = VAL_2B(inPoint.point.x, size); + if (!secret) + return 1; + + return tpm2_ecdh_x(dctx->ad, &secret, secretlen, &inPoint, NULL); +} + + +/* + * Two different names: RSA does asymmetric cipher (encrypts private key) + * EC does key derivation called key exchange. + */ +static const OSSL_DISPATCH asymcipher_fns[] = { + { OSSL_FUNC_ASYM_CIPHER_NEWCTX, (void (*)(void))tpm2_decryption_newctx }, + { OSSL_FUNC_ASYM_CIPHER_FREECTX, (void (*)(void))tpm2_decryption_freectx }, + { OSSL_FUNC_ASYM_CIPHER_DECRYPT_INIT, (void (*)(void))tpm2_decryption_init }, + { OSSL_FUNC_ASYM_CIPHER_DECRYPT, (void (*)(void))tpm2_decryption }, + { OSSL_FUNC_ASYM_CIPHER_SET_CTX_PARAMS, (void (*)(void))tpm2_decryption_set_params, }, + { OSSL_FUNC_ASYM_CIPHER_SETTABLE_CTX_PARAMS, (void (*)(void))osslm_decryption_settable_params }, + { 0, NULL } +}; + +static const OSSL_DISPATCH keyexch_fns[] = { + { OSSL_FUNC_KEYEXCH_NEWCTX, (void(*)(void))tpm2_decryption_newctx }, + { OSSL_FUNC_KEYEXCH_FREECTX, (void(*)(void))tpm2_decryption_freectx }, + { OSSL_FUNC_KEYEXCH_INIT, (void(*)(void))tpm2_keyexch_init }, + { OSSL_FUNC_KEYEXCH_SET_PEER, (void(*)(void))tpm2_keyexch_set_peer }, + { OSSL_FUNC_KEYEXCH_DERIVE, (void(*)(void))tpm2_keyexch_derive }, + { 0, NULL } +}; + +const OSSL_ALGORITHM asymciphers[] = { + { "RSA", "provider=tpm2", asymcipher_fns }, + { NULL, NULL, NULL } +}; + +const OSSL_ALGORITHM keyexchs[] = { + { "EC", "provider=tpm2", keyexch_fns }, + { NULL, NULL, NULL } +}; diff --git a/src/provider/keymgmt.c b/src/provider/keymgmt.c index d11172c..6b79660 100644 --- a/src/provider/keymgmt.c +++ b/src/provider/keymgmt.c @@ -17,8 +17,6 @@ static void *tpm2_keymgmt_load(void *ref, size_t ref_size) ad = *actual_ref; *actual_ref = NULL; - atomic_fetch_add_explicit(&ad->refs, 1, memory_order_relaxed); - return ad; } @@ -138,7 +136,100 @@ static const OSSL_PARAM *tpm2_keymgmt_export_types(int selection) return NULL; } -static const OSSL_DISPATCH keymgmt_fns[] = { +static const OSSL_DISPATCH rsa_keymgmt_fns[] = { + { OSSL_FUNC_KEYMGMT_LOAD, (void (*)(void))tpm2_keymgmt_load }, + { OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))tpm2_keymgmt_free }, + { OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))tpm2_keymgmt_has }, + { OSSL_FUNC_KEYMGMT_GET_PARAMS, (void (*)(void))tpm2_keymgmt_get_params }, + { OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (void (*)(void))tpm2_keymgmt_gettable_params }, + /* both MUST be provided (enforced) although no-one knows why + * since openssl never uses export_types */ + { OSSL_FUNC_KEYMGMT_EXPORT, (void (*)(void))tpm2_keymgmt_export }, + { OSSL_FUNC_KEYMGMT_EXPORT_TYPES, (void (*)(void))tpm2_keymgmt_export_types }, + { 0, NULL} +}; + +/* + * the remaining two functions are for EC key derivation only. + * OpenSSL will only derive a key if both keys belong to the provider. + * So even though all we need to know is the public point, we have to + * be able to import an external EC public key to our internal + * format + */ +void *tpm2_keymgmt_new(void *pctx) +{ + struct app_data *ad = OPENSSL_zalloc(sizeof(*ad)); + + if (!ad) + return 0; + + ad->refs = 1; + + return ad; +} + +static int tpm2_keymgmt_import(void *key, int selection, + const OSSL_PARAM params[]) +{ + const OSSL_PARAM *p; + struct app_data *ad = key; + EC_GROUP *g = NULL; + EC_POINT *pt; + BIGNUM *x, *y; + TPMS_ECC_POINT *tpt = &ad->Public.publicArea.unique.ecc; + int order; + int ret = 1; + + if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) == 0) + return 1; + + p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_GROUP_NAME); + if (p != NULL) { + TPMI_ECC_CURVE curve = tpm2_curve_name_to_TPMI(p->data); + if (curve == TPM_ECC_NONE) + return 0; + tpm2_public_template_ecc(&ad->Public.publicArea, curve); + g = EC_GROUP_new_by_curve_name(tpm2_curve_name_to_nid(curve)); + order = tpm2_curve_to_order(curve); + } + + p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PUB_KEY); + if (p == NULL) + goto out_free_group; + + ret = 0; + if (p->data_type != OSSL_PARAM_OCTET_STRING || g == NULL) + goto out_free_group; + + pt = EC_POINT_new(g); + if (!pt) + goto out_free_group; + if (!EC_POINT_oct2point(g, pt, p->data, p->data_size, NULL)) + goto out_free_pt; + x = BN_new(); + y = BN_new(); + if (!x || !y || !EC_POINT_get_affine_coordinates(g, pt, x, y, NULL)) + goto out_free; + + VAL_2B(tpt->x, size) = + BN_bn2binpad(x, VAL_2B(tpt->x, buffer), order); + VAL_2B(tpt->y, size) = + BN_bn2binpad(y, VAL_2B(tpt->y, buffer), order); + + ret = 1; + out_free: + BN_free(x); + BN_free(y); + out_free_pt: + EC_POINT_free(pt); + out_free_group: + EC_GROUP_free(g); + + return ret; +} + +static const OSSL_DISPATCH ec_keymgmt_fns[] = { + { OSSL_FUNC_KEYMGMT_NEW, (void(*)(void))tpm2_keymgmt_new }, { OSSL_FUNC_KEYMGMT_LOAD, (void (*)(void))tpm2_keymgmt_load }, { OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))tpm2_keymgmt_free }, { OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))tpm2_keymgmt_has }, @@ -148,11 +239,13 @@ static const OSSL_DISPATCH keymgmt_fns[] = { * since openssl never uses export_types */ { OSSL_FUNC_KEYMGMT_EXPORT, (void (*)(void))tpm2_keymgmt_export }, { OSSL_FUNC_KEYMGMT_EXPORT_TYPES, (void (*)(void))tpm2_keymgmt_export_types }, + { OSSL_FUNC_KEYMGMT_IMPORT, (void(*)(void))tpm2_keymgmt_import }, + { OSSL_FUNC_KEYMGMT_IMPORT_TYPES, (void(*)(void))tpm2_keymgmt_export_types }, { 0, NULL} }; const OSSL_ALGORITHM keymgmts[]= { - { "RSA", "provider=tpm2", keymgmt_fns }, - { "EC", "provider=tpm2", keymgmt_fns }, + { "RSA", "provider=tpm2", rsa_keymgmt_fns }, + { "EC", "provider=tpm2", ec_keymgmt_fns }, { NULL, NULL, NULL} }; diff --git a/src/provider/provider.c b/src/provider/provider.c index 1936ecf..3db944b 100644 --- a/src/provider/provider.c +++ b/src/provider/provider.c @@ -71,6 +71,8 @@ static struct { QOP(OSSL_OP_ENCODER, encoders), QOP(OSSL_OP_KEYMGMT, keymgmts), QOP(OSSL_OP_SIGNATURE, signatures), + QOP(OSSL_OP_ASYM_CIPHER, asymciphers), + QOP(OSSL_OP_KEYEXCH, keyexchs), QOP(OSSL_OP_STORE, NULL), }; diff --git a/src/provider/provider.h b/src/provider/provider.h index f265b4e..bb44f9b 100644 --- a/src/provider/provider.h +++ b/src/provider/provider.h @@ -31,8 +31,16 @@ extern const OSSL_ALGORITHM decoders[]; extern const OSSL_ALGORITHM keymgmts[]; +void *tpm2_keymgmt_new(void *pctx); /* needed by decode_encode.c */ + /* signatures.c */ extern const OSSL_ALGORITHM signatures[]; +/* decryption.c */ + +extern const OSSL_ALGORITHM asymciphers[]; +extern const OSSL_ALGORITHM keyexchs[]; + + #endif |