]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
Use soname instead of file name in fipshmac sections
authorZoltan Fridrich <zfridric@redhat.com>
Fri, 2 Dec 2022 12:12:30 +0000 (13:12 +0100)
committerZoltan Fridrich <zfridric@redhat.com>
Wed, 7 Dec 2022 14:40:24 +0000 (15:40 +0100)
Using fipshmac program with an argument, for example:
fipshmac /usr/lib64/libgnutls.so.30.28.1
would create a section [libgnutls.so.30.28.1]
and the internal comparison with soname would fail.

Signed-off-by: Zoltan Fridrich <zfridric@redhat.com>
configure.ac
lib/fips.c
lib/fipshmac.c

index b9cd6234c537fbcec6d864aa461dc8be7fa8610d..71d6dd116ece7965ad0785cb52dfc6f56a60bb75 100644 (file)
@@ -619,6 +619,8 @@ if [ test "$enable_fips" = "yes" ];then
     if test "x$fips_module_version" != xnone; then
        AC_DEFINE_UNQUOTED([FIPS_MODULE_VERSION], ["$fips_module_version"], [The FIPS140 module version])
     fi
+
+    AC_CHECK_FUNCS(dl_iterate_phdr)
   else
     enable_fips=no
     AC_MSG_WARN([[
index e8a6c194656c40e0bf6699b2da0fe3bef64078d4..c8277e50b15f0c8ef869b33f262f877cbece8069 100644 (file)
 #include <gnutls/gnutls.h>
 #include <gnutls/crypto.h>
 #include <unistd.h>
+#include "dirname.h"
 #include "errors.h"
 #include "file.h"
 #include "inih/ini.h"
+#include "str.h"
 #include <fips.h>
 #include <gnutls/self-test.h>
 #include <stdio.h>
 
 #include "gthreads.h"
 
+#ifdef HAVE_DL_ITERATE_PHDR
+#include <link.h>
+#endif
+
 unsigned int _gnutls_lib_state = LIB_STATE_POWERON;
 
 struct gnutls_fips140_context_st {
@@ -161,51 +167,32 @@ struct hmac_entry
        uint8_t hmac[HMAC_SIZE];
 };
 
-typedef struct
+struct hmac_file
 {
        int version;
        struct hmac_entry gnutls;
        struct hmac_entry nettle;
        struct hmac_entry hogweed;
        struct hmac_entry gmp;
-} hmac_file;
+};
 
-static int get_library_path(const char* lib, const char* symbol, char* path, size_t path_size)
+struct lib_paths
 {
-       int ret;
-       void *dl, *sym;
-       Dl_info info;
-
-       dl = dlopen(lib, RTLD_LAZY);
-       if (dl == NULL)
-               return gnutls_assert_val(GNUTLS_E_FILE_ERROR);
-
-       sym = dlsym(dl, symbol);
-       if (sym == NULL) {
-               ret = gnutls_assert_val(GNUTLS_E_FILE_ERROR);
-               goto cleanup;
-       }
-
-       ret = dladdr(sym, &info);
-       if (ret == 0) {
-               ret = gnutls_assert_val(GNUTLS_E_FILE_ERROR);
-               goto cleanup;
-       }
-
-       ret = snprintf(path, path_size, "%s", info.dli_fname);
-       if ((size_t)ret >= path_size) {
-               ret = gnutls_assert_val(GNUTLS_E_SHORT_MEMORY_BUFFER);
-               goto cleanup;
-       }
-
-       ret = 0;
-cleanup:
-       dlclose(dl);
-       return ret;
-}
+       char gnutls[GNUTLS_PATH_MAX];
+       char nettle[GNUTLS_PATH_MAX];
+       char hogweed[GNUTLS_PATH_MAX];
+       char gmp[GNUTLS_PATH_MAX];
+};
 
-/* Parses hmac data and copies hex value into dest.
+/*
+ * get_hmac:
+ * @dest: buffer for the hex value
+ * @value: hmac value
+ *
+ * Parses hmac data and copies hex value into dest.
  * dest must point to at least HMAC_SIZE amount of memory
+ *
+ * Returns: 0 on success, a negative error code otherwise
  */
 static int get_hmac(uint8_t *dest, const char *value)
 {
@@ -244,7 +231,7 @@ lib_handler(struct hmac_entry *entry,
 
 static int handler(void *user, const char *section, const char *name, const char *value)
 {
-       hmac_file *p = (hmac_file *)user;
+       struct hmac_file *p = (struct hmac_file *)user;
 
        if (!strcmp(section, "global")) {
                if (!strcmp(name, "format-version")) {
@@ -266,26 +253,29 @@ static int handler(void *user, const char *section, const char *name, const char
        return 1;
 }
 
-static int get_hmac_path(char *mac_file, size_t mac_file_size)
+/*
+ * get_hmac_path:
+ * @mac_file: buffer where the hmac file path will be written to
+ * @mac_file_size: size of the mac_file buffer
+ * @gnutls_path: path to the gnutls library, used to deduce hmac file path
+ * 
+ * Deduces hmac file path from the gnutls library path.
+ *
+ * Returns: 0 on success, a negative error code otherwise
+ */
+static int get_hmac_path(char *mac_file, size_t mac_file_size, const char *gnutls_path)
 {
        int ret;
        char *p;
-       char file[GNUTLS_PATH_MAX];
 
-       ret = get_library_path(GNUTLS_LIBRARY_NAME, "gnutls_global_init",
-                              file, sizeof(file));
-       if (ret < 0)
-               return ret;
+       p = strrchr(gnutls_path, '/');
 
-       p = strrchr(file, '/');
-
-       if (p == NULL) {
-               ret = snprintf(mac_file, mac_file_size, ".%s.hmac",
-                              file);
-       } else {
+       if (p == NULL)
+               ret = snprintf(mac_file, mac_file_size, ".%s.hmac", gnutls_path);
+       else
                ret = snprintf(mac_file, mac_file_size, "%.*s/.%s.hmac",
-                              (int)(p - file), file, p + 1);
-       }
+                              (int)(p - gnutls_path), gnutls_path, p + 1);
+
        if ((size_t)ret >= mac_file_size)
                return gnutls_assert_val(GNUTLS_E_SHORT_MEMORY_BUFFER);
 
@@ -293,13 +283,12 @@ static int get_hmac_path(char *mac_file, size_t mac_file_size)
        if (ret == 0)
                return GNUTLS_E_SUCCESS;
 
-       if (p == NULL) {
-               ret = snprintf(mac_file, mac_file_size, "fipscheck/.%s.hmac",
-                              file);
-       } else {
+       if (p == NULL)
+               ret = snprintf(mac_file, mac_file_size, "fipscheck/.%s.hmac", gnutls_path);
+       else
                ret = snprintf(mac_file, mac_file_size, "%.*s/fipscheck/.%s.hmac",
-                              (int)(p - file), file, p + 1);
-       }
+                              (int)(p - gnutls_path), gnutls_path, p + 1);
+
        if ((size_t)ret >= mac_file_size)
                return gnutls_assert_val(GNUTLS_E_SHORT_MEMORY_BUFFER);
 
@@ -310,51 +299,52 @@ static int get_hmac_path(char *mac_file, size_t mac_file_size)
        return GNUTLS_E_FILE_ERROR;
 }
 
-static int load_hmac_file(hmac_file *p)
+/*
+ * load_hmac_file:
+ * @hmac_file: hmac file structure
+ * @hmac_path: path to the hmac file
+ *
+ * Loads the hmac file into the hmac file structure.
+ *
+ * Returns: 0 on success, a negative error code otherwise
+ */
+static int load_hmac_file(struct hmac_file *hmac_file, const char *hmac_path)
 {
        int ret;
        FILE *stream;
-       char hmac_path[GNUTLS_PATH_MAX];
-
-       ret = get_hmac_path(hmac_path, sizeof(hmac_path));
-       if (ret < 0)
-               return gnutls_assert_val(ret);
 
        stream = fopen(hmac_path, "r");
        if (stream == NULL)
                return gnutls_assert_val(GNUTLS_E_FILE_ERROR);
 
-       gnutls_memset(p, 0, sizeof(*p));
-       ret = ini_parse_file(stream, handler, p);
+       gnutls_memset(hmac_file, 0, sizeof(*hmac_file));
+       ret = ini_parse_file(stream, handler, hmac_file);
        fclose(stream);
        if (ret < 0)
                return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
 
-       if (p->version != HMAC_FORMAT_VERSION)
+       if (hmac_file->version != HMAC_FORMAT_VERSION)
                return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
 
        return 0;
 }
 
-/* Run an HMAC using the key above on the library binary data.
- * Returns 0 on success and negative value on error.
+/*
+ * check_lib_hmac:
+ * @entry: hmac file entry
+ * @path: path to the library which hmac should be compared
+ *
+ * Verify that HMAC from hmac file entry matches HMAC of given library.
+ *
+ * Returns: 0 on successful HMAC verification, a negative error code otherwise
  */
-static int check_lib_hmac(struct hmac_entry *entry,
-                         const char *lib, const char *sym)
+static int check_lib_hmac(struct hmac_entry *entry, const char *path)
 {
        int ret;
        unsigned prev;
-       char path[GNUTLS_PATH_MAX];
        uint8_t hmac[HMAC_SIZE];
        gnutls_datum_t data;
 
-       ret = get_library_path(lib, sym, path, sizeof(path));
-       if (ret < 0) {
-               _gnutls_debug_log("Could not get lib path for %s: %s\n",
-                                 lib, gnutls_strerror(ret));
-               return gnutls_assert_val(ret);
-       }
-
        _gnutls_debug_log("Loading: %s\n", path);
        ret = gnutls_load_file(path, &data);
        if (ret < 0) {
@@ -385,28 +375,99 @@ static int check_lib_hmac(struct hmac_entry *entry,
        return 0;
 }
 
+#ifdef HAVE_DL_ITERATE_PHDR
+
+static int callback(struct dl_phdr_info *info, size_t size, void *data)
+{
+       const char *path = info->dlpi_name;
+       const char *soname = last_component(path);
+       struct lib_paths *paths = (struct lib_paths *)data;
+
+       if (!strcmp(soname, GNUTLS_LIBRARY_SONAME))
+               _gnutls_str_cpy(paths->gnutls, GNUTLS_PATH_MAX, path);
+       else if (!strcmp(soname, NETTLE_LIBRARY_SONAME))
+               _gnutls_str_cpy(paths->nettle, GNUTLS_PATH_MAX, path);
+       else if (!strcmp(soname, HOGWEED_LIBRARY_SONAME))
+               _gnutls_str_cpy(paths->hogweed, GNUTLS_PATH_MAX, path);
+       else if (!strcmp(soname, GMP_LIBRARY_SONAME))
+               _gnutls_str_cpy(paths->gmp, GNUTLS_PATH_MAX, path);
+       return 0;
+}
+
+static int load_lib_paths(struct lib_paths *paths)
+{
+       memset(paths, 0, sizeof(*paths));
+       dl_iterate_phdr(callback, paths);
+       
+       if (paths->gnutls[0] == '\0') {
+               _gnutls_debug_log("Gnutls library path was not found\n");
+               return gnutls_assert_val(GNUTLS_E_FILE_ERROR);
+       }
+       if (paths->nettle[0] == '\0') {
+               _gnutls_debug_log("Nettle library path was not found\n");
+               return gnutls_assert_val(GNUTLS_E_FILE_ERROR);
+       }
+       if (paths->hogweed[0] == '\0') {
+               _gnutls_debug_log("Hogweed library path was not found\n");
+               return gnutls_assert_val(GNUTLS_E_FILE_ERROR);
+       }
+       if (paths->gmp[0] == '\0') {
+               _gnutls_debug_log("Gmp library path was not found\n");
+               return gnutls_assert_val(GNUTLS_E_FILE_ERROR);
+       }
+
+       return GNUTLS_E_SUCCESS;
+}
+
+#else
+
+static int load_lib_paths(struct lib_paths *paths)
+{
+       (void)paths;
+       _gnutls_debug_log("Function dl_iterate_phdr is missing\n");
+       return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
+}
+
+#endif /* HAVE_DL_ITERATE_PHDR */
+
 static int check_binary_integrity(void)
 {
        int ret;
-       hmac_file file;
+       struct lib_paths paths;
+       struct hmac_file hmac;
+       char hmac_path[GNUTLS_PATH_MAX];
+
+       ret = load_lib_paths(&paths);
+       if (ret < 0) {
+               _gnutls_debug_log("Could not load library paths: %s\n",
+                                 gnutls_strerror(ret));
+               return ret;
+       }
+
+       ret = get_hmac_path(hmac_path, sizeof(hmac_path), paths.gnutls);
+       if (ret < 0) {
+               _gnutls_debug_log("Could not get hmac file path: %s\n",
+                                 gnutls_strerror(ret));
+               return ret;
+       }
 
-       ret = load_hmac_file(&file);
+       ret = load_hmac_file(&hmac, hmac_path);
        if (ret < 0) {
                _gnutls_debug_log("Could not load hmac file: %s\n",
                                  gnutls_strerror(ret));
                return ret;
        }
 
-       ret = check_lib_hmac(&file.gnutls, GNUTLS_LIBRARY_NAME, "gnutls_global_init");
+       ret = check_lib_hmac(&hmac.gnutls, paths.gnutls);
        if (ret < 0)
                return ret;
-       ret = check_lib_hmac(&file.nettle, NETTLE_LIBRARY_NAME, "nettle_aes_set_encrypt_key");
+       ret = check_lib_hmac(&hmac.nettle, paths.nettle);
        if (ret < 0)
                return ret;
-       ret = check_lib_hmac(&file.hogweed, HOGWEED_LIBRARY_NAME, "nettle_mpz_sizeinbase_256_u");
+       ret = check_lib_hmac(&hmac.hogweed, paths.hogweed);
        if (ret < 0)
                return ret;
-       ret = check_lib_hmac(&file.gmp, GMP_LIBRARY_NAME, "__gmpz_init");
+       ret = check_lib_hmac(&hmac.gmp, paths.gmp);
        if (ret < 0)
                return ret;
 
index 13051dfdab68cdd224997d6981d8a0b718692f03..14944c53fc85518b2c4437d7c16ae37e08b02aa9 100644 (file)
 
 #include "config.h"
 
-#include <gnutls/gnutls.h>
-#include <gnutls/crypto.h>
-#include <dlfcn.h>
-#include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
+
+#ifdef HAVE_DL_ITERATE_PHDR
+
+#include <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
+#include <link.h>
 #include "dirname.h"
 #include "errors.h"
 
 #define HMAC_ALGO GNUTLS_MAC_SHA256
 #define HMAC_STR_SIZE (2 * HMAC_SIZE + 1)
 
-static int get_path(const char *lib, const char *symbol, char *path, size_t path_size)
-{
-       int ret;
-       void *dl, *sym;
-       Dl_info info;
-
-       dl = dlopen(lib, RTLD_LAZY);
-       if (dl == NULL)
-               return gnutls_assert_val(GNUTLS_E_FILE_ERROR);
-
-       sym = dlsym(dl, symbol);
-       if (sym == NULL) {
-               ret = gnutls_assert_val(GNUTLS_E_FILE_ERROR);
-               goto cleanup;
-       }
-
-       ret = dladdr(sym, &info);
-       if (ret == 0) {
-               ret = gnutls_assert_val(GNUTLS_E_FILE_ERROR);
-               goto cleanup;
-       }
-
-       ret = snprintf(path, path_size, "%s", info.dli_fname);
-       if ((size_t)ret >= path_size) {
-               ret = gnutls_assert_val(GNUTLS_E_SHORT_MEMORY_BUFFER);
-               goto cleanup;
-       }
-
-       ret = 0;
-cleanup:
-       dlclose(dl);
-       return ret;
-}
-
 static int get_hmac(const char *path, char *hmac, size_t hmac_size)
 {
        int ret;
@@ -99,7 +67,7 @@ static int get_hmac(const char *path, char *hmac, size_t hmac_size)
        return 0;
 }
 
-static int print_lib_path(const char *path)
+static int print_lib(const char *path, const char *soname)
 {
        int ret;
        char *real_path = NULL;
@@ -119,7 +87,7 @@ static int print_lib_path(const char *path)
                goto cleanup;
        }
 
-       printf("[%s]\n", last_component(path));
+       printf("[%s]\n", soname);
        printf("path = %s\n", real_path);
        printf("hmac = %s\n", hmac);
 
@@ -128,25 +96,24 @@ cleanup:
        return ret;
 }
 
-static int print_lib_dl(const char *lib, const char *sym)
+static int callback(struct dl_phdr_info *info, size_t size, void *data)
 {
-       int ret;
-       char path[GNUTLS_PATH_MAX];
-
-       ret = get_path(lib, sym, path, sizeof(path));
-       if (ret < 0) {
-               fprintf(stderr, "Could not get lib path for %s: %s\n",
-                        lib, gnutls_strerror(ret));
-               return ret;
-       }
-
-       return print_lib_path(path);
+       const char *path = info->dlpi_name;
+       const char *soname = last_component(path);
+
+       if (!strcmp(soname, GNUTLS_LIBRARY_SONAME))
+               return print_lib(data ? data : path, soname);
+       if (!strcmp(soname, NETTLE_LIBRARY_SONAME))
+               return print_lib(path, soname);
+       if (!strcmp(soname, HOGWEED_LIBRARY_SONAME))
+               return print_lib(path, soname);
+       if (!strcmp(soname, GMP_LIBRARY_SONAME))
+               return print_lib(path, soname);
+        return 0;
 }
 
 int main(int argc, char **argv)
 {
-       int ret;
-
        if (argc != 1 && argc != 2) {
                fprintf(stderr, "Usage: %s [gnutls_so_path]\n", last_component(argv[0]));
                return EXIT_FAILURE;
@@ -155,24 +122,15 @@ int main(int argc, char **argv)
        printf("[global]\n");
        printf("format-version = %d\n", FORMAT_VERSION);
 
-       if (argc == 2)
-               ret = print_lib_path(argv[1]);
-       else
-               ret = print_lib_dl(GNUTLS_LIBRARY_SONAME, "gnutls_global_init");
-       if (ret < 0)
-               return EXIT_FAILURE;
+       return dl_iterate_phdr(callback, argc == 2 ? argv[1] : NULL);
+}
 
-       ret = print_lib_dl(NETTLE_LIBRARY_SONAME, "nettle_aes_set_encrypt_key");
-       if (ret < 0)
-               return EXIT_FAILURE;
-       
-       ret = print_lib_dl(HOGWEED_LIBRARY_SONAME, "nettle_mpz_sizeinbase_256_u");
-       if (ret < 0)
-               return EXIT_FAILURE;
-       
-       ret = print_lib_dl(GMP_LIBRARY_SONAME, "__gmpz_init");
-       if (ret < 0)
-               return EXIT_FAILURE;
+#else
 
-       return EXIT_SUCCESS;
+int main(void)
+{
+       fprintf(stderr, "Function dl_iterate_phdr is missing\n");
+       return EXIT_FAILURE;
 }
+
+#endif /* HAVE_DL_ITERATE_PHDR */