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