#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 {
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;
/* 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)
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) {
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;
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);
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;
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
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
--- /dev/null
+/*
+ * 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 */
# 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);
#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
void *provctx;
CMAC_CTX *ctx;
PROV_CIPHER cipher;
+ OSSL_FIPS_IND_DECLARE
};
static void *cmac_new(void *provctx)
macctx = NULL;
} else {
macctx->provctx = provctx;
+ OSSL_FIPS_IND_INIT(macctx)
}
return macctx;
cmac_free(dst);
return NULL;
}
+ OSSL_FIPS_IND_COPY(dst, src)
return dst;
}
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;
}
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,
&& !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;
}
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,
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;
#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;
}
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