aboutsummaryrefslogtreecommitdiff
path: root/providers/implementations/kdfs/tls1_prf.c
diff options
context:
space:
mode:
Diffstat (limited to 'providers/implementations/kdfs/tls1_prf.c')
-rw-r--r--providers/implementations/kdfs/tls1_prf.c230
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)) {