NIIBE Yutaka <gni...@fsij.org> 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.
-- 
>From e52adf0948c60b2e9accd7996fcece0f9b443763 Mon Sep 17 00:00:00 2001
From: NIIBE Yutaka <gni...@fsij.org>
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 <gni...@fsij.org>
---
 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

_______________________________________________
Gcrypt-devel mailing list
Gcrypt-devel@gnupg.org
https://lists.gnupg.org/mailman/listinfo/gcrypt-devel

Reply via email to