aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Bottomley <James.Bottomley@HansenPartnership.com>2023-03-06 16:17:55 -0500
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2023-03-22 22:59:44 -0400
commit5fe4ac30a30bc8fa1693dbbf4ca6a3ab2b57bff6 (patch)
treeb6874800c258b897937258637e7170bc19970fdd
parentf6fae5fb6b3cba927e8cf49ad9d1f2d9a2a801da (diff)
downloadopenssl_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.am2
-rw-r--r--src/provider/decode_encode.c2
-rw-r--r--src/provider/decryption.c172
-rw-r--r--src/provider/keymgmt.c103
-rw-r--r--src/provider/provider.c2
-rw-r--r--src/provider/provider.h8
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