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

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

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

Reply via email to