Hello community, here is the log from the commit of package libgcrypt for openSUSE:Factory checked in at 2020-05-19 14:43:00 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/libgcrypt (Old) and /work/SRC/openSUSE:Factory/.libgcrypt.new.2738 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "libgcrypt" Tue May 19 14:43:00 2020 rev:80 rq:805629 version:1.8.5 Changes: -------- --- /work/SRC/openSUSE:Factory/libgcrypt/libgcrypt.changes 2020-01-30 09:32:02.957189834 +0100 +++ /work/SRC/openSUSE:Factory/.libgcrypt.new.2738/libgcrypt.changes 2020-05-19 14:43:07.315382924 +0200 @@ -1,0 +2,70 @@ +Mon Apr 27 08:55:12 UTC 2020 - Pedro Monreal Gonzalez <pmonrealgonza...@suse.com> + +- 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 + +------------------------------------------------------------------- +Thu Apr 16 16:45:23 UTC 2020 - Vítězslav Čížek <vci...@suse.com> + +- 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 + +------------------------------------------------------------------- +Wed Apr 15 13:55:27 UTC 2020 - Pedro Monreal Gonzalez <pmonrealgonza...@suse.com> + +- 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 + +------------------------------------------------------------------- +Mon Mar 30 10:48:02 UTC 2020 - Pedro Monreal Gonzalez <pmonrealgonza...@suse.com> + +- 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 + +------------------------------------------------------------------- +Thu Mar 26 18:09:47 UTC 2020 - Pedro Monreal Gonzalez <pmonrealgonza...@suse.com> + +- FIPS: Run self-tests from constructor during power-on [bsc#1166748] + * Set up global_init as the constructor function: + - libgcrypt-global_init-constructor.patch + * Relax the entropy requirements on selftest. This is especially + important for virtual machines to boot properly before the RNG + is available: + - libgcrypt-random_selftests-testentropy.patch + - libgcrypt-rsa-no-blinding.patch + - libgcrypt-ecc-ecdsa-no-blinding.patch + * Fix benchmark regression test in FIPS mode: + - libgcrypt-FIPS-GMAC_AES-benckmark.patch + +------------------------------------------------------------------- +Thu Mar 12 16:54:33 UTC 2020 - Pedro Monreal Gonzalez <pmonrealgonza...@suse.com> + +- Remove check not needed in _gcry_global_constructor [bsc#1164950] + * Update libgcrypt-Restore-self-tests-from-constructor.patch + +------------------------------------------------------------------- +Tue Feb 25 22:13:24 UTC 2020 - Pedro Monreal Gonzalez <pmonrealgonza...@suse.com> + +- FIPS: Run the self-tests from the constructor [bsc#1164950] + * Add libgcrypt-invoke-global_init-from-constructor.patch + +------------------------------------------------------------------- Old: ---- libgcrypt-binary_integrity_in_non-FIPS.patch New: ---- libgcrypt-FIPS-GMAC_AES-benckmark.patch libgcrypt-PCT-DSA.patch libgcrypt-PCT-ECC.patch libgcrypt-PCT-RSA.patch libgcrypt-Restore-self-tests-from-constructor.patch libgcrypt-ecc-ecdsa-no-blinding.patch libgcrypt-fips_selftest_trigger_file.patch libgcrypt-global_init-constructor.patch libgcrypt-invoke-global_init-from-constructor.patch libgcrypt-random_selftests-testentropy.patch libgcrypt-rsa-no-blinding.patch ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ libgcrypt.spec ++++++ --- /var/tmp/diff_new_pack.ZdJnLU/_old 2020-05-19 14:43:08.959386437 +0200 +++ /var/tmp/diff_new_pack.ZdJnLU/_new 2020-05-19 14:43:08.959386437 +0200 @@ -18,7 +18,8 @@ %define build_hmac256 1 %define separate_hmac256_binary 0 -%define libsoname %{name}20 +%define libsover 20 +%define libsoname %{name}%{libsover} %define cavs_dir %{_libexecdir}/%{name}/cavs Name: libgcrypt Version: 1.8.5 @@ -55,7 +56,6 @@ #PATCH-FIX-UPSTREAM bsc#1064455 fipsdrv patch to enable --algo for dsa-verify Patch36: libgcrypt-fipsdrv-enable-algo-for-dsa-verify.patch Patch39: libgcrypt-1.8.3-fips-ctor.patch -Patch41: libgcrypt-binary_integrity_in_non-FIPS.patch Patch42: libgcrypt-fips_rsa_no_enforced_mode.patch Patch43: libgcrypt-1.8.4-use_xfree.patch Patch44: libgcrypt-1.8.4-allow_FSM_same_state.patch @@ -75,6 +75,20 @@ Patch53: libgcrypt-FIPS-RSA-DSA-ECDSA-hashing-operation.patch #PATCH-FIX-SUSE bsc#1161220 FIPS: libgcrypt RSA siggen/keygen: 4k not supported Patch54: libgcrypt-1.8.4-fips-keygen.patch +#PATCH-FIX-SUSE bsc#1164950 Run self-tests from the constructor +Patch55: libgcrypt-invoke-global_init-from-constructor.patch +#PATCH-FIX-SUSE bsc#1164950 Restore the self-tests from the constructor +Patch56: libgcrypt-Restore-self-tests-from-constructor.patch +Patch57: libgcrypt-FIPS-GMAC_AES-benckmark.patch +Patch58: libgcrypt-global_init-constructor.patch +Patch59: libgcrypt-random_selftests-testentropy.patch +Patch60: libgcrypt-rsa-no-blinding.patch +Patch61: libgcrypt-ecc-ecdsa-no-blinding.patch +#PATCH-FIX-SUSE bsc#1165539 FIPS: Use the new signature operation in PCT +Patch62: libgcrypt-PCT-RSA.patch +Patch63: libgcrypt-PCT-DSA.patch +Patch64: libgcrypt-PCT-ECC.patch +Patch65: libgcrypt-fips_selftest_trigger_file.patch BuildRequires: automake >= 1.14 BuildRequires: fipscheck BuildRequires: libgpg-error-devel >= 1.25 @@ -205,6 +219,11 @@ mv %{buildroot}%{_bindir}/fipsdrv %{buildroot}%{cavs_dir} mv %{buildroot}%{_bindir}/drbg_test %{buildroot}%{cavs_dir} +# create the FIPS "module is complete" trigger file +%if 0%{?build_hmac256} +touch %{buildroot}/%{_libdir}/.%{name}.so.%{libsover}.fips +%endif + %post -n %{libsoname} -p /sbin/ldconfig %postun -n %{libsoname} -p /sbin/ldconfig %post devel @@ -216,10 +235,13 @@ %files -n %{libsoname} %license COPYING.LIB %{_libdir}/%{name}.so.* +%if 0%{?build_hmac256} +%{_libdir}/.libgcrypt.so.*.hmac +%endif # %%if 0%%{?build_hmac256} %files -n %{libsoname}-hmac %if 0%{?build_hmac256} -%{_libdir}/.libgcrypt.so.*.hmac +%{_libdir}/.libgcrypt.so.*.fips %endif # %%if 0%%{?build_hmac256} %files devel ++++++ libgcrypt-FIPS-GMAC_AES-benckmark.patch ++++++ Index: libgcrypt-1.8.2/tests/benchmark.c =================================================================== --- libgcrypt-1.8.2.orig/tests/benchmark.c +++ libgcrypt-1.8.2/tests/benchmark.c @@ -598,7 +598,7 @@ mac_bench ( const char *algoname ) if (!algoname) { for (i=1; i < 600; i++) - if (in_fips_mode && i == GCRY_MAC_HMAC_MD5) + if (in_fips_mode && (i == GCRY_MAC_HMAC_MD5 || i == GCRY_MAC_GMAC_AES)) ; /* Don't use MD5 in fips mode. */ else if ( !gcry_mac_test_algo (i) ) mac_bench (gcry_mac_algo_name (i)); ++++++ libgcrypt-FIPS-RSA-DSA-ECDSA-hashing-operation.patch ++++++ --- /var/tmp/diff_new_pack.ZdJnLU/_old 2020-05-19 14:43:09.055386642 +0200 +++ /var/tmp/diff_new_pack.ZdJnLU/_new 2020-05-19 14:43:09.059386650 +0200 @@ -1,80 +1,13 @@ -Index: libgcrypt-1.8.2/cipher/pubkey-internal.h -=================================================================== ---- libgcrypt-1.8.2.orig/cipher/pubkey-internal.h -+++ libgcrypt-1.8.2/cipher/pubkey-internal.h -@@ -43,6 +43,7 @@ void _gcry_pk_util_free_encoding_ctx (st - gcry_err_code_t _gcry_pk_util_data_to_mpi (gcry_sexp_t input, - gcry_mpi_t *ret_mpi, - struct pk_encoding_ctx *ctx); -+gcry_err_code_t _gcry_pk_util_get_algo (gcry_sexp_t input, int *algo); - - - -Index: libgcrypt-1.8.2/cipher/pubkey-util.c -=================================================================== ---- libgcrypt-1.8.2.orig/cipher/pubkey-util.c -+++ libgcrypt-1.8.2/cipher/pubkey-util.c -@@ -1119,3 +1119,50 @@ _gcry_pk_util_data_to_mpi (gcry_sexp_t i - - return rc; - } -+ -+ -+gcry_err_code_t -+_gcry_pk_util_get_algo (gcry_sexp_t input, int *algo) -+{ -+ gcry_err_code_t rc = 0; -+ gcry_sexp_t ldata, list = NULL; -+ const char *s; -+ size_t n; -+ int lalgo; -+ -+ ldata = sexp_find_token (input, "data", 0); -+ if (!ldata) -+ { -+ rc = GPG_ERR_INV_OBJ; -+ goto leave; -+ } -+ -+ list = sexp_find_token (ldata, "hash-algo", 0); -+ if (!list) -+ { -+ rc = GPG_ERR_INV_OBJ; -+ goto leave; -+ } -+ -+ s = sexp_nth_data (list, 1, &n); -+ if (!s) -+ { -+ rc = GPG_ERR_NO_OBJ; -+ goto leave; -+ } -+ -+ lalgo = get_hash_algo (s, n); -+ if (!lalgo) -+ { -+ rc = GPG_ERR_DIGEST_ALGO; -+ goto leave; -+ } -+ -+ *algo = lalgo; -+ -+ leave: -+ sexp_release (ldata); -+ sexp_release (list); -+ -+ return rc; -+} Index: libgcrypt-1.8.2/cipher/pubkey.c =================================================================== --- libgcrypt-1.8.2.orig/cipher/pubkey.c +++ libgcrypt-1.8.2/cipher/pubkey.c -@@ -383,6 +383,33 @@ _gcry_pk_decrypt (gcry_sexp_t *r_plain, - return rc; +@@ -384,6 +384,33 @@ _gcry_pk_decrypt (gcry_sexp_t *r_plain, } + +static gcry_err_code_t -+calculate_hash (gcry_md_hd_t hd, gcry_sexp_t s_hash) ++calculate_hash (gcry_md_hd_t hd, gcry_sexp_t* s_hash) +{ + gcry_err_code_t rc; + const unsigned char *digest; @@ -83,27 +16,27 @@ + if (!hd) + return 0; + -+ rc = _gcry_pk_util_get_algo (s_hash, &algo); ++ rc = _gcry_pk_util_get_algo (*s_hash, &algo); + if (rc) + return rc; + + digest = _gcry_md_read(hd, algo); + if (!digest) -+ return GPG_ERR_DIGEST_ALGO; ++ return GPG_ERR_DIGEST_ALGO; + -+ rc = _gcry_sexp_build (&s_hash, NULL, -+ "(data (flags pkcs1)(hash %s %b))", -+ _gcry_md_algo_name(algo), (int) _gcry_md_get_algo_dlen(algo), digest); ++ rc = _gcry_sexp_build (s_hash, NULL, ++ "(data (flags pkcs1)(hash %s %b))", ++ _gcry_md_algo_name(algo), ++ (int) _gcry_md_get_algo_dlen(algo), ++ digest); + + return rc; +} + -+ -+ - /* -@@ -414,7 +442,8 @@ _gcry_pk_decrypt (gcry_sexp_t *r_plain, + Create a signature. +@@ -414,7 +441,8 @@ _gcry_pk_decrypt (gcry_sexp_t *r_plain, Note that (hash algo) in R_SIG is not used. */ gcry_err_code_t @@ -113,21 +46,21 @@ { gcry_err_code_t rc; gcry_pk_spec_t *spec; -@@ -426,6 +455,10 @@ _gcry_pk_sign (gcry_sexp_t *r_sig, gcry_ +@@ -426,6 +454,10 @@ _gcry_pk_sign (gcry_sexp_t *r_sig, gcry_ if (rc) goto leave; -+ rc = calculate_hash (hd, s_hash); ++ rc = calculate_hash (hd, &s_hash); + if (rc) + goto leave; + if (spec->sign) rc = spec->sign (r_sig, s_hash, keyparms); else -@@ -436,6 +469,13 @@ _gcry_pk_sign (gcry_sexp_t *r_sig, gcry_ - return rc; +@@ -437,6 +469,13 @@ _gcry_pk_sign (gcry_sexp_t *r_sig, gcry_ } + +gcry_err_code_t +_gcry_pk_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_hash, gcry_sexp_t s_skey) +{ @@ -135,51 +68,127 @@ +} + + - /* Verify a signature. -@@ -445,7 +485,8 @@ _gcry_pk_sign (gcry_sexp_t *r_sig, gcry_ + +@@ -445,7 +484,8 @@ _gcry_pk_sign (gcry_sexp_t *r_sig, gcry_ as an S-Exp, sig is a S-Exp as returned from gcry_pk_sign and data must be an S-Exp like the one in sign too. */ gcry_err_code_t -_gcry_pk_verify (gcry_sexp_t s_sig, gcry_sexp_t s_hash, gcry_sexp_t s_pkey) +_gcry_pk_verify_md (gcry_sexp_t s_sig, gcry_md_hd_t hd, gcry_sexp_t s_hash, -+ gcry_sexp_t s_pkey) ++ gcry_sexp_t s_pkey) { gcry_err_code_t rc; gcry_pk_spec_t *spec; -@@ -455,6 +496,10 @@ _gcry_pk_verify (gcry_sexp_t s_sig, gcry +@@ -455,6 +495,10 @@ _gcry_pk_verify (gcry_sexp_t s_sig, gcry if (rc) goto leave; -+ rc = calculate_hash (hd, s_hash); ++ rc = calculate_hash (hd, &s_hash); + if (rc) + goto leave; + if (spec->verify) rc = spec->verify (s_sig, s_hash, keyparms); else -@@ -465,6 +510,12 @@ _gcry_pk_verify (gcry_sexp_t s_sig, gcry - return rc; +@@ -466,6 +510,13 @@ _gcry_pk_verify (gcry_sexp_t s_sig, gcry } + +gcry_err_code_t +_gcry_pk_verify (gcry_sexp_t s_sig, gcry_sexp_t s_hash, gcry_sexp_t s_pkey) +{ + return _gcry_pk_verify_md (s_sig, NULL, s_hash, s_pkey); +} + - ++ /* Test a key. -@@ -497,6 +548,7 @@ _gcry_pk_testkey (gcry_sexp_t s_key) - } + +Index: libgcrypt-1.8.2/cipher/pubkey-internal.h +=================================================================== +--- libgcrypt-1.8.2.orig/cipher/pubkey-internal.h ++++ libgcrypt-1.8.2/cipher/pubkey-internal.h +@@ -43,6 +43,8 @@ void _gcry_pk_util_free_encoding_ctx (st + gcry_err_code_t _gcry_pk_util_data_to_mpi (gcry_sexp_t input, + gcry_mpi_t *ret_mpi, + struct pk_encoding_ctx *ctx); ++gcry_err_code_t _gcry_pk_util_get_algo (gcry_sexp_t input, ++ int *algo); + +Index: libgcrypt-1.8.2/cipher/pubkey-util.c +=================================================================== +--- libgcrypt-1.8.2.orig/cipher/pubkey-util.c ++++ libgcrypt-1.8.2/cipher/pubkey-util.c +@@ -1119,3 +1119,50 @@ _gcry_pk_util_data_to_mpi (gcry_sexp_t i + + return rc; + } + - /* - Create a public key pair and return it in r_key. - How the key is created depends on s_parms: ++ ++gcry_err_code_t ++_gcry_pk_util_get_algo (gcry_sexp_t input, int *algo) ++{ ++ gcry_err_code_t rc = 0; ++ gcry_sexp_t ldata, list = NULL; ++ const char *s; ++ size_t n; ++ int lalgo; ++ ++ ldata = sexp_find_token (input, "data", 0); ++ if (!ldata) ++ { ++ rc = GPG_ERR_INV_OBJ; ++ goto leave; ++ } ++ ++ list = sexp_find_token (ldata, "hash-algo", 0); ++ if (!list) ++ { ++ rc = GPG_ERR_INV_OBJ; ++ goto leave; ++ } ++ ++ s = sexp_nth_data (list, 1, &n); ++ if (!s) ++ { ++ rc = GPG_ERR_NO_OBJ; ++ goto leave; ++ } ++ ++ lalgo = get_hash_algo (s, n); ++ if (!lalgo) ++ { ++ rc = GPG_ERR_DIGEST_ALGO; ++ goto leave; ++ } ++ ++ *algo = lalgo; ++ ++ leave: ++ sexp_release (ldata); ++ sexp_release (list); ++ ++ return rc; ++} +Index: libgcrypt-1.8.2/src/g10lib.h +=================================================================== +--- libgcrypt-1.8.2.orig/src/g10lib.h ++++ libgcrypt-1.8.2/src/g10lib.h +@@ -288,6 +288,10 @@ gpg_err_code_t _gcry_generate_fips186_3_ + gpg_err_code_t _gcry_fips186_4_prime_check (const gcry_mpi_t x, + unsigned int bits); + ++gcry_err_code_t _gcry_pk_sign_md (gcry_sexp_t *r_sig, gcry_md_hd_t hd, ++ gcry_sexp_t s_hash, gcry_sexp_t s_skey); ++gcry_err_code_t _gcry_pk_verify_md (gcry_sexp_t s_sig, gcry_md_hd_t hd, ++ gcry_sexp_t s_hash, gcry_sexp_t s_pkey); + + /* Replacements of missing functions (missing-string.c). */ + #ifndef HAVE_STPCPY Index: libgcrypt-1.8.2/src/visibility.c =================================================================== --- libgcrypt-1.8.2.orig/src/visibility.c @@ -219,3 +228,18 @@ gcry_pk_verify (gcry_sexp_t sigval, gcry_sexp_t data, gcry_sexp_t pkey) { if (!fips_is_operational ()) +Index: libgcrypt-1.8.2/src/visibility.h +=================================================================== +--- libgcrypt-1.8.2.orig/src/visibility.h ++++ libgcrypt-1.8.2/src/visibility.h +@@ -357,8 +357,10 @@ MARK_VISIBLEX (_gcry_mpi_get_const) + #define gcry_pk_get_param _gcry_USE_THE_UNDERSCORED_FUNCTION + #define gcry_pk_get_nbits _gcry_USE_THE_UNDERSCORED_FUNCTION + #define gcry_pk_map_name _gcry_USE_THE_UNDERSCORED_FUNCTION ++#define gcry_pk_sign_md _gcry_USE_THE_UNDERSCORED_FUNCTION + #define gcry_pk_sign _gcry_USE_THE_UNDERSCORED_FUNCTION + #define gcry_pk_testkey _gcry_USE_THE_UNDERSCORED_FUNCTION ++#define gcry_pk_verify_md _gcry_USE_THE_UNDERSCORED_FUNCTION + #define gcry_pk_verify _gcry_USE_THE_UNDERSCORED_FUNCTION + #define gcry_pubkey_get_sexp _gcry_USE_THE_UNDERSCORED_FUNCTION + ++++++ libgcrypt-PCT-DSA.patch ++++++ Index: libgcrypt-1.8.2/cipher/dsa.c =================================================================== --- libgcrypt-1.8.2.orig/cipher/dsa.c +++ libgcrypt-1.8.2/cipher/dsa.c @@ -181,24 +181,91 @@ test_keys (DSA_secret_key *sk, unsigned /* Create a random plaintext. */ _gcry_mpi_randomize (data, qbits, GCRY_WEAK_RANDOM); - /* Sign DATA using the secret key. */ - sign (sig_a, sig_b, data, sk, 0, 0); + /* Use the gcry_pk_sign_md API in order to comply with FIPS 140-2, + * which requires full signature operation for PCT (hashing + + * asymmetric operation) */ + gcry_sexp_t s_skey = NULL; + gcry_sexp_t s_pkey = NULL; + gcry_sexp_t r_sig = NULL; + gcry_sexp_t s_hash = NULL; + gcry_md_hd_t hd = NULL; + gcry_mpi_t r_sig_mpi = NULL; + gcry_mpi_t s_sig_mpi = NULL; + unsigned char *buf = NULL; + size_t buflen; + + if (_gcry_md_open (&hd, GCRY_MD_SHA256, 0)) + { + log_debug ("gcry_pk_sign failed\n"); + goto leave; + } + + _gcry_mpi_aprint (GCRYMPI_FMT_STD, &buf, &buflen, data); + _gcry_md_write (hd, buf, buflen); + + xfree (buf); + + /* build DSA private key sexp in s_skey */ + sexp_build (&s_skey, NULL, "(private-key (dsa(p %m)(q %m)(g %m)(y %m)(x %m)))", + sk->p, sk->q, sk->g, sk->y, sk->x); + sexp_build (&s_hash, NULL, "(data (flags pkcs1)(hash-algo sha256))"); + if (_gcry_pk_sign_md (&r_sig, hd, s_hash, s_skey)) + { + log_debug ("gcry_pk_sign failed\n"); + goto leave; + } + + /* Check that the signature and the original plaintext differ. */ + if (_gcry_sexp_extract_param (r_sig, NULL, "rs", &r_sig_mpi, &s_sig_mpi, NULL)) + { + log_debug ("extracting signature data failed\n"); + goto leave; + } + + if ( !verify (r_sig_mpi, s_sig_mpi, data, &pk)) + { + log_debug ("Signature failed\n"); + goto leave; /* Signature matches but should not. */ + } + + _gcry_sexp_release (s_hash); + _gcry_md_close (hd); + + /* build DSA public key sexp in s_pkey */ + sexp_build (&s_pkey, NULL, "(public-key (dsa(p %m)(q %m)(g %m)(y %m)))", + pk.p, pk.q, pk.g, pk.y); + sexp_build (&s_hash, NULL, "(data (flags pkcs1)(hash-algo sha256))"); + + if (_gcry_md_open (&hd, GCRY_MD_SHA256, 0)) + log_debug ("gcry_md_open failed\n"); + + _gcry_mpi_aprint (GCRYMPI_FMT_STD, &buf, &buflen, data); + _gcry_md_write (hd, buf, buflen); + + xfree (buf); + + /* verify the signature */ + if (_gcry_pk_verify_md (r_sig, hd, s_hash, s_pkey)) + { + log_debug ("gcry_pk_verify failed\n"); + goto leave; /* Signature does not match. */ + } - /* Verify the signature using the public key. */ - if ( verify (sig_a, sig_b, data, &pk) ) - goto leave; /* Signature does not match. */ - - /* Modify the data and check that the signing fails. */ - mpi_add_ui (data, data, 1); - if ( !verify (sig_a, sig_b, data, &pk) ) - goto leave; /* Signature matches but should not. */ - - result = 0; /* The test succeeded. */ + result = 0; /* The test succeeded. */ leave: _gcry_mpi_release (sig_b); _gcry_mpi_release (sig_a); _gcry_mpi_release (data); + + _gcry_sexp_release (s_skey); + _gcry_sexp_release (s_pkey); + _gcry_sexp_release (s_hash); + _gcry_sexp_release (r_sig); + _gcry_mpi_release (r_sig_mpi); + _gcry_mpi_release (s_sig_mpi); + _gcry_md_close (hd); + return result; } ++++++ libgcrypt-PCT-ECC.patch ++++++ Index: libgcrypt-1.8.2/cipher/ecc.c =================================================================== --- libgcrypt-1.8.2.orig/cipher/ecc.c +++ libgcrypt-1.8.2/cipher/ecc.c @@ -99,7 +99,7 @@ static void *progress_cb_data; /* Local prototypes. */ -static void test_keys (ECC_secret_key * sk, unsigned int nbits); +static int test_keys (ECC_secret_key * sk, unsigned int nbits); static void test_ecdh_only_keys (ECC_secret_key * sk, unsigned int nbits, int flags); static unsigned int ecc_get_nbits (gcry_sexp_t parms); @@ -152,6 +152,7 @@ nist_generate_key (ECC_secret_key *sk, e gcry_random_level_t random_level; gcry_mpi_t x, y; const unsigned int pbits = mpi_get_nbits (E->p); + int free_skEname = 0; point_init (&Q); @@ -176,7 +177,6 @@ nist_generate_key (ECC_secret_key *sk, e else sk->d = _gcry_dsa_gen_k (E->n, random_level); - /* Compute Q. */ _gcry_mpi_ec_mul_point (&Q, sk->d, &E->G, ctx); @@ -190,6 +190,12 @@ nist_generate_key (ECC_secret_key *sk, e point_set (&sk->E.G, &E->G); sk->E.n = mpi_copy (E->n); sk->E.h = mpi_copy (E->h); + if (E->name) + { + free_skEname = 1; + sk->E.name = _gcry_xstrdup(E->name); + } + point_init (&sk->Q); x = mpi_new (pbits); @@ -261,10 +267,16 @@ nist_generate_key (ECC_secret_key *sk, e if ((flags & PUBKEY_FLAG_NO_KEYTEST)) ; /* User requested to skip the test. */ else if (sk->E.model != MPI_EC_MONTGOMERY) - test_keys (sk, nbits - 64); + { + if (test_keys (sk, nbits - 64)) + return GPG_ERR_BAD_SIGNATURE; + } else test_ecdh_only_keys (sk, nbits - 64, flags); + if (free_skEname) + xfree ((void*)sk->E.name); + return 0; } @@ -275,9 +287,10 @@ nist_generate_key (ECC_secret_key *sk, e * test if the information is recuperated. * Second, test with the sign and verify functions. */ -static void +static int test_keys (ECC_secret_key *sk, unsigned int nbits) { + int result = -1; /* Default to failure. */ ECC_public_key pk; gcry_mpi_t test = mpi_new (nbits); mpi_point_struct R_; @@ -297,17 +310,161 @@ test_keys (ECC_secret_key *sk, unsigned _gcry_mpi_randomize (test, nbits, GCRY_WEAK_RANDOM); - if (_gcry_ecc_ecdsa_sign (test, sk, r, s, 0, 0) ) - log_fatal ("ECDSA operation: sign failed\n"); + /* Use the gcry_pk_sign_md API in order to comply with FIPS 140-2, + * which requires full signature operation for PCT (hashing + + * asymmetric operation). */ + gcry_sexp_t r_sig = NULL; + gcry_sexp_t s_skey = NULL; + gcry_sexp_t s_pkey = NULL; + gcry_sexp_t s_hash = NULL; + gcry_mpi_t s_sig_mpi = NULL; + gcry_md_hd_t hd = NULL; + unsigned char *buf = NULL; + size_t buflen; + mpi_ec_t ctx; + int flags = 0; + + if (_gcry_md_open (&hd, GCRY_MD_SHA256, 0)) + log_debug ("gcry_pk_sign failed: _gcry_md_open\n"); + + _gcry_mpi_aprint (GCRYMPI_FMT_STD, &buf, &buflen, test); + _gcry_md_write (hd, buf, buflen); + + xfree (buf); + + sexp_build (&s_hash, NULL, "(data (flags rfc6979)(hash-algo sha256))"); + + /* Assemble the point Q from affine coordinates by simple + * concatenation. */ + gcry_mpi_t Qx = NULL; + gcry_mpi_t Qy = NULL; + Qx = mpi_new (0); + Qy = mpi_new (0); + ctx = _gcry_mpi_ec_p_internal_new (sk->E.model, sk->E.dialect, flags, + sk->E.p, sk->E.a, sk->E.b); + if (_gcry_mpi_ec_get_affine (Qx, Qy, &(sk->Q), ctx)) + log_debug ("ecdh: Failed to get affine coordinates for Q\n"); + + unsigned char *rawqx, *rawqy; + unsigned int rawqxlen, rawqylen; + rawqx = _gcry_mpi_get_buffer (Qx, 0, &rawqxlen, NULL); + rawqy = _gcry_mpi_get_buffer (Qy, 0, &rawqylen, NULL); + + if (rawqxlen != rawqylen) + { + // log_debug ("qx and qy size differ: %d != %d\n", rawqxlen, rawqylen); + if (rawqxlen < rawqylen) + { + size_t diff = rawqylen - rawqxlen; + unsigned char *zeros = xmalloc (rawqxlen + diff); + memset (zeros, 0, rawqxlen + diff); + memmove (zeros + diff, rawqx, rawqxlen); + xfree (rawqx); + rawqx = zeros; + rawqxlen += diff; + } + if (rawqylen < rawqxlen) + { + size_t diff = rawqxlen - rawqylen; + unsigned char *zeros = xmalloc (rawqylen + diff); + memset (zeros, 0, rawqylen + diff); + memmove (zeros + diff, rawqy, rawqylen); + xfree (rawqy); + rawqy = zeros; + rawqylen += diff; + } + } + + unsigned char q[1 + rawqxlen + rawqxlen]; + size_t qlen; + memset (&q, 0, sizeof(q)); + *q = 4; + memcpy (q + 1, rawqx, rawqxlen); + memcpy (q + 1 + rawqxlen, rawqy, rawqylen); + qlen = 1 + rawqxlen + rawqylen; + + _gcry_mpi_release (Qx); + _gcry_mpi_release (Qy); + xfree (rawqx); + xfree (rawqy); - if (_gcry_ecc_ecdsa_verify (test, &pk, r, s)) + /* build ECC private key sexp in s_skey */ + if (sk->E.name) { - log_fatal ("ECDSA operation: sign, verify failed\n"); + if (sexp_build (&s_skey, NULL, + "(private-key (ecc (curve %s)(d %m)(q %b)))", + sk->E.name, sk->d, qlen, q)) + log_debug ("ecc: Failed to build sexp for private key.\n"); + } + else + { + if (sexp_build (&s_skey, NULL, + "(private-key" + " (ecc (curve %s)(d %m)(p %m)(a %m)(b %m)(n %m)(h %m)(q %b)))", + "NIST P-512", sk->d, sk->E.p, sk->E.a, sk->E.b, sk->E.n, sk->E.h, + qlen, q)) + log_debug ("ecc: Failed to build sexp for private key.\n"); + } + + if (_gcry_pk_sign_md (&r_sig, hd, s_hash, s_skey)) + { + log_debug ("ecc: gcry_pk_sign failed\n"); + goto leave; + } + + /* Check that the signature and the original test differ. */ + if (_gcry_sexp_extract_param (r_sig, NULL, "s", &s_sig_mpi, NULL)) + { + log_debug ("extracting signature data failed\n"); + goto leave; + } + + if (!mpi_cmp (s_sig_mpi, test)) + { + log_debug ("Signature failed\n"); + goto leave; /* Signature and test match but should not. */ + } + + /* verify */ + /* build public key sexp in s_pkey */ + if (pk.E.name) + { + if (sexp_build (&s_pkey, NULL, + "(public-key (ecc (curve %s)(q %b)))", pk.E.name, qlen, q)) + log_debug ("ecc: Failed to build sexp for public key.\n"); + } + else + { + if (sexp_build (&s_pkey, NULL, + "(public-key" + " (ecc (curve %s)(p %m)(a %m)(b %m)(n %m)(h %m)(q %b)))", + "NIST P-512", pk.E.p, pk.E.a, pk.E.b, pk.E.n, pk.E.h, qlen, q)) + log_debug ("ecc: Failed to build sexp for private key.\n"); + } + + _gcry_md_close (hd); + + if (_gcry_md_open (&hd, GCRY_MD_SHA256, 0)) + log_debug ("gcry_pk_verify failed: _gcry_md_open\n"); + + _gcry_mpi_aprint (GCRYMPI_FMT_STD, &buf, &buflen, test); + _gcry_md_write (hd, buf, buflen); + + xfree (buf); + + /* verify the signature */ + if (_gcry_pk_verify_md (r_sig, hd, s_hash, s_pkey)) + { + log_debug ("ecc: gcry_pk_verify failed\n"); + goto leave; /* Signature does not match. */ } if (DBG_CIPHER) log_debug ("ECDSA operation: sign, verify ok.\n"); + result = 0; /* The test succeeded. */ + + leave: point_free (&pk.Q); _gcry_ecc_curve_free (&pk.E); @@ -317,6 +474,16 @@ test_keys (ECC_secret_key *sk, unsigned mpi_free (out); mpi_free (c); mpi_free (test); + + _gcry_sexp_release (r_sig); + _gcry_sexp_release (s_skey); + _gcry_sexp_release (s_pkey); + _gcry_sexp_release (s_hash); + _gcry_mpi_release (s_sig_mpi); + _gcry_md_close (hd); + xfree (ctx); + + return result; } Index: libgcrypt-1.8.2/cipher/pubkey.c =================================================================== --- libgcrypt-1.8.2.orig/cipher/pubkey.c +++ libgcrypt-1.8.2/cipher/pubkey.c @@ -390,6 +390,7 @@ calculate_hash (gcry_md_hd_t hd, gcry_se gcry_err_code_t rc; const unsigned char *digest; int algo; + const char *flags; if (!hd) return 0; @@ -398,16 +399,21 @@ calculate_hash (gcry_md_hd_t hd, gcry_se if (rc) return rc; + rc = _gcry_pk_util_get_flags (*s_hash, &flags); + if (rc) + return rc; + digest = _gcry_md_read(hd, algo); if (!digest) return GPG_ERR_DIGEST_ALGO; rc = _gcry_sexp_build (s_hash, NULL, - "(data (flags pkcs1)(hash %s %b))", + "(data (flags %s)(hash %s %b))", flags, _gcry_md_algo_name(algo), (int) _gcry_md_get_algo_dlen(algo), digest); + xfree ((void *)flags); return rc; } Index: libgcrypt-1.8.2/cipher/pubkey-internal.h =================================================================== --- libgcrypt-1.8.2.orig/cipher/pubkey-internal.h +++ libgcrypt-1.8.2/cipher/pubkey-internal.h @@ -45,6 +45,8 @@ gcry_err_code_t _gcry_pk_util_data_to_mp struct pk_encoding_ctx *ctx); gcry_err_code_t _gcry_pk_util_get_algo (gcry_sexp_t input, int *algo); +gcry_err_code_t _gcry_pk_util_get_flags (gcry_sexp_t input, + const char **flags); Index: libgcrypt-1.8.2/cipher/pubkey-util.c =================================================================== --- libgcrypt-1.8.2.orig/cipher/pubkey-util.c +++ libgcrypt-1.8.2/cipher/pubkey-util.c @@ -1120,6 +1120,40 @@ _gcry_pk_util_data_to_mpi (gcry_sexp_t i return rc; } +gcry_err_code_t +_gcry_pk_util_get_flags (gcry_sexp_t input, const char **flags) +{ + gcry_err_code_t rc = 0; + gcry_sexp_t ldata, list = NULL; + + ldata = sexp_find_token (input, "data", 0); + if (!ldata) + { + rc = GPG_ERR_INV_OBJ; + goto leave; + } + + list = sexp_find_token (ldata, "flags", 0); + if (!list) + { + rc = GPG_ERR_INV_OBJ; + goto leave; + } + + /* FIXME: gets only the first flag */ + *flags = sexp_nth_string (list, 1); + if (!*flags) + { + rc = GPG_ERR_NO_OBJ; + goto leave; + } + + leave: + sexp_release (ldata); + sexp_release (list); + + return rc; +} gcry_err_code_t _gcry_pk_util_get_algo (gcry_sexp_t input, int *algo) ++++++ libgcrypt-PCT-RSA.patch ++++++ Index: libgcrypt-1.8.2/cipher/rsa.c =================================================================== --- libgcrypt-1.8.2.orig/cipher/rsa.c +++ libgcrypt-1.8.2/cipher/rsa.c @@ -159,27 +159,93 @@ test_keys (RSA_secret_key *sk, unsigned /* Create another random plaintext as data for signature checking. */ _gcry_mpi_randomize (plaintext, nbits, GCRY_WEAK_RANDOM); - /* Use the RSA secret function to create a signature of the plaintext. */ - secret (signature, plaintext, sk); + /* Use the gcry_pk_sign_md API in order to comply with FIPS 140-2, + * which requires full signature operation for PCT (hashing + + * asymmetric operation */ + gcry_sexp_t s_skey = NULL; + gcry_sexp_t s_pkey = NULL; + gcry_sexp_t r_sig = NULL; + gcry_sexp_t s_hash = NULL; + gcry_md_hd_t hd = NULL; + gcry_mpi_t r_sig_mpi = NULL; + unsigned char *buf = NULL; + size_t buflen; - /* Use the RSA public function to verify this signature. */ - public (decr_plaintext, signature, &pk); - if (mpi_cmp (decr_plaintext, plaintext)) - goto leave; /* Signature does not match. */ - - /* Modify the signature and check that the signing fails. */ - mpi_add_ui (signature, signature, 1); - public (decr_plaintext, signature, &pk); - if (!mpi_cmp (decr_plaintext, plaintext)) - goto leave; /* Signature matches but should not. */ + if (_gcry_md_open (&hd, GCRY_MD_SHA256, 0)) + { + log_debug ("gcry_pk_sign failed\n"); + goto leave_hash; + } + + _gcry_mpi_aprint (GCRYMPI_FMT_STD, &buf, &buflen, plaintext); + _gcry_md_write (hd, buf, buflen); + + xfree (buf); + + /* build RSA private key sexp in s_skey */ + sexp_build (&s_skey, NULL, + "(private-key (rsa(n %m)(e %m)(d %m)(p %m)(q %m)))", + sk->n, sk->e, sk->d, sk->p, sk->q); + sexp_build (&s_hash, NULL, + "(data (flags pkcs1)(hash-algo sha256))"); + + if (_gcry_pk_sign_md (&r_sig, hd, s_hash, s_skey)) + { + log_debug ("gcry_pk_sign failed\n"); + goto leave_hash; + } + + /* Check that the signature and the original plaintext differ. */ + if (_gcry_sexp_extract_param (r_sig, "sig-val!rsa", "s", &r_sig_mpi, NULL)) + { + log_debug ("extracting signature data failed\n"); + goto leave_hash; + } + + if (!mpi_cmp (r_sig_mpi, plaintext)) + { + log_debug ("Signature failed\n"); + goto leave_hash; /* Signature and plaintext match but should not. */ + } + + _gcry_sexp_release (s_hash); + _gcry_md_close (hd); + + /* build RSA public key sexp in s_pkey */ + sexp_build (&s_pkey, NULL, "(public-key (rsa(n %m)(e %m)))", pk.n, pk.e); + sexp_build (&s_hash, NULL, "(data (flags pkcs1)(hash-algo sha256))"); + + if (_gcry_md_open (&hd, GCRY_MD_SHA256, 0)) + log_debug ("gcry_md_open failed\n"); + + _gcry_mpi_aprint (GCRYMPI_FMT_STD, &buf, &buflen, plaintext); + _gcry_md_write (hd, buf, buflen); + + xfree (buf); + + /* verify the signature */ + if (_gcry_pk_verify_md (r_sig, hd, s_hash, s_pkey)) + { + log_debug ("gcry_pk_verify failed\n"); + goto leave_hash; /* Signature does not match. */ + } result = 0; /* All tests succeeded. */ + leave_hash: + _gcry_sexp_release (s_skey); + _gcry_sexp_release (s_pkey); + _gcry_sexp_release (s_hash); + _gcry_sexp_release (r_sig); + _gcry_md_close (hd); + _gcry_mpi_release (r_sig_mpi); + leave: _gcry_mpi_release (signature); _gcry_mpi_release (decr_plaintext); _gcry_mpi_release (ciphertext); _gcry_mpi_release (plaintext); + return result; } @@ -1903,7 +1969,7 @@ selftest_encr_2048 (gcry_sexp_t pkey, gc /* This sexp trickery is to prevent the use of blinding. * The flag doesn't get inherited by encr, so we have to * derive a new sexp from the ciphertext */ - char buf[1024]; + unsigned char buf[1024]; memset(buf, 0, sizeof(buf)); err = _gcry_mpi_print (GCRYMPI_FMT_STD, buf, sizeof buf, NULL, ciphertext); if (err) ++++++ libgcrypt-Restore-self-tests-from-constructor.patch ++++++ Index: libgcrypt-1.8.2/src/global.c =================================================================== --- libgcrypt-1.8.2.orig/src/global.c +++ libgcrypt-1.8.2/src/global.c @@ -140,8 +140,9 @@ global_init (void) /* We always need the FSM lock to be functional. */ _gcry_initialize_fsm_lock (); - /* Run the self-tests from the constructor. */ - global_init (); + /* 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 ++++++ libgcrypt-ecc-ecdsa-no-blinding.patch ++++++ Index: libgcrypt-1.8.5/cipher/ecc.c =================================================================== --- libgcrypt-1.8.5.orig/cipher/ecc.c +++ libgcrypt-1.8.5/cipher/ecc.c @@ -2060,11 +2060,11 @@ selftest_sign (gcry_sexp_t pkey, gcry_se { /* Sample data from RFC 6979 section A.2.5, hash is of message "sample" */ static const char sample_data[] = - "(data (flags rfc6979)" + "(data (flags rfc6979 no-blinding)" " (hash sha256 #af2bdbe1aa9b6ec1e2ade1d694f41fc71a831d0268e98915" /**/ "62113d8a62add1bf#))"; static const char sample_data_bad[] = - "(data (flags rfc6979)" + "(data (flags rfc6979 no-blinding)" " (hash sha256 #bf2bdbe1aa9b6ec1e2ade1d694f41fc71a831d0268e98915" /**/ "62113d8a62add1bf#))"; static const char signature_r[] = Index: libgcrypt-1.8.5/cipher/ecc-ecdsa.c =================================================================== --- libgcrypt-1.8.5.orig/cipher/ecc-ecdsa.c +++ libgcrypt-1.8.5/cipher/ecc-ecdsa.c @@ -52,6 +52,7 @@ _gcry_ecc_ecdsa_sign (gcry_mpi_t input, mpi_ec_t ctx; gcry_mpi_t b; /* Random number needed for blinding. */ gcry_mpi_t bi; /* multiplicative inverse of B. */ + int with_blinding = !(flags & PUBKEY_FLAG_NO_BLINDING); if (DBG_CIPHER) log_mpidump ("ecdsa sign hash ", input ); @@ -65,12 +66,15 @@ _gcry_ecc_ecdsa_sign (gcry_mpi_t input, b = mpi_snew (qbits); bi = mpi_snew (qbits); - do + if (with_blinding) { - _gcry_mpi_randomize (b, qbits, GCRY_WEAK_RANDOM); - mpi_mod (b, b, skey->E.n); + do + { + _gcry_mpi_randomize (b, qbits, GCRY_WEAK_RANDOM); + mpi_mod (b, b, skey->E.n); + } + while (!mpi_invm (bi, b, skey->E.n)); } - while (!mpi_invm (bi, b, skey->E.n)); k = NULL; dr = mpi_alloc (0); @@ -128,15 +132,26 @@ _gcry_ecc_ecdsa_sign (gcry_mpi_t input, } while (!mpi_cmp_ui (r, 0)); - /* Computation of dr, sum, and s are blinded with b. */ - mpi_mulm (dr, b, skey->d, skey->E.n); - mpi_mulm (dr, dr, r, skey->E.n); /* dr = d*r mod n */ - mpi_mulm (sum, b, hash, skey->E.n); - mpi_addm (sum, sum, dr, skey->E.n); /* sum = hash + (d*r) mod n */ + if (!with_blinding) + { + mpi_mulm (dr, skey->d, r, skey->E.n); /* dr = d*r mod n */ + mpi_addm (sum, hash, dr, skey->E.n); /* sum = hash + (d*r) mod n */ + } + else + { + /* Computation of dr, sum, and s are blinded with b. */ + mpi_mulm (dr, b, skey->d, skey->E.n); + mpi_mulm (dr, dr, r, skey->E.n); /* dr = d*r mod n */ + mpi_mulm (sum, b, hash, skey->E.n); + mpi_addm (sum, sum, dr, skey->E.n); /* sum = hash + (d*r) mod n */ + } mpi_invm (k_1, k, skey->E.n); /* k_1 = k^(-1) mod n */ mpi_mulm (s, k_1, sum, skey->E.n); /* s = k^(-1)*(hash+(d*r)) mod n */ - /* Undo blinding by b^-1 */ - mpi_mulm (s, bi, s, skey->E.n); + if (with_blinding) + { + /* Undo blinding by b^-1 */ + mpi_mulm (s, bi, s, skey->E.n); + } } while (!mpi_cmp_ui (s, 0)); ++++++ libgcrypt-fips_selftest_trigger_file.patch ++++++ Index: libgcrypt-1.8.2/src/fips.c =================================================================== --- libgcrypt-1.8.2.orig/src/fips.c 2020-04-16 21:15:01.633217969 +0200 +++ libgcrypt-1.8.2/src/fips.c 2020-04-16 21:21:44.279376166 +0200 @@ -651,7 +651,7 @@ get_library_path(const char *libname, co } static gpg_error_t -get_hmac_path(char **fname) +get_hmac_path(char **fname, char *suffix) { char libpath[4096]; gpg_error_t err; @@ -676,7 +676,7 @@ get_hmac_path(char **fname) p = *fname; memmove (p+1, p, strlen (p)+1); *p = '.'; - strcat (*fname, ".hmac"); + strcat (*fname, suffix); err = 0; } } @@ -708,7 +708,7 @@ check_binary_integrity (void) else { FILE *fp; - err = get_hmac_path(&fname); + err = get_hmac_path(&fname, ".hmac"); if (!err) { /* Open the file. */ @@ -769,7 +769,7 @@ can_skip_selftests(void) if (fips_mode()) return 0; - if (get_hmac_path(&fname)) + if (get_hmac_path(&fname, ".fips")) return 0; /* check the hmac presence */ ++++++ libgcrypt-global_init-constructor.patch ++++++ 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; ++++++ libgcrypt-invoke-global_init-from-constructor.patch ++++++ Index: libgcrypt-1.8.2/src/global.c =================================================================== --- libgcrypt-1.8.2.orig/src/global.c +++ libgcrypt-1.8.2/src/global.c @@ -145,6 +145,9 @@ void __attribute__ ((constructor)) _gcry { /* We always need the FSM lock to be functional. */ _gcry_initialize_fsm_lock (); + + /* Run the self-tests from the constructor. */ + global_init (); } /* This function is called by the macro fips_is_operational and makes ++++++ libgcrypt-random_selftests-testentropy.patch ++++++ Index: libgcrypt-1.8.2/random/random-drbg.c =================================================================== --- libgcrypt-1.8.2.orig/random/random-drbg.c +++ libgcrypt-1.8.2/random/random-drbg.c @@ -2428,6 +2428,10 @@ drbg_healthcheck_sanity (struct gcry_drb /* if the following tests fail, it is likely that there is a buffer * overflow and we get a SIGSEV */ + test_data.testentropy = &testentropy; + test_data.fail_seed_source = 0; + drbg_string_fill (&testentropy, test->entropy, test->entropylen); + drbg->test_data = &test_data; ret = drbg_instantiate (drbg, NULL, coreref, 1); if (ret) goto outbuf; ++++++ libgcrypt-rsa-no-blinding.patch ++++++ --- libgcrypt-1.8.2.orig/cipher/rsa.c 2020-03-26 07:23:17.392861551 +0100 +++ libgcrypt-1.8.2.orig/cipher/rsa.c 2020-03-26 15:43:29.556282072 +0100 @@ -91,10 +91,16 @@ static const char sample_secret_key[] = " 79C974A6FA69E4D52FE796650623DE70622862713932AA2FD9F2EC856EAEAA77" " 88B4EA6084DC81C902F014829B18EA8B2666EC41586818E0589E18876065F97E" " 8D22CE2DA53A05951EC132DCEF41E70A9C35F4ACC268FFAC2ADF54FA1DA110B919#)" +"))"; +/* We need to get rid of the u value, in order to end in + * secret_core_std when called from secret. It's not used anyway. */ + +/* " (u #67CF0FD7635205DD80FA814EE9E9C267C17376BF3209FB5D1BC42890D2822A04" " 479DAF4D5B6ED69D0F8D1AF94164D07F8CD52ECEFE880641FA0F41DDAB1785E4" " A37A32F997A516480B4CD4F6482B9466A1765093ED95023CA32D5EDC1E34CEE9" " AF595BC51FE43C4BF810FA225AF697FB473B83815966188A4312C048B885E3F7#)))"; +*/ /* A sample 2048 bit RSA key used for the selftests (public only). */ static const char sample_public_key[] = @@ -1252,8 +1258,8 @@ rsa_check_secret_key (gcry_sexp_t keypar RSA_secret_key sk = {NULL, NULL, NULL, NULL, NULL, NULL}; /* To check the key we need the optional parameters. */ - rc = sexp_extract_param (keyparms, NULL, "nedpqu", - &sk.n, &sk.e, &sk.d, &sk.p, &sk.q, &sk.u, + rc = sexp_extract_param (keyparms, NULL, "npq", + &sk.n, &sk.p, &sk.q, NULL); if (rc) goto leave; @@ -1263,11 +1269,8 @@ rsa_check_secret_key (gcry_sexp_t keypar leave: _gcry_mpi_release (sk.n); - _gcry_mpi_release (sk.e); - _gcry_mpi_release (sk.d); _gcry_mpi_release (sk.p); _gcry_mpi_release (sk.q); - _gcry_mpi_release (sk.u); if (DBG_CIPHER) log_debug ("rsa_testkey => %s\n", gpg_strerror (rc)); return rc; @@ -1710,11 +1713,11 @@ static const char * selftest_sign_2048 (gcry_sexp_t pkey, gcry_sexp_t skey) { static const char sample_data[] = - "(data (flags pkcs1)" + "(data (flags pkcs1 no-blinding)" " (hash sha256 #11223344556677889900aabbccddeeff" /**/ "102030405060708090a0b0c0d0f01121#))"; static const char sample_data_bad[] = - "(data (flags pkcs1)" + "(data (flags pkcs1 no-blinding)" " (hash sha256 #11223344556677889900aabbccddeeff" /**/ "802030405060708090a0b0c0d0f01121#))"; @@ -1857,7 +1860,7 @@ selftest_encr_2048 (gcry_sexp_t pkey, gc gcry_mpi_t ref_mpi = NULL; /* Put the plaintext into an S-expression. */ - err = sexp_build (&plain, NULL, "(data (flags raw) (value %s))", plaintext); + err = sexp_build (&plain, NULL, "(data (flags raw no-blinding) (value %s))", plaintext); if (err) { errtxt = "converting data failed"; @@ -1897,6 +1900,26 @@ selftest_encr_2048 (gcry_sexp_t pkey, gc goto leave; } + /* This sexp trickery is to prevent the use of blinding. + * The flag doesn't get inherited by encr, so we have to + * derive a new sexp from the ciphertext */ + char buf[1024]; + memset(buf, 0, sizeof(buf)); + err = _gcry_mpi_print (GCRYMPI_FMT_STD, buf, sizeof buf, NULL, ciphertext); + if (err) + { + errtxt = "Dumping ciphertext mpi to buffer failed"; + goto leave; + } + + sexp_release (encr); + err = sexp_build (&encr, NULL, "(enc-val (flags no-blinding) (rsa (a %s)))", buf); + if (err) + { + errtxt = "Adding no-blinding flag to ciphertext failed"; + goto leave; + } + /* Decrypt. */ err = _gcry_pk_decrypt (&decr, encr, skey); if (err)