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:25:04 +0100 |
commit | e8115bd1654d5cd7718109679b2047ca573083a8 (patch) | |
tree | f0f1df9070e2de5e6b697c902766bd38befd9076 /providers/implementations | |
parent | 624efd2ba6f1dabdcdecf17c77bd206c421efdaf (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)
Diffstat (limited to 'providers/implementations')
-rw-r--r-- | providers/implementations/kdfs/hkdf.c | 78 |
1 files changed, 60 insertions, 18 deletions
diff --git a/providers/implementations/kdfs/hkdf.c b/providers/implementations/kdfs/hkdf.c index 1293d6fc8a..867d27c79e 100644 --- a/providers/implementations/kdfs/hkdf.c +++ b/providers/implementations/kdfs/hkdf.c @@ -32,6 +32,7 @@ #include "internal/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_dupctx_fn kdf_hkdf_dup; @@ -83,7 +84,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; @@ -120,7 +121,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; } @@ -142,10 +143,10 @@ static void *kdf_hkdf_dup(void *vctx) &dest->label, &dest->label_len) || !ossl_prov_memdup(src->data, src->data_len, &dest->data, &dest->data_len) + || !ossl_prov_memdup(src->info, src->info_len, + &dest->info, &dest->info_len) || !ossl_prov_digest_copy(&dest->digest, &src->digest)) goto err; - memcpy(dest->info, src->info, sizeof(dest->info)); - dest->info_len = src->info_len; dest->mode = src->mode; } return dest; @@ -273,6 +274,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; @@ -286,20 +322,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; } |