]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
Add FIPS indicator to CMAC.
authorslontis <shane.lontis@oracle.com>
Mon, 29 Jul 2024 07:47:46 +0000 (17:47 +1000)
committerPauli <ppzgs1@gmail.com>
Tue, 30 Jul 2024 23:04:17 +0000 (09:04 +1000)
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)

crypto/cmac/cmac.c
doc/man7/EVP_MAC-CMAC.pod
include/crypto/cmac.h [new file with mode: 0644]
providers/common/include/prov/fipsindicator.h
providers/implementations/macs/cmac_prov.c
test/recipes/30-test_evp_data/evpmac_cmac_des.txt

index 2012774f8d9056d900eccf536dccd23c0ee2c1e1..16f4b904ad853477ae420ab5d5e90f053953f056 100644 (file)
@@ -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;
index 44c5fc7c44e18f45f3731bbc910fa9aa5a3a5269..0610d050f4ca94d8d364a0bec2d6c64a70e979a3 100644 (file)
@@ -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
diff --git a/include/crypto/cmac.h b/include/crypto/cmac.h
new file mode 100644 (file)
index 0000000..df55b68
--- /dev/null
@@ -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 */
index a1f4f55e6ebd5db1166eae08b5f773f781c35ced..9bc068ad512513a9ba20cbb7023a1183014a4e45 100644 (file)
@@ -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);
index ec7be448eb2e150f1bc9bd2d6e7ee8b71eb3276c..39ab09172bb09e8889cf2d8f513ebde1ea7679a4 100644 (file)
@@ -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;
             }
index d23abe1f974e7c3c0d8f3cb1de2c466f983ce1e1..14169c45b449e93ca6fa507c15a83cc4d657a3d4 100644 (file)
@@ -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