]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
Consolidate FIPS .hmac files
authorZoltan Fridrich <zfridric@redhat.com>
Wed, 23 Mar 2022 15:55:51 +0000 (16:55 +0100)
committerZoltan Fridrich <zfridric@redhat.com>
Wed, 30 Mar 2022 15:51:52 +0000 (17:51 +0200)
Signed-off-by: Zoltan Fridrich <zfridric@redhat.com>
lib/Makefile.am
lib/fips.c
lib/fipshmac.c

index c3d7b6ea90c19e506e1d34c5e8aab6d8e626c37e..4354cc53dd194896f394681f2362f46c9449ed55 100644 (file)
@@ -202,12 +202,12 @@ noinst_PROGRAMS = fipshmac
 fipshmac_SOURCES = fipshmac.c
 fipshmac_LDADD = libgnutls.la
 
-hmac_files = .libs/.$(gnutls_so).hmac
+hmac_files = .libs/.gnutls.hmac
 
 all-local: $(hmac_files)
 
-.libs/.$(gnutls_so).hmac: libgnutls.la fipshmac
-       $(AM_V_GEN) $(builddir)/fipshmac .libs/$(gnutls_so) > $@-t && mv $@-t $@
+.libs/.gnutls.hmac: libgnutls.la fipshmac
+       $(AM_V_GEN) $(builddir)/fipshmac > $@-t && mv $@-t $@
 
 CLEANFILES = $(hmac_files)
 endif
index f3d7773d3a5e91e8d96919f483540cffd844466b..33c903b10e70c1436e7e629b2af49311a58e4548 100644 (file)
@@ -24,6 +24,8 @@
 #include <gnutls/crypto.h>
 #include <unistd.h>
 #include "errors.h"
+#include "file.h"
+#include "inih/ini.h" 
 #include <fips.h>
 #include <gnutls/self-test.h>
 #include <stdio.h>
@@ -149,15 +151,29 @@ void _gnutls_fips_mode_reset_zombie(void)
 #define HOGWEED_LIBRARY_NAME HOGWEED_LIBRARY_SONAME
 #define GMP_LIBRARY_NAME GMP_LIBRARY_SONAME
 
-#define HMAC_SUFFIX ".hmac"
 #define HMAC_SIZE 32
 #define HMAC_ALGO GNUTLS_MAC_SHA256
+#define HMAC_FILE_NAME ".gnutls.hmac"
+#define HMAC_FORMAT_VERSION 1
+
+typedef struct
+{
+       int version;
+       char gnutls_path[GNUTLS_PATH_MAX];
+       char nettle_path[GNUTLS_PATH_MAX];
+       char hogweed_path[GNUTLS_PATH_MAX];
+       char gmp_path[GNUTLS_PATH_MAX];
+       uint8_t gnutls_hmac[HMAC_SIZE];
+       uint8_t nettle_hmac[HMAC_SIZE];
+       uint8_t hogweed_hmac[HMAC_SIZE];
+       uint8_t gmp_hmac[HMAC_SIZE];
+} hmac_file;
 
 static int get_library_path(const char* lib, const char* symbol, char* path, size_t path_size)
 {
-Dl_info info;
-int ret;
-void *dl, *sym;
+       int ret;
+       void *dl, *sym;
+       Dl_info info;
 
        dl = dlopen(lib, RTLD_LAZY);
        if (dl == NULL)
@@ -175,7 +191,11 @@ void *dl, *sym;
                goto cleanup;
        }
        
-       snprintf(path, path_size, "%s", info.dli_fname);
+       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:
@@ -183,55 +203,191 @@ cleanup:
        return ret;
 }
 
-static void get_hmac_file(char *mac_file, size_t mac_file_size, const char* orig)
+/* Parses hmac data and copies hex value into dest.
+ * dest must point to at least HMAC_SIZE amount of memory
+ */
+static int get_hmac(uint8_t *dest, const char *value)
 {
-char* p;
+       int ret;
+       size_t hmac_size;
+       gnutls_datum_t data;
 
-       p = strrchr(orig, '/');
-       if (p==NULL) {
-               snprintf(mac_file, mac_file_size, ".%s"HMAC_SUFFIX, orig);
-               return;
+       data.size = strlen(value);
+       if (hex_data_size(data.size) != HMAC_SIZE)
+               return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
+
+       data.data = (uint8_t *)gnutls_strdup(value);
+       if (data.data == NULL)
+               return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+
+       hmac_size = HMAC_SIZE;
+       ret = gnutls_hex_decode(&data, dest, &hmac_size);
+       gnutls_free(data.data);
+       if (ret < 0)
+               return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
+
+       if (hmac_size != HMAC_SIZE)
+               return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
+
+       return 0;
+}
+
+static int handler(void *user, const char *section, const char *name, const char *value)
+{
+       hmac_file *p = (hmac_file *)user;
+
+       if (!strcmp(section, "global")) {
+               if (!strcmp(name, "format-version")) {
+                       p->version = strtol(value, NULL, 10);
+               } else {
+                       return 0;
+               }
+       } else if (!strcmp(section, GNUTLS_LIBRARY_NAME)) {
+               if (!strcmp(name, "path")) {
+                       snprintf(p->gnutls_path, GNUTLS_PATH_MAX, "%s", value);
+               } else if (!strcmp(name, "hmac")) {
+                       if (get_hmac(p->gnutls_hmac, value) < 0)
+                               return 0;
+               } else {
+                       return 0;
+               }
+       } else if (!strcmp(section, NETTLE_LIBRARY_NAME)) {
+               if (!strcmp(name, "path")) {
+                       snprintf(p->nettle_path, GNUTLS_PATH_MAX, "%s", value);
+               } else if (!strcmp(name, "hmac")) {
+                       if (get_hmac(p->nettle_hmac, value) < 0)
+                               return 0;
+               } else {
+                       return 0;
+               }
+       } else if (!strcmp(section, HOGWEED_LIBRARY_NAME)) {
+               if (!strcmp(name, "path")) {
+                       snprintf(p->hogweed_path, GNUTLS_PATH_MAX, "%s", value);
+               } else if (!strcmp(name, "hmac")) {
+                       if (get_hmac(p->hogweed_hmac, value) < 0)
+                               return 0;
+               } else {
+                       return 0;
+               }
+       } else if (!strcmp(section, GMP_LIBRARY_NAME)) {
+               if (!strcmp(name, "path")) {
+                       snprintf(p->gmp_path, GNUTLS_PATH_MAX, "%s", value);
+               } else if (!strcmp(name, "hmac")) {
+                       if (get_hmac(p->gmp_hmac, value) < 0)
+                               return 0;
+               } else {
+                       return 0;
+               }
+       } else {
+               return 0;
        }
-       snprintf(mac_file, mac_file_size, "%.*s/.%s"HMAC_SUFFIX, (int)(p-orig), orig, p+1);
+       return 1;
 }
 
-static void get_hmac_file2(char *mac_file, size_t mac_file_size, const char* orig)
+static int get_hmac_path(char *mac_file, size_t mac_file_size)
 {
-char* p;
+       int ret;
+       char *p;
+       char file[GNUTLS_PATH_MAX];
 
-       p = strrchr(orig, '/');
-       if (p==NULL) {
-               snprintf(mac_file, mac_file_size, "fipscheck/%s"HMAC_SUFFIX, orig);
-               return;
+       ret = get_library_path(GNUTLS_LIBRARY_NAME, "gnutls_global_init",
+                              file, sizeof(file));
+       if (ret < 0)
+               return ret;
+
+       p = strrchr(file, '/');
+
+       if (p == NULL)
+               ret = snprintf(mac_file, mac_file_size, HMAC_FILE_NAME);
+       else
+               ret = snprintf(mac_file, mac_file_size,
+                              "%.*s/"HMAC_FILE_NAME, (int)(p - file), file);
+       if ((size_t)ret >= mac_file_size)
+               return gnutls_assert_val(GNUTLS_E_SHORT_MEMORY_BUFFER);
+
+       ret = _gnutls_file_exists(mac_file);
+       if (ret == 0)
+               return GNUTLS_E_SUCCESS;
+
+       if (p == NULL)
+               ret = snprintf(mac_file, mac_file_size, "fipscheck/"HMAC_FILE_NAME);
+       else
+               ret = snprintf(mac_file, mac_file_size,
+                              "%.*s/fipscheck/"HMAC_FILE_NAME, (int)(p - file), file);
+       if ((size_t)ret >= mac_file_size)
+               return gnutls_assert_val(GNUTLS_E_SHORT_MEMORY_BUFFER);
+
+       ret = _gnutls_file_exists(mac_file);
+       if (ret == 0)
+               return GNUTLS_E_SUCCESS;
+
+       return GNUTLS_E_FILE_ERROR;
+}
+
+static int load_hmac_file(hmac_file *p)
+{
+       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);
+       fclose(stream);
+       if (ret < 0)
+               return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
+
+       if (p->version != HMAC_FORMAT_VERSION)
+               return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
+
+       return 0;
+}
+
+static int check_lib_path(const char path[GNUTLS_PATH_MAX],
+                         const char *lib, const char *sym)
+{
+       int ret;
+       char new_path[GNUTLS_PATH_MAX];
+       
+       ret = get_library_path(lib, sym, new_path, sizeof(new_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);
        }
-       snprintf(mac_file, mac_file_size, "%.*s/fipscheck/%s"HMAC_SUFFIX, (int)(p-orig), orig, p+1);
+
+       if (strncmp(path, new_path, GNUTLS_PATH_MAX)) {
+               _gnutls_debug_log("Library path for %s does not match with HMAC file\n", lib);
+               return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
+       }
+
+       return 0;
 }
 
 /* Run an HMAC using the key above on the library binary data. 
- * Returns true on success and false on error.
+ * Returns 0 on success and negative value on error.
  */
-static unsigned check_binary_integrity(const char* libname, const char* symbol)
+static int check_lib_hmac(const char path[GNUTLS_PATH_MAX],
+                         const uint8_t hmac[HMAC_SIZE])
 {
        int ret;
        unsigned prev;
-       char mac_file[GNUTLS_PATH_MAX];
-       char file[GNUTLS_PATH_MAX];
-       uint8_t hmac[HMAC_SIZE];
        uint8_t new_hmac[HMAC_SIZE];
-       size_t hmac_size;
        gnutls_datum_t data;
-
-       ret = get_library_path(libname, symbol, file, sizeof(file));
-       if (ret < 0) {
-               _gnutls_debug_log("Could not get path for library %s\n", libname);
-               return 0;
-       }
-
-       _gnutls_debug_log("Loading: %s\n", file);
-       ret = gnutls_load_file(file, &data);
+       
+       _gnutls_debug_log("Loading: %s\n", path);
+       ret = gnutls_load_file(path, &data);
        if (ret < 0) {
-               _gnutls_debug_log("Could not load: %s\n", file);
-               return gnutls_assert_val(0);
+               _gnutls_debug_log("Could not load %s: %s\n",
+                                 path, gnutls_strerror(ret));
+               return gnutls_assert_val(ret);
        }
 
        prev = _gnutls_get_lib_state();
@@ -239,49 +395,61 @@ static unsigned check_binary_integrity(const char* libname, const char* symbol)
        ret = gnutls_hmac_fast(HMAC_ALGO, FIPS_KEY, sizeof(FIPS_KEY)-1,
                data.data, data.size, new_hmac);
        _gnutls_switch_lib_state(prev);
-       
-       gnutls_free(data.data);
-
-       if (ret < 0)
-               return gnutls_assert_val(0);
-
-       /* now open the .hmac file and compare */
-       get_hmac_file(mac_file, sizeof(mac_file), file);
 
-       ret = gnutls_load_file(mac_file, &data);
+       gnutls_free(data.data);
        if (ret < 0) {
-               get_hmac_file2(mac_file, sizeof(mac_file), file);
-               ret = gnutls_load_file(mac_file, &data);
-               if (ret < 0) {
-                       _gnutls_debug_log("Could not open %s for MAC testing: %s\n", mac_file, gnutls_strerror(ret));
-                       return gnutls_assert_val(0);
-               }
+               _gnutls_debug_log("Could not calculate HMAC for %s: %s\n",
+                                 path, gnutls_strerror(ret));
+               return gnutls_assert_val(ret);
        }
 
-       hmac_size = hex_data_size(data.size);
-
-       /* trim eventual newlines from the end of the data read from file */
-       while ((data.size > 0) && (data.data[data.size - 1] == '\n')) {
-               data.data[data.size - 1] = 0;
-               data.size--;
+       if (gnutls_memcmp(hmac, new_hmac, HMAC_SIZE)) {
+               _gnutls_debug_log("Calculated MAC for %s does not match\n", path);
+               return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
        }
+       _gnutls_debug_log("Successfully verified MAC for %s\n", path);
+       
+       return 0;
+}
 
-       ret = gnutls_hex_decode(&data, hmac, &hmac_size);
-       gnutls_free(data.data);
+static int check_binary_integrity(void)
+{
+       int ret;
+       hmac_file file;
 
+       ret = load_hmac_file(&file);
        if (ret < 0) {
-               _gnutls_debug_log("Could not convert hex data to binary for MAC testing for %s.\n", libname);
-               return gnutls_assert_val(0);
+               _gnutls_debug_log("Could not load hmac file: %s\n",
+                                 gnutls_strerror(ret));
+               return ret;
        }
 
-       if (hmac_size != sizeof(hmac) ||
-                       memcmp(hmac, new_hmac, sizeof(hmac)) != 0) {
-               _gnutls_debug_log("Calculated MAC for %s does not match\n", libname);
-               return gnutls_assert_val(0);
-       }
-       _gnutls_debug_log("Successfully verified MAC for %s (%s)\n", mac_file, libname);
-       
-       return 1;
+       ret = check_lib_path(file.gnutls_path, GNUTLS_LIBRARY_NAME, "gnutls_global_init");
+       if (ret < 0)
+               return ret;
+       ret = check_lib_hmac(file.gnutls_path, file.gnutls_hmac);
+       if (ret < 0)
+               return ret;
+       ret = check_lib_path(file.nettle_path, NETTLE_LIBRARY_NAME, "nettle_aes_set_encrypt_key");
+       if (ret < 0)
+               return ret;
+       ret = check_lib_hmac(file.nettle_path, file.nettle_hmac);
+       if (ret < 0)
+               return ret;
+       ret = check_lib_path(file.hogweed_path, HOGWEED_LIBRARY_NAME, "nettle_mpz_sizeinbase_256_u");
+       if (ret < 0)
+               return ret;
+       ret = check_lib_hmac(file.hogweed_path, file.hogweed_hmac);
+       if (ret < 0)
+               return ret;
+       ret = check_lib_path(file.gmp_path, GMP_LIBRARY_NAME, "__gmpz_init");
+       if (ret < 0)
+               return ret;
+       ret = check_lib_hmac(file.gmp_path, file.gmp_hmac);
+       if (ret < 0)
+               return ret;
+
+       return 0;
 }
 
 int _gnutls_fips_perform_self_checks1(void)
@@ -471,31 +639,13 @@ int _gnutls_fips_perform_self_checks2(void)
        }
 
        if (_skip_integrity_checks == 0) {
-               ret = check_binary_integrity(GNUTLS_LIBRARY_NAME, "gnutls_global_init");
-               if (ret == 0) {
-                       gnutls_assert();
-                       goto error;
-               }
-
-               ret = check_binary_integrity(NETTLE_LIBRARY_NAME, "nettle_aes_set_encrypt_key");
-               if (ret == 0) {
-                       gnutls_assert();
-                       goto error;
-               }
-
-               ret = check_binary_integrity(HOGWEED_LIBRARY_NAME, "nettle_mpz_sizeinbase_256_u");
-               if (ret == 0) {
-                       gnutls_assert();
-                       goto error;
-               }
-
-               ret = check_binary_integrity(GMP_LIBRARY_NAME, "__gmpz_init");
-               if (ret == 0) {
+               ret = check_binary_integrity();
+               if (ret < 0) {
                        gnutls_assert();
                        goto error;
                }
        }
-       
+
        return 0;
 
 error:
index 001417ff5974a51b5cb7149c0e7118848bfcb792..a75035fd73905b5337464289293d4f8a40a2ecbd 100644 (file)
@@ -1,7 +1,7 @@
 /*
- * Copyright (C) 2020 Red Hat
+ * Copyright (C) 2020-2022 Red Hat, Inc.
  *
- * Author: Ondrej Moris
+ * Authors: Ondrej Moris, Zoltan Fridrich
  *
  * This file is part of GnuTLS.
  *
 
 #include <gnutls/gnutls.h>
 #include <gnutls/crypto.h>
+#include <dlfcn.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include "errors.h"
 
+#define FORMAT_VERSION 1
 #define HMAC_SIZE 32
 #define HMAC_ALGO GNUTLS_MAC_SHA256
+#define HMAC_STR_SIZE (2 * HMAC_SIZE + 1)
 
-int main(int argc, char *argv[]) {
-       gnutls_datum_t data = { NULL, 0 };
-       gnutls_datum_t hex = { NULL, 0 };
-       uint8_t buffer[HMAC_SIZE];
-       gnutls_datum_t hmac = { buffer, sizeof(buffer) };
-       int status = EXIT_FAILURE;
+static int get_path(const char *lib, const char *symbol, char *path, size_t path_size)
+{
        int ret;
+       void *dl, *sym;
+       Dl_info info;
 
-       if (argc != 2) {
-               fprintf(stderr, "Usage: %s <file>\n", argv[0]);
-               goto error;
-       }
+       dl = dlopen(lib, RTLD_LAZY);
+       if (dl == NULL)
+               return gnutls_assert_val(GNUTLS_E_FILE_ERROR);
 
-       ret = gnutls_load_file(argv[1], &data);
-       if (ret < 0) {
-               fprintf(stderr, "Could not load %s: %s\n", argv[1],
-                       gnutls_strerror(ret));
-               goto 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;
+       size_t size;
+       uint8_t buffer[HMAC_SIZE];
+       gnutls_datum_t hex = { buffer, sizeof(buffer) };
+       gnutls_datum_t data = { NULL, 0 };
+
+       ret = gnutls_load_file(path, &data);
+       if (ret < 0)
+               return gnutls_assert_val(ret);
 
        GNUTLS_FIPS140_SET_LAX_MODE();
+       ret = gnutls_hmac_fast(HMAC_ALGO, FIPS_KEY, sizeof(FIPS_KEY) - 1,
+                               data.data, data.size, buffer);
+       GNUTLS_FIPS140_SET_STRICT_MODE();
+
+       gnutls_free(data.data);
+       if (ret < 0)
+               return gnutls_assert_val(ret);
+
+       size = hmac_size;
+       ret = gnutls_hex_encode(&hex, hmac, &size);
+       if (ret < 0)
+               return gnutls_assert_val(ret);
 
-       ret = gnutls_hmac_fast(HMAC_ALGO, FIPS_KEY, sizeof(FIPS_KEY)-1,
-                              data.data, data.size, buffer);
+       return 0;
+}
+
+static int print_lib(const char *lib, const char *sym)
+{
+       int ret;
+       char path[GNUTLS_PATH_MAX];
+       char hmac[HMAC_STR_SIZE];
+
+       ret = get_path(lib, sym, path, sizeof(path));
        if (ret < 0) {
-               fprintf(stderr, "Could not calculate MAC on %s: %s\n", argv[1],
-                       gnutls_strerror(ret));
-               goto error;
+               fprintf(stderr, "Could not get lib path for %s: %s\n",
+                        lib, gnutls_strerror(ret));
+               return ret;
        }
 
-       GNUTLS_FIPS140_SET_STRICT_MODE();
-
-       ret = gnutls_hex_encode2(&hmac, &hex);
+       ret = get_hmac(path, hmac, sizeof(hmac));
        if (ret < 0) {
-               fprintf(stderr, "Could not encode MAC value: %s\n",
-                       gnutls_strerror(ret));
-               goto error;
+               fprintf(stderr, "Could not calculate HMAC for %s: %s\n",
+                        lib, gnutls_strerror(ret));
+               return ret;
        }
 
-       printf("%s\n", hex.data);
+       printf("[%s]\n", lib);
+       printf("path = %s\n", path);
+       printf("hmac = %s\n", hmac);
 
-       status = EXIT_SUCCESS;
+       return 0;
+}
 
- error:
-       gnutls_free(data.data);
-       gnutls_free(hex.data);
+int main(void)
+{
+       printf("[global]\n");
+       printf("format-version = %d\n", FORMAT_VERSION);
+
+       if (print_lib(GNUTLS_LIBRARY_SONAME, "gnutls_global_init") < 0)
+               return EXIT_FAILURE;
+       if (print_lib(NETTLE_LIBRARY_SONAME, "nettle_aes_set_encrypt_key") < 0)
+               return EXIT_FAILURE;
+       if (print_lib(HOGWEED_LIBRARY_SONAME, "nettle_mpz_sizeinbase_256_u") < 0)
+               return EXIT_FAILURE;
+       if (print_lib(GMP_LIBRARY_SONAME, "__gmpz_init") < 0)
+               return EXIT_FAILURE;
 
-       return status;
+       return EXIT_SUCCESS;
 }