File libgcrypt-FIPS-SLI-Introduce-GCRYCTL_FIPS_REJECT_NON_FIPS.patch of Package libgcrypt.38414
From e52adf0948c60b2e9accd7996fcece0f9b443763 Mon Sep 17 00:00:00 2001
From: NIIBE Yutaka <gniibe@fsij.org>
Date: Thu, 19 Dec 2024 11:30:28 +0900
Subject: [PATCH 22/24] 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 <gniibe@fsij.org>
Signed-off-by: Lucas Mulling <lucas.mulling@suse.com>
---
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.47.1