diff options
author | slontis <shane.lontis@oracle.com> | 2022-12-16 12:26:44 +1000 |
---|---|---|
committer | Tomas Mraz <tomas@openssl.org> | 2022-12-22 12:26:41 +0100 |
commit | 12f64521194470d9d357c2cc3252254e1c591f62 (patch) | |
tree | d91af4622de0c61ae49862c8777ff793d2e15f5a /providers | |
parent | 053e06bd05094d9f2883aea7549561e97b4f7ad8 (diff) |
Change HKDF to alloc the info buffer.
Fixes #19909
I have enforced a maximum bound still but it is much higher.
Note also that TLS13 still uses the 2048 buffer size.
Reviewed-by: Hugo Landau <hlandau@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/19923)
(cherry picked from commit e8115bd1654d5cd7718109679b2047ca573083a8)
Diffstat (limited to 'providers')
-rw-r--r-- | providers/implementations/kdfs/hkdf.c | 74 |
1 files changed, 58 insertions, 16 deletions
diff --git a/providers/implementations/kdfs/hkdf.c b/providers/implementations/kdfs/hkdf.c index afdb7138e1..dfa7786bde 100644 --- a/providers/implementations/kdfs/hkdf.c +++ b/providers/implementations/kdfs/hkdf.c @@ -32,6 +32,7 @@ #include "e_os.h" #define HKDF_MAXBUF 2048 +#define HKDF_MAXINFO (32*1024) static OSSL_FUNC_kdf_newctx_fn kdf_hkdf_new; static OSSL_FUNC_kdf_freectx_fn kdf_hkdf_free; @@ -82,7 +83,7 @@ typedef struct { size_t label_len; unsigned char *data; size_t data_len; - unsigned char info[HKDF_MAXBUF]; + unsigned char *info; size_t info_len; } KDF_HKDF; @@ -121,7 +122,7 @@ static void kdf_hkdf_reset(void *vctx) OPENSSL_free(ctx->label); OPENSSL_clear_free(ctx->data, ctx->data_len); OPENSSL_clear_free(ctx->key, ctx->key_len); - OPENSSL_cleanse(ctx->info, ctx->info_len); + OPENSSL_clear_free(ctx->info, ctx->info_len); memset(ctx, 0, sizeof(*ctx)); ctx->provctx = provctx; } @@ -244,6 +245,41 @@ static int hkdf_common_set_ctx_params(KDF_HKDF *ctx, const OSSL_PARAM params[]) return 1; } +/* + * Use WPACKET to concat one or more OSSL_KDF_PARAM_INFO fields into a fixed + * out buffer of size *outlen. + * If out is NULL then outlen is used to return the required buffer size. + */ +static int setinfo_fromparams(const OSSL_PARAM *p, unsigned char *out, size_t *outlen) +{ + int ret = 0; + WPACKET pkt; + + if (out == NULL) { + if (!WPACKET_init_null(&pkt, 0)) + return 0; + } else { + if (!WPACKET_init_static_len(&pkt, out, *outlen, 0)) + return 0; + } + + for (; p != NULL; p = OSSL_PARAM_locate_const(p + 1, OSSL_KDF_PARAM_INFO)) { + if (p->data_type != OSSL_PARAM_OCTET_STRING) + goto err; + if (p->data != NULL + && p->data_size != 0 + && !WPACKET_memcpy(&pkt, p->data, p->data_size)) + goto err; + } + if (!WPACKET_get_total_written(&pkt, outlen) + || !WPACKET_finish(&pkt)) + goto err; + ret = 1; +err: + WPACKET_cleanup(&pkt); + return ret; +} + static int kdf_hkdf_set_ctx_params(void *vctx, const OSSL_PARAM params[]) { const OSSL_PARAM *p; @@ -257,20 +293,26 @@ static int kdf_hkdf_set_ctx_params(void *vctx, const OSSL_PARAM params[]) /* The info fields concatenate, so process them all */ if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_INFO)) != NULL) { - ctx->info_len = 0; - for (; p != NULL; p = OSSL_PARAM_locate_const(p + 1, - OSSL_KDF_PARAM_INFO)) { - const void *q = ctx->info + ctx->info_len; - size_t sz = 0; - - if (p->data_size != 0 - && p->data != NULL - && !OSSL_PARAM_get_octet_string(p, (void **)&q, - HKDF_MAXBUF - ctx->info_len, - &sz)) - return 0; - ctx->info_len += sz; - } + size_t sz = 0; + + /* calculate the total size */ + if (!setinfo_fromparams(p, NULL, &sz)) + return 0; + if (sz > HKDF_MAXINFO) + return 0; + + OPENSSL_clear_free(ctx->info, ctx->info_len); + ctx->info = NULL; + if (sz == 0) + return 1; + /* Alloc the buffer */ + ctx->info = OPENSSL_malloc(sz); + if (ctx->info == NULL) + return 0; + ctx->info_len = sz; + /* Concat one or more OSSL_KDF_PARAM_INFO fields */ + if (!setinfo_fromparams(p, ctx->info, &sz)) + return 0; } return 1; } |