Re: FIPS 140 service indicator revamp

NIIBE Yutaka via Gcrypt-devel <[email protected]>
Newsgroups gmane.comp.encryption.gpg.libgcrypt.devel
Message-ID <[email protected]>
NIIBE Yutaka <[email protected]> wrote:
> Here are changes for gcry_pk_hash_* functions.
>
> This change includes stop rejecting non-compliant cases.
>
> With LIBGCRYPT_FORCE_FIPS_MODE=true, "make check" result 7 failures.
>
> FAIL: basic
> FAIL: t-kem
> FAIL: dsa-rfc6979
> FAIL: curves
> FAIL: t-cv25519
> FAIL: t-x448
> FAIL: basic-disable-all-hwf

To support old behavior, I introduced GCRYCTL_FIPS_REJECT_NON_FIPS.
--

_______________________________________________
Gcrypt-devel mailing list
[email protected]
https://lists.gnupg.org/mailman/listinfo/gcrypt-devel
0003-fips-Introduce-GCRYCTL_FIPS_REJECT_NON_FIPS.patch (text/x-diff, 8.8 KB)
>From e52adf0948c60b2e9accd7996fcece0f9b443763 Mon Sep 17 00:00:00 2001
From: NIIBE Yutaka <[email protected]>
Date: Thu, 19 Dec 2024 11:30:28 +0900
Subject: [PATCH 3/3] fips: Introduce GCRYCTL_FIPS_REJECT_NON_FIPS.

* src/gcrypt.h.in (GCRYCTL_FIPS_REJECT_NON_FIPS): New.
(GCRY_FIPS_FLAG_REJECT_*): New.
* src/fips.c (struct gcry_thread_context): Add flags_reject_non_fips.
(the_tc): Add initial value.
(_gcry_thread_context_set_reject): New.
(_gcry_thread_context_check_rejection): New.
* src/gcrypt-int.h (fips_check_rejection): New.
* src/global.c (_gcry_vcontrol): Handle GCRYCTL_FIPS_REJECT_NON_FIPS.
* tests/t-fips-service-ind.c (main): Use GCRYCTL_FIPS_REJECT_NON_FIPS.

--

GnuPG-bug-id: 7338
Signed-off-by: NIIBE Yutaka <[email protected]>
---
 cipher/ecc-curves.c        |  7 ++++++-
 cipher/pubkey.c            | 34 ++++++++++++++++++++++++++--------
 src/fips.c                 | 17 ++++++++++++++++-
 src/gcrypt-int.h           |  9 ++++++++-
 src/gcrypt.h.in            | 28 ++++++++++++++++++++++++++--
 src/global.c               |  7 +++++++
 tests/t-fips-service-ind.c |  2 ++
 7 files changed, 91 insertions(+), 13 deletions(-)

diff --git a/cipher/ecc-curves.c b/cipher/ecc-curves.c
index ddf9cbe1..fe0a1eb2 100644
--- a/cipher/ecc-curves.c
+++ b/cipher/ecc-curves.c
@@ -645,7 +645,12 @@ _gcry_ecc_fill_in_curve (unsigned int nbits, const char *name,
      possible to bypass this check by specifying the curve parameters
      directly.  */
   if (fips_mode () && !domain_parms[idx].fips )
-    fips_service_indicator_mark_non_compliant ();
+    {
+      if (fips_check_rejection (GCRY_FIPS_FLAG_REJECT_PK))
+        return GPG_ERR_NOT_SUPPORTED;
+      else
+        fips_service_indicator_mark_non_compliant ();
+    }
 
   switch (domain_parms[idx].model)
     {
diff --git a/cipher/pubkey.c b/cipher/pubkey.c
index e2e54199..11bf1ec9 100644
--- a/cipher/pubkey.c
+++ b/cipher/pubkey.c
@@ -510,7 +510,12 @@ prepare_datasexp_to_be_signed (const char *tmpl, gcry_md_hd_t hd,
       algo = _gcry_md_get_algo (hd);
 
       if (fips_mode () && algo == GCRY_MD_SHA1)
-        fips_service_indicator_mark_non_compliant ();
+        {
+          if (fips_check_rejection (GCRY_FIPS_FLAG_REJECT_PK))
+            return GPG_ERR_DIGEST_ALGO;
+          else
+            fips_service_indicator_mark_non_compliant ();
+        }
 
       digest_name = _gcry_md_algo_name (algo);
       digest_size = (int)_gcry_md_get_algo_dlen (algo);
@@ -538,7 +543,12 @@ prepare_datasexp_to_be_signed (const char *tmpl, gcry_md_hd_t hd,
 	  return GPG_ERR_DIGEST_ALGO;
 	}
       else if (fips_mode () && algo == GCRY_MD_SHA1)
-        fips_service_indicator_mark_non_compliant ();
+        {
+          if (fips_check_rejection (GCRY_FIPS_FLAG_REJECT_PK))
+            return GPG_ERR_DIGEST_ALGO;
+          else
+            fips_service_indicator_mark_non_compliant ();
+        }
 
       digest_size = (int)_gcry_md_get_algo_dlen (algo);
       digest = _gcry_md_read (hd, algo);
@@ -611,11 +621,15 @@ _gcry_pk_sign_md (gcry_sexp_t *r_sig, const char *tmpl, gcry_md_hd_t hd_orig,
   if (rc)
     goto leave;
 
-  if (!spec->flags.fips && fips_mode ())
-    fips_service_indicator_mark_non_compliant ();
-
   if (spec->flags.disabled)
     rc = GPG_ERR_PUBKEY_ALGO;
+  else if (!spec->flags.fips && fips_mode ())
+    {
+      if (fips_check_rejection (GCRY_FIPS_FLAG_REJECT_PK))
+        return GPG_ERR_PUBKEY_ALGO;
+      else
+        fips_service_indicator_mark_non_compliant ();
+    }
   else if (spec->sign)
     rc = spec->sign (r_sig, s_data, keyparms);
   else
@@ -689,11 +703,15 @@ _gcry_pk_verify_md (gcry_sexp_t s_sig, const char *tmpl, gcry_md_hd_t hd_orig,
   if (rc)
     goto leave;
 
-  if (!spec->flags.fips && fips_mode ())
-    fips_service_indicator_mark_non_compliant ();
-
   if (spec->flags.disabled)
     rc = GPG_ERR_PUBKEY_ALGO;
+  else if (!spec->flags.fips && fips_mode ())
+    {
+      if (fips_check_rejection (GCRY_FIPS_FLAG_REJECT_PK))
+        return GPG_ERR_PUBKEY_ALGO;
+      else
+        fips_service_indicator_mark_non_compliant ();
+    }
   else if (spec->verify)
     rc = spec->verify (s_sig, s_data, keyparms);
   else
diff --git a/src/fips.c b/src/fips.c
index d3eaf85f..7ae89503 100644
--- a/src/fips.c
+++ b/src/fips.c
@@ -69,14 +69,29 @@ static enum module_states current_state;
 
 struct gcry_thread_context {
   unsigned long fips_service_indicator;
+  unsigned int flags_reject_non_fips;
 };
 
 #ifdef HAVE_GCC_STORAGE_CLASS__THREAD
-static __thread struct gcry_thread_context the_tc;
+static __thread struct gcry_thread_context the_tc = {
+  0, GCRY_FIPS_FLAG_REJECT_DEFAULT
+};
 #else
 #error libgcrypt requires thread-local storage to support FIPS mode
 #endif
 
+void
+_gcry_thread_context_set_reject (unsigned int flags)
+{
+  the_tc.flags_reject_non_fips = flags;
+}
+
+int
+_gcry_thread_context_check_rejection (unsigned int flag)
+{
+  return !!(the_tc.flags_reject_non_fips & flag);
+}
+
 void
 _gcry_thread_context_set_fsi (unsigned long fsi)
 {
diff --git a/src/gcrypt-int.h b/src/gcrypt-int.h
index aa49d766..d52a1b1b 100644
--- a/src/gcrypt-int.h
+++ b/src/gcrypt-int.h
@@ -298,6 +298,12 @@ void _gcry_set_log_handler (gcry_handler_log_t f, void *opaque);
 void _gcry_set_gettext_handler (const char *(*f)(const char*));
 void _gcry_set_progress_handler (gcry_handler_progress_t cb, void *cb_data);
 
+void _gcry_thread_context_set_reject (unsigned int flags);
+int _gcry_thread_context_check_rejection (unsigned int flag);
+
+#define fips_check_rejection(flag) \
+  _gcry_thread_context_check_rejection (flag)
+
 void _gcry_thread_context_set_fsi (unsigned long fsi);
 unsigned long _gcry_thread_context_get_fsi (void);
 #define fips_service_indicator_init() do \
@@ -306,7 +312,8 @@ unsigned long _gcry_thread_context_get_fsi (void);
       _gcry_thread_context_set_fsi (0);  \
   } while (0)
 /* Should be used only when fips_mode()==TRUE.  */
-#define fips_service_indicator_mark_non_compliant() _gcry_thread_context_set_fsi (1)
+#define fips_service_indicator_mark_non_compliant() \
+  _gcry_thread_context_set_fsi (1)
 
 /* Return a pointer to a string containing a description of the error
    code in the error value ERR.  */
diff --git a/src/gcrypt.h.in b/src/gcrypt.h.in
index 2ed9914b..4a882c55 100644
--- a/src/gcrypt.h.in
+++ b/src/gcrypt.h.in
@@ -336,7 +336,8 @@ enum gcry_ctl_cmds
     GCRYCTL_FIPS_SERVICE_INDICATOR_MD = 86,
     GCRYCTL_FIPS_SERVICE_INDICATOR_PK_FLAGS = 87,
     GCRYCTL_MD_CUSTOMIZE = 88,
-    GCRYCTL_FIPS_SERVICE_INDICATOR = 89
+    GCRYCTL_FIPS_SERVICE_INDICATOR = 89,
+    GCRYCTL_FIPS_REJECT_NON_FIPS = 90
   };
 
 /* Perform various operations defined by CMD. */
@@ -1979,7 +1980,30 @@ void gcry_log_debugsxp (const char *text, gcry_sexp_t sexp);
 char *gcry_get_config (int mode, const char *what);
 
 /* Convinience macro to access the FIPS service indicator.  */
-#define gcry_get_fips_service_indicator() gcry_control (GCRYCTL_FIPS_SERVICE_INDICATOR)
+#define gcry_get_fips_service_indicator()       \
+  gcry_control (GCRYCTL_FIPS_SERVICE_INDICATOR)
+
+#define GCRY_FIPS_FLAG_REJECT_KDF           (1 << 0)
+#define GCRY_FIPS_FLAG_REJECT_MD_MD5        (1 << 1)
+#define GCRY_FIPS_FLAG_REJECT_MD_OTHERS     (1 << 2)
+#define GCRY_FIPS_FLAG_REJECT_MAC           (1 << 3)
+#define GCRY_FIPS_FLAG_REJECT_CIPHER        (1 << 4)
+#define GCRY_FIPS_FLAG_REJECT_PK            (1 << 5)
+
+#define GCRY_FIPS_FLAG_REJECT_MD \
+  (GCRY_FIPS_FLAG_REJECT_MD_MD5 | GCRY_FIPS_FLAG_REJECT_MD_OTHERS)
+
+/* Note: Don't reject MD5 */
+#define GCRY_FIPS_FLAG_REJECT_COMPAT110 \
+  (GCRY_FIPS_FLAG_REJECT_MD_OTHERS      \
+   | GCRY_FIPS_FLAG_REJECT_MAC          \
+   | GCRY_FIPS_FLAG_REJECT_CIPHER       \
+   | GCRY_FIPS_FLAG_REJECT_KDF          \
+   | GCRY_FIPS_FLAG_REJECT_PK)
+
+#define GCRY_FIPS_FLAG_REJECT_DEFAULT \
+  GCRY_FIPS_FLAG_REJECT_COMPAT110
+
 
 /* Log levels used by the internal logging facility. */
 enum gcry_log_levels
diff --git a/src/global.c b/src/global.c
index ce2541d4..a5a48cb5 100644
--- a/src/global.c
+++ b/src/global.c
@@ -791,6 +791,13 @@ _gcry_vcontrol (enum gcry_ctl_cmds cmd, va_list arg_ptr)
       rc = _gcry_fips_indicator ();
       break;
 
+    case GCRYCTL_FIPS_REJECT_NON_FIPS:
+      {
+        unsigned int flags = va_arg (arg_ptr, unsigned int);
+        _gcry_thread_context_set_reject (flags);
+      }
+      break;
+
     case GCRYCTL_FIPS_SERVICE_INDICATOR_CIPHER:
       /* Get FIPS Service Indicator for a given symmetric algorithm and
        * optional mode. Returns GPG_ERR_NO_ERROR if algorithm is allowed or
diff --git a/tests/t-fips-service-ind.c b/tests/t-fips-service-ind.c
index 9a22d696..d092bfae 100644
--- a/tests/t-fips-service-ind.c
+++ b/tests/t-fips-service-ind.c
@@ -1138,6 +1138,8 @@ main (int argc, char **argv)
   if (debug)
     xgcry_control ((GCRYCTL_SET_DEBUG_FLAGS, 1u , 0));
 
+  xgcry_control ((GCRYCTL_FIPS_REJECT_NON_FIPS, 0));
+
   check_kdf_derive ();
   check_hash_buffer ();
   check_hash_buffers ();
-- 
2.39.5
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.