Add FIPS indicator to CMAC.
There is a issue currently related to CMAC TDES, when the new provider is tested against older branches. The new strict check caused backwards compatibility issues when using old branch with the new FIPS provider. To get around this CMAC now allows TDES by default, but it can be either enabled via config or a settable. (i.e it uses an indicator) Where the TDES cipher check can be done turned out to be problematic. Shifting the check in the TDES cipherout of the init doesnt work because ciphers can run thru either final or cipher (and checking on every cipher call seemed bad). This means it needs to stay in the cipher init. So the check needs to be done in CMAC BEFORE the underlying TDES cipher does it check. When using an indicator the TDES cipher needs its "encrypt-check" set so that needs to be propagated from the CMAC object. This requires the ability to set the param at the time the cipher ctx is inited. An internal function was required in order to pass params to CMAC_Init. Note also that the check was done where it is, because EVP_Q_mac() calls EVP_MAC_CTX_set_params(ctx, cipher_param) EVP_MAC_CTX_set_params(ctx, params) EVP_MAC_init(ctx, key, keylen, params) Where the second call to set_params would set up "encrypt-check" after "cipher". Reviewed-by: Neil Horman <nhorman@openssl.org> Reviewed-by: Paul Dale <pauli@openssl.org> (Merged from https://github.com/openssl/openssl/pull/25022)
This commit is contained in:
parent
efba3f1351
commit
4f5febe2c6
@ -19,6 +19,7 @@
|
||||
#include "internal/cryptlib.h"
|
||||
#include <openssl/cmac.h>
|
||||
#include <openssl/err.h>
|
||||
#include "crypto/cmac.h"
|
||||
|
||||
#define LOCAL_BUF_SIZE 2048
|
||||
struct CMAC_CTX_st {
|
||||
@ -107,8 +108,9 @@ int CMAC_CTX_copy(CMAC_CTX *out, const CMAC_CTX *in)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CMAC_Init(CMAC_CTX *ctx, const void *key, size_t keylen,
|
||||
const EVP_CIPHER *cipher, ENGINE *impl)
|
||||
int ossl_cmac_init(CMAC_CTX *ctx, const void *key, size_t keylen,
|
||||
const EVP_CIPHER *cipher, ENGINE *impl,
|
||||
const OSSL_PARAM param[])
|
||||
{
|
||||
static const unsigned char zero_iv[EVP_MAX_BLOCK_LENGTH] = { 0 };
|
||||
int block_len;
|
||||
@ -118,7 +120,7 @@ int CMAC_Init(CMAC_CTX *ctx, const void *key, size_t keylen,
|
||||
/* Not initialised */
|
||||
if (ctx->nlast_block == -1)
|
||||
return 0;
|
||||
if (!EVP_EncryptInit_ex(ctx->cctx, NULL, NULL, NULL, zero_iv))
|
||||
if (!EVP_EncryptInit_ex2(ctx->cctx, NULL, NULL, zero_iv, param))
|
||||
return 0;
|
||||
block_len = EVP_CIPHER_CTX_get_block_size(ctx->cctx);
|
||||
if (block_len == 0)
|
||||
@ -131,8 +133,13 @@ int CMAC_Init(CMAC_CTX *ctx, const void *key, size_t keylen,
|
||||
if (cipher != NULL) {
|
||||
/* Ensure we can't use this ctx until we also have a key */
|
||||
ctx->nlast_block = -1;
|
||||
if (!EVP_EncryptInit_ex(ctx->cctx, cipher, impl, NULL, NULL))
|
||||
return 0;
|
||||
if (impl != NULL) {
|
||||
if (!EVP_EncryptInit_ex(ctx->cctx, cipher, impl, NULL, NULL))
|
||||
return 0;
|
||||
} else {
|
||||
if (!EVP_EncryptInit_ex2(ctx->cctx, cipher, NULL, NULL, param))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* Non-NULL key means initialisation complete */
|
||||
if (key != NULL) {
|
||||
@ -144,7 +151,7 @@ int CMAC_Init(CMAC_CTX *ctx, const void *key, size_t keylen,
|
||||
return 0;
|
||||
if (EVP_CIPHER_CTX_set_key_length(ctx->cctx, keylen) <= 0)
|
||||
return 0;
|
||||
if (!EVP_EncryptInit_ex(ctx->cctx, NULL, NULL, key, zero_iv))
|
||||
if (!EVP_EncryptInit_ex2(ctx->cctx, NULL, key, zero_iv, param))
|
||||
return 0;
|
||||
if ((bl = EVP_CIPHER_CTX_get_block_size(ctx->cctx)) < 0)
|
||||
return 0;
|
||||
@ -154,7 +161,7 @@ int CMAC_Init(CMAC_CTX *ctx, const void *key, size_t keylen,
|
||||
make_kn(ctx->k2, ctx->k1, bl);
|
||||
OPENSSL_cleanse(ctx->tbl, bl);
|
||||
/* Reset context again ready for first data block */
|
||||
if (!EVP_EncryptInit_ex(ctx->cctx, NULL, NULL, NULL, zero_iv))
|
||||
if (!EVP_EncryptInit_ex2(ctx->cctx, NULL, NULL, zero_iv, param))
|
||||
return 0;
|
||||
/* Zero tbl so resume works */
|
||||
memset(ctx->tbl, 0, bl);
|
||||
@ -163,6 +170,12 @@ int CMAC_Init(CMAC_CTX *ctx, const void *key, size_t keylen,
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CMAC_Init(CMAC_CTX *ctx, const void *key, size_t keylen,
|
||||
const EVP_CIPHER *cipher, ENGINE *impl)
|
||||
{
|
||||
return ossl_cmac_init(ctx, key, keylen, cipher, impl, NULL);
|
||||
}
|
||||
|
||||
int CMAC_Update(CMAC_CTX *ctx, const void *in, size_t dlen)
|
||||
{
|
||||
const unsigned char *data = in;
|
||||
|
@ -47,6 +47,17 @@ Sets the properties to be queried when trying to fetch the underlying cipher.
|
||||
This must be given together with the cipher naming parameter to be considered
|
||||
valid.
|
||||
|
||||
=item "encrypt-check" (B<OSSL_CIPHER_PARAM_FIPS_ENCRYPT_CHECK>) <integer>
|
||||
|
||||
If required this parameter should be set before EVP_MAC_init()
|
||||
|
||||
The default value of 1 causes an error when a unapproved Triple-DES encryption
|
||||
operation is triggered.
|
||||
Setting this to 0 will ignore the error and set the approved "fips-indicator" to
|
||||
0.
|
||||
This option is used by the OpenSSL FIPS provider, and breaks FIPS compliance if
|
||||
set to 0.
|
||||
|
||||
=back
|
||||
|
||||
The following parameters can be retrieved with
|
||||
@ -59,15 +70,18 @@ EVP_MAC_CTX_get_params():
|
||||
The "size" parameter can also be retrieved with with EVP_MAC_CTX_get_mac_size().
|
||||
The length of the "size" parameter is equal to that of an B<unsigned int>.
|
||||
|
||||
=back
|
||||
|
||||
=over 4
|
||||
|
||||
=item "block-size" (B<OSSL_MAC_PARAM_BLOCK_SIZE>) <unsigned integer>
|
||||
|
||||
Gets the MAC block size. The "block-size" parameter can also be retrieved with
|
||||
EVP_MAC_CTX_get_block_size().
|
||||
|
||||
=item "fips-indicator" (B<OSSL_CIPHER_PARAM_FIPS_APPROVED_INDICATOR>) <integer>
|
||||
|
||||
A getter that returns 1 if the operation is FIPS approved, or 0 otherwise.
|
||||
This may be used after calling EVP_MAC_final().
|
||||
It may return 0 if the "encrypt-check" option is set to 0.
|
||||
|
||||
=back
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
22
include/crypto/cmac.h
Normal file
22
include/crypto/cmac.h
Normal file
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 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
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#ifndef OSSL_CRYPTO_CMAC_H
|
||||
# define OSSL_CRYPTO_CMAC_H
|
||||
# pragma once
|
||||
|
||||
# include <openssl/types.h>
|
||||
# include <openssl/cmac.h>
|
||||
# include <openssl/params.h>
|
||||
|
||||
int ossl_cmac_init(CMAC_CTX *ctx, const void *key, size_t keylen,
|
||||
const EVP_CIPHER *cipher, ENGINE *impl,
|
||||
const OSSL_PARAM param[]);
|
||||
|
||||
#endif /* OSSL_CRYPTO_CMAC_H */
|
@ -114,7 +114,12 @@ void ossl_FIPS_IND_copy(OSSL_FIPS_IND *dst, const OSSL_FIPS_IND *src);
|
||||
# define OSSL_FIPS_IND_GET_CTX_PARAM(ctx, prms) \
|
||||
ossl_FIPS_IND_get_ctx_param(&((ctx)->indicator), prms)
|
||||
|
||||
#define OSSL_FIPS_IND_GET(ctx) &((ctx)->indicator)
|
||||
# define OSSL_FIPS_IND_GET(ctx) &((ctx)->indicator)
|
||||
|
||||
# define OSSL_FIPS_IND_GET_PARAM(ctx, p, settable, id, name) \
|
||||
*settable = ossl_FIPS_IND_get_settable(&((ctx)->indicator), id); \
|
||||
if (*settable != OSSL_FIPS_IND_STATE_UNKNOWN) \
|
||||
*p = OSSL_PARAM_construct_int(name, settable); \
|
||||
|
||||
int ossl_fips_ind_rsa_key_check(OSSL_FIPS_IND *ind, int id, OSSL_LIB_CTX *libctx,
|
||||
const RSA *rsa, const char *desc, int protect);
|
||||
|
@ -25,6 +25,9 @@
|
||||
#include "prov/provider_ctx.h"
|
||||
#include "prov/provider_util.h"
|
||||
#include "prov/providercommon.h"
|
||||
#include "prov/fipscommon.h"
|
||||
#include "prov/fipsindicator.h"
|
||||
#include "crypto/cmac.h"
|
||||
|
||||
/*
|
||||
* Forward declaration of everything implemented here. This is not strictly
|
||||
@ -48,6 +51,7 @@ struct cmac_data_st {
|
||||
void *provctx;
|
||||
CMAC_CTX *ctx;
|
||||
PROV_CIPHER cipher;
|
||||
OSSL_FIPS_IND_DECLARE
|
||||
};
|
||||
|
||||
static void *cmac_new(void *provctx)
|
||||
@ -63,6 +67,7 @@ static void *cmac_new(void *provctx)
|
||||
macctx = NULL;
|
||||
} else {
|
||||
macctx->provctx = provctx;
|
||||
OSSL_FIPS_IND_INIT(macctx)
|
||||
}
|
||||
|
||||
return macctx;
|
||||
@ -95,6 +100,7 @@ static void *cmac_dup(void *vsrc)
|
||||
cmac_free(dst);
|
||||
return NULL;
|
||||
}
|
||||
OSSL_FIPS_IND_COPY(dst, src)
|
||||
return dst;
|
||||
}
|
||||
|
||||
@ -109,12 +115,55 @@ static size_t cmac_size(void *vmacctx)
|
||||
return EVP_CIPHER_CTX_get_block_size(cipherctx);
|
||||
}
|
||||
|
||||
#ifdef FIPS_MODULE
|
||||
/*
|
||||
* TDES Encryption is not approved in FIPS 140-3.
|
||||
*
|
||||
* In strict approved mode we just fail here (by returning 0).
|
||||
* If we are going to bypass it using a FIPS indicator then we need to pass that
|
||||
* information down to the cipher also.
|
||||
* This function returns the param to pass down in 'p'.
|
||||
* state will return OSSL_FIPS_IND_STATE_UNKNOWN if the param has not been set.
|
||||
*
|
||||
* The name 'OSSL_CIPHER_PARAM_FIPS_ENCRYPT_CHECK' used below matches the
|
||||
* key name used by the Triple-DES.
|
||||
*/
|
||||
static int tdes_check_param(struct cmac_data_st *macctx, OSSL_PARAM *p,
|
||||
int *state)
|
||||
{
|
||||
OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(macctx->provctx);
|
||||
const EVP_CIPHER *cipher = ossl_prov_cipher_cipher(&macctx->cipher);
|
||||
|
||||
*state = OSSL_FIPS_IND_STATE_UNKNOWN;
|
||||
if (EVP_CIPHER_is_a(cipher, "DES-EDE3-CBC")) {
|
||||
if (!OSSL_FIPS_IND_ON_UNAPPROVED(macctx, OSSL_FIPS_IND_SETTABLE0,
|
||||
libctx, "CMAC", "Triple-DES",
|
||||
FIPS_tdes_encrypt_check))
|
||||
return 0;
|
||||
OSSL_FIPS_IND_GET_PARAM(macctx, p, state, OSSL_FIPS_IND_SETTABLE0,
|
||||
OSSL_CIPHER_PARAM_FIPS_ENCRYPT_CHECK)
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int cmac_setkey(struct cmac_data_st *macctx,
|
||||
const unsigned char *key, size_t keylen)
|
||||
{
|
||||
int rv = CMAC_Init(macctx->ctx, key, keylen,
|
||||
ossl_prov_cipher_cipher(&macctx->cipher),
|
||||
ossl_prov_cipher_engine(&macctx->cipher));
|
||||
int rv;
|
||||
OSSL_PARAM *p = NULL;
|
||||
#ifdef FIPS_MODULE
|
||||
int state = OSSL_FIPS_IND_STATE_UNKNOWN;
|
||||
OSSL_PARAM prms[2] = { OSSL_PARAM_END, OSSL_PARAM_END };
|
||||
|
||||
if (!tdes_check_param(macctx, &prms[0], &state))
|
||||
return 0;
|
||||
if (state != OSSL_FIPS_IND_STATE_UNKNOWN)
|
||||
p = prms;
|
||||
#endif
|
||||
rv = ossl_cmac_init(macctx->ctx, key, keylen,
|
||||
ossl_prov_cipher_cipher(&macctx->cipher),
|
||||
ossl_prov_cipher_engine(&macctx->cipher), p);
|
||||
ossl_prov_cipher_reset(&macctx->cipher);
|
||||
return rv;
|
||||
}
|
||||
@ -154,6 +203,7 @@ static int cmac_final(void *vmacctx, unsigned char *out, size_t *outl,
|
||||
static const OSSL_PARAM known_gettable_ctx_params[] = {
|
||||
OSSL_PARAM_size_t(OSSL_MAC_PARAM_SIZE, NULL),
|
||||
OSSL_PARAM_size_t(OSSL_MAC_PARAM_BLOCK_SIZE, NULL),
|
||||
OSSL_FIPS_IND_GETTABLE_CTX_PARAM()
|
||||
OSSL_PARAM_END
|
||||
};
|
||||
static const OSSL_PARAM *cmac_gettable_ctx_params(ossl_unused void *ctx,
|
||||
@ -174,6 +224,8 @@ static int cmac_get_ctx_params(void *vmacctx, OSSL_PARAM params[])
|
||||
&& !OSSL_PARAM_set_size_t(p, cmac_size(vmacctx)))
|
||||
return 0;
|
||||
|
||||
if (!OSSL_FIPS_IND_GET_CTX_PARAM((struct cmac_data_st *)vmacctx, params))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -181,6 +233,7 @@ static const OSSL_PARAM known_settable_ctx_params[] = {
|
||||
OSSL_PARAM_utf8_string(OSSL_MAC_PARAM_CIPHER, NULL, 0),
|
||||
OSSL_PARAM_utf8_string(OSSL_MAC_PARAM_PROPERTIES, NULL, 0),
|
||||
OSSL_PARAM_octet_string(OSSL_MAC_PARAM_KEY, NULL, 0),
|
||||
OSSL_FIPS_IND_SETTABLE_CTX_PARAM(OSSL_CIPHER_PARAM_FIPS_ENCRYPT_CHECK)
|
||||
OSSL_PARAM_END
|
||||
};
|
||||
static const OSSL_PARAM *cmac_settable_ctx_params(ossl_unused void *ctx,
|
||||
@ -201,6 +254,11 @@ static int cmac_set_ctx_params(void *vmacctx, const OSSL_PARAM params[])
|
||||
if (params == NULL)
|
||||
return 1;
|
||||
|
||||
if (!OSSL_FIPS_IND_SET_CTX_PARAM(macctx,
|
||||
OSSL_FIPS_IND_SETTABLE0, params,
|
||||
OSSL_CIPHER_PARAM_FIPS_ENCRYPT_CHECK))
|
||||
return 0;
|
||||
|
||||
if ((p = OSSL_PARAM_locate_const(params, OSSL_MAC_PARAM_CIPHER)) != NULL) {
|
||||
if (!ossl_prov_cipher_load_from_params(&macctx->cipher, params, ctx))
|
||||
return 0;
|
||||
@ -213,11 +271,11 @@ static int cmac_set_ctx_params(void *vmacctx, const OSSL_PARAM params[])
|
||||
#ifdef FIPS_MODULE
|
||||
{
|
||||
const EVP_CIPHER *cipher = ossl_prov_cipher_cipher(&macctx->cipher);
|
||||
int approved = EVP_CIPHER_is_a(cipher, "AES-256-CBC")
|
||||
|| EVP_CIPHER_is_a(cipher, "AES-192-CBC")
|
||||
|| EVP_CIPHER_is_a(cipher, "AES-128-CBC");
|
||||
|
||||
if (!approved) {
|
||||
if (!EVP_CIPHER_is_a(cipher, "AES-256-CBC")
|
||||
&& !EVP_CIPHER_is_a(cipher, "AES-192-CBC")
|
||||
&& !EVP_CIPHER_is_a(cipher, "AES-128-CBC")
|
||||
&& !EVP_CIPHER_is_a(cipher, "DES-EDE3-CBC")) {
|
||||
ERR_raise(ERR_LIB_PROV, EVP_R_UNSUPPORTED_CIPHER);
|
||||
return 0;
|
||||
}
|
||||
|
@ -27,3 +27,19 @@ Algorithm = DES-EDE3-CBC
|
||||
Key = 89BCD952A8C8AB371AF48AC7D07085D5EFF702E6D62CDC23
|
||||
Input = FA620C1BBE97319E9A0CF0492121F7A20EB08A6A709DCBD00AAF38E4F99E754E
|
||||
Output = 8F49A1B7D6AA2258
|
||||
|
||||
FIPSversion = >=3.4.0
|
||||
MAC = CMAC
|
||||
Algorithm = DES-EDE3-CBC
|
||||
Key = 89BCD952A8C8AB371AF48AC7D07085D5EFF702E6D62CDC23
|
||||
Input = FA620C1BBE97319E9A0CF0492121F7A20EB08A6A709DCBD00AAF38E4F99E754E
|
||||
Result = MAC_INIT_ERROR
|
||||
|
||||
FIPSversion = >=3.4.0
|
||||
MAC = CMAC
|
||||
Unapproved = 1
|
||||
Ctrl = encrypt-check:0
|
||||
Algorithm = DES-EDE3-CBC
|
||||
Key = 89BCD952A8C8AB371AF48AC7D07085D5EFF702E6D62CDC23
|
||||
Input = FA620C1BBE97319E9A0CF0492121F7A20EB08A6A709DCBD00AAF38E4F99E754E
|
||||
Output = 8F49A1B7D6AA2258
|
||||
|
Loading…
x
Reference in New Issue
Block a user