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:
> continue on gcry_pk_hash_* functions.

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

Perhaps, to keep old behavior, we would introduce

	GCRYCTL_FIPS_NO_REJECTION

for a thread (of new code) which wants no-rejection behavior.
--

_______________________________________________
Gcrypt-devel mailing list
[email protected]
https://lists.gnupg.org/mailman/listinfo/gcrypt-devel
0001-fips-md-gcry_md_copy-should-care-about-FIPS-service-.patch (text/x-diff, 2.1 KB)
>From 60db2a175d120aba6818de49638b36006878abf7 Mon Sep 17 00:00:00 2001
From: NIIBE Yutaka <[email protected]>
Date: Wed, 18 Dec 2024 14:14:37 +0900
Subject: [PATCH 1/2] fips,md: gcry_md_copy should care about FIPS service
 indicator.

* cipher/md.c (md_copy): In a case of non-compliant, mark with
fips_service_indicator_mark_non_compliant.
* src/visibility.c (gcry_md_copy): Initialize the indicator.

--

GnuPG-bug-id: 7338
Signed-off-by: NIIBE Yutaka <[email protected]>
---
 cipher/md.c      | 11 +++++++++++
 src/visibility.c |  1 +
 2 files changed, 12 insertions(+)

diff --git a/cipher/md.c b/cipher/md.c
index 666e1dfa..08a564ad 100644
--- a/cipher/md.c
+++ b/cipher/md.c
@@ -673,6 +673,7 @@ md_copy (gcry_md_hd_t ahd, gcry_md_hd_t *b_hd)
   GcryDigestEntry *ar, *br;
   gcry_md_hd_t bhd;
   size_t n;
+  int is_compliant_algo = 1;
 
   if (ahd->bufpos)
     md_write (ahd, NULL, 0);
@@ -699,10 +700,15 @@ md_copy (gcry_md_hd_t ahd, gcry_md_hd_t *b_hd)
   b->list = NULL;
   b->debug = NULL;
 
+  if (!a->list)
+    is_compliant_algo = 0;
+
   /* Copy the complete list of algorithms.  The copied list is
      reversed, but that doesn't matter. */
   for (ar = a->list; ar; ar = ar->next)
     {
+      const gcry_md_spec_t *spec = ar->spec;
+
       if (a->flags.secure)
         br = xtrymalloc_secure (ar->actual_struct_size);
       else
@@ -714,6 +720,8 @@ md_copy (gcry_md_hd_t ahd, gcry_md_hd_t *b_hd)
           goto leave;
         }
 
+      is_compliant_algo &= spec->flags.fips;
+
       memcpy (br, ar, ar->actual_struct_size);
       br->next = b->list;
       b->list = br;
@@ -724,6 +732,9 @@ md_copy (gcry_md_hd_t ahd, gcry_md_hd_t *b_hd)
 
   *b_hd = bhd;
 
+  if (!is_compliant_algo)
+    fips_service_indicator_mark_non_compliant ();
+
  leave:
   return err;
 }
diff --git a/src/visibility.c b/src/visibility.c
index d219f1a6..c9d07f0b 100644
--- a/src/visibility.c
+++ b/src/visibility.c
@@ -1232,6 +1232,7 @@ gcry_md_copy (gcry_md_hd_t *bhd, gcry_md_hd_t ahd)
       *bhd = NULL;
       return gpg_error (fips_not_operational ());
     }
+  fips_service_indicator_init ();
   return gpg_error (_gcry_md_copy (bhd, ahd));
 }
 
-- 
2.39.5
0002-fips-cipher-Implement-FIPS-service-indicator-for-gcr.patch (text/x-diff, 11.8 KB)
>From edb43bc290046bd22548bf69ae2fbeb453112e44 Mon Sep 17 00:00:00 2001
From: NIIBE Yutaka <[email protected]>
Date: Wed, 18 Dec 2024 14:18:26 +0900
Subject: [PATCH 2/2] fips,cipher: Implement FIPS service indicator for
 gcry_pk_hash_ API.

* src/visibility.c (gcry_pk_hash_sign): Initialize the indicator.
(gcry_pk_hash_verify): Likewise.
* tests/t-fips-service-ind.c (check_pk_hash_sign_verify): New.
(main): Call check_pk_hash_sign_verify.
* cipher/ecc-curves.c (_gcry_ecc_fill_in_curve): Don't reject, but
mark non-compliance.
* cipher/pubkey.c (prepare_datasexp_to_be_signed): Likewise.
(_gcry_pk_sign_md, _gcry_pk_verify_md): Likewise.

--

GnuPG-bug-id: 7338
Signed-off-by: NIIBE Yutaka <[email protected]>
---
 cipher/ecc-curves.c        |   2 +-
 cipher/pubkey.c            |  20 ++--
 src/visibility.c           |   2 +
 tests/t-fips-service-ind.c | 209 +++++++++++++++++++++++++++++++++++++
 4 files changed, 222 insertions(+), 11 deletions(-)

diff --git a/cipher/ecc-curves.c b/cipher/ecc-curves.c
index 17fa5505..ddf9cbe1 100644
--- a/cipher/ecc-curves.c
+++ b/cipher/ecc-curves.c
@@ -645,7 +645,7 @@ _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 )
-    return GPG_ERR_NOT_SUPPORTED;
+    fips_service_indicator_mark_non_compliant ();
 
   switch (domain_parms[idx].model)
     {
diff --git a/cipher/pubkey.c b/cipher/pubkey.c
index 214bd611..e2e54199 100644
--- a/cipher/pubkey.c
+++ b/cipher/pubkey.c
@@ -510,10 +510,7 @@ 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)
-        {
-          _gcry_md_close (hd);
-          return GPG_ERR_DIGEST_ALGO;
-        }
+        fips_service_indicator_mark_non_compliant ();
 
       digest_name = _gcry_md_algo_name (algo);
       digest_size = (int)_gcry_md_get_algo_dlen (algo);
@@ -535,12 +532,13 @@ prepare_datasexp_to_be_signed (const char *tmpl, gcry_md_hd_t hd,
 
       algo = _gcry_md_map_name (digest_name_supplied);
       xfree (digest_name_supplied);
-      if (algo == 0
-          || (fips_mode () && algo == GCRY_MD_SHA1))
+      if (algo == 0)
 	{
 	  _gcry_md_close (hd);
 	  return GPG_ERR_DIGEST_ALGO;
 	}
+      else if (fips_mode () && algo == GCRY_MD_SHA1)
+        fips_service_indicator_mark_non_compliant ();
 
       digest_size = (int)_gcry_md_get_algo_dlen (algo);
       digest = _gcry_md_read (hd, algo);
@@ -613,10 +611,11 @@ _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 ())
-    rc = GPG_ERR_PUBKEY_ALGO;
   else if (spec->sign)
     rc = spec->sign (r_sig, s_data, keyparms);
   else
@@ -690,10 +689,11 @@ _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 ())
-    rc = GPG_ERR_PUBKEY_ALGO;
   else if (spec->verify)
     rc = spec->verify (s_sig, s_data, keyparms);
   else
diff --git a/src/visibility.c b/src/visibility.c
index c9d07f0b..d22c8b59 100644
--- a/src/visibility.c
+++ b/src/visibility.c
@@ -1056,6 +1056,7 @@ gcry_pk_hash_sign (gcry_sexp_t *result, const char *data_tmpl, gcry_sexp_t skey,
       *result = NULL;
       return gpg_error (fips_not_operational ());
     }
+  fips_service_indicator_init ();
   return gpg_error (_gcry_pk_sign_md (result, data_tmpl, hd, skey, ctx));
 }
 
@@ -1073,6 +1074,7 @@ gcry_pk_hash_verify (gcry_sexp_t sigval, const char *data_tmpl, gcry_sexp_t pkey
 {
   if (!fips_is_operational ())
     return gpg_error (fips_not_operational ());
+  fips_service_indicator_init ();
   return gpg_error (_gcry_pk_verify_md (sigval, data_tmpl, hd, pkey, ctx));
 }
 
diff --git a/tests/t-fips-service-ind.c b/tests/t-fips-service-ind.c
index 4b13436f..9a22d696 100644
--- a/tests/t-fips-service-ind.c
+++ b/tests/t-fips-service-ind.c
@@ -29,6 +29,7 @@
 
 #define PGM "t-fips-service-ind"
 
+#define NEED_HEX2BUFFER
 #include "t-common.h"
 static int in_fips_mode;
 #define MAX_DATA_LEN 1040
@@ -39,6 +40,213 @@ static int in_fips_mode;
 # include <windows.h>
 #endif
 
+/* Check gcry_pk_hash_sign, gcry_pk_hash_verify API.  */
+static void
+check_pk_hash_sign_verify (void)
+{
+  static struct {
+    int md_algo;
+    const char *prvkey;
+    const char *pubkey;
+    const char *data_tmpl;
+    const char *k;
+    int expect_failure;
+    int expect_failure_hash;
+  } tv[] = {
+    {                           /* non-compliant hash */
+      GCRY_MD_BLAKE2B_512,
+      "(private-key (ecc (curve nistp256)"
+      " (d #519b423d715f8b581f4fa8ee59f4771a5b44c8130b4e3eacca54a56dda72b464#)))",
+      "(public-key (ecc (curve nistp256)"
+      " (q #041ccbe91c075fc7f4f033bfa248db8fccd3565de94bbfb12f3c59ff46c271bf83"
+      "ce4014c68811f9a21a1fdb2c0e6113e06db7ca93b7404e78dc7ccd5ca89a4ca9#)))",
+      "(data(flags raw)(hash %s %b)(label %b))",
+      "94a1bbb14b906a61a280f245f9e93c7f3b4a6247824f5d33b9670787642a68de",
+      1, 1
+    },
+    {                           /* non-compliant curve */
+      GCRY_MD_SHA256,
+      "(private-key (ecc (curve secp256k1)"
+      " (d #c2cdf0a8b0a83b35ace53f097b5e6e6a0a1f2d40535eff1cf434f52a43d59d8f#)))",
+
+      "(public-key (ecc (curve secp256k1)"
+      " (q #046fcc37ea5e9e09fec6c83e5fbd7a745e3eee81d16ebd861c9e66f55518c19798"
+      "4e9f113c07f875691df8afc1029496fc4cb9509b39dcd38f251a83359cc8b4f7#)))",
+      "(data(flags raw)(hash %s %b)(label %b))",
+      "94a1bbb14b906a61a280f245f9e93c7f3b4a6247824f5d33b9670787642a68de",
+      1, 0
+    },
+    {
+      GCRY_MD_SHA256,
+      "(private-key (ecc (curve nistp256)"
+      " (d #519b423d715f8b581f4fa8ee59f4771a5b44c8130b4e3eacca54a56dda72b464#)))",
+      "(public-key (ecc (curve nistp256)"
+      " (q #041ccbe91c075fc7f4f033bfa248db8fccd3565de94bbfb12f3c59ff46c271bf83"
+      "ce4014c68811f9a21a1fdb2c0e6113e06db7ca93b7404e78dc7ccd5ca89a4ca9#)))",
+      "(data(flags raw)(hash %s %b)(label %b))",
+      "94a1bbb14b906a61a280f245f9e93c7f3b4a6247824f5d33b9670787642a68de",
+      0, 0
+    }
+  };
+  int tvidx;
+  gpg_error_t err;
+  gpg_err_code_t ec;
+  const char *msg = "Takerufuji Mikiya, who won the championship in March 2024";
+  int msglen;
+
+  msglen = strlen (msg);
+  for (tvidx=0; tvidx < DIM(tv); tvidx++)
+    {
+      gcry_md_hd_t hd = NULL;
+      gcry_sexp_t s_sk = NULL;
+      gcry_sexp_t s_pk = NULL;
+      void *buffer = NULL;
+      size_t buflen;
+      gcry_ctx_t ctx = NULL;
+      gcry_sexp_t s_sig= NULL;
+
+      if (verbose)
+        info ("checking gcry_pk_hash_ test %d\n", tvidx);
+
+      err = gcry_md_open (&hd, tv[tvidx].md_algo, 0);
+      if (err)
+        {
+          fail ("algo %d, gcry_md_open failed: %s\n", tv[tvidx].md_algo,
+                gpg_strerror (err));
+          goto next;
+        }
+
+      ec = gcry_get_fips_service_indicator ();
+      if (ec == GPG_ERR_INV_OP)
+        {
+          /* libgcrypt is old, no support of the FIPS service indicator.  */
+          fail ("gcry_pk_hash test %d unexpectedly failed to check the FIPS service indicator.\n",
+                tvidx);
+          goto next;
+        }
+
+      if (in_fips_mode && !tv[tvidx].expect_failure_hash && ec)
+        {
+          /* Success with the FIPS service indicator == 0 expected, but != 0.  */
+          fail ("gcry_pk_hash test %d unexpectedly set the indicator in FIPS mode.\n",
+                tvidx);
+          goto next;
+        }
+      else if (in_fips_mode && tv[tvidx].expect_failure_hash && !ec)
+        {
+          /* Success with the FIPS service indicator != 0 expected, but == 0.  */
+          fail ("gcry_pk_hash test %d unexpectedly cleared the indicator in FIPS mode.\n",
+                tvidx);
+          goto next;
+        }
+
+      err = gcry_sexp_build (&s_sk, NULL, tv[tvidx].prvkey);
+      if (err)
+        {
+          fail ("error building SEXP for test, %s: %s",
+                "sk", gpg_strerror (err));
+          goto next;
+        }
+
+      err = gcry_sexp_build (&s_pk, NULL, tv[tvidx].pubkey);
+      if (err)
+        {
+          fail ("error building SEXP for test, %s: %s",
+                "pk", gpg_strerror (err));
+          goto next;
+        }
+
+      if (!(buffer = hex2buffer (tv[tvidx].k, &buflen)))
+        {
+          fail ("error parsing for test, %s: %s",
+                "msg", "invalid hex string");
+          goto next;
+        }
+
+      err = gcry_pk_random_override_new (&ctx, buffer, buflen);
+      if (err)
+        {
+          fail ("error setting 'k' for test: %s",
+                gpg_strerror (err));
+          goto next;
+        }
+
+      gcry_md_write (hd, msg, msglen);
+
+      err = gcry_pk_hash_sign (&s_sig, tv[tvidx].data_tmpl, s_sk, hd, ctx);
+      if (err)
+        {
+          fail ("gcry_pk_hash_sign failed: %s", gpg_strerror (err));
+          goto next;
+        }
+
+      ec = gcry_get_fips_service_indicator ();
+      if (ec == GPG_ERR_INV_OP)
+        {
+          /* libgcrypt is old, no support of the FIPS service indicator.  */
+          fail ("gcry_pk_hash test %d unexpectedly failed to check the FIPS service indicator.\n",
+                tvidx);
+          goto next;
+        }
+
+      if (in_fips_mode && !tv[tvidx].expect_failure && ec)
+        {
+          /* Success with the FIPS service indicator == 0 expected, but != 0.  */
+          fail ("gcry_pk_hash test %d unexpectedly set the indicator in FIPS mode.\n",
+                tvidx);
+          goto next;
+        }
+      else if (in_fips_mode && tv[tvidx].expect_failure && !ec)
+        {
+          /* Success with the FIPS service indicator != 0 expected, but == 0.  */
+          fail ("gcry_pk_hash_sign test %d unexpectedly cleared the indicator in FIPS mode.\n",
+                tvidx);
+          goto next;
+        }
+
+      err = gcry_pk_hash_verify (s_sig, tv[tvidx].data_tmpl, s_pk, hd, ctx);
+      if (err)
+        {
+          fail ("gcry_pk_hash_verify failed for test: %s",
+                gpg_strerror (err));
+          goto next;
+        }
+
+      ec = gcry_get_fips_service_indicator ();
+      if (ec == GPG_ERR_INV_OP)
+        {
+          /* libgcrypt is old, no support of the FIPS service indicator.  */
+          fail ("gcry_pk_hash test %d unexpectedly failed to check the FIPS service indicator.\n",
+                tvidx);
+          goto next;
+        }
+
+      if (in_fips_mode && !tv[tvidx].expect_failure && ec)
+        {
+          /* Success with the FIPS service indicator == 0 expected, but != 0.  */
+          fail ("gcry_pk_hash test %d unexpectedly set the indicator in FIPS mode.\n",
+                tvidx);
+          goto next;
+        }
+      else if (in_fips_mode && tv[tvidx].expect_failure && !ec)
+        {
+          /* Success with the FIPS service indicator != 0 expected, but == 0.  */
+          fail ("gcry_pk_hash_verify test %d unexpectedly cleared the indicator in FIPS mode.\n",
+                tvidx);
+          goto next;
+        }
+
+    next:
+      gcry_sexp_release (s_sig);
+      xfree (buffer);
+      gcry_ctx_release (ctx);
+      gcry_sexp_release (s_pk);
+      gcry_sexp_release (s_sk);
+      if (hd)
+        gcry_md_close (hd);
+    }
+}
+
 /* Check gcry_cipher_open, gcry_cipher_setkey, gcry_cipher_encrypt,
    gcry_cipher_decrypt, gcry_cipher_close API.  */
 static void
@@ -936,6 +1144,7 @@ main (int argc, char **argv)
   check_md_o_w_r_c ();
   check_mac_o_w_r_c ();
   check_cipher_o_s_e_d_c ();
+  check_pk_hash_sign_verify ();
 
   return !!error_count;
 }
-- 
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.