forked from pool/libica
This commit is contained in:
parent
fe79785559
commit
1f072ef96a
@ -1,354 +0,0 @@
|
|||||||
From 231bba3b32bd246d8286f1c7dc231d836ea92bd9 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Joerg Schmidbauer <jschmidb@de.ibm.com>
|
|
||||||
Date: Mon, 27 Apr 2020 11:18:26 +0200
|
|
||||||
Subject: [PATCH] FIPS: introduce HMAC based library integrity check
|
|
||||||
|
|
||||||
When in FIPS mode, perform an integrity check on libica.so by calculating
|
|
||||||
an HMAC from the file contents using a static HMAC key, and comparing it
|
|
||||||
to a pre-calculated HMAC in a separate file. The HMAC key and HMAC file
|
|
||||||
may be provided by a Distributor when building the packet. The test
|
|
||||||
succeeds if the HMAC file is not present.
|
|
||||||
|
|
||||||
Signed-off-by: Joerg Schmidbauer <jschmidb@de.ibm.com>
|
|
||||||
---
|
|
||||||
include/ica_api.h | 2 +-
|
|
||||||
src/Makefile.am | 4 +-
|
|
||||||
src/fips.c | 224 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
|
|
||||||
src/include/fips.h | 4 +-
|
|
||||||
test/fips_test.c | 4 +
|
|
||||||
5 files changed, 232 insertions(+), 6 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/include/ica_api.h b/include/ica_api.h
|
|
||||||
index 91bf0be..8221f55 100644
|
|
||||||
--- a/include/ica_api.h
|
|
||||||
+++ b/include/ica_api.h
|
|
||||||
@@ -216,7 +216,7 @@ typedef ica_adapter_handle_t ICA_ADAPTER_HANDLE;
|
|
||||||
*/
|
|
||||||
/* Cryptographic algorithm test (KAT or pair-wise consistency test) */
|
|
||||||
#define ICA_FIPS_CRYPTOALG 2
|
|
||||||
-/* Software/Firmware integrity test (not implemented yet) */
|
|
||||||
+/* Software/Firmware integrity test */
|
|
||||||
#define ICA_FIPS_INTEGRITY 4
|
|
||||||
/* Critical functions test (N/A) */
|
|
||||||
#define ICA_FIPS_CRITICALFUNC 8
|
|
||||||
diff --git a/src/Makefile.am b/src/Makefile.am
|
|
||||||
index 65f471f..9e4ef52 100644
|
|
||||||
--- a/src/Makefile.am
|
|
||||||
+++ b/src/Makefile.am
|
|
||||||
@@ -9,7 +9,7 @@
|
|
||||||
libica_la_CFLAGS = ${AM_CFLAGS} -I${srcdir}/include -I${srcdir}/../include \
|
|
||||||
-fvisibility=hidden
|
|
||||||
libica_la_CCASFLAGS = ${AM_CFLAGS}
|
|
||||||
-libica_la_LIBADD = @LIBS@ -lrt -lcrypto
|
|
||||||
+libica_la_LIBADD = @LIBS@ -lrt -lcrypto -ldl
|
|
||||||
libica_la_LDFLAGS = -Wl,--version-script=${srcdir}/../libica.map \
|
|
||||||
-version-number ${VERSION}
|
|
||||||
libica_la_SOURCES = ica_api.c init.c icastats_shared.c s390_rsa.c \
|
|
||||||
@@ -53,7 +53,7 @@
|
|
||||||
-DICA_INTERNAL_TEST \
|
|
||||||
-DICA_INTERNAL_TEST_EC
|
|
||||||
internal_tests_ec_internal_test_CCASFLAGS = ${AM_CFLAGS}
|
|
||||||
-internal_tests_ec_internal_test_LDADD = @LIBS@ -lrt -lcrypto -lpthread
|
|
||||||
+internal_tests_ec_internal_test_LDADD = @LIBS@ -lrt -lcrypto -lpthread -ldl
|
|
||||||
internal_tests_ec_internal_test_SOURCES = \
|
|
||||||
ica_api.c init.c icastats_shared.c s390_rsa.c \
|
|
||||||
s390_crypto.c s390_ecc.c s390_prng.c s390_sha.c \
|
|
||||||
diff --git a/src/fips.c b/src/fips.c
|
|
||||||
index d09a553..bab00db 100644
|
|
||||||
--- a/src/fips.c
|
|
||||||
+++ b/src/fips.c
|
|
||||||
@@ -13,11 +13,13 @@
|
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
#include <openssl/crypto.h>
|
|
||||||
+#include <openssl/evp.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <syslog.h>
|
|
||||||
+#include <dlfcn.h>
|
|
||||||
|
|
||||||
#include <openssl/opensslconf.h>
|
|
||||||
#ifdef OPENSSL_FIPS
|
|
||||||
@@ -28,6 +30,24 @@
|
|
||||||
#include "ica_api.h"
|
|
||||||
#include "test_vec.h"
|
|
||||||
|
|
||||||
+#ifndef PATH_MAX
|
|
||||||
+#define PATH_MAX 4096
|
|
||||||
+#endif
|
|
||||||
+
|
|
||||||
+#define HMAC_PREFIX "."
|
|
||||||
+#define HMAC_SUFFIX ".hmac"
|
|
||||||
+#define READ_BUFFER_LENGTH 16384
|
|
||||||
+
|
|
||||||
+/*
|
|
||||||
+ * The hard-coded HMAC key to be optionally provided for the library
|
|
||||||
+ * integrity test. The recommended key size for HMAC-SHA256 is 64 bytes.
|
|
||||||
+ * The known HMAC is supposed to be provided as hex string in a file
|
|
||||||
+ * libica.so.MAJOR.hmac in the same directory as the .so module.
|
|
||||||
+ */
|
|
||||||
+static const char hmackey[] =
|
|
||||||
+ "0000000000000000000000000000000000000000000000000000000000000000"
|
|
||||||
+ "0000000000000000000000000000000000000000000000000000000000000000";
|
|
||||||
+
|
|
||||||
int fips;
|
|
||||||
|
|
||||||
static int aes_ecb_kat(void);
|
|
||||||
@@ -101,6 +121,206 @@ fips_init(void)
|
|
||||||
FIPS_mode_set(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+static int get_library_path(const char *libname, const char *symbolname,
|
|
||||||
+ char *path, size_t pathlen)
|
|
||||||
+{
|
|
||||||
+ Dl_info info;
|
|
||||||
+ void *dl, *sym;
|
|
||||||
+ int rc = -1;
|
|
||||||
+
|
|
||||||
+ dl = dlopen(libname, RTLD_LAZY);
|
|
||||||
+ if (dl == NULL)
|
|
||||||
+ goto done;
|
|
||||||
+
|
|
||||||
+ sym = dlsym(dl, symbolname);
|
|
||||||
+ if (sym != NULL && dladdr(sym, &info)) {
|
|
||||||
+ if (strlen(info.dli_fname) < pathlen)
|
|
||||||
+ strcpy(path, info.dli_fname);
|
|
||||||
+ else
|
|
||||||
+ goto done;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ rc = 0;
|
|
||||||
+
|
|
||||||
+done:
|
|
||||||
+ if (dl != NULL)
|
|
||||||
+ dlclose(dl);
|
|
||||||
+
|
|
||||||
+ return rc;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static char *make_hmac_path(const char *origpath)
|
|
||||||
+{
|
|
||||||
+ char *path;
|
|
||||||
+ const char *fn;
|
|
||||||
+
|
|
||||||
+ path = calloc(1,sizeof(HMAC_PREFIX) + sizeof(HMAC_SUFFIX) + strlen(origpath) + 1);
|
|
||||||
+ if (path == NULL)
|
|
||||||
+ return NULL;
|
|
||||||
+
|
|
||||||
+ fn = strrchr(origpath, '/');
|
|
||||||
+ if (fn == NULL) {
|
|
||||||
+ fn = origpath;
|
|
||||||
+ } else {
|
|
||||||
+ ++fn;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ strncpy(path, origpath, fn - origpath);
|
|
||||||
+ strcat(path, HMAC_PREFIX);
|
|
||||||
+ strcat(path, fn);
|
|
||||||
+ strcat(path, HMAC_SUFFIX);
|
|
||||||
+
|
|
||||||
+ return path;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int compute_file_hmac(const char *path, void **buf, size_t *hmaclen)
|
|
||||||
+{
|
|
||||||
+ FILE *fp = NULL;
|
|
||||||
+ int rc = -1;
|
|
||||||
+ unsigned char rbuf[READ_BUFFER_LENGTH];
|
|
||||||
+ unsigned char *keybuf;
|
|
||||||
+ EVP_MD_CTX *mdctx = NULL;
|
|
||||||
+ EVP_PKEY *pkey = NULL;
|
|
||||||
+ size_t hlen, len;
|
|
||||||
+ long keylen;
|
|
||||||
+
|
|
||||||
+ keybuf = OPENSSL_hexstr2buf(hmackey, &keylen);
|
|
||||||
+ pkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, keybuf, (int)keylen);
|
|
||||||
+ if (!pkey)
|
|
||||||
+ goto end;
|
|
||||||
+
|
|
||||||
+ mdctx = EVP_MD_CTX_create();
|
|
||||||
+ if (!mdctx)
|
|
||||||
+ goto end;
|
|
||||||
+
|
|
||||||
+ fp = fopen(path, "r");
|
|
||||||
+ if (fp == NULL)
|
|
||||||
+ goto end;
|
|
||||||
+
|
|
||||||
+ if (EVP_DigestSignInit(mdctx, NULL, EVP_sha256(), NULL, pkey) <= 0)
|
|
||||||
+ goto end;
|
|
||||||
+
|
|
||||||
+ while ((len = fread(rbuf, 1, sizeof(rbuf), fp)) != 0) {
|
|
||||||
+ if (EVP_DigestSignUpdate(mdctx, rbuf, len) <= 0) {
|
|
||||||
+ goto end;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (EVP_DigestSignFinal(mdctx, rbuf, &hlen) <= 0)
|
|
||||||
+ goto end;
|
|
||||||
+
|
|
||||||
+ *buf = malloc(hlen);
|
|
||||||
+ if (*buf == NULL)
|
|
||||||
+ goto end;
|
|
||||||
+
|
|
||||||
+ *hmaclen = hlen;
|
|
||||||
+
|
|
||||||
+ memcpy(*buf, rbuf, hlen);
|
|
||||||
+
|
|
||||||
+ rc = 0;
|
|
||||||
+
|
|
||||||
+end:
|
|
||||||
+
|
|
||||||
+ if (pkey != NULL)
|
|
||||||
+ EVP_PKEY_free(pkey);
|
|
||||||
+
|
|
||||||
+ free(keybuf);
|
|
||||||
+ EVP_MD_CTX_destroy(mdctx);
|
|
||||||
+ if (fp)
|
|
||||||
+ fclose(fp);
|
|
||||||
+
|
|
||||||
+ return rc;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+/**
|
|
||||||
+ * Performs the FIPS check.
|
|
||||||
+ *
|
|
||||||
+ * @return 1 if check succeeded
|
|
||||||
+ * 0 otherwise
|
|
||||||
+ */
|
|
||||||
+static int FIPSCHECK_verify(const char *path)
|
|
||||||
+{
|
|
||||||
+ int rc = 0;
|
|
||||||
+ FILE *fp;
|
|
||||||
+ unsigned char *hmac_buf = NULL;
|
|
||||||
+ long hmaclen;
|
|
||||||
+ char *hmacpath, *p;
|
|
||||||
+ char *hmac_str = NULL;
|
|
||||||
+ size_t n, buflen;
|
|
||||||
+ void *buf = NULL;
|
|
||||||
+
|
|
||||||
+ hmacpath = make_hmac_path(path);
|
|
||||||
+ if (hmacpath == NULL)
|
|
||||||
+ return 0;
|
|
||||||
+
|
|
||||||
+ fp = fopen(hmacpath, "r");
|
|
||||||
+ if (fp == NULL) {
|
|
||||||
+ rc = 1;
|
|
||||||
+ goto end;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (getline(&hmac_str, &n, fp) <= 0)
|
|
||||||
+ goto end;
|
|
||||||
+
|
|
||||||
+ if ((p = strchr(hmac_str, '\n')) != NULL)
|
|
||||||
+ *p = '\0';
|
|
||||||
+
|
|
||||||
+ hmac_buf = OPENSSL_hexstr2buf(hmac_str, &hmaclen);
|
|
||||||
+
|
|
||||||
+ if (compute_file_hmac(path, &buf, &buflen) != 0)
|
|
||||||
+ goto end;
|
|
||||||
+
|
|
||||||
+ if (memcmp(buf, hmac_buf, hmaclen) != 0)
|
|
||||||
+ goto end;
|
|
||||||
+
|
|
||||||
+ rc = 1;
|
|
||||||
+
|
|
||||||
+end:
|
|
||||||
+
|
|
||||||
+ free(buf);
|
|
||||||
+ free(hmac_str);
|
|
||||||
+ free(hmacpath);
|
|
||||||
+
|
|
||||||
+ OPENSSL_free(hmac_buf);
|
|
||||||
+
|
|
||||||
+ if (fp)
|
|
||||||
+ fclose(fp);
|
|
||||||
+
|
|
||||||
+ return rc;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static const char msg1[] = "Libica FIPS library integrity check failed. Cannot determine library path.\n";
|
|
||||||
+static const char msg2[] = "Libica FIPS library integrity check failed. Module %s probably corrupted.\n";
|
|
||||||
+static const char msg3[] = "Libica FIPS library integrity check passed.\n";
|
|
||||||
+
|
|
||||||
+/*
|
|
||||||
+ * Perform an integrity check on libica.so by calculating an HMAC from
|
|
||||||
+ * the file contents using a static HMAC key, and comparing it to a
|
|
||||||
+ * pre-calculated HMAC in a separate file. The HMAC key and HMAC file
|
|
||||||
+ * may be provided by a Distributor when building the packet.
|
|
||||||
+ */
|
|
||||||
+static void fips_lib_integrity_check(void)
|
|
||||||
+{
|
|
||||||
+ int rc;
|
|
||||||
+ char path[PATH_MAX];
|
|
||||||
+ const char *libname = "libica.so";
|
|
||||||
+ const char *symbolname = "ica_sha256";
|
|
||||||
+
|
|
||||||
+ rc = get_library_path(libname, symbolname, path, sizeof(path));
|
|
||||||
+ if (rc != 0) {
|
|
||||||
+ syslog(LOG_ERR, msg1);
|
|
||||||
+ fips |= ICA_FIPS_INTEGRITY;
|
|
||||||
+ return;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (!FIPSCHECK_verify(path)) {
|
|
||||||
+ syslog(LOG_ERR, msg2, path);
|
|
||||||
+ fips |= ICA_FIPS_INTEGRITY;
|
|
||||||
+ return;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ syslog(LOG_INFO, msg3);
|
|
||||||
+}
|
|
||||||
|
|
||||||
void
|
|
||||||
fips_powerup_tests(void)
|
|
||||||
@@ -117,6 +337,9 @@ fips_powerup_tests(void)
|
|
||||||
fips |= ICA_FIPS_CRYPTOALG;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
+
|
|
||||||
+ /* Library integrity test */
|
|
||||||
+ fips_lib_integrity_check();
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
@@ -933,5 +1156,4 @@ _err_:
|
|
||||||
syslog(LOG_ERR, "Libica RSA test failed.");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
-
|
|
||||||
#endif /* FIPS_H */
|
|
||||||
diff --git a/src/include/fips.h b/src/include/fips.h
|
|
||||||
index 421be4c..0ffdef6 100644
|
|
||||||
--- a/src/include/fips.h
|
|
||||||
+++ b/src/include/fips.h
|
|
||||||
@@ -27,8 +27,8 @@ extern int fips; /* module status */
|
|
||||||
void fips_init(void);
|
|
||||||
|
|
||||||
/*
|
|
||||||
- * Powerup tests: crypto algorithm test, SW/FW integrity test (not implemented
|
|
||||||
- * yet), critical function test (no critical functions). The tests set the
|
|
||||||
+ * Powerup tests: crypto algorithm test, SW/FW integrity test, critical
|
|
||||||
+ * function test (no critical functions). The tests set the
|
|
||||||
* corresponding status flags.
|
|
||||||
*/
|
|
||||||
void fips_powerup_tests(void);
|
|
||||||
diff --git a/test/fips_test.c b/test/fips_test.c
|
|
||||||
index 06563e3..0f1940d 100644
|
|
||||||
--- a/test/fips_test.c
|
|
||||||
+++ b/test/fips_test.c
|
|
||||||
@@ -57,6 +57,10 @@ main(void)
|
|
||||||
printf("Libica FIPS powerup test failed.\n");
|
|
||||||
rv = EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
+ if (fips & ICA_FIPS_INTEGRITY) {
|
|
||||||
+ printf("Libica FIPS integrity check failed.\n");
|
|
||||||
+ rv = EXIT_FAILURE;
|
|
||||||
+ }
|
|
||||||
#endif /* ICA_FIPS */
|
|
||||||
|
|
||||||
printf("OpenSSL version is '%s'.\n", OPENSSL_VERSION_TEXT);
|
|
||||||
--
|
|
||||||
2.16.4
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
|||||||
#
|
#
|
||||||
# spec file for package libica
|
# spec file for package libica
|
||||||
#
|
#
|
||||||
# Copyright (c) 2018-2020 SUSE LLC
|
# Copyright (c) 2020 SUSE LLC
|
||||||
#
|
#
|
||||||
# All modifications and additions to the file contributed by third parties
|
# All modifications and additions to the file contributed by third parties
|
||||||
# remain the property of their copyright owners, unless otherwise agreed
|
# remain the property of their copyright owners, unless otherwise agreed
|
||||||
|
Loading…
Reference in New Issue
Block a user