Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
SUSE:SLE-15-SP2:Update
libica.16467
libica-sles15sp2-FIPS-introduce-HMAC-based-libr...
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File libica-sles15sp2-FIPS-introduce-HMAC-based-library-integrity-check.patch of Package libica.16467
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 @@ lib_LTLIBRARIES = libica.la libica_la_CFLAGS = ${AM_CFLAGS} -I${srcdir}/include -I${srcdir}/../include \ -fvisibility=hidden -pthread 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 @@ internal_tests_ec_internal_test_CFLAGS = ${AM_CFLAGS} -I${srcdir}/include \ -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 = malloc(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.26.2
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor