Hello community, here is the log from the commit of package libgcrypt for openSUSE:Leap:15.2 checked in at 2020-05-04 08:22:17 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Leap:15.2/libgcrypt (Old) and /work/SRC/openSUSE:Leap:15.2/.libgcrypt.new.2738 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "libgcrypt" Mon May 4 08:22:17 2020 rev:44 rq:797127 version:1.8.2 Changes: -------- --- /work/SRC/openSUSE:Leap:15.2/libgcrypt/libgcrypt.changes 2020-04-12 15:37:58.401993146 +0200 +++ /work/SRC/openSUSE:Leap:15.2/.libgcrypt.new.2738/libgcrypt.changes 2020-05-04 08:22:18.676320007 +0200 @@ -1,0 +2,32 @@ +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 + +------------------------------------------------------------------- Old: ---- libgcrypt-binary_integrity_in_non-FIPS.patch New: ---- libgcrypt-PCT-DSA.patch libgcrypt-PCT-ECC.patch libgcrypt-PCT-RSA.patch libgcrypt-fips_selftest_trigger_file.patch ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ libgcrypt.spec ++++++ --- /var/tmp/diff_new_pack.5MMGvE/_old 2020-05-04 08:22:19.496321764 +0200 +++ /var/tmp/diff_new_pack.5MMGvE/_new 2020-05-04 08:22:19.496321764 +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.2 @@ -60,7 +61,6 @@ #PATCH-FIX-UPSTREAM bsc#1097410 fix novel side-channel attack Patch37: CVE-2018-0495.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-allow_FSM_same_state.patch #PATCH-FIX-UPSTREAM bsc#1138939 CVE-2019-12904 C implementation of AES is @@ -95,6 +95,11 @@ Patch62: libgcrypt-ecc-ecdsa-no-blinding.patch #PATCH-FIX-UPSTREAM bsc#1167674 FIPS: Fix drbg to be threadsafe Patch63: libgcrypt-check-re-open-dev_random-after-fork.patch +#PATCH-FIX-SUSE bsc#1165539 FIPS: Use the new signature operation in PCT +Patch64: libgcrypt-PCT-RSA.patch +Patch65: libgcrypt-PCT-DSA.patch +Patch66: libgcrypt-PCT-ECC.patch +Patch67: libgcrypt-fips_selftest_trigger_file.patch BuildRequires: automake >= 1.14 BuildRequires: fipscheck BuildRequires: libgpg-error-devel >= 1.25 @@ -134,7 +139,7 @@ Requires: %{libsoname} = %{version} Requires: glibc-devel Requires: libgpg-error-devel >= 1.13 -Requires(post): %{install_info_prereq} +#Requires(post): %{install_info_prereq} %description devel Libgcrypt is a general purpose library of cryptographic building @@ -194,7 +199,6 @@ %patch36 -p1 %patch37 -p1 %patch39 -p1 -%patch41 -p1 %patch42 -p1 %patch43 -p1 %patch44 -p1 @@ -217,6 +221,10 @@ %patch61 -p1 %patch62 -p1 %patch63 -p1 +%patch64 -p1 +%patch65 -p1 +%patch66 -p1 +%patch67 -p1 %build echo building with build_hmac256 set to %{build_hmac256} @@ -272,6 +280,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 @@ -283,10 +296,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-RSA-DSA-ECDSA-hashing-operation.patch ++++++ --- /var/tmp/diff_new_pack.5MMGvE/_old 2020-05-04 08:22:19.576321935 +0200 +++ /var/tmp/diff_new_pack.5MMGvE/_new 2020-05-04 08:22:19.576321935 +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,88 @@ 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; + 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); + + /* 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. */ + gcry_mpi_t r_sig_mpi = NULL; + gcry_mpi_t s_sig_mpi = NULL; + 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); + xfree (buf); + + /* 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); + + /* 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); + mpi_free (r_sig_mpi); + mpi_free (s_sig_mpi); + _gcry_md_close (hd); + xfree (buf); + 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,149 @@ 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_md_hd_t hd = NULL; + unsigned char *buf = NULL; + size_t buflen; + 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); + + mpi_ec_t ctx; + int flags = 0; + gcry_sexp_t r_sig = NULL; + gcry_sexp_t s_hash = NULL; + gcry_sexp_t s_pkey = NULL; + gcry_sexp_t s_skey = NULL; + 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; + + /* build ECC private key sexp in s_skey */ + if (sk->E.name) + { + 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. */ + gcry_mpi_t s_sig_mpi = NULL; + 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"); + } + + 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); - if (_gcry_ecc_ecdsa_verify (test, &pk, r, s)) + /* verify the signature */ + if (_gcry_pk_verify_md (r_sig, hd, s_hash, s_pkey)) { - log_fatal ("ECDSA operation: sign, verify failed\n"); + 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 +462,20 @@ test_keys (ECC_secret_key *sk, unsigned mpi_free (out); mpi_free (c); mpi_free (test); + _gcry_sexp_release (s_skey); + _gcry_sexp_release (s_pkey); + _gcry_sexp_release (s_hash); + _gcry_sexp_release (r_sig); + _gcry_md_close (hd); + mpi_free (Qx); + mpi_free (Qy); + mpi_free (s_sig_mpi); + xfree (buf); + xfree (ctx); + xfree (rawqx); + xfree (rawqy); + + 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,19 +159,73 @@ 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; + 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; + } + + _gcry_mpi_aprint (GCRYMPI_FMT_STD, &buf, &buflen, plaintext); + _gcry_md_write (hd, buf, buflen); + + /* 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; + } + + /* Check that the signature and the original plaintext differ. */ + gcry_mpi_t r_sig_mpi = NULL; + if (_gcry_sexp_extract_param (r_sig, "sig-val!rsa", "s", &r_sig_mpi, NULL)) + { + log_debug ("extracting signature data failed\n"); + goto leave; + } + + if (!mpi_cmp (r_sig_mpi, plaintext)) + { + log_debug ("Signature failed\n"); + goto leave; /* Signature and plaintext match but should not. */ + } + + _gcry_sexp_release (s_hash); + _gcry_md_close (hd); + xfree (buf); + + /* 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); + + /* 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. */ + } result = 0; /* All tests succeeded. */ @@ -180,6 +234,12 @@ test_keys (RSA_secret_key *sk, unsigned _gcry_mpi_release (decr_plaintext); _gcry_mpi_release (ciphertext); _gcry_mpi_release (plaintext); + _gcry_sexp_release (s_skey); + _gcry_sexp_release (s_pkey); + _gcry_sexp_release (s_hash); + _gcry_sexp_release (r_sig); + _gcry_md_close (hd); + mpi_free (r_sig_mpi); return result; } @@ -1903,7 +1963,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-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 ++++++ --- /var/tmp/diff_new_pack.5MMGvE/_old 2020-05-04 08:22:19.620322029 +0200 +++ /var/tmp/diff_new_pack.5MMGvE/_new 2020-05-04 08:22:19.624322038 +0200 @@ -1,7 +1,7 @@ Index: libgcrypt-1.8.2/src/global.c =================================================================== ---- libgcrypt-1.8.2.orig/src/global.c -+++ 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 @@ -47,9 +47,9 @@ 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 -+++ libgcrypt-1.8.2/src/fips.c -@@ -169,6 +169,7 @@ void +--- 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; @@ -57,7 +57,7 @@ /* Make sure we are not accidentally called twice. */ if (done) -@@ -258,6 +259,23 @@ _gcry_initialize_fips_mode (int force) +@@ -214,6 +215,23 @@ _gcry_initialize_fips_mode (int force) /* Yes, we are in FIPS mode. */ FILE *fp; @@ -81,7 +81,7 @@ /* 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"); -@@ -658,10 +676,10 @@ get_library_path(const char *libname, co +@@ -614,10 +632,10 @@ get_library_path(const char *libname, co void *dl, *sym; int rv = -1; @@ -96,7 +96,7 @@ sym = dlsym(dl, symbolname); -@@ -676,6 +694,39 @@ get_library_path(const char *libname, co +@@ -632,6 +650,39 @@ get_library_path(const char *libname, co return rv; } @@ -135,8 +135,8 @@ + /* Run an integrity check on the binary. Returns 0 on success. */ static int - check_binary_integrity () -@@ -700,25 +751,10 @@ check_binary_integrity () + check_binary_integrity (void) +@@ -656,25 +707,10 @@ check_binary_integrity (void) err = gpg_error (GPG_ERR_INTERNAL); else { @@ -166,7 +166,7 @@ /* Open the file. */ fp = fopen (fname, "r"); if (!fp) -@@ -776,6 +812,32 @@ check_binary_integrity () +@@ -725,6 +761,32 @@ check_binary_integrity (void) #endif } @@ -199,7 +199,7 @@ /* Run the self-tests. If EXTENDED is true, extended versions of the selftest are run, that is more tests than required by FIPS. */ -@@ -784,26 +846,13 @@ _gcry_fips_run_selftests (int extended) +@@ -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; @@ -230,7 +230,7 @@ if (run_cipher_selftests (extended)) goto leave; -@@ -813,6 +862,9 @@ _gcry_fips_run_selftests (int extended) +@@ -762,6 +811,9 @@ _gcry_fips_run_selftests (int extended) if (run_mac_selftests (extended)) goto leave; @@ -240,7 +240,7 @@ /* Run random tests before the pubkey tests because the latter require random. */ if (run_random_selftests ()) -@@ -826,7 +878,8 @@ _gcry_fips_run_selftests (int extended) +@@ -775,7 +827,8 @@ _gcry_fips_run_selftests (int extended) ec = 0; leave: @@ -250,7 +250,7 @@ return ec; } -@@ -882,7 +935,6 @@ fips_new_state (enum module_states new_s +@@ -831,7 +884,6 @@ fips_new_state (enum module_states new_s { case STATE_POWERON: if (new_state == STATE_INIT @@ -258,7 +258,7 @@ || new_state == STATE_ERROR || new_state == STATE_FATALERROR) ok = 1; -@@ -897,8 +949,6 @@ fips_new_state (enum module_states new_s +@@ -846,8 +898,6 @@ fips_new_state (enum module_states new_s case STATE_SELFTEST: if (new_state == STATE_OPERATIONAL