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