[PATCH] cipher: Check and mark non-compliant cipher modes in the SLI

Lucas Mulling via Gcrypt-devel <[email protected]>
Newsgroups gmane.comp.encryption.gpg.libgcrypt.devel
Message-ID <CAK8Nc5NYMET_3Xr9s8wmu++c0-+LPTLTdvvwCRCuyqDCSczZLg@mail.gmail.com>
Hello,

Attached patch.

Best,
Lucas Mülling

_______________________________________________
Gcrypt-devel mailing list
[email protected]
https://lists.gnupg.org/mailman/listinfo/gcrypt-devel
0001-cipher-Check-and-mark-non-compliant-cipher-modes-in-the-SLI.patch (text/x-patch, 7.6 KB)
From 5e7f85294c1ecd6b16947a3049cec91497ec9aea Mon Sep 17 00:00:00 2001
From: Lucas Mulling <[email protected]>
Date: Fri, 24 Jan 2025 09:57:49 -0300
Subject: [PATCH] cipher: Check and mark non-compliant cipher modes in the SLI

* cipher/cipher.c (_gcry_cipher_open_internal): Check and mark if the
cipher mode is compliant and reject accordingly.
(_gcry_cipher_is_mode_fips_compliant): New.
* src/gcrypt.h.in (GCRY_FIPS_FLAG_REJECT_CIPHER_MODE): New.
* tests/t-fips-service-ind.c (check_cipher_o_s_e_d_c): Add test to
verify that the service level indication is correctly set for non-
compliant cipher modes, and correctly rejected if
GCRY_FIPS_FLAG_REJECT_CIPHER_MODE is set.

Signed-off-by: Lucas Mulling <[email protected]>
---
 cipher/cipher.c            | 43 ++++++++++++++++++----
 src/gcrypt.h.in            |  1 +
 tests/t-fips-service-ind.c | 74 +++++++++++++++++++++++++++++++++-----
 3 files changed, 104 insertions(+), 14 deletions(-)

diff --git a/cipher/cipher.c b/cipher/cipher.c
index 74dc2df7..b5420671 100644
--- a/cipher/cipher.c
+++ b/cipher/cipher.c
@@ -504,6 +504,26 @@ _gcry_cipher_open (gcry_cipher_hd_t *handle,
   return rc;
 }
 
+int
+_gcry_cipher_is_mode_fips_compliant(int mode)
+{
+  switch (mode)
+    {
+    case GCRY_CIPHER_MODE_ECB:
+    case GCRY_CIPHER_MODE_CBC:
+    case GCRY_CIPHER_MODE_CFB:
+    case GCRY_CIPHER_MODE_CFB8:
+    case GCRY_CIPHER_MODE_OFB:
+    case GCRY_CIPHER_MODE_CTR:
+    case GCRY_CIPHER_MODE_CCM:
+    case GCRY_CIPHER_MODE_XTS:
+    case GCRY_CIPHER_MODE_AESWRAP:
+      return GPG_ERR_NO_ERROR;
+    default:
+      return GPG_ERR_NOT_SUPPORTED;
+    }
+}
+
 
 gcry_err_code_t
 _gcry_cipher_open_internal (gcry_cipher_hd_t *handle,
@@ -523,14 +543,25 @@ _gcry_cipher_open_internal (gcry_cipher_hd_t *handle,
     err = GPG_ERR_CIPHER_ALGO;
   else if (spec->flags.disabled)
     err = GPG_ERR_CIPHER_ALGO;
-  else if (!spec->flags.fips && fips_mode ())
+  else if (fips_mode ())
     {
-      if (fips_check_rejection (GCRY_FIPS_FLAG_REJECT_CIPHER))
-        err = GPG_ERR_CIPHER_ALGO;
-      else
+      if (!spec->flags.fips)
         {
-          fips_service_indicator_mark_non_compliant ();
-          err = 0;
+          if (fips_check_rejection (GCRY_FIPS_FLAG_REJECT_CIPHER))
+            err = GPG_ERR_CIPHER_ALGO;
+          else
+            {
+              fips_service_indicator_mark_non_compliant ();
+              err = 0;
+            }
+        }
+      else if ((err = _gcry_cipher_is_mode_fips_compliant(mode)))
+        {
+          if (!fips_check_rejection (GCRY_FIPS_FLAG_REJECT_CIPHER_MODE))
+            {
+              fips_service_indicator_mark_non_compliant ();
+              err = 0;
+            }
         }
     }
   else
diff --git a/src/gcrypt.h.in b/src/gcrypt.h.in
index fcb6a327..1a6f7269 100644
--- a/src/gcrypt.h.in
+++ b/src/gcrypt.h.in
@@ -1988,6 +1988,7 @@ char *gcry_get_config (int mode, const char *what);
 #define GCRY_FIPS_FLAG_REJECT_PK            (1 << 5)
 #define GCRY_FIPS_FLAG_REJECT_PK_MD         (1 << 6)
 #define GCRY_FIPS_FLAG_REJECT_PK_GOST_SM2   (1 << 7)
+#define GCRY_FIPS_FLAG_REJECT_CIPHER_MODE   (1 << 8)
 
 #define GCRY_FIPS_FLAG_REJECT_MD \
   (GCRY_FIPS_FLAG_REJECT_MD_MD5 | GCRY_FIPS_FLAG_REJECT_MD_OTHERS)
diff --git a/tests/t-fips-service-ind.c b/tests/t-fips-service-ind.c
index fe963fa5..74521bb3 100644
--- a/tests/t-fips-service-ind.c
+++ b/tests/t-fips-service-ind.c
@@ -606,27 +606,41 @@ check_cipher_o_s_e_d_c (int reject)
 {
   static struct {
     int algo;
+    int mode;
     const char *key;
     int keylen;
+    const char *tag;
+    int taglen;
     const char *expect;
     int expect_failure;
   } tv[] = {
 #if USE_DES
-      { GCRY_CIPHER_3DES,
-	"\xe3\x34\x7a\x6b\x0b\xc1\x15\x2c\x64\x2a\x25\xcb\xd3\xbc\x31\xab"
-	"\xfb\xa1\x62\xa8\x1f\x19\x7c\x15", 24,
-        "\x3f\x1a\xb8\x83\x18\x8b\xb5\x97", 1 },
+   { GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_ECB,
+	 "\xe3\x34\x7a\x6b\x0b\xc1\x15\x2c\x64\x2a\x25\xcb\xd3\xbc\x31\xab"
+	 "\xfb\xa1\x62\xa8\x1f\x19\x7c\x15", 24,
+     "", -1,
+     "\x3f\x1a\xb8\x83\x18\x8b\xb5\x97", 1 },
 #endif
-      { GCRY_CIPHER_AES,
-	"\x2b\x7e\x15\x16\x28\xae\xd2\xa6\xab\xf7\x15\x88\x09\xcf\x4f\x3c", 16,
-        "\x5c\x71\xd8\x5d\x26\x5e\xcd\xb5\x95\x40\x41\xab\xff\x25\x6f\xd1" }
+   { GCRY_CIPHER_AES, GCRY_CIPHER_MODE_ECB,
+	 "\x2b\x7e\x15\x16\x28\xae\xd2\xa6\xab\xf7\x15\x88\x09\xcf\x4f\x3c", 16,
+     "", -1,
+     "\x5c\x71\xd8\x5d\x26\x5e\xcd\xb5\x95\x40\x41\xab\xff\x25\x6f\xd1" },
+   { GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_SIV,
+	 "\xff\xfe\xfd\xfc\xfb\xfa\xf9\xf8\xf7\xf6\xf5\xf4\xf3\xf2\xf1\xf0"
+	 "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff", 32,
+     "\x51\x66\x54\xc4\xe1\xb5\xd9\x37\x31\x52\xdb\xea\x35\x10\x8b\x7b", 16,
+     "\x83\x69\xf6\xf3\x20\xff\xa2\x72\x31\x67\x15\xcf\xf4\x75\x01\x9a", 1 }
   };
+
   const char *pt = "Shohei Ohtani 2024: 54 HR, 59 SB";
   int ptlen;
   int tvidx;
   unsigned char out[MAX_DATA_LEN];
   gpg_error_t err;
 
+  unsigned char tag[16];
+  size_t taglen = 0;
+
   ptlen = strlen (pt);
   assert (ptlen == 32);
   for (tvidx=0; tvidx < DIM(tv); tvidx++)
@@ -640,10 +654,12 @@ check_cipher_o_s_e_d_c (int reject)
                  tvidx);
 
       blklen = gcry_cipher_get_algo_blklen (tv[tvidx].algo);
+
       assert (blklen != 0);
       assert (blklen <= ptlen);
       assert (blklen <= DIM (out));
-      err = gcry_cipher_open (&h, tv[tvidx].algo, GCRY_CIPHER_MODE_ECB, 0);
+      assert (tv[tvidx].taglen <= 16);
+      err = gcry_cipher_open (&h, tv[tvidx].algo, tv[tvidx].mode, 0);
       if (err)
         {
           if (in_fips_mode && reject && tv[tvidx].expect_failure)
@@ -694,6 +710,18 @@ check_cipher_o_s_e_d_c (int reject)
           continue;
         }
 
+      if (tv[tvidx].taglen >= 0)
+        {
+          err = gcry_cipher_info (h, GCRYCTL_GET_TAGLEN, NULL, &taglen);
+          if (err)
+              fail ("gcry_cipher_info %d failed: %s\n", tvidx,
+                    gpg_strerror (err));
+
+          if (taglen != tv[tvidx].taglen)
+              fail ("gcry_cipher_info %d failed: taglen mismatch %d != %ld\n", tvidx,
+                    tv[tvidx].taglen, taglen);
+        }
+
       err = gcry_cipher_encrypt (h, out, MAX_DATA_LEN, pt, blklen);
       if (err)
         {
@@ -714,6 +742,35 @@ check_cipher_o_s_e_d_c (int reject)
           putc ('\n', stderr);
         }
 
+      if (tv[tvidx].taglen >= 0)
+        {
+           err = gcry_cipher_gettag (h, tag, tv[tvidx].taglen);
+           if (err)
+              fail ("gcry_cipher_gettag %d failed: %s", tvidx,
+                     gpg_strerror(err));
+
+          if (memcmp (tv[tvidx].tag, tag, tv[tvidx].taglen))
+            {
+              int i;
+
+              fail ("gcry_cipher_gettag %d: tag mismatch\n", tvidx);
+              fputs ("got:", stderr);
+              for (i=0; i < 16 ; i++)
+                fprintf (stderr, " %02x", tag[i]);
+              putc ('\n', stderr);
+            }
+
+          err = gcry_cipher_reset (h);
+          if (err)
+            fail("gcry_cipher_reset %d failed: %s", tvidx,
+                  gpg_strerror(err));
+
+          err = gcry_cipher_set_decryption_tag (h, tag, 16);
+          if (err)
+            fail ("gcry_cipher_set_decryption_tag %d failed: %s\n", tvidx<
+                   gpg_strerror (err));
+      }
+
       err = gcry_cipher_decrypt (h, out, blklen, NULL, 0);
       if (err)
         {
@@ -1483,6 +1540,7 @@ main (int argc, char **argv)
 
   xgcry_control ((GCRYCTL_FIPS_REJECT_NON_FIPS,
                   (GCRY_FIPS_FLAG_REJECT_MD_MD5
+                   | GCRY_FIPS_FLAG_REJECT_CIPHER_MODE
                    | GCRY_FIPS_FLAG_REJECT_PK_MD
                    | GCRY_FIPS_FLAG_REJECT_PK_GOST_SM2
                    | GCRY_FIPS_FLAG_REJECT_COMPAT110)));
-- 
2.48.1
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.