diff options
Diffstat (limited to 'providers/implementations/kdfs/tls1_prf.c')
-rw-r--r-- | providers/implementations/kdfs/tls1_prf.c | 230 |
1 files changed, 202 insertions, 28 deletions
diff --git a/providers/implementations/kdfs/tls1_prf.c b/providers/implementations/kdfs/tls1_prf.c index a4d64b935222..4b6469c00d23 100644 --- a/providers/implementations/kdfs/tls1_prf.c +++ b/providers/implementations/kdfs/tls1_prf.c @@ -1,5 +1,5 @@ /* - * Copyright 2016-2022 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2016-2024 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 @@ -45,6 +45,13 @@ * A(0) = seed * A(i) = HMAC_<hash>(secret, A(i-1)) */ + +/* + * Low level APIs (such as DH) are deprecated for public use, but still ok for + * internal use. + */ +#include "internal/deprecated.h" + #include <stdio.h> #include <stdarg.h> #include <string.h> @@ -60,9 +67,14 @@ #include "prov/providercommon.h" #include "prov/implementations.h" #include "prov/provider_util.h" -#include "e_os.h" +#include "prov/securitycheck.h" +#include "internal/e_os.h" +#include "internal/safe_math.h" + +OSSL_SAFE_MATH_UNSIGNED(size_t, size_t) static OSSL_FUNC_kdf_newctx_fn kdf_tls1_prf_new; +static OSSL_FUNC_kdf_dupctx_fn kdf_tls1_prf_dup; static OSSL_FUNC_kdf_freectx_fn kdf_tls1_prf_free; static OSSL_FUNC_kdf_reset_fn kdf_tls1_prf_reset; static OSSL_FUNC_kdf_derive_fn kdf_tls1_prf_derive; @@ -76,7 +88,8 @@ static int tls1_prf_alg(EVP_MAC_CTX *mdctx, EVP_MAC_CTX *sha1ctx, const unsigned char *seed, size_t seed_len, unsigned char *out, size_t olen); -#define TLS1_PRF_MAXBUF 1024 +#define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74" +#define TLS_MD_MASTER_SECRET_CONST_SIZE 13 /* TLS KDF kdf context structure */ typedef struct { @@ -90,9 +103,11 @@ typedef struct { /* Secret value to use for PRF */ unsigned char *sec; size_t seclen; - /* Buffer of concatenated seed data */ - unsigned char seed[TLS1_PRF_MAXBUF]; + /* Concatenated seed data */ + unsigned char *seed; size_t seedlen; + + OSSL_FIPS_IND_DECLARE } TLS1_PRF; static void *kdf_tls1_prf_new(void *provctx) @@ -102,11 +117,10 @@ static void *kdf_tls1_prf_new(void *provctx) if (!ossl_prov_is_running()) return NULL; - if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL) { - ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); - return NULL; + if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) != NULL) { + ctx->provctx = provctx; + OSSL_FIPS_IND_INIT(ctx) } - ctx->provctx = provctx; return ctx; } @@ -128,11 +142,108 @@ static void kdf_tls1_prf_reset(void *vctx) EVP_MAC_CTX_free(ctx->P_hash); EVP_MAC_CTX_free(ctx->P_sha1); OPENSSL_clear_free(ctx->sec, ctx->seclen); - OPENSSL_cleanse(ctx->seed, ctx->seedlen); + OPENSSL_clear_free(ctx->seed, ctx->seedlen); memset(ctx, 0, sizeof(*ctx)); ctx->provctx = provctx; } +static void *kdf_tls1_prf_dup(void *vctx) +{ + const TLS1_PRF *src = (const TLS1_PRF *)vctx; + TLS1_PRF *dest; + + dest = kdf_tls1_prf_new(src->provctx); + if (dest != NULL) { + if (src->P_hash != NULL + && (dest->P_hash = EVP_MAC_CTX_dup(src->P_hash)) == NULL) + goto err; + if (src->P_sha1 != NULL + && (dest->P_sha1 = EVP_MAC_CTX_dup(src->P_sha1)) == NULL) + goto err; + if (!ossl_prov_memdup(src->sec, src->seclen, &dest->sec, &dest->seclen)) + goto err; + if (!ossl_prov_memdup(src->seed, src->seedlen, &dest->seed, + &dest->seedlen)) + goto err; + OSSL_FIPS_IND_COPY(dest, src) + } + return dest; + + err: + kdf_tls1_prf_free(dest); + return NULL; +} + +#ifdef FIPS_MODULE + +static int fips_ems_check_passed(TLS1_PRF *ctx) +{ + OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(ctx->provctx); + /* + * Check that TLS is using EMS. + * + * The seed buffer is prepended with a label. + * If EMS mode is enforced then the label "master secret" is not allowed, + * We do the check this way since the PRF is used for other purposes, as well + * as "extended master secret". + */ + int ems_approved = (ctx->seedlen < TLS_MD_MASTER_SECRET_CONST_SIZE + || memcmp(ctx->seed, TLS_MD_MASTER_SECRET_CONST, + TLS_MD_MASTER_SECRET_CONST_SIZE) != 0); + + if (!ems_approved) { + if (!OSSL_FIPS_IND_ON_UNAPPROVED(ctx, OSSL_FIPS_IND_SETTABLE0, + libctx, "TLS_PRF", "EMS", + ossl_fips_config_tls1_prf_ems_check)) { + ERR_raise(ERR_LIB_PROV, PROV_R_EMS_NOT_ENABLED); + return 0; + } + } + return 1; +} + +static int fips_digest_check_passed(TLS1_PRF *ctx, const EVP_MD *md) +{ + OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(ctx->provctx); + /* + * Perform digest check + * + * According to NIST SP 800-135r1 section 5.2, the valid hash functions are + * specified in FIPS 180-3. ACVP also only lists the same set of hash + * functions. + */ + int digest_unapproved = !EVP_MD_is_a(md, SN_sha256) + && !EVP_MD_is_a(md, SN_sha384) + && !EVP_MD_is_a(md, SN_sha512); + + if (digest_unapproved) { + if (!OSSL_FIPS_IND_ON_UNAPPROVED(ctx, OSSL_FIPS_IND_SETTABLE1, + libctx, "TLS_PRF", "Digest", + ossl_fips_config_tls1_prf_digest_check)) { + ERR_raise(ERR_LIB_PROV, PROV_R_DIGEST_NOT_ALLOWED); + return 0; + } + } + return 1; +} + +static int fips_key_check_passed(TLS1_PRF *ctx) +{ + OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(ctx->provctx); + int key_approved = ossl_kdf_check_key_size(ctx->seclen); + + if (!key_approved) { + if (!OSSL_FIPS_IND_ON_UNAPPROVED(ctx, OSSL_FIPS_IND_SETTABLE2, + libctx, "TLS_PRF", "Key size", + ossl_fips_config_tls1_prf_key_check)) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); + return 0; + } + } + return 1; +} +#endif + static int kdf_tls1_prf_derive(void *vctx, unsigned char *key, size_t keylen, const OSSL_PARAM params[]) { @@ -158,6 +269,11 @@ static int kdf_tls1_prf_derive(void *vctx, unsigned char *key, size_t keylen, return 0; } +#ifdef FIPS_MODULE + if (!fips_ems_check_passed(ctx)) + return 0; +#endif + return tls1_prf_alg(ctx->P_hash, ctx->P_sha1, ctx->sec, ctx->seclen, ctx->seed, ctx->seedlen, @@ -170,10 +286,23 @@ static int kdf_tls1_prf_set_ctx_params(void *vctx, const OSSL_PARAM params[]) TLS1_PRF *ctx = vctx; OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(ctx->provctx); - if (params == NULL) + if (ossl_param_is_empty(params)) return 1; + if (!OSSL_FIPS_IND_SET_CTX_PARAM(ctx, OSSL_FIPS_IND_SETTABLE0, params, + OSSL_KDF_PARAM_FIPS_EMS_CHECK)) + return 0; + if (!OSSL_FIPS_IND_SET_CTX_PARAM(ctx, OSSL_FIPS_IND_SETTABLE1, params, + OSSL_KDF_PARAM_FIPS_DIGEST_CHECK)) + return 0; + if (!OSSL_FIPS_IND_SET_CTX_PARAM(ctx, OSSL_FIPS_IND_SETTABLE2, params, + OSSL_KDF_PARAM_FIPS_KEY_CHECK)) + return 0; + if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_DIGEST)) != NULL) { + PROV_DIGEST digest; + const EVP_MD *md = NULL; + if (OPENSSL_strcasecmp(p->data, SN_md5_sha1) == 0) { if (!ossl_prov_macctx_load_from_params(&ctx->P_hash, params, OSSL_MAC_NAME_HMAC, @@ -189,6 +318,26 @@ static int kdf_tls1_prf_set_ctx_params(void *vctx, const OSSL_PARAM params[]) NULL, NULL, libctx)) return 0; } + + memset(&digest, 0, sizeof(digest)); + if (!ossl_prov_digest_load_from_params(&digest, params, libctx)) + return 0; + + md = ossl_prov_digest_md(&digest); + if (EVP_MD_xof(md)) { + ERR_raise(ERR_LIB_PROV, PROV_R_XOF_DIGESTS_NOT_ALLOWED); + ossl_prov_digest_reset(&digest); + return 0; + } + +#ifdef FIPS_MODULE + if (!fips_digest_check_passed(ctx, md)) { + ossl_prov_digest_reset(&digest); + return 0; + } +#endif + + ossl_prov_digest_reset(&digest); } if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SECRET)) != NULL) { @@ -196,21 +345,39 @@ static int kdf_tls1_prf_set_ctx_params(void *vctx, const OSSL_PARAM params[]) ctx->sec = NULL; if (!OSSL_PARAM_get_octet_string(p, (void **)&ctx->sec, 0, &ctx->seclen)) return 0; + +#ifdef FIPS_MODULE + if (!fips_key_check_passed(ctx)) + return 0; +#endif } /* The seed fields concatenate, so process them all */ if ((p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SEED)) != NULL) { for (; p != NULL; p = OSSL_PARAM_locate_const(p + 1, OSSL_KDF_PARAM_SEED)) { - const void *q = ctx->seed + ctx->seedlen; - size_t sz = 0; - - if (p->data_size != 0 - && p->data != NULL - && !OSSL_PARAM_get_octet_string(p, (void **)&q, - TLS1_PRF_MAXBUF - ctx->seedlen, - &sz)) - return 0; - ctx->seedlen += sz; + if (p->data_size != 0 && p->data != NULL) { + const void *val = NULL; + size_t sz = 0; + unsigned char *seed; + size_t seedlen; + int err = 0; + + if (!OSSL_PARAM_get_octet_string_ptr(p, &val, &sz)) + return 0; + + seedlen = safe_add_size_t(ctx->seedlen, sz, &err); + if (err) + return 0; + + seed = OPENSSL_clear_realloc(ctx->seed, ctx->seedlen, seedlen); + if (!seed) + return 0; + + ctx->seed = seed; + if (ossl_assert(sz != 0)) + memcpy(ctx->seed + ctx->seedlen, val, sz); + ctx->seedlen = seedlen; + } } } return 1; @@ -224,6 +391,9 @@ static const OSSL_PARAM *kdf_tls1_prf_settable_ctx_params( OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_DIGEST, NULL, 0), OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SECRET, NULL, 0), OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SEED, NULL, 0), + OSSL_FIPS_IND_SETTABLE_CTX_PARAM(OSSL_KDF_PARAM_FIPS_EMS_CHECK) + OSSL_FIPS_IND_SETTABLE_CTX_PARAM(OSSL_KDF_PARAM_FIPS_DIGEST_CHECK) + OSSL_FIPS_IND_SETTABLE_CTX_PARAM(OSSL_KDF_PARAM_FIPS_KEY_CHECK) OSSL_PARAM_END }; return known_settable_ctx_params; @@ -233,9 +403,13 @@ static int kdf_tls1_prf_get_ctx_params(void *vctx, OSSL_PARAM params[]) { OSSL_PARAM *p; - if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE)) != NULL) - return OSSL_PARAM_set_size_t(p, SIZE_MAX); - return -2; + if ((p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE)) != NULL) { + if (!OSSL_PARAM_set_size_t(p, SIZE_MAX)) + return 0; + } + if (!OSSL_FIPS_IND_GET_CTX_PARAM(((TLS1_PRF *)vctx), params)) + return 0; + return 1; } static const OSSL_PARAM *kdf_tls1_prf_gettable_ctx_params( @@ -243,6 +417,7 @@ static const OSSL_PARAM *kdf_tls1_prf_gettable_ctx_params( { static const OSSL_PARAM known_gettable_ctx_params[] = { OSSL_PARAM_size_t(OSSL_KDF_PARAM_SIZE, NULL), + OSSL_FIPS_IND_GETTABLE_CTX_PARAM() OSSL_PARAM_END }; return known_gettable_ctx_params; @@ -250,6 +425,7 @@ static const OSSL_PARAM *kdf_tls1_prf_gettable_ctx_params( const OSSL_DISPATCH ossl_kdf_tls1_prf_functions[] = { { OSSL_FUNC_KDF_NEWCTX, (void(*)(void))kdf_tls1_prf_new }, + { OSSL_FUNC_KDF_DUPCTX, (void(*)(void))kdf_tls1_prf_dup }, { OSSL_FUNC_KDF_FREECTX, (void(*)(void))kdf_tls1_prf_free }, { OSSL_FUNC_KDF_RESET, (void(*)(void))kdf_tls1_prf_reset }, { OSSL_FUNC_KDF_DERIVE, (void(*)(void))kdf_tls1_prf_derive }, @@ -261,7 +437,7 @@ const OSSL_DISPATCH ossl_kdf_tls1_prf_functions[] = { (void(*)(void))kdf_tls1_prf_gettable_ctx_params }, { OSSL_FUNC_KDF_GET_CTX_PARAMS, (void(*)(void))kdf_tls1_prf_get_ctx_params }, - { 0, NULL } + OSSL_DISPATCH_END }; /* @@ -387,10 +563,8 @@ static int tls1_prf_alg(EVP_MAC_CTX *mdctx, EVP_MAC_CTX *sha1ctx, seed, seed_len, out, olen)) return 0; - if ((tmp = OPENSSL_malloc(olen)) == NULL) { - ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + if ((tmp = OPENSSL_malloc(olen)) == NULL) return 0; - } if (!tls1_prf_P_hash(sha1ctx, sec + slen - L_S2, L_S2, seed, seed_len, tmp, olen)) { |