587dbb
From ff90bb8474b1e724727f4014b446e7c851e609bd Mon Sep 17 00:00:00 2001
587dbb
From: Colin Walters <walters@verbum.org>
587dbb
Date: Fri, 7 Jun 2019 18:44:43 +0000
587dbb
Subject: [PATCH 1/4] ghmac: Split off wrapper functions into ghmac-utils.c
587dbb
587dbb
Prep for adding a GnuTLS HMAC implementation; these are just
587dbb
utility functions that call the "core" API.
587dbb
---
587dbb
 glib/ghmac-utils.c | 145 +++++++++++++++++++++++++++++++++++++++++++++
587dbb
 glib/ghmac.c       | 112 ----------------------------------
587dbb
 glib/meson.build   |   1 +
587dbb
 3 files changed, 146 insertions(+), 112 deletions(-)
587dbb
 create mode 100644 glib/ghmac-utils.c
587dbb
587dbb
diff --git a/glib/ghmac-utils.c b/glib/ghmac-utils.c
587dbb
new file mode 100644
587dbb
index 000000000..a17359ff1
587dbb
--- /dev/null
587dbb
+++ b/glib/ghmac-utils.c
587dbb
@@ -0,0 +1,145 @@
587dbb
+/* ghmac.h - data hashing functions
587dbb
+ *
587dbb
+ * Copyright (C) 2011  Collabora Ltd.
587dbb
+ * Copyright (C) 2019  Red Hat, Inc.
587dbb
+ *
587dbb
+ * This library is free software; you can redistribute it and/or
587dbb
+ * modify it under the terms of the GNU Lesser General Public
587dbb
+ * License as published by the Free Software Foundation; either
587dbb
+ * version 2.1 of the License, or (at your option) any later version.
587dbb
+ *
587dbb
+ * This library is distributed in the hope that it will be useful,
587dbb
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
587dbb
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
587dbb
+ * Lesser General Public License for more details.
587dbb
+ *
587dbb
+ * You should have received a copy of the GNU Lesser General Public License
587dbb
+ * along with this library; if not, see <http://www.gnu.org/licenses/>.
587dbb
+ */
587dbb
+
587dbb
+#include "config.h"
587dbb
+
587dbb
+#include <string.h>
587dbb
+
587dbb
+#include "ghmac.h"
587dbb
+
587dbb
+#include "glib/galloca.h"
587dbb
+#include "gatomic.h"
587dbb
+#include "gslice.h"
587dbb
+#include "gmem.h"
587dbb
+#include "gstrfuncs.h"
587dbb
+#include "gtestutils.h"
587dbb
+#include "gtypes.h"
587dbb
+#include "glibintl.h"
587dbb
+
587dbb
+/**
587dbb
+ * g_compute_hmac_for_data:
587dbb
+ * @digest_type: a #GChecksumType to use for the HMAC
587dbb
+ * @key: (array length=key_len): the key to use in the HMAC
587dbb
+ * @key_len: the length of the key
587dbb
+ * @data: (array length=length): binary blob to compute the HMAC of
587dbb
+ * @length: length of @data
587dbb
+ *
587dbb
+ * Computes the HMAC for a binary @data of @length. This is a
587dbb
+ * convenience wrapper for g_hmac_new(), g_hmac_get_string()
587dbb
+ * and g_hmac_unref().
587dbb
+ *
587dbb
+ * The hexadecimal string returned will be in lower case.
587dbb
+ *
587dbb
+ * Returns: the HMAC of the binary data as a string in hexadecimal.
587dbb
+ *   The returned string should be freed with g_free() when done using it.
587dbb
+ *
587dbb
+ * Since: 2.30
587dbb
+ */
587dbb
+gchar *
587dbb
+g_compute_hmac_for_data (GChecksumType  digest_type,
587dbb
+                         const guchar  *key,
587dbb
+                         gsize          key_len,
587dbb
+                         const guchar  *data,
587dbb
+                         gsize          length)
587dbb
+{
587dbb
+  GHmac *hmac;
587dbb
+  gchar *retval;
587dbb
+
587dbb
+  g_return_val_if_fail (length == 0 || data != NULL, NULL);
587dbb
+
587dbb
+  hmac = g_hmac_new (digest_type, key, key_len);
587dbb
+  if (!hmac)
587dbb
+    return NULL;
587dbb
+
587dbb
+  g_hmac_update (hmac, data, length);
587dbb
+  retval = g_strdup (g_hmac_get_string (hmac));
587dbb
+  g_hmac_unref (hmac);
587dbb
+
587dbb
+  return retval;
587dbb
+}
587dbb
+
587dbb
+/**
587dbb
+ * g_compute_hmac_for_bytes:
587dbb
+ * @digest_type: a #GChecksumType to use for the HMAC
587dbb
+ * @key: the key to use in the HMAC
587dbb
+ * @data: binary blob to compute the HMAC of
587dbb
+ *
587dbb
+ * Computes the HMAC for a binary @data. This is a
587dbb
+ * convenience wrapper for g_hmac_new(), g_hmac_get_string()
587dbb
+ * and g_hmac_unref().
587dbb
+ *
587dbb
+ * The hexadecimal string returned will be in lower case.
587dbb
+ *
587dbb
+ * Returns: the HMAC of the binary data as a string in hexadecimal.
587dbb
+ *   The returned string should be freed with g_free() when done using it.
587dbb
+ *
587dbb
+ * Since: 2.50
587dbb
+ */
587dbb
+gchar *
587dbb
+g_compute_hmac_for_bytes (GChecksumType  digest_type,
587dbb
+                          GBytes        *key,
587dbb
+                          GBytes        *data)
587dbb
+{
587dbb
+  gconstpointer byte_data;
587dbb
+  gsize length;
587dbb
+  gconstpointer key_data;
587dbb
+  gsize key_len;
587dbb
+
587dbb
+  g_return_val_if_fail (data != NULL, NULL);
587dbb
+  g_return_val_if_fail (key != NULL, NULL);
587dbb
+
587dbb
+  byte_data = g_bytes_get_data (data, &length);
587dbb
+  key_data = g_bytes_get_data (key, &key_len);
587dbb
+  return g_compute_hmac_for_data (digest_type, key_data, key_len, byte_data, length);
587dbb
+}
587dbb
+
587dbb
+
587dbb
+/**
587dbb
+ * g_compute_hmac_for_string:
587dbb
+ * @digest_type: a #GChecksumType to use for the HMAC
587dbb
+ * @key: (array length=key_len): the key to use in the HMAC
587dbb
+ * @key_len: the length of the key
587dbb
+ * @str: the string to compute the HMAC for
587dbb
+ * @length: the length of the string, or -1 if the string is nul-terminated
587dbb
+ *
587dbb
+ * Computes the HMAC for a string.
587dbb
+ *
587dbb
+ * The hexadecimal string returned will be in lower case.
587dbb
+ *
587dbb
+ * Returns: the HMAC as a hexadecimal string.
587dbb
+ *     The returned string should be freed with g_free()
587dbb
+ *     when done using it.
587dbb
+ *
587dbb
+ * Since: 2.30
587dbb
+ */
587dbb
+gchar *
587dbb
+g_compute_hmac_for_string (GChecksumType  digest_type,
587dbb
+                           const guchar  *key,
587dbb
+                           gsize          key_len,
587dbb
+                           const gchar   *str,
587dbb
+                           gssize         length)
587dbb
+{
587dbb
+  g_return_val_if_fail (length == 0 || str != NULL, NULL);
587dbb
+
587dbb
+  if (length < 0)
587dbb
+    length = strlen (str);
587dbb
+
587dbb
+  return g_compute_hmac_for_data (digest_type, key, key_len,
587dbb
+                                  (const guchar *) str, length);
587dbb
+}
587dbb
diff --git a/glib/ghmac.c b/glib/ghmac.c
587dbb
index 49fd272f0..4f181f21f 100644
587dbb
--- a/glib/ghmac.c
587dbb
+++ b/glib/ghmac.c
587dbb
@@ -329,115 +329,3 @@ g_hmac_get_digest (GHmac  *hmac,
587dbb
   g_checksum_update (hmac->digesto, buffer, len);
587dbb
   g_checksum_get_digest (hmac->digesto, buffer, digest_len);
587dbb
 }
587dbb
-
587dbb
-/**
587dbb
- * g_compute_hmac_for_data:
587dbb
- * @digest_type: a #GChecksumType to use for the HMAC
587dbb
- * @key: (array length=key_len): the key to use in the HMAC
587dbb
- * @key_len: the length of the key
587dbb
- * @data: (array length=length): binary blob to compute the HMAC of
587dbb
- * @length: length of @data
587dbb
- *
587dbb
- * Computes the HMAC for a binary @data of @length. This is a
587dbb
- * convenience wrapper for g_hmac_new(), g_hmac_get_string()
587dbb
- * and g_hmac_unref().
587dbb
- *
587dbb
- * The hexadecimal string returned will be in lower case.
587dbb
- *
587dbb
- * Returns: the HMAC of the binary data as a string in hexadecimal.
587dbb
- *   The returned string should be freed with g_free() when done using it.
587dbb
- *
587dbb
- * Since: 2.30
587dbb
- */
587dbb
-gchar *
587dbb
-g_compute_hmac_for_data (GChecksumType  digest_type,
587dbb
-                         const guchar  *key,
587dbb
-                         gsize          key_len,
587dbb
-                         const guchar  *data,
587dbb
-                         gsize          length)
587dbb
-{
587dbb
-  GHmac *hmac;
587dbb
-  gchar *retval;
587dbb
-
587dbb
-  g_return_val_if_fail (length == 0 || data != NULL, NULL);
587dbb
-
587dbb
-  hmac = g_hmac_new (digest_type, key, key_len);
587dbb
-  if (!hmac)
587dbb
-    return NULL;
587dbb
-
587dbb
-  g_hmac_update (hmac, data, length);
587dbb
-  retval = g_strdup (g_hmac_get_string (hmac));
587dbb
-  g_hmac_unref (hmac);
587dbb
-
587dbb
-  return retval;
587dbb
-}
587dbb
-
587dbb
-/**
587dbb
- * g_compute_hmac_for_bytes:
587dbb
- * @digest_type: a #GChecksumType to use for the HMAC
587dbb
- * @key: the key to use in the HMAC
587dbb
- * @data: binary blob to compute the HMAC of
587dbb
- *
587dbb
- * Computes the HMAC for a binary @data. This is a
587dbb
- * convenience wrapper for g_hmac_new(), g_hmac_get_string()
587dbb
- * and g_hmac_unref().
587dbb
- *
587dbb
- * The hexadecimal string returned will be in lower case.
587dbb
- *
587dbb
- * Returns: the HMAC of the binary data as a string in hexadecimal.
587dbb
- *   The returned string should be freed with g_free() when done using it.
587dbb
- *
587dbb
- * Since: 2.50
587dbb
- */
587dbb
-gchar *
587dbb
-g_compute_hmac_for_bytes (GChecksumType  digest_type,
587dbb
-                          GBytes        *key,
587dbb
-                          GBytes        *data)
587dbb
-{
587dbb
-  gconstpointer byte_data;
587dbb
-  gsize length;
587dbb
-  gconstpointer key_data;
587dbb
-  gsize key_len;
587dbb
-
587dbb
-  g_return_val_if_fail (data != NULL, NULL);
587dbb
-  g_return_val_if_fail (key != NULL, NULL);
587dbb
-
587dbb
-  byte_data = g_bytes_get_data (data, &length);
587dbb
-  key_data = g_bytes_get_data (key, &key_len);
587dbb
-  return g_compute_hmac_for_data (digest_type, key_data, key_len, byte_data, length);
587dbb
-}
587dbb
-
587dbb
-
587dbb
-/**
587dbb
- * g_compute_hmac_for_string:
587dbb
- * @digest_type: a #GChecksumType to use for the HMAC
587dbb
- * @key: (array length=key_len): the key to use in the HMAC
587dbb
- * @key_len: the length of the key
587dbb
- * @str: the string to compute the HMAC for
587dbb
- * @length: the length of the string, or -1 if the string is nul-terminated
587dbb
- *
587dbb
- * Computes the HMAC for a string.
587dbb
- *
587dbb
- * The hexadecimal string returned will be in lower case.
587dbb
- *
587dbb
- * Returns: the HMAC as a hexadecimal string.
587dbb
- *     The returned string should be freed with g_free()
587dbb
- *     when done using it.
587dbb
- *
587dbb
- * Since: 2.30
587dbb
- */
587dbb
-gchar *
587dbb
-g_compute_hmac_for_string (GChecksumType  digest_type,
587dbb
-                           const guchar  *key,
587dbb
-                           gsize          key_len,
587dbb
-                           const gchar   *str,
587dbb
-                           gssize         length)
587dbb
-{
587dbb
-  g_return_val_if_fail (length == 0 || str != NULL, NULL);
587dbb
-
587dbb
-  if (length < 0)
587dbb
-    length = strlen (str);
587dbb
-
587dbb
-  return g_compute_hmac_for_data (digest_type, key, key_len,
587dbb
-                                  (const guchar *) str, length);
587dbb
-}
587dbb
diff --git a/glib/meson.build b/glib/meson.build
587dbb
index 8c18e6de4..329b8d197 100644
587dbb
--- a/glib/meson.build
587dbb
+++ b/glib/meson.build
587dbb
@@ -253,6 +253,7 @@ glib_sources = files(
587dbb
   'ggettext.c',
587dbb
   'ghash.c',
587dbb
   'ghmac.c',
587dbb
+  'ghmac-utils.c',
587dbb
   'ghook.c',
587dbb
   'ghostutils.c',
587dbb
   'giochannel.c',
587dbb
-- 
587dbb
2.31.1
587dbb
587dbb
From 5395d36e6685e0b7377794c59c5820970bb472ef Mon Sep 17 00:00:00 2001
587dbb
From: Colin Walters <walters@verbum.org>
587dbb
Date: Fri, 7 Jun 2019 19:36:54 +0000
587dbb
Subject: [PATCH 2/4] Add a gnutls backend for GHmac
587dbb
587dbb
For RHEL we want apps to use FIPS-certified crypto libraries,
587dbb
and HMAC apparently counts as "keyed" and hence needs to
587dbb
be validated.
587dbb
587dbb
Bug: https://bugzilla.redhat.com/show_bug.cgi?id=1630260
587dbb
Replaces: https://gitlab.gnome.org/GNOME/glib/merge_requests/897
587dbb
587dbb
This is a build-time option that backs the GHmac API with GnuTLS.
587dbb
Most distributors ship glib-networking built with GnuTLS, and
587dbb
most apps use glib-networking, so this isn't a net-new library
587dbb
in most cases.
587dbb
587dbb
=======================================================================
587dbb
587dbb
mcatanzaro note:
587dbb
587dbb
I've updated Colin's original patch with several enhancements:
587dbb
587dbb
Implement g_hmac_copy() using gnutls_hmac_copy(), which didn't exist
587dbb
when Colin developed this patch.
587dbb
587dbb
Removed use of GSlice
587dbb
587dbb
Better error checking in g_hmac_new(). It is possible for
587dbb
gnutls_hmac_init() to fail if running in FIPS mode and an MD5 digest is
587dbb
requested. In this case, we should return NULL rather than returning a
587dbb
broken GHmac with a NULL gnutls_hmac_hd_t. This was leading to a later
587dbb
null pointer dereference inside gnutls_hmac_update(). Applications are
587dbb
responsible for checking to ensure the return value of g_hmac_new() is
587dbb
not NULL since it is annotated as nullable. Added documentation to
587dbb
indicate this possibility.
587dbb
587dbb
Properly handle length -1 in g_hmac_update(). This means we've been
587dbb
given a NUL-terminated string and should use strlen(). GnuTLS doesn't
587dbb
accept -1, so let's call strlen() ourselves.
587dbb
587dbb
Crash the application with g_error() if gnutls_hmac() fails for any
587dbb
reason. This is necessary because g_hmac_update() is not fallible, so we
587dbb
have no way to indicate error. Crashing seems better than returning the
587dbb
wrong result later when g_hmac_get_string() or g_hmac_get_digest() is
587dbb
later called. (Those functions are also not fallible.) Fortunately, I
587dbb
don't think this error should actually be hit in practice.
587dbb
587dbb
https://gitlab.gnome.org/GNOME/glib/-/merge_requests/903
587dbb
---
587dbb
 glib/gchecksum.c        |   9 +-
587dbb
 glib/gchecksumprivate.h |  32 +++++++
587dbb
 glib/ghmac-gnutls.c     | 187 ++++++++++++++++++++++++++++++++++++++++
587dbb
 glib/ghmac.c            |  15 ++++
587dbb
 glib/meson.build        |  10 ++-
587dbb
 meson.build             |   7 ++
587dbb
 meson_options.txt       |   7 +-
587dbb
 7 files changed, 260 insertions(+), 7 deletions(-)
587dbb
 create mode 100644 glib/gchecksumprivate.h
587dbb
 create mode 100644 glib/ghmac-gnutls.c
587dbb
587dbb
diff --git a/glib/gchecksum.c b/glib/gchecksum.c
587dbb
index 29b479bc6..929958c3a 100644
587dbb
--- a/glib/gchecksum.c
587dbb
+++ b/glib/gchecksum.c
587dbb
@@ -20,7 +20,7 @@
587dbb
 
587dbb
 #include <string.h>
587dbb
 
587dbb
-#include "gchecksum.h"
587dbb
+#include "gchecksumprivate.h"
587dbb
 
587dbb
 #include "gslice.h"
587dbb
 #include "gmem.h"
587dbb
@@ -173,9 +173,9 @@ sha_byte_reverse (guint32 *buffer,
587dbb
 }
587dbb
 #endif /* G_BYTE_ORDER == G_BIG_ENDIAN */
587dbb
 
587dbb
-static gchar *
587dbb
-digest_to_string (guint8 *digest,
587dbb
-                  gsize   digest_len)
587dbb
+gchar *
587dbb
+gchecksum_digest_to_string (guint8 *digest,
587dbb
+                            gsize   digest_len)
587dbb
 {
587dbb
   gsize i, len = digest_len * 2;
587dbb
   gchar *retval;
587dbb
@@ -194,6 +194,7 @@ digest_to_string (guint8 *digest,
587dbb
 
587dbb
   return retval;
587dbb
 }
587dbb
+#define digest_to_string gchecksum_digest_to_string
587dbb
 
587dbb
 /*
587dbb
  * MD5 Checksum
587dbb
diff --git a/glib/gchecksumprivate.h b/glib/gchecksumprivate.h
587dbb
new file mode 100644
587dbb
index 000000000..86c7a3b61
587dbb
--- /dev/null
587dbb
+++ b/glib/gchecksumprivate.h
587dbb
@@ -0,0 +1,32 @@
587dbb
+/* gstdioprivate.h - Private GLib stdio functions
587dbb
+ *
587dbb
+ * Copyright 2017 Руслан Ижбулатов
587dbb
+ *
587dbb
+ * This library is free software; you can redistribute it and/or
587dbb
+ * modify it under the terms of the GNU Lesser General Public
587dbb
+ * License as published by the Free Software Foundation; either
587dbb
+ * version 2.1 of the License, or (at your option) any later version.
587dbb
+ *
587dbb
+ * This library is distributed in the hope that it will be useful,
587dbb
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
587dbb
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
587dbb
+ * Lesser General Public License for more details.
587dbb
+ *
587dbb
+ * You should have received a copy of the GNU Lesser General Public License
587dbb
+ * along with this library; if not, see <http://www.gnu.org/licenses/>.
587dbb
+ */
587dbb
+
587dbb
+#ifndef __G_CHECKSUMPRIVATE_H__
587dbb
+#define __G_CHECKSUMPRIVATE_H__
587dbb
+
587dbb
+#include "gchecksum.h"
587dbb
+
587dbb
+G_BEGIN_DECLS
587dbb
+
587dbb
+gchar *
587dbb
+gchecksum_digest_to_string (guint8 *digest,
587dbb
+                            gsize   digest_len);
587dbb
+
587dbb
+G_END_DECLS
587dbb
+
587dbb
+#endif
587dbb
\ No newline at end of file
587dbb
diff --git a/glib/ghmac-gnutls.c b/glib/ghmac-gnutls.c
587dbb
new file mode 100644
587dbb
index 000000000..9fb775f89
587dbb
--- /dev/null
587dbb
+++ b/glib/ghmac-gnutls.c
587dbb
@@ -0,0 +1,187 @@
587dbb
+/* ghmac.h - data hashing functions
587dbb
+ *
587dbb
+ * Copyright (C) 2011  Collabora Ltd.
587dbb
+ * Copyright (C) 2019  Red Hat, Inc.
587dbb
+ *
587dbb
+ * This library is free software; you can redistribute it and/or
587dbb
+ * modify it under the terms of the GNU Lesser General Public
587dbb
+ * License as published by the Free Software Foundation; either
587dbb
+ * version 2.1 of the License, or (at your option) any later version.
587dbb
+ *
587dbb
+ * This library is distributed in the hope that it will be useful,
587dbb
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
587dbb
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
587dbb
+ * Lesser General Public License for more details.
587dbb
+ *
587dbb
+ * You should have received a copy of the GNU Lesser General Public License
587dbb
+ * along with this library; if not, see <http://www.gnu.org/licenses/>.
587dbb
+ */
587dbb
+
587dbb
+#include "config.h"
587dbb
+
587dbb
+#include <string.h>
587dbb
+#include <gnutls/crypto.h>
587dbb
+
587dbb
+#include "ghmac.h"
587dbb
+
587dbb
+#include "glib/galloca.h"
587dbb
+#include "gatomic.h"
587dbb
+#include "gslice.h"
587dbb
+#include "gmem.h"
587dbb
+#include "gstrfuncs.h"
587dbb
+#include "gchecksumprivate.h"
587dbb
+#include "gtestutils.h"
587dbb
+#include "gtypes.h"
587dbb
+#include "glibintl.h"
587dbb
+
587dbb
+#ifndef HAVE_GNUTLS
587dbb
+#error "build configuration error"
587dbb
+#endif
587dbb
+
587dbb
+struct _GHmac
587dbb
+{
587dbb
+  int ref_count;
587dbb
+  GChecksumType digest_type;
587dbb
+  gnutls_hmac_hd_t hmac;
587dbb
+  gchar *digest_str;
587dbb
+};
587dbb
+
587dbb
+GHmac *
587dbb
+g_hmac_new (GChecksumType  digest_type,
587dbb
+            const guchar  *key,
587dbb
+            gsize          key_len)
587dbb
+{
587dbb
+  gnutls_mac_algorithm_t algo;
587dbb
+  GHmac *hmac = g_new0 (GHmac, 1);
587dbb
+  int ret;
587dbb
+
587dbb
+  hmac->ref_count = 1;
587dbb
+  hmac->digest_type = digest_type;
587dbb
+
587dbb
+  switch (digest_type)
587dbb
+    {
587dbb
+    case G_CHECKSUM_MD5:
587dbb
+      algo = GNUTLS_MAC_MD5;
587dbb
+      break;
587dbb
+    case G_CHECKSUM_SHA1:
587dbb
+      algo = GNUTLS_MAC_SHA1;
587dbb
+      break;
587dbb
+    case G_CHECKSUM_SHA256:
587dbb
+      algo = GNUTLS_MAC_SHA256;
587dbb
+      break;
587dbb
+    case G_CHECKSUM_SHA384:
587dbb
+      algo = GNUTLS_MAC_SHA384;
587dbb
+      break;
587dbb
+    case G_CHECKSUM_SHA512:
587dbb
+      algo = GNUTLS_MAC_SHA512;
587dbb
+      break;
587dbb
+    default:
587dbb
+      g_free (hmac);
587dbb
+      g_return_val_if_reached (NULL);
587dbb
+    }
587dbb
+
587dbb
+  ret = gnutls_hmac_init (&hmac->hmac, algo, key, key_len);
587dbb
+  if (ret != 0)
587dbb
+    {
587dbb
+      /* There is no way to report an error here, but one possible cause of
587dbb
+       * failure is that the requested digest may be disabled by FIPS mode.
587dbb
+       */
587dbb
+      g_free (hmac);
587dbb
+      return NULL;
587dbb
+    }
587dbb
+
587dbb
+  return hmac;
587dbb
+}
587dbb
+
587dbb
+GHmac *
587dbb
+g_hmac_copy (const GHmac *hmac)
587dbb
+{
587dbb
+  GHmac *copy;
587dbb
+
587dbb
+  g_return_val_if_fail (hmac != NULL, NULL);
587dbb
+
587dbb
+  copy = g_new0 (GHmac, 1);
587dbb
+  copy->ref_count = 1;
587dbb
+  copy->digest_type = hmac->digest_type;
587dbb
+  copy->hmac = gnutls_hmac_copy (hmac->hmac);
587dbb
+
587dbb
+  /* g_hmac_copy is not allowed to fail, so we'll have to crash on error. */
587dbb
+  if (!copy->hmac)
587dbb
+    g_error ("gnutls_hmac_copy failed");
587dbb
+
587dbb
+  return copy;
587dbb
+}
587dbb
+
587dbb
+GHmac *
587dbb
+g_hmac_ref (GHmac *hmac)
587dbb
+{
587dbb
+  g_return_val_if_fail (hmac != NULL, NULL);
587dbb
+
587dbb
+  g_atomic_int_inc (&hmac->ref_count);
587dbb
+
587dbb
+  return hmac;
587dbb
+}
587dbb
+
587dbb
+void
587dbb
+g_hmac_unref (GHmac *hmac)
587dbb
+{
587dbb
+  g_return_if_fail (hmac != NULL);
587dbb
+
587dbb
+  if (g_atomic_int_dec_and_test (&hmac->ref_count))
587dbb
+    {
587dbb
+      gnutls_hmac_deinit (hmac->hmac, NULL);
587dbb
+      g_free (hmac->digest_str);
587dbb
+      g_free (hmac);
587dbb
+    }
587dbb
+}
587dbb
+
587dbb
+
587dbb
+void
587dbb
+g_hmac_update (GHmac        *hmac,
587dbb
+               const guchar *data,
587dbb
+               gssize        length)
587dbb
+{
587dbb
+  int ret;
587dbb
+
587dbb
+  g_return_if_fail (hmac != NULL);
587dbb
+  g_return_if_fail (length == 0 || data != NULL);
587dbb
+
587dbb
+  if (length == -1)
587dbb
+    length = strlen ((const char *)data);
587dbb
+
587dbb
+  /* g_hmac_update is not allowed to fail, so we'll have to crash on error. */
587dbb
+  ret = gnutls_hmac (hmac->hmac, data, length);
587dbb
+  if (ret != 0)
587dbb
+    g_error ("gnutls_hmac failed: %s", gnutls_strerror (ret));
587dbb
+}
587dbb
+
587dbb
+const gchar *
587dbb
+g_hmac_get_string (GHmac *hmac)
587dbb
+{
587dbb
+  guint8 *buffer;
587dbb
+  gsize digest_len;
587dbb
+
587dbb
+  g_return_val_if_fail (hmac != NULL, NULL);
587dbb
+
587dbb
+  if (hmac->digest_str)
587dbb
+    return hmac->digest_str;
587dbb
+
587dbb
+  digest_len = g_checksum_type_get_length (hmac->digest_type);
587dbb
+  buffer = g_alloca (digest_len);
587dbb
+
587dbb
+  gnutls_hmac_output (hmac->hmac, buffer);
587dbb
+  hmac->digest_str = gchecksum_digest_to_string (buffer, digest_len);
587dbb
+  return hmac->digest_str;
587dbb
+}
587dbb
+
587dbb
+
587dbb
+void
587dbb
+g_hmac_get_digest (GHmac  *hmac,
587dbb
+                   guint8 *buffer,
587dbb
+                   gsize  *digest_len)
587dbb
+{
587dbb
+  g_return_if_fail (hmac != NULL);
587dbb
+
587dbb
+  gnutls_hmac_output (hmac->hmac, buffer);
587dbb
+  *digest_len = g_checksum_type_get_length (hmac->digest_type);
587dbb
+}
587dbb
diff --git a/glib/ghmac.c b/glib/ghmac.c
587dbb
index 4f181f21f..0e39ea40a 100644
587dbb
--- a/glib/ghmac.c
587dbb
+++ b/glib/ghmac.c
587dbb
@@ -33,6 +33,9 @@
587dbb
 #include "gtypes.h"
587dbb
 #include "glibintl.h"
587dbb
 
587dbb
+#ifdef HAVE_GNUTLS
587dbb
+#error "build configuration error"
587dbb
+#endif
587dbb
 
587dbb
 /**
587dbb
  * SECTION:hmac
587dbb
@@ -84,6 +87,18 @@ struct _GHmac
587dbb
  * Support for digests of type %G_CHECKSUM_SHA512 has been added in GLib 2.42.
587dbb
  * Support for %G_CHECKSUM_SHA384 was added in GLib 2.52.
587dbb
  *
587dbb
+ * Note that #GHmac creation may fail, in which case this function will
587dbb
+ * return %NULL. Since there is no error parameter, it is not possible
587dbb
+ * to indicate why.
587dbb
+ *
587dbb
+ * In Fedora, CentOS Stream, and Red Hat Enterprise Linux, GLib is
587dbb
+ * configured to use GnuTLS to implement #GHmac in order to support FIPS
587dbb
+ * compliance. This introduces additional failure possibilities that are
587dbb
+ * not present in upstream GLib. For example, the creation of a #GHmac
587dbb
+ * will fail if @digest_type is %G_CHECKSUM_MD5 and the system is
587dbb
+ * running in FIPS mode. #GHmac creation may also fail if GLib is unable
587dbb
+ * to load GnuTLS.
587dbb
+ *
587dbb
  * Returns: the newly created #GHmac, or %NULL.
587dbb
  *   Use g_hmac_unref() to free the memory allocated by it.
587dbb
  *
587dbb
diff --git a/glib/meson.build b/glib/meson.build
587dbb
index 329b8d197..2417de53d 100644
587dbb
--- a/glib/meson.build
587dbb
+++ b/glib/meson.build
587dbb
@@ -252,7 +252,6 @@ glib_sources = files(
587dbb
   'gfileutils.c',
587dbb
   'ggettext.c',
587dbb
   'ghash.c',
587dbb
-  'ghmac.c',
587dbb
   'ghmac-utils.c',
587dbb
   'ghook.c',
587dbb
   'ghostutils.c',
587dbb
@@ -308,6 +307,7 @@ glib_sources = files(
587dbb
   'guriprivate.h',
587dbb
   'gutils.c',
587dbb
   'gutilsprivate.h',
587dbb
+  'gchecksumprivate.h',
587dbb
   'guuid.c',
587dbb
   'gvariant.c',
587dbb
   'gvariant-core.c',
587dbb
@@ -352,6 +352,12 @@ else
587dbb
   glib_dtrace_hdr = []
587dbb
 endif
587dbb
 
587dbb
+if get_option('gnutls')
587dbb
+  glib_sources += files('ghmac-gnutls.c')
587dbb
+else
587dbb
+  glib_sources += files('ghmac.c')
587dbb
+endif
587dbb
+
587dbb
 pcre_static_args = []
587dbb
 
587dbb
 if use_pcre_static_flag
587dbb
@@ -378,7 +384,7 @@ libglib = library('glib-2.0',
587dbb
   # intl.lib is not compatible with SAFESEH
587dbb
   link_args : [noseh_link_args, glib_link_flags, win32_ldflags],
587dbb
   include_directories : configinc,
587dbb
-  dependencies : pcre_deps + [thread_dep, librt] + libintl_deps + libiconv + platform_deps + [gnulib_libm_dependency, libm] + [libsysprof_capture_dep],
587dbb
+  dependencies : pcre_deps + [thread_dep, librt] + libgnutls_dep + libintl_deps + libiconv + platform_deps + [gnulib_libm_dependency, libm] + [libsysprof_capture_dep],
587dbb
   c_args : glib_c_args,
587dbb
   objc_args : glib_c_args,
587dbb
 )
587dbb
diff --git a/meson.build b/meson.build
587dbb
index e2eba1871..cca15f653 100644
587dbb
--- a/meson.build
587dbb
+++ b/meson.build
587dbb
@@ -2090,6 +2090,13 @@ if host_system == 'linux'
587dbb
   glib_conf.set('HAVE_LIBMOUNT', libmount_dep.found())
587dbb
 endif
587dbb
 
587dbb
+# gnutls is used optionally by ghmac
587dbb
+libgnutls_dep = []
587dbb
+if get_option('gnutls')
587dbb
+  libgnutls_dep = [dependency('gnutls', version : '>=3.6.9', required : true)]
587dbb
+  glib_conf.set('HAVE_GNUTLS', 1)
587dbb
+endif
587dbb
+
587dbb
 if host_system == 'windows'
587dbb
   winsock2 = cc.find_library('ws2_32')
587dbb
 endif
587dbb
diff --git a/meson_options.txt b/meson_options.txt
587dbb
index 072765361..c8f26ac02 100644
587dbb
--- a/meson_options.txt
587dbb
+++ b/meson_options.txt
587dbb
@@ -39,6 +39,11 @@ option('internal_pcre',
587dbb
        value : false,
587dbb
        description : 'whether to use internal PCRE')
587dbb
 
587dbb
+option('gnutls',
587dbb
+       type : 'boolean',
587dbb
+       value : false,
587dbb
+       description : 'build with gnutls support')
587dbb
+
587dbb
 option('man',
587dbb
        type : 'boolean',
587dbb
        value : false,
587dbb
-- 
587dbb
2.31.1
587dbb
587dbb
From 61c175277acb8d1e080305acd444201c5ad1fb81 Mon Sep 17 00:00:00 2001
587dbb
From: Michael Catanzaro <mcatanzaro@redhat.com>
587dbb
Date: Wed, 16 Jun 2021 20:35:00 -0500
587dbb
Subject: [PATCH 3/4] dlopen GnuTLS instead of linking directly
587dbb
587dbb
I'd like to enable our GnuTLS GHmac patchset in Fedora in order to
587dbb
ensure it is receiving sufficient real-world testing, since we've
587dbb
discovered several bugs thus far. Problem is Fedora has one requirement
587dbb
that RHEL does not: it needs to build glib as a static lib. This is
587dbb
needed by QEMU in Fedora for complicated technical reasons that I don't
587dbb
understand. However, nothing in RHEL needs it. This means we failed to
587dbb
notice that glib2-static is broken in RHEL, because there is no
587dbb
gnutls-static! We could fix this by adding a gnutls-static package, but
587dbb
that seems like overkill, and adding more static libraries where they're
587dbb
not truly necessary is not the direction we want to move in anyway. So
587dbb
instead, let's just dlopen GnuTLS to sidestep this problem entirely.
587dbb
587dbb
This would not be a good solution for upstream, but upstream has made
587dbb
clear that this patchset is already non-upstreamable, so it will be fine
587dbb
for our purposes.
587dbb
---
587dbb
 glib/ghmac-gnutls.c | 101 ++++++++++++++++++++++++++++++++++++++++++--
587dbb
 glib/ghmac.c        |   2 +-
587dbb
 glib/meson.build    |   2 +-
587dbb
 meson.build         |   6 +--
587dbb
 4 files changed, 102 insertions(+), 9 deletions(-)
587dbb
587dbb
diff --git a/glib/ghmac-gnutls.c b/glib/ghmac-gnutls.c
587dbb
index 9fb775f89..1800fc2e0 100644
587dbb
--- a/glib/ghmac-gnutls.c
587dbb
+++ b/glib/ghmac-gnutls.c
587dbb
@@ -19,8 +19,8 @@
587dbb
 
587dbb
 #include "config.h"
587dbb
 
587dbb
+#include <dlfcn.h>
587dbb
 #include <string.h>
587dbb
-#include <gnutls/crypto.h>
587dbb
 
587dbb
 #include "ghmac.h"
587dbb
 
587dbb
@@ -31,13 +31,16 @@
587dbb
 #include "gstrfuncs.h"
587dbb
 #include "gchecksumprivate.h"
587dbb
 #include "gtestutils.h"
587dbb
+#include "gthread.h"
587dbb
 #include "gtypes.h"
587dbb
 #include "glibintl.h"
587dbb
 
587dbb
-#ifndef HAVE_GNUTLS
587dbb
+#ifndef USE_GNUTLS
587dbb
 #error "build configuration error"
587dbb
 #endif
587dbb
 
587dbb
+typedef gpointer gnutls_hmac_hd_t;
587dbb
+
587dbb
 struct _GHmac
587dbb
 {
587dbb
   int ref_count;
587dbb
@@ -46,15 +49,107 @@ struct _GHmac
587dbb
   gchar *digest_str;
587dbb
 };
587dbb
 
587dbb
+typedef enum
587dbb
+{
587dbb
+  GNUTLS_MAC_MD5 = 2,
587dbb
+  GNUTLS_MAC_SHA1 = 3,
587dbb
+  GNUTLS_MAC_SHA256 = 6,
587dbb
+  GNUTLS_MAC_SHA384 = 7,
587dbb
+  GNUTLS_MAC_SHA512 = 8,
587dbb
+} gnutls_mac_algorithm_t;
587dbb
+
587dbb
+/* Why are we dlopening GnuTLS instead of linking to it directly? Because we
587dbb
+ * want to be able to build GLib as a static library without depending on a
587dbb
+ * static build of GnuTLS. QEMU depends on static linking with GLib, but Fedora
587dbb
+ * does not ship a static build of GnuTLS, and this allows us to avoid changing
587dbb
+ * that.
587dbb
+ */
587dbb
+static int              (*gnutls_hmac_init)   (gnutls_hmac_hd_t *dig, gnutls_mac_algorithm_t algorithm, const void *key, size_t keylen);
587dbb
+static gnutls_hmac_hd_t (*gnutls_hmac_copy)   (gnutls_hmac_hd_t handle);
587dbb
+static void             (*gnutls_hmac_deinit) (gnutls_hmac_hd_t handle, void *digest);
587dbb
+static int              (*gnutls_hmac)        (gnutls_hmac_hd_t handle, const void *ptext, size_t ptext_len);
587dbb
+static void             (*gnutls_hmac_output) (gnutls_hmac_hd_t handle, void *digest);
587dbb
+static const char *     (*gnutls_strerror)    (int error);
587dbb
+
587dbb
+static gsize gnutls_initialize_attempted = 0;
587dbb
+static gboolean gnutls_initialize_successful = FALSE;
587dbb
+
587dbb
+static void
587dbb
+initialize_gnutls (void)
587dbb
+{
587dbb
+  gpointer libgnutls;
587dbb
+
587dbb
+  libgnutls = dlopen ("libgnutls.so.30", RTLD_LAZY | RTLD_GLOBAL);
587dbb
+  if (!libgnutls)
587dbb
+    {
587dbb
+      g_warning ("Cannot use GHmac: failed to load libgnutls.so.30: %s", dlerror ());
587dbb
+      return;
587dbb
+    }
587dbb
+
587dbb
+  gnutls_hmac_init = dlsym (libgnutls, "gnutls_hmac_init");
587dbb
+  if (!gnutls_hmac_init)
587dbb
+    {
587dbb
+      g_warning ("Cannot use GHmac: failed to load gnutls_hmac_init: %s", dlerror ());
587dbb
+      return;
587dbb
+    }
587dbb
+
587dbb
+  gnutls_hmac_copy = dlsym (libgnutls, "gnutls_hmac_copy");
587dbb
+  if (!gnutls_hmac_copy)
587dbb
+    {
587dbb
+      g_warning ("Cannot use GHmac: failed to load gnutls_hmac_copy: %s", dlerror ());
587dbb
+      return;
587dbb
+    }
587dbb
+
587dbb
+  gnutls_hmac_deinit = dlsym (libgnutls, "gnutls_hmac_deinit");
587dbb
+  if (!gnutls_hmac_deinit)
587dbb
+    {
587dbb
+      g_warning ("Cannot use GHmac: failed to load gnutls_hmac_deinit: %s", dlerror ());
587dbb
+      return;
587dbb
+    }
587dbb
+
587dbb
+  gnutls_hmac = dlsym (libgnutls, "gnutls_hmac");
587dbb
+  if (!gnutls_hmac)
587dbb
+    {
587dbb
+      g_warning ("Cannot use GHmac: failed to load gnutls_hmac: %s", dlerror ());
587dbb
+      return;
587dbb
+    }
587dbb
+
587dbb
+  gnutls_hmac_output = dlsym (libgnutls, "gnutls_hmac_output");
587dbb
+  if (!gnutls_hmac_output)
587dbb
+    {
587dbb
+      g_warning ("Cannot use GHmac: failed to load gnutls_hmac_output: %s", dlerror ());
587dbb
+      return;
587dbb
+    }
587dbb
+
587dbb
+  gnutls_strerror = dlsym (libgnutls, "gnutls_strerror");
587dbb
+  if (!gnutls_strerror)
587dbb
+    {
587dbb
+      g_warning ("Cannot use GHmac: failed to load gnutls_strerror: %s", dlerror ());
587dbb
+      return;
587dbb
+    }
587dbb
+
587dbb
+  gnutls_initialize_successful = TRUE;
587dbb
+}
587dbb
+
587dbb
 GHmac *
587dbb
 g_hmac_new (GChecksumType  digest_type,
587dbb
             const guchar  *key,
587dbb
             gsize          key_len)
587dbb
 {
587dbb
   gnutls_mac_algorithm_t algo;
587dbb
-  GHmac *hmac = g_new0 (GHmac, 1);
587dbb
+  GHmac *hmac;
587dbb
   int ret;
587dbb
 
587dbb
+  if (g_once_init_enter (&gnutls_initialize_attempted))
587dbb
+    {
587dbb
+      initialize_gnutls ();
587dbb
+      g_once_init_leave (&gnutls_initialize_attempted, 1);
587dbb
+    }
587dbb
+
587dbb
+  if (!gnutls_initialize_successful)
587dbb
+    return NULL;
587dbb
+
587dbb
+  hmac = g_new0 (GHmac, 1);
587dbb
   hmac->ref_count = 1;
587dbb
   hmac->digest_type = digest_type;
587dbb
 
587dbb
diff --git a/glib/ghmac.c b/glib/ghmac.c
587dbb
index 0e39ea40a..2d9be91b8 100644
587dbb
--- a/glib/ghmac.c
587dbb
+++ b/glib/ghmac.c
587dbb
@@ -33,7 +33,7 @@
587dbb
 #include "gtypes.h"
587dbb
 #include "glibintl.h"
587dbb
 
587dbb
-#ifdef HAVE_GNUTLS
587dbb
+#ifdef USE_GNUTLS
587dbb
 #error "build configuration error"
587dbb
 #endif
587dbb
 
587dbb
diff --git a/glib/meson.build b/glib/meson.build
587dbb
index 2417de53d..ba42951aa 100644
587dbb
--- a/glib/meson.build
587dbb
+++ b/glib/meson.build
587dbb
@@ -384,7 +384,7 @@ libglib = library('glib-2.0',
587dbb
   # intl.lib is not compatible with SAFESEH
587dbb
   link_args : [noseh_link_args, glib_link_flags, win32_ldflags],
587dbb
   include_directories : configinc,
587dbb
-  dependencies : pcre_deps + [thread_dep, librt] + libgnutls_dep + libintl_deps + libiconv + platform_deps + [gnulib_libm_dependency, libm] + [libsysprof_capture_dep],
587dbb
+  dependencies : pcre_deps + [thread_dep, librt] + libintl_deps + libiconv + platform_deps + [gnulib_libm_dependency, libm] + [libsysprof_capture_dep] + [libdl_dep],
587dbb
   c_args : glib_c_args,
587dbb
   objc_args : glib_c_args,
587dbb
 )
587dbb
diff --git a/meson.build b/meson.build
587dbb
index cca15f653..404ef1790 100644
587dbb
--- a/meson.build
587dbb
+++ b/meson.build
587dbb
@@ -2090,11 +2090,9 @@ if host_system == 'linux'
587dbb
   glib_conf.set('HAVE_LIBMOUNT', libmount_dep.found())
587dbb
 endif
587dbb
 
587dbb
-# gnutls is used optionally by ghmac
587dbb
-libgnutls_dep = []
587dbb
+# gnutls is used optionally by GHmac
587dbb
 if get_option('gnutls')
587dbb
-  libgnutls_dep = [dependency('gnutls', version : '>=3.6.9', required : true)]
587dbb
-  glib_conf.set('HAVE_GNUTLS', 1)
587dbb
+  glib_conf.set('USE_GNUTLS', 1)
587dbb
 endif
587dbb
 
587dbb
 if host_system == 'windows'
587dbb
-- 
587dbb
2.31.1
587dbb
587dbb
From 7d1d96311b6ecd4f90ebbdd6fc58d28e06a86887 Mon Sep 17 00:00:00 2001
587dbb
From: Michael Catanzaro <mcatanzaro@redhat.com>
587dbb
Date: Wed, 16 Jun 2021 20:46:24 -0500
587dbb
Subject: [PATCH 4/4] Add test for GHmac in FIPS mode
587dbb
587dbb
This will test a few problems that we hit recently:
587dbb
587dbb
g_hmac_copy() is broken, https://bugzilla.redhat.com/show_bug.cgi?id=1786538
587dbb
587dbb
Crash in g_hmac_update() in FIPS mode, https://bugzilla.redhat.com/show_bug.cgi?id=1971533
587dbb
587dbb
Crash when passing -1 length to g_hmac_update() (discovered in #1971533)
587dbb
587dbb
We'll also test to ensure MD5 fails, and stop compiling the other MD5
587dbb
tests.
587dbb
---
587dbb
 glib/tests/hmac.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
587dbb
 1 file changed, 46 insertions(+)
587dbb
587dbb
diff --git a/glib/tests/hmac.c b/glib/tests/hmac.c
587dbb
index 3ac3206df..2fa447984 100644
587dbb
--- a/glib/tests/hmac.c
587dbb
+++ b/glib/tests/hmac.c
587dbb
@@ -1,7 +1,10 @@
587dbb
+#include "config.h"
587dbb
+
587dbb
 #include <glib.h>
587dbb
 #include <string.h>
587dbb
 #include <stdlib.h>
587dbb
 
587dbb
+#ifndef USE_GNUTLS
587dbb
 /* HMAC-MD5 test vectors as per RFC 2202 */
587dbb
 
587dbb
 /* Test 1 */
587dbb
@@ -81,6 +84,7 @@ guint8 key_md5_test7[] = {
587dbb
 guint8 result_md5_test7[] = {
587dbb
     0x6f, 0x63, 0x0f, 0xad, 0x67, 0xcd, 0xa0, 0xee, 0x1f, 0xb1,
587dbb
     0xf5, 0x62, 0xdb, 0x3a, 0xa5, 0x3e };
587dbb
+#endif
587dbb
 
587dbb
 /* HMAC-SHA1, HMAC-SHA256, HMAC-SHA384 and HMAC-SHA512 test vectors
587dbb
  * as per RFCs 2202 and 4868.
587dbb
@@ -299,6 +303,7 @@ typedef struct {
587dbb
   gconstpointer result;
587dbb
 } HmacCase;
587dbb
 
587dbb
+#ifndef USE_GNUTLS
587dbb
 HmacCase hmac_md5_tests[] = {
587dbb
   { G_CHECKSUM_MD5, key_md5_test1, 16, "Hi There", 8, result_md5_test1 },
587dbb
   { G_CHECKSUM_MD5, "Jefe", 4, "what do ya want for nothing?", 28,
587dbb
@@ -317,6 +322,7 @@ HmacCase hmac_md5_tests[] = {
587dbb
       73, result_md5_test7 },
587dbb
   { -1, NULL, 0, NULL, 0, NULL },
587dbb
 };
587dbb
+#endif
587dbb
 
587dbb
 HmacCase hmac_sha1_tests[] = {
587dbb
   { G_CHECKSUM_SHA1, key_sha_test1, 20, "Hi There", 8, result_sha1_test1 },
587dbb
@@ -493,11 +499,45 @@ test_hmac_for_bytes (void)
587dbb
   g_bytes_unref (data);
587dbb
 }
587dbb
 
587dbb
+#ifdef USE_GNUTLS
587dbb
+static void
587dbb
+test_gnutls_fips_mode (void)
587dbb
+{
587dbb
+  GHmac *hmac;
587dbb
+  GHmac *copy;
587dbb
+
587dbb
+  /* No MD5 in FIPS mode. */
587dbb
+  hmac = g_hmac_new (G_CHECKSUM_MD5, "abc123", sizeof ("abc123"));
587dbb
+  g_assert_null (hmac);
587dbb
+
587dbb
+  /* SHA-256 should be good. */
587dbb
+  hmac = g_hmac_new (G_CHECKSUM_SHA256, "abc123", sizeof ("abc123"));
587dbb
+  g_assert_nonnull (hmac);
587dbb
+
587dbb
+  /* Ensure g_hmac_update() does not crash when called with -1. */
587dbb
+  g_hmac_update (hmac, "You win again, gravity!", -1);
587dbb
+
587dbb
+  /* Ensure g_hmac_copy() does not crash. */
587dbb
+  copy = g_hmac_copy (hmac);
587dbb
+  g_assert_nonnull (hmac);
587dbb
+  g_hmac_unref (hmac);
587dbb
+
587dbb
+  g_assert_cmpstr (g_hmac_get_string (copy), ==, "795ba6900bcb22e8ce65c2ec02db4e85697da921deb960ee3143bf88a4a60f83");
587dbb
+  g_hmac_unref (copy);
587dbb
+}
587dbb
+#endif
587dbb
+
587dbb
 int
587dbb
 main (int argc,
587dbb
     char **argv)
587dbb
 {
587dbb
   int i;
587dbb
+
587dbb
+#ifdef USE_GNUTLS
587dbb
+  /* This has to happen before GnuTLS is dlopened. */
587dbb
+  g_setenv ("GNUTLS_FORCE_FIPS_MODE", "1", FALSE);
587dbb
+#endif
587dbb
+
587dbb
   g_test_init (&argc, &argv, NULL);
587dbb
 
587dbb
   for (i = 0 ; hmac_sha1_tests[i].key_len > 0 ; i++)
587dbb
@@ -532,6 +572,7 @@ main (int argc,
587dbb
       g_free (name);
587dbb
     }
587dbb
 
587dbb
+#ifndef USE_GNUTLS
587dbb
   for (i = 0 ; hmac_md5_tests[i].key_len > 0 ; i++)
587dbb
     {
587dbb
       gchar *name = g_strdup_printf ("/hmac/md5-%d", i + 1);
587dbb
@@ -539,6 +580,7 @@ main (int argc,
587dbb
         (void (*)(const void *)) test_hmac);
587dbb
       g_free (name);
587dbb
     }
587dbb
+#endif
587dbb
 
587dbb
   g_test_add_func ("/hmac/ref-unref", test_hmac_ref_unref);
587dbb
   g_test_add_func ("/hmac/copy", test_hmac_copy);
587dbb
@@ -546,5 +588,9 @@ main (int argc,
587dbb
   g_test_add_func ("/hmac/for-string", test_hmac_for_string);
587dbb
   g_test_add_func ("/hmac/for-bytes", test_hmac_for_bytes);
587dbb
 
587dbb
+#ifdef USE_GNUTLS
587dbb
+  g_test_add_func ("/hmac/gnutls-fips-mode", test_gnutls_fips_mode);
587dbb
+#endif
587dbb
+
587dbb
   return g_test_run ();
587dbb
 }
587dbb
-- 
587dbb
2.31.1