Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fips: enforce minimum MAC key length of 112 bits #24199

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions doc/man1/openssl-dgst.pod.in
Expand Up @@ -176,12 +176,14 @@ Following options are supported by both by B<HMAC> and B<gost-mac>:
Specifies MAC key as alphanumeric string (use if key contain printable
characters only). String length must conform to any restrictions of
the MAC algorithm for example exactly 32 chars for gost-mac.
FIPS provider minimum key length is 14 characters (112 bits).

=item B<hexkey>:I<string>

Specifies MAC key in hexadecimal form (two hex digits per byte).
Key length must conform to any restrictions of the MAC algorithm
for example exactly 32 chars for gost-mac.
FIPS provider minimum key length is 28 hexadecimals (112 bits).

=back

Expand Down
4 changes: 2 additions & 2 deletions doc/man1/openssl-kdf.pod.in
Expand Up @@ -149,12 +149,12 @@ SSHKDF, X942KDF-ASN1, X942KDF-CONCAT, X963KDF and SCRYPT.

Use TLS1-PRF to create a hex-encoded derived key from a secret key and seed:

openssl kdf -keylen 16 -kdfopt digest:SHA2-256 -kdfopt key:secret \
openssl kdf -keylen 16 -kdfopt digest:SHA2-256 -kdfopt key:16charlongsecret \
-kdfopt seed:seed TLS1-PRF

Use HKDF to create a hex-encoded derived key from a secret key, salt and info:

openssl kdf -keylen 10 -kdfopt digest:SHA2-256 -kdfopt key:secret \
openssl kdf -keylen 10 -kdfopt digest:SHA2-256 -kdfopt key:16charlongsecret \
-kdfopt salt:salt -kdfopt info:label HKDF

Use SSKDF with KMAC to create a hex-encoded derived key from a secret key, salt and info:
Expand Down
2 changes: 2 additions & 0 deletions doc/man1/openssl-mac.pod.in
Expand Up @@ -72,12 +72,14 @@ Common parameter names used by EVP_MAC_CTX_get_params() are:
Specifies the MAC key as an alphanumeric string (use if the key contains
printable characters only).
The string length must conform to any restrictions of the MAC algorithm.
FIPS provider minimum key length is 14 characters (112 bits).
A key must be specified for every MAC algorithm.

=item B<hexkey:>I<string>

Specifies the MAC key in hexadecimal form (two hex digits per byte).
The key length must conform to any restrictions of the MAC algorithm.
FIPS provider minimum key length is 28 hexadecimals (112 bits).
A key must be specified for every MAC algorithm.

=item B<iv:>I<string>
Expand Down
1 change: 1 addition & 0 deletions providers/common/include/prov/securitycheck.h
Expand Up @@ -14,6 +14,7 @@ int ossl_rsa_check_key(OSSL_LIB_CTX *ctx, const RSA *rsa, int operation);
int ossl_ec_check_key(OSSL_LIB_CTX *ctx, const EC_KEY *ec, int protect);
int ossl_dsa_check_key(OSSL_LIB_CTX *ctx, const DSA *dsa, int sign);
int ossl_dh_check_key(OSSL_LIB_CTX *ctx, const DH *dh);
int ossl_mac_check_key(size_t min, size_t requested);

int ossl_digest_is_allowed(OSSL_LIB_CTX *ctx, const EVP_MD *md);
/* With security check enabled it can return -1 to indicate disallowed md */
Expand Down
13 changes: 13 additions & 0 deletions providers/common/securitycheck.c
Expand Up @@ -232,6 +232,19 @@ int ossl_dh_check_key(OSSL_LIB_CTX *ctx, const DH *dh)
}
#endif /* OPENSSL_NO_DH */

/*
* Check for valid MAC key size
*
*/
int ossl_mac_check_key(size_t min, size_t requested)
{
#ifndef FIPS_MODULE
return (requested >= min);
#else
return (requested >= 112);
# endif
}

int ossl_digest_get_approved_nid_with_sha1(OSSL_LIB_CTX *ctx, const EVP_MD *md,
int sha1_allowed)
{
Expand Down
51 changes: 35 additions & 16 deletions providers/implementations/kdfs/hkdf.c
Expand Up @@ -48,12 +48,12 @@ static OSSL_FUNC_kdf_derive_fn kdf_tls1_3_derive;
static OSSL_FUNC_kdf_settable_ctx_params_fn kdf_tls1_3_settable_ctx_params;
static OSSL_FUNC_kdf_set_ctx_params_fn kdf_tls1_3_set_ctx_params;

static int HKDF(OSSL_LIB_CTX *libctx, const EVP_MD *evp_md,
static int HKDF(const EVP_MD *evp_md,
const unsigned char *salt, size_t salt_len,
const unsigned char *key, size_t key_len,
const unsigned char *info, size_t info_len,
unsigned char *okm, size_t okm_len);
static int HKDF_Extract(OSSL_LIB_CTX *libctx, const EVP_MD *evp_md,
static int HKDF_Extract(const EVP_MD *evp_md,
const unsigned char *salt, size_t salt_len,
const unsigned char *ikm, size_t ikm_len,
unsigned char *prk, size_t prk_len);
Expand Down Expand Up @@ -180,7 +180,6 @@ static int kdf_hkdf_derive(void *vctx, unsigned char *key, size_t keylen,
const OSSL_PARAM params[])
{
KDF_HKDF *ctx = (KDF_HKDF *)vctx;
OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(ctx->provctx);
const EVP_MD *md;

if (!ossl_prov_is_running() || !kdf_hkdf_set_ctx_params(ctx, params))
Expand All @@ -203,11 +202,11 @@ static int kdf_hkdf_derive(void *vctx, unsigned char *key, size_t keylen,
switch (ctx->mode) {
case EVP_KDF_HKDF_MODE_EXTRACT_AND_EXPAND:
default:
return HKDF(libctx, md, ctx->salt, ctx->salt_len,
return HKDF(md, ctx->salt, ctx->salt_len,
ctx->key, ctx->key_len, ctx->info, ctx->info_len, key, keylen);

case EVP_KDF_HKDF_MODE_EXTRACT_ONLY:
return HKDF_Extract(libctx, md, ctx->salt, ctx->salt_len,
return HKDF_Extract(md, ctx->salt, ctx->salt_len,
ctx->key, ctx->key_len, key, keylen);

case EVP_KDF_HKDF_MODE_EXPAND_ONLY:
Expand Down Expand Up @@ -377,7 +376,7 @@ const OSSL_DISPATCH ossl_kdf_hkdf_functions[] = {
* 2.3. Step 2: Expand
* HKDF-Expand(PRK, info, L) -> OKM
*/
static int HKDF(OSSL_LIB_CTX *libctx, const EVP_MD *evp_md,
static int HKDF(const EVP_MD *evp_md,
const unsigned char *salt, size_t salt_len,
const unsigned char *ikm, size_t ikm_len,
const unsigned char *info, size_t info_len,
Expand All @@ -393,7 +392,7 @@ static int HKDF(OSSL_LIB_CTX *libctx, const EVP_MD *evp_md,
prk_len = (size_t)sz;

/* Step 1: HKDF-Extract(salt, IKM) -> PRK */
if (!HKDF_Extract(libctx, evp_md,
if (!HKDF_Extract(evp_md,
salt, salt_len, ikm, ikm_len, prk, prk_len))
return 0;

Expand Down Expand Up @@ -428,24 +427,44 @@ static int HKDF(OSSL_LIB_CTX *libctx, const EVP_MD *evp_md,
*
* PRK = HMAC-Hash(salt, IKM)
*/
static int HKDF_Extract(OSSL_LIB_CTX *libctx, const EVP_MD *evp_md,
static int HKDF_Extract(const EVP_MD *evp_md,
const unsigned char *salt, size_t salt_len,
const unsigned char *ikm, size_t ikm_len,
unsigned char *prk, size_t prk_len)
{
int sz = EVP_MD_get_size(evp_md);
HMAC_CTX *hmac = NULL;
unsigned int sz = EVP_MD_get_size(evp_md);

if (sz < 0)
return 0;
if (prk_len != (size_t)sz) {
ERR_raise(ERR_LIB_PROV, PROV_R_WRONG_OUTPUT_BUFFER_SIZE);
return 0;
}

/* calc: PRK = HMAC-Hash(salt, IKM) */
return
EVP_Q_mac(libctx, "HMAC", NULL, EVP_MD_get0_name(evp_md), NULL, salt,
salt_len, ikm, ikm_len, prk, EVP_MD_get_size(evp_md), NULL)
!= NULL;

if (prk == NULL)
prk = OPENSSL_malloc(sz);

if (salt == NULL && salt_len == 0)
salt = ikm;

if ((hmac = HMAC_CTX_new()) == NULL
|| !HMAC_Init_ex(hmac, salt, salt_len, evp_md, NULL)
|| !HMAC_Update(hmac, ikm, ikm_len)
|| !HMAC_Final(hmac, prk, &sz)) {
goto err;
}
return 1;

err:
HMAC_CTX_free(hmac);
if (prk != NULL) {
OPENSSL_free(prk);
prk = NULL;
}
return 0;
}

/*
Expand Down Expand Up @@ -601,7 +620,7 @@ static int prov_tls13_hkdf_expand(const EVP_MD *md,
out, outlen);
}

static int prov_tls13_hkdf_generate_secret(OSSL_LIB_CTX *libctx,
static int prov_tls13_hkdf_generate_secret(
const EVP_MD *md,
const unsigned char *prevsecret,
size_t prevsecretlen,
Expand Down Expand Up @@ -654,7 +673,7 @@ static int prov_tls13_hkdf_generate_secret(OSSL_LIB_CTX *libctx,
prevsecretlen = mdlen;
}

ret = HKDF_Extract(libctx, md, prevsecret, prevsecretlen,
ret = HKDF_Extract(md, prevsecret, prevsecretlen,
insecret, insecretlen, out, outlen);

if (prevsecret == preextractsec)
Expand Down Expand Up @@ -682,7 +701,7 @@ static int kdf_tls1_3_derive(void *vctx, unsigned char *key, size_t keylen,
return 0;

case EVP_KDF_HKDF_MODE_EXTRACT_ONLY:
return prov_tls13_hkdf_generate_secret(PROV_LIBCTX_OF(ctx->provctx),
return prov_tls13_hkdf_generate_secret(
md,
ctx->salt, ctx->salt_len,
ctx->key, ctx->key_len,
Expand Down
5 changes: 5 additions & 0 deletions providers/implementations/kdfs/kbkdf.c
Expand Up @@ -43,6 +43,7 @@
#include "prov/provider_ctx.h"
#include "prov/provider_util.h"
#include "prov/providercommon.h"
#include "prov/securitycheck.h"

#include "internal/e_os.h"
#include "internal/params.h"
Expand Down Expand Up @@ -289,6 +290,10 @@ static int kbkdf_derive(void *vctx, unsigned char *key, size_t keylen,
ERR_raise(ERR_LIB_PROV, PROV_R_NO_KEY_SET);
return 0;
}
if (!ossl_mac_check_key(0, ctx->ki_len * 8)) {
ERR_raise(ERR_LIB_PROV, PROV_R_KEY_SIZE_TOO_SMALL);
return 0;
}
/* Could either be missing MAC or missing message digest or missing
* cipher - arbitrarily, I pick this one. */
ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_MAC);
Expand Down
8 changes: 8 additions & 0 deletions providers/implementations/macs/hmac_prov.c
Expand Up @@ -20,13 +20,16 @@
#include <openssl/params.h>
#include <openssl/evp.h>
#include <openssl/hmac.h>
#include <openssl/err.h>
#include <openssl/proverr.h>

#include "internal/ssl3_cbc.h"

#include "prov/implementations.h"
#include "prov/provider_ctx.h"
#include "prov/provider_util.h"
#include "prov/providercommon.h"
#include "prov/securitycheck.h"

/*
* Forward declaration of everything implemented here. This is not strictly
Expand Down Expand Up @@ -144,6 +147,11 @@ static int hmac_setkey(struct hmac_data_st *macctx,
{
const EVP_MD *digest;

if (!ossl_mac_check_key(0, keylen * 8)) {
ERR_raise(ERR_LIB_PROV, PROV_R_KEY_SIZE_TOO_SMALL);
return 0;
}

if (macctx->key != NULL)
OPENSSL_secure_clear_free(macctx->key, macctx->keylen);
/* Keep a copy of the key in case we need it for TLS HMAC */
Expand Down
4 changes: 3 additions & 1 deletion providers/implementations/macs/kmac_prov.c
Expand Up @@ -59,6 +59,8 @@
#include "prov/provider_ctx.h"
#include "prov/provider_util.h"
#include "prov/providercommon.h"
#include "prov/securitycheck.h"

#include "internal/cryptlib.h" /* ossl_assert */

/*
Expand Down Expand Up @@ -251,7 +253,7 @@ static int kmac_setkey(struct kmac_data_st *kctx, const unsigned char *key,
const EVP_MD *digest = ossl_prov_digest_md(&kctx->digest);
int w = EVP_MD_get_block_size(digest);

if (keylen < KMAC_MIN_KEY || keylen > KMAC_MAX_KEY) {
if (!ossl_mac_check_key(KMAC_MIN_KEY * 8, keylen * 8) || keylen > KMAC_MAX_KEY) {
ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH);
return 0;
}
Expand Down