From 8b84b075ff065554c0cdd1086950f1a8614d93a4 Mon Sep 17 00:00:00 2001 From: Richard Levitte Date: Sun, 7 Jul 2019 10:56:46 +0200 Subject: Adapt DH to use with KEYMGMT The biggest part in this was to move the key->param builder from EVP to the DH ASN.1 method, and to implement the KEYMGMT support in the provider DH. Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/9394) --- providers/common/build.info | 2 +- providers/common/exchange/build.info | 2 +- providers/common/exchange/dh.c | 194 ---------------------- providers/common/exchange/dh_exch.c | 152 +++++++++++++++++ providers/common/include/internal/provider_algs.h | 5 +- providers/common/keymgmt/build.info | 5 + providers/common/keymgmt/dh_kmgmt.c | 88 ++++++++++ providers/default/defltprov.c | 11 +- 8 files changed, 261 insertions(+), 198 deletions(-) delete mode 100644 providers/common/exchange/dh.c create mode 100644 providers/common/exchange/dh_exch.c create mode 100644 providers/common/keymgmt/build.info create mode 100644 providers/common/keymgmt/dh_kmgmt.c (limited to 'providers') diff --git a/providers/common/build.info b/providers/common/build.info index c77606a..bc106d0 100644 --- a/providers/common/build.info +++ b/providers/common/build.info @@ -1,4 +1,4 @@ -SUBDIRS=digests ciphers exchange +SUBDIRS=digests ciphers exchange keymgmt SOURCE[../../libcrypto]=\ provider_err.c provlib.c diff --git a/providers/common/exchange/build.info b/providers/common/exchange/build.info index 7957f51..c99c9d8 100644 --- a/providers/common/exchange/build.info +++ b/providers/common/exchange/build.info @@ -1,7 +1,7 @@ LIBS=../../../libcrypto IF[{- !$disabled{dh} -}] SOURCE[../../../libcrypto]=\ - dh.c + dh_exch.c ENDIF diff --git a/providers/common/exchange/dh.c b/providers/common/exchange/dh.c deleted file mode 100644 index ca6f0fc..0000000 --- a/providers/common/exchange/dh.c +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved. - * - * Licensed under the Apache License 2.0 (the "License"). You may not use - * this file except in compliance with the License. You can obtain a copy - * in the file LICENSE in the source distribution or at - * https://www.openssl.org/source/license.html - */ - -#include -#include -#include -#include -#include -#include "internal/provider_algs.h" - -static OSSL_OP_keyexch_newctx_fn dh_newctx; -static OSSL_OP_keyexch_init_fn dh_init; -static OSSL_OP_keyexch_set_peer_fn dh_set_peer; -static OSSL_OP_keyexch_derive_fn dh_derive; -static OSSL_OP_keyexch_freectx_fn dh_freectx; -static OSSL_OP_keyexch_dupctx_fn dh_dupctx; - - -typedef struct { - DH *dh; - DH *dhpeer; - int pad; -} PROV_DH_CTX; - -static void *dh_newctx(void *provctx) -{ - return OPENSSL_zalloc(sizeof(PROV_DH_CTX)); -} - -static DH *param_to_dh(OSSL_PARAM params[], int priv) -{ - DH *dh = DH_new(); - OSSL_PARAM *paramptr; - BIGNUM *p = NULL, *g = NULL, *pub_key = NULL, *priv_key = NULL; - - if (dh == NULL) - return NULL; - - paramptr = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_DH_P); - if (paramptr == NULL - || !OSSL_PARAM_get_BN(paramptr, &p)) - goto err; - - paramptr = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_DH_G); - if (paramptr == NULL || !OSSL_PARAM_get_BN(paramptr, &g)) - goto err; - - if (!DH_set0_pqg(dh, p, NULL, g)) - goto err; - p = g = NULL; - - paramptr = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_DH_PUB_KEY); - if (paramptr == NULL || !OSSL_PARAM_get_BN(paramptr, &pub_key)) - goto err; - - /* Private key is optional */ - if (priv) { - paramptr = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_DH_PRIV_KEY); - if (paramptr == NULL - || (priv_key = BN_secure_new()) == NULL - || !OSSL_PARAM_get_BN(paramptr, &priv_key)) - goto err; - } - - if (!DH_set0_key(dh, pub_key, priv_key)) - goto err; - - return dh; - - err: - BN_free(p); - BN_free(g); - BN_free(pub_key); - BN_free(priv_key); - DH_free(dh); - return NULL; -} - -static int dh_init(void *vpdhctx, OSSL_PARAM params[]) -{ - PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx; - - DH_free(pdhctx->dh); - pdhctx->dh = param_to_dh(params, 1); - - return pdhctx->dh != NULL; -} - -static int dh_set_peer(void *vpdhctx, OSSL_PARAM params[]) -{ - PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx; - - DH_free(pdhctx->dhpeer); - pdhctx->dhpeer = param_to_dh(params, 0); - - return pdhctx->dhpeer != NULL; -} - -static int dh_derive(void *vpdhctx, unsigned char *key, size_t *keylen, - size_t outlen) -{ - PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx; - int ret; - size_t dhsize; - const BIGNUM *pub_key = NULL; - - /* TODO(3.0): Add errors to stack */ - if (pdhctx->dh == NULL || pdhctx->dhpeer == NULL) - return 0; - - dhsize = (size_t)DH_size(pdhctx->dh); - if (key == NULL) { - *keylen = dhsize; - return 1; - } - if (outlen < dhsize) - return 0; - - DH_get0_key(pdhctx->dhpeer, &pub_key, NULL); - ret = (pdhctx->pad) ? DH_compute_key_padded(key, pub_key, pdhctx->dh) - : DH_compute_key(key, pub_key, pdhctx->dh); - if (ret <= 0) - return 0; - - *keylen = ret; - return 1; -} - -static void dh_freectx(void *vpdhctx) -{ - PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx; - - DH_free(pdhctx->dh); - DH_free(pdhctx->dhpeer); - - OPENSSL_free(pdhctx); -} - -static void *dh_dupctx(void *vpdhctx) -{ - PROV_DH_CTX *srcctx = (PROV_DH_CTX *)vpdhctx; - PROV_DH_CTX *dstctx; - - dstctx = OPENSSL_zalloc(sizeof(*srcctx)); - - *dstctx = *srcctx; - if (dstctx->dh != NULL && !DH_up_ref(dstctx->dh)) { - OPENSSL_free(dstctx); - return NULL; - } - - if (dstctx->dhpeer != NULL && !DH_up_ref(dstctx->dhpeer)) { - DH_free(dstctx->dh); - OPENSSL_free(dstctx); - return NULL; - } - - return dstctx; -} - -static int dh_set_params(void *vpdhctx, OSSL_PARAM params[]) -{ - PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx; - const OSSL_PARAM *p; - int pad; - - if (pdhctx == NULL || params == NULL) - return 0; - - p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_PAD); - if (p == NULL || !OSSL_PARAM_get_int(p, &pad)) - return 0; - - pdhctx->pad = pad; - - return 1; -} - -const OSSL_DISPATCH dh_functions[] = { - { OSSL_FUNC_KEYEXCH_NEWCTX, (void (*)(void))dh_newctx }, - { OSSL_FUNC_KEYEXCH_INIT, (void (*)(void))dh_init }, - { OSSL_FUNC_KEYEXCH_DERIVE, (void (*)(void))dh_derive }, - { OSSL_FUNC_KEYEXCH_SET_PEER, (void (*)(void))dh_set_peer }, - { OSSL_FUNC_KEYEXCH_FREECTX, (void (*)(void))dh_freectx }, - { OSSL_FUNC_KEYEXCH_DUPCTX, (void (*)(void))dh_dupctx }, - { OSSL_FUNC_KEYEXCH_SET_PARAMS, (void (*)(void))dh_set_params }, - { 0, NULL } -}; diff --git a/providers/common/exchange/dh_exch.c b/providers/common/exchange/dh_exch.c new file mode 100644 index 0000000..439b28a --- /dev/null +++ b/providers/common/exchange/dh_exch.c @@ -0,0 +1,152 @@ +/* + * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include +#include +#include +#include +#include +#include "internal/provider_algs.h" + +static OSSL_OP_keyexch_newctx_fn dh_newctx; +static OSSL_OP_keyexch_init_fn dh_init; +static OSSL_OP_keyexch_set_peer_fn dh_set_peer; +static OSSL_OP_keyexch_derive_fn dh_derive; +static OSSL_OP_keyexch_freectx_fn dh_freectx; +static OSSL_OP_keyexch_dupctx_fn dh_dupctx; + +/* + * What's passed as an actual key is defined by the KEYMGMT interface. + * We happen to know that our KEYMGMT simply passes DH structures, so + * we use that here too. + */ + +typedef struct { + DH *dh; + DH *dhpeer; + int pad; +} PROV_DH_CTX; + +static void *dh_newctx(void *provctx) +{ + return OPENSSL_zalloc(sizeof(PROV_DH_CTX)); +} + +static int dh_init(void *vpdhctx, void *vdh) +{ + PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx; + + DH_free(pdhctx->dh); + pdhctx->dh = vdh; + DH_up_ref(pdhctx->dh); + + return pdhctx->dh != NULL; +} + +static int dh_set_peer(void *vpdhctx, void *vdh) +{ + PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx; + + DH_free(pdhctx->dhpeer); + pdhctx->dhpeer = vdh; + DH_up_ref(pdhctx->dhpeer); + + return pdhctx->dhpeer != NULL; +} + +static int dh_derive(void *vpdhctx, unsigned char *key, size_t *keylen, + size_t outlen) +{ + PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx; + int ret; + size_t dhsize; + const BIGNUM *pub_key = NULL; + + /* TODO(3.0): Add errors to stack */ + if (pdhctx->dh == NULL || pdhctx->dhpeer == NULL) + return 0; + + dhsize = (size_t)DH_size(pdhctx->dh); + if (key == NULL) { + *keylen = dhsize; + return 1; + } + if (outlen < dhsize) + return 0; + + DH_get0_key(pdhctx->dhpeer, &pub_key, NULL); + ret = (pdhctx->pad) ? DH_compute_key_padded(key, pub_key, pdhctx->dh) + : DH_compute_key(key, pub_key, pdhctx->dh); + if (ret <= 0) + return 0; + + *keylen = ret; + return 1; +} + +static void dh_freectx(void *vpdhctx) +{ + PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx; + + DH_free(pdhctx->dh); + DH_free(pdhctx->dhpeer); + + OPENSSL_free(pdhctx); +} + +static void *dh_dupctx(void *vpdhctx) +{ + PROV_DH_CTX *srcctx = (PROV_DH_CTX *)vpdhctx; + PROV_DH_CTX *dstctx; + + dstctx = OPENSSL_zalloc(sizeof(*srcctx)); + + *dstctx = *srcctx; + if (dstctx->dh != NULL && !DH_up_ref(dstctx->dh)) { + OPENSSL_free(dstctx); + return NULL; + } + + if (dstctx->dhpeer != NULL && !DH_up_ref(dstctx->dhpeer)) { + DH_free(dstctx->dh); + OPENSSL_free(dstctx); + return NULL; + } + + return dstctx; +} + +static int dh_set_params(void *vpdhctx, const OSSL_PARAM params[]) +{ + PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx; + const OSSL_PARAM *p; + int pad; + + if (pdhctx == NULL || params == NULL) + return 0; + + p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_PAD); + if (p == NULL || !OSSL_PARAM_get_int(p, &pad)) + return 0; + + pdhctx->pad = pad; + + return 1; +} + +const OSSL_DISPATCH dh_keyexch_functions[] = { + { OSSL_FUNC_KEYEXCH_NEWCTX, (void (*)(void))dh_newctx }, + { OSSL_FUNC_KEYEXCH_INIT, (void (*)(void))dh_init }, + { OSSL_FUNC_KEYEXCH_DERIVE, (void (*)(void))dh_derive }, + { OSSL_FUNC_KEYEXCH_SET_PEER, (void (*)(void))dh_set_peer }, + { OSSL_FUNC_KEYEXCH_FREECTX, (void (*)(void))dh_freectx }, + { OSSL_FUNC_KEYEXCH_DUPCTX, (void (*)(void))dh_dupctx }, + { OSSL_FUNC_KEYEXCH_SET_PARAMS, (void (*)(void))dh_set_params }, + { 0, NULL } +}; diff --git a/providers/common/include/internal/provider_algs.h b/providers/common/include/internal/provider_algs.h index dbc79a5..80946ca 100644 --- a/providers/common/include/internal/provider_algs.h +++ b/providers/common/include/internal/provider_algs.h @@ -58,5 +58,8 @@ extern const OSSL_DISPATCH aes256ctr_functions[]; extern const OSSL_DISPATCH aes192ctr_functions[]; extern const OSSL_DISPATCH aes128ctr_functions[]; +/* Key management */ +extern const OSSL_DISPATCH dh_keymgmt_functions[]; + /* Key Exchange */ -extern const OSSL_DISPATCH dh_functions[]; +extern const OSSL_DISPATCH dh_keyexch_functions[]; diff --git a/providers/common/keymgmt/build.info b/providers/common/keymgmt/build.info new file mode 100644 index 0000000..a41f3da --- /dev/null +++ b/providers/common/keymgmt/build.info @@ -0,0 +1,5 @@ +LIBS=../../../libcrypto +IF[{- !$disabled{dh} -}] + SOURCE[../../../libcrypto]=\ + dh_kmgmt.c +ENDIF diff --git a/providers/common/keymgmt/dh_kmgmt.c b/providers/common/keymgmt/dh_kmgmt.c new file mode 100644 index 0000000..67e3205 --- /dev/null +++ b/providers/common/keymgmt/dh_kmgmt.c @@ -0,0 +1,88 @@ +/* + * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include +#include +#include +#include +#include +#include "internal/provider_algs.h" + +static OSSL_OP_keymgmt_importkey_fn dh_importkey; + +static int params_to_key(DH *dh, const OSSL_PARAM params[]) +{ + const OSSL_PARAM *param_p, *param_g, *param_priv_key, *param_pub_key; + BIGNUM *p = NULL, *g = NULL, *priv_key = NULL, *pub_key = NULL; + + if (dh == NULL) + return 0; + + param_p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_DH_P); + param_g = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_DH_G); + param_priv_key = + OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_DH_PRIV_KEY); + param_pub_key = + OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_DH_PUB_KEY); + + /* + * DH documentation says that a public key must be present if a + * private key is present. + * We want to have at least a public key either way, so we end up + * requiring it unconditionally. + */ + if (param_pub_key == NULL) + return 0; + + if ((param_p != NULL && !OSSL_PARAM_get_BN(param_p, &p)) + || (param_g != NULL && !OSSL_PARAM_get_BN(param_g, &g)) + || (param_priv_key != NULL + && !OSSL_PARAM_get_BN(param_priv_key, &priv_key)) + || !OSSL_PARAM_get_BN(param_pub_key, &pub_key)) + goto err; + + if (!DH_set0_pqg(dh, p, NULL, g)) + goto err; + p = g = NULL; + + if (!DH_set0_key(dh, pub_key, priv_key)) + goto err; + priv_key = pub_key = NULL; + + return 1; + + err: + BN_free(p); + BN_free(g); + BN_free(priv_key); + BN_free(pub_key); + return 0; +} + +static void *dh_importkey(void *provctx, const OSSL_PARAM params[]) +{ + DH *dh; + + if ((dh = DH_new()) == NULL + || !params_to_key(dh, params)) { + DH_free(dh); + dh = NULL; + } + return dh; +} + +const OSSL_DISPATCH dh_keymgmt_functions[] = { + /* + * TODO(3.0) When implementing OSSL_FUNC_KEYMGMT_GENKEY, remember to also + * implement OSSL_FUNC_KEYMGMT_EXPORTKEY. + */ + { OSSL_FUNC_KEYMGMT_IMPORTKEY, (void (*)(void))dh_importkey }, + { OSSL_FUNC_KEYMGMT_FREEKEY, (void (*)(void))DH_free }, + { 0, NULL } +}; diff --git a/providers/default/defltprov.c b/providers/default/defltprov.c index 2c25bf7..95534b1 100644 --- a/providers/default/defltprov.c +++ b/providers/default/defltprov.c @@ -116,7 +116,14 @@ static const OSSL_ALGORITHM deflt_ciphers[] = { static const OSSL_ALGORITHM deflt_keyexch[] = { #ifndef OPENSSL_NO_DH - { "dhKeyAgreement", "default=yes", dh_functions }, + { "dhKeyAgreement", "default=yes", dh_keyexch_functions }, +#endif + { NULL, NULL, NULL } +}; + +static const OSSL_ALGORITHM deflt_keymgmt[] = { +#ifndef OPENSSL_NO_DH + { "dhKeyAgreement", "default=yes", dh_keymgmt_functions }, #endif { NULL, NULL, NULL } }; @@ -131,6 +138,8 @@ static const OSSL_ALGORITHM *deflt_query(OSSL_PROVIDER *prov, return deflt_digests; case OSSL_OP_CIPHER: return deflt_ciphers; + case OSSL_OP_KEYMGMT: + return deflt_keymgmt; case OSSL_OP_KEYEXCH: return deflt_keyexch; } -- cgit v1.1