forked from pool/libgcrypt
9a7cde5372
- FIPS: libgcrypt: Double free in test_keys() on failed signature verification [bsc#1169944] * Use safer gcry_mpi_release() instead of mpi_free() - Update patches: * libgcrypt-PCT-DSA.patch * libgcrypt-PCT-RSA.patch * libgcrypt-PCT-ECC.patch - Ship the FIPS checksum file in the shared library package and create a separate trigger file for the FIPS selftests (bsc#1169569) * add libgcrypt-fips_selftest_trigger_file.patch * refresh libgcrypt-global_init-constructor.patch - Remove libgcrypt-binary_integrity_in_non-FIPS.patch obsoleted by libgcrypt-global_init-constructor.patch - FIPS: Verify that the generated signature and the original input differ in test_keys function for RSA, DSA and ECC: [bsc#1165539] - Add zero-padding when qx and qy have different lengths when assembling the Q point from affine coordinates. - Refreshed patches: * libgcrypt-PCT-DSA.patch * libgcrypt-PCT-RSA.patch * libgcrypt-PCT-ECC.patch - FIPS: Switch the PCT to use the new signature operation [bsc#1165539] * Patches for DSA, RSA and ECDSA test_keys functions: - libgcrypt-PCT-DSA.patch - libgcrypt-PCT-RSA.patch - libgcrypt-PCT-ECC.patch - Update patch: libgcrypt-FIPS-RSA-DSA-ECDSA-hashing-operation.patch OBS-URL: https://build.opensuse.org/request/show/805624 OBS-URL: https://build.opensuse.org/package/show/devel:libraries:c_c++/libgcrypt?expand=0&rev=134
271 lines
7.3 KiB
Diff
271 lines
7.3 KiB
Diff
Index: libgcrypt-1.8.2/src/global.c
|
|
===================================================================
|
|
--- libgcrypt-1.8.2.orig/src/global.c 2020-04-16 21:13:28.252717330 +0200
|
|
+++ libgcrypt-1.8.2/src/global.c 2020-04-16 21:13:47.960822991 +0200
|
|
@@ -86,7 +86,7 @@ static gpg_err_code_t external_lock_test
|
|
likely to be called at startup. The suggested way for an
|
|
application to make sure that this has been called is by using
|
|
gcry_check_version. */
|
|
-static void
|
|
+static void __attribute__((constructor))
|
|
global_init (void)
|
|
{
|
|
gcry_error_t err = 0;
|
|
@@ -134,6 +134,16 @@ global_init (void)
|
|
if (err)
|
|
goto fail;
|
|
|
|
+ int no_secmem_save;
|
|
+ /* it should be always 0 at this point but let's keep on the safe side */
|
|
+ no_secmem_save = no_secure_memory;
|
|
+ no_secure_memory = 1;
|
|
+ err = _gcry_fips_run_selftests (0);
|
|
+ no_secure_memory = no_secmem_save;
|
|
+
|
|
+ if (err)
|
|
+ goto fail;
|
|
+
|
|
return;
|
|
|
|
fail:
|
|
@@ -141,16 +151,6 @@ global_init (void)
|
|
}
|
|
|
|
|
|
-void __attribute__ ((constructor)) _gcry_global_constructor (void)
|
|
-{
|
|
- /* We always need the FSM lock to be functional. */
|
|
- _gcry_initialize_fsm_lock ();
|
|
-
|
|
- /* We run the integrity check at this point. The remaining
|
|
- selftests are run before use of the library by application. */
|
|
- _gcry_fips_run_selftests (0);
|
|
-}
|
|
-
|
|
/* This function is called by the macro fips_is_operational and makes
|
|
sure that the minimal initialization has been done. This is far
|
|
from a perfect solution and hides problems with an improper
|
|
Index: libgcrypt-1.8.2/src/fips.c
|
|
===================================================================
|
|
--- libgcrypt-1.8.2.orig/src/fips.c 2020-04-16 21:13:28.252717330 +0200
|
|
+++ libgcrypt-1.8.2/src/fips.c 2020-04-16 21:14:44.781127616 +0200
|
|
@@ -125,6 +125,7 @@ void
|
|
_gcry_initialize_fips_mode (int force)
|
|
{
|
|
static int done;
|
|
+ gpg_error_t err;
|
|
|
|
/* Make sure we are not accidentally called twice. */
|
|
if (done)
|
|
@@ -214,6 +215,23 @@ _gcry_initialize_fips_mode (int force)
|
|
/* Yes, we are in FIPS mode. */
|
|
FILE *fp;
|
|
|
|
+ /* Intitialize the lock to protect the FSM. */
|
|
+ err = gpgrt_lock_init (&fsm_lock);
|
|
+ if (err)
|
|
+ {
|
|
+ /* If that fails we can't do anything but abort the
|
|
+ process. We need to use log_info so that the FSM won't
|
|
+ get involved. */
|
|
+ log_info ("FATAL: failed to create the FSM lock in libgcrypt: %s\n",
|
|
+ gpg_strerror (err));
|
|
+#ifdef HAVE_SYSLOG
|
|
+ syslog (LOG_USER|LOG_ERR, "Libgcrypt error: "
|
|
+ "creating FSM lock failed: %s - abort",
|
|
+ gpg_strerror (err));
|
|
+#endif /*HAVE_SYSLOG*/
|
|
+ abort ();
|
|
+ }
|
|
+
|
|
/* If the FIPS force files exists, is readable and has a number
|
|
!= 0 on its first line, we enable the enforced fips mode. */
|
|
fp = fopen (FIPS_FORCE_FILE, "r");
|
|
@@ -614,10 +632,10 @@ get_library_path(const char *libname, co
|
|
void *dl, *sym;
|
|
int rv = -1;
|
|
|
|
- dl = dlopen(libname, RTLD_LAZY);
|
|
- if (dl == NULL) {
|
|
- return -1;
|
|
- }
|
|
+ dl = dlopen(libname, RTLD_LAZY);
|
|
+ if (dl == NULL) {
|
|
+ return -1;
|
|
+ }
|
|
|
|
sym = dlsym(dl, symbolname);
|
|
|
|
@@ -632,6 +650,39 @@ get_library_path(const char *libname, co
|
|
return rv;
|
|
}
|
|
|
|
+static gpg_error_t
|
|
+get_hmac_path(char **fname)
|
|
+{
|
|
+ char libpath[4096];
|
|
+ gpg_error_t err;
|
|
+
|
|
+ if (get_library_path ("libgcrypt.so.20", "gcry_check_version", libpath, sizeof(libpath)))
|
|
+ err = gpg_error_from_syserror ();
|
|
+ else
|
|
+ {
|
|
+ *fname = _gcry_malloc (strlen (libpath) + 1 + 5 + 1 );
|
|
+ if (!*fname)
|
|
+ err = gpg_error_from_syserror ();
|
|
+ else
|
|
+ {
|
|
+ char *p;
|
|
+
|
|
+ /* Prefix the basename with a dot. */
|
|
+ strcpy (*fname, libpath);
|
|
+ p = strrchr (*fname, '/');
|
|
+ if (p)
|
|
+ p++;
|
|
+ else
|
|
+ p = *fname;
|
|
+ memmove (p+1, p, strlen (p)+1);
|
|
+ *p = '.';
|
|
+ strcat (*fname, ".hmac");
|
|
+ err = 0;
|
|
+ }
|
|
+ }
|
|
+ return err;
|
|
+}
|
|
+
|
|
/* Run an integrity check on the binary. Returns 0 on success. */
|
|
static int
|
|
check_binary_integrity (void)
|
|
@@ -656,25 +707,10 @@ check_binary_integrity (void)
|
|
err = gpg_error (GPG_ERR_INTERNAL);
|
|
else
|
|
{
|
|
- fname = xtrymalloc (strlen (libpath) + 1 + 5 + 1 );
|
|
- if (!fname)
|
|
- err = gpg_error_from_syserror ();
|
|
- else
|
|
- {
|
|
- FILE *fp;
|
|
- char *p;
|
|
-
|
|
- /* Prefix the basename with a dot. */
|
|
- strcpy (fname, libpath);
|
|
- p = strrchr (fname, '/');
|
|
- if (p)
|
|
- p++;
|
|
- else
|
|
- p = fname;
|
|
- memmove (p+1, p, strlen (p)+1);
|
|
- *p = '.';
|
|
- strcat (fname, ".hmac");
|
|
-
|
|
+ FILE *fp;
|
|
+ err = get_hmac_path(&fname);
|
|
+ if (!err)
|
|
+ {
|
|
/* Open the file. */
|
|
fp = fopen (fname, "r");
|
|
if (!fp)
|
|
@@ -725,6 +761,33 @@ check_binary_integrity (void)
|
|
#endif
|
|
}
|
|
|
|
+int
|
|
+can_skip_selftests(void)
|
|
+{
|
|
+ char *fname = NULL;
|
|
+ int ret = 0;
|
|
+
|
|
+ if (fips_mode())
|
|
+ return 0;
|
|
+
|
|
+ if (get_hmac_path(&fname))
|
|
+ return 0;
|
|
+
|
|
+ /* check the hmac presence */
|
|
+ if (access(fname, F_OK))
|
|
+ /* no hmac file is present, don't run the tests */
|
|
+ if (errno == ENOENT)
|
|
+ ret = 1;
|
|
+ /* otherwise one of these events happened:
|
|
+ * access() returned 0
|
|
+ * -> run the tests
|
|
+ * some error other than ENOENT occurred
|
|
+ * -> run the tests anyway and let them fail
|
|
+ */
|
|
+
|
|
+ xfree(fname);
|
|
+ return ret;
|
|
+}
|
|
|
|
/* Run the self-tests. If EXTENDED is true, extended versions of the
|
|
selftest are run, that is more tests than required by FIPS. */
|
|
@@ -733,26 +795,13 @@ _gcry_fips_run_selftests (int extended)
|
|
{
|
|
enum module_states result = STATE_ERROR;
|
|
gcry_err_code_t ec = GPG_ERR_SELFTEST_FAILED;
|
|
- int in_poweron;
|
|
|
|
- lock_fsm ();
|
|
- in_poweron = (current_state == STATE_POWERON);
|
|
- unlock_fsm ();
|
|
-
|
|
- fips_new_state (STATE_SELFTEST);
|
|
-
|
|
- /* We first check the integrity of the binary.
|
|
- If run from the constructor we are in POWERON state,
|
|
- we return and finish the remaining selftests before
|
|
- real use of the library. It will be in the POWERON
|
|
- state meanwhile. */
|
|
- if (in_poweron)
|
|
- if (check_binary_integrity ())
|
|
- goto leave;
|
|
-
|
|
- if (in_poweron)
|
|
+ if (can_skip_selftests())
|
|
return 0;
|
|
|
|
+ if (fips_mode ())
|
|
+ fips_new_state (STATE_SELFTEST);
|
|
+
|
|
if (run_cipher_selftests (extended))
|
|
goto leave;
|
|
|
|
@@ -762,6 +811,9 @@ _gcry_fips_run_selftests (int extended)
|
|
if (run_mac_selftests (extended))
|
|
goto leave;
|
|
|
|
+ if (check_binary_integrity ())
|
|
+ goto leave;
|
|
+
|
|
/* Run random tests before the pubkey tests because the latter
|
|
require random. */
|
|
if (run_random_selftests ())
|
|
@@ -775,7 +827,8 @@ _gcry_fips_run_selftests (int extended)
|
|
ec = 0;
|
|
|
|
leave:
|
|
- fips_new_state (result);
|
|
+ if (fips_mode ())
|
|
+ fips_new_state (result);
|
|
|
|
return ec;
|
|
}
|
|
@@ -831,7 +884,6 @@ fips_new_state (enum module_states new_s
|
|
{
|
|
case STATE_POWERON:
|
|
if (new_state == STATE_INIT
|
|
- || new_state == STATE_SELFTEST
|
|
|| new_state == STATE_ERROR
|
|
|| new_state == STATE_FATALERROR)
|
|
ok = 1;
|
|
@@ -846,8 +898,6 @@ fips_new_state (enum module_states new_s
|
|
|
|
case STATE_SELFTEST:
|
|
if (new_state == STATE_OPERATIONAL
|
|
- || new_state == STATE_INIT
|
|
- || new_state == STATE_SELFTEST
|
|
|| new_state == STATE_ERROR
|
|
|| new_state == STATE_FATALERROR)
|
|
ok = 1;
|