diff --git a/SOURCES/libgcrypt-1.10.0-allow-short-salt.patch b/SOURCES/libgcrypt-1.10.0-allow-short-salt.patch new file mode 100644 index 0000000..46054cf --- /dev/null +++ b/SOURCES/libgcrypt-1.10.0-allow-short-salt.patch @@ -0,0 +1,51 @@ +From 58c92098d053aae7c78cc42bdd7c80c13efc89bb Mon Sep 17 00:00:00 2001 +From: NIIBE Yutaka +Date: Fri, 24 Jun 2022 08:59:31 +0900 +Subject: [PATCH] hmac,hkdf: Allow use of shorter salt for HKDF. + +* cipher/md.c (prepare_macpads): Move the check to... +* src/visibility.c (gcry_mac_setkey): ... here. +* tests/t-kdf.c (check_hkdf): No failure is expected. + +-- + +GnuPG-bug-id: 6039 +Fixes-commit: 76aad97dd312e83f2f9b8d086553f2b72ab6546f +Signed-off-by: NIIBE Yutaka +--- + cipher/md.c | 3 --- + src/visibility.c | 3 +++ + tests/t-kdf.c | 12 +----------- + 3 files changed, 4 insertions(+), 14 deletions(-) + +diff --git a/cipher/md.c b/cipher/md.c +index 4f4fc9bf..34336b5c 100644 +--- a/cipher/md.c ++++ b/cipher/md.c +@@ -903,9 +903,6 @@ prepare_macpads (gcry_md_hd_t a, const unsigned char *key, size_t keylen) + { + GcryDigestEntry *r; + +- if (fips_mode () && keylen < 14) +- return GPG_ERR_INV_VALUE; +- + if (!a->ctx->list) + return GPG_ERR_DIGEST_ALGO; /* Might happen if no algo is enabled. */ + +diff --git a/src/visibility.c b/src/visibility.c +index c98247d8..aee5bffb 100644 +--- a/src/visibility.c ++++ b/src/visibility.c +@@ -946,6 +946,9 @@ gcry_mac_setkey (gcry_mac_hd_t hd, const void *key, size_t keylen) + if (!fips_is_operational ()) + return gpg_error (fips_not_operational ()); + ++ if (fips_mode () && keylen < 14) ++ return GPG_ERR_INV_VALUE; ++ + return gpg_error (_gcry_mac_setkey (hd, key, keylen)); + } + +-- +2.37.1 + diff --git a/SOURCES/libgcrypt-1.10.0-allow-small-RSA-verify.patch b/SOURCES/libgcrypt-1.10.0-allow-small-RSA-verify.patch new file mode 100644 index 0000000..278afa7 --- /dev/null +++ b/SOURCES/libgcrypt-1.10.0-allow-small-RSA-verify.patch @@ -0,0 +1,70 @@ +From ca2afc9fb64d9a9b2f8930ba505d9ab6c8a57667 Mon Sep 17 00:00:00 2001 +From: Jakub Jelen +Date: Thu, 12 May 2022 10:56:47 +0200 +Subject: [PATCH] cipher: Allow verification of small RSA signatures in FIPS + mode + +* cipher/rsa.c (rsa_check_keysize): Formatting. + (rsa_check_verify_keysize): New function. + (rsa_verify): Allow using smaller keys for verification. +-- + +GnuPG-bug-id: 5975 +Signed-off-by: Jakub Jelen +--- + cipher/rsa.c | 26 ++++++++++++++++++++++++-- + 1 file changed, 24 insertions(+), 2 deletions(-) + +diff --git a/cipher/rsa.c b/cipher/rsa.c +index c6319b67..9f2b36e8 100644 +--- a/cipher/rsa.c ++++ b/cipher/rsa.c +@@ -352,13 +352,35 @@ generate_std (RSA_secret_key *sk, unsigned int nbits, unsigned long use_e, + static gpg_err_code_t + rsa_check_keysize (unsigned int nbits) + { +- if (fips_mode() && nbits < 2048) ++ if (fips_mode () && nbits < 2048) + return GPG_ERR_INV_VALUE; + + return GPG_ERR_NO_ERROR; + } + + ++/* Check the RSA key length is acceptable for signature verification ++ * ++ * FIPS allows signature verification with RSA keys of size ++ * 1024, 1280, 1536 and 1792 in legacy mode, but this is up to the ++ * calling application to decide if the signature is legacy and ++ * should be accepted. ++ */ ++static gpg_err_code_t ++rsa_check_verify_keysize (unsigned int nbits) ++{ ++ if (fips_mode ()) ++ { ++ if ((nbits >= 1024 && (nbits % 256) == 0) || nbits >= 2048) ++ return GPG_ERR_NO_ERROR; ++ ++ return GPG_ERR_INV_VALUE; ++ } ++ ++ return GPG_ERR_NO_ERROR; ++} ++ ++ + /**************** + * Generate a key pair with a key of size NBITS. + * USE_E = 0 let Libcgrypt decide what exponent to use. +@@ -1602,7 +1624,7 @@ rsa_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t keyparms) + gcry_mpi_t result = NULL; + unsigned int nbits = rsa_get_nbits (keyparms); + +- rc = rsa_check_keysize (nbits); ++ rc = rsa_check_verify_keysize (nbits); + if (rc) + return rc; + +-- +2.37.1 + diff --git a/SOURCES/libgcrypt-1.10.0-fips-disable-oaep.patch b/SOURCES/libgcrypt-1.10.0-fips-disable-oaep.patch new file mode 100644 index 0000000..3de63c8 --- /dev/null +++ b/SOURCES/libgcrypt-1.10.0-fips-disable-oaep.patch @@ -0,0 +1,151 @@ +From 34d8fc576b3a06dd205f45327a971eb6771e808c Mon Sep 17 00:00:00 2001 +From: Jakub Jelen +Date: Wed, 17 Aug 2022 09:01:44 +0200 +Subject: [PATCH 1/2] Disable RSA-OAEP padding in FIPS mode + +* cipher/pubkey-util.c (_gcry_pk_util_data_to_mpi): Block OAEP padding + in FIPS mode for encryption +* cipher/rsa.c (rsa_decrypt): Block OAEP padding in FIPS mode for + decryption +--- + +Signed-off-by: Jakub Jelen +--- + cipher/pubkey-util.c | 5 ++++- + cipher/rsa.c | 3 ++- + 2 files changed, 6 insertions(+), 2 deletions(-) + +diff --git a/cipher/pubkey-util.c b/cipher/pubkey-util.c +index 4953caf3..244dd5d4 100644 +--- a/cipher/pubkey-util.c ++++ b/cipher/pubkey-util.c +@@ -1092,7 +1092,10 @@ _gcry_pk_util_data_to_mpi (gcry_sexp_t input, gcry_mpi_t *ret_mpi, + const void * value; + size_t valuelen; + +- if ( !(value=sexp_nth_data (lvalue, 1, &valuelen)) || !valuelen ) ++ /* The RSA OAEP encryption requires some more assurances in FIPS */ ++ if (fips_mode ()) ++ rc = GPG_ERR_INV_FLAG; ++ else if ( !(value=sexp_nth_data (lvalue, 1, &valuelen)) || !valuelen ) + rc = GPG_ERR_INV_OBJ; + else + { +diff --git a/cipher/rsa.c b/cipher/rsa.c +index 96dba090..87f57b55 100644 +--- a/cipher/rsa.c ++++ b/cipher/rsa.c +@@ -1457,7 +1457,8 @@ rsa_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t keyparms) + rc = GPG_ERR_INV_DATA; + goto leave; + } +- if (fips_mode () && (ctx.encoding == PUBKEY_ENC_PKCS1)) ++ if (fips_mode () && (ctx.encoding == PUBKEY_ENC_PKCS1 || ++ ctx.encoding == PUBKEY_ENC_OAEP)) + { + rc = GPG_ERR_INV_FLAG; + goto leave; +-- +2.37.1 + + +From c6d64e697c2748a49e875060aa753fc568c5f772 Mon Sep 17 00:00:00 2001 +From: Jakub Jelen +Date: Wed, 17 Aug 2022 10:31:19 +0200 +Subject: [PATCH 2/2] tests: Expect the OEAP tests to fail in FIPS mode + +* tests/basic.c (check_pubkey_crypt): Expect the OAEP padding encryption + to fail in FIPS mode +* tests/pkcs1v2.c (check_oaep): Expect the OAEP tests to fail in FIPS + mode +--- + +Signed-off-by: Jakub Jelen +--- + tests/basic.c | 14 +++++++++----- + tests/pkcs1v2.c | 13 +++++++++++++ + 2 files changed, 22 insertions(+), 5 deletions(-) + +diff --git a/tests/basic.c b/tests/basic.c +index 26980e15..b4102c9f 100644 +--- a/tests/basic.c ++++ b/tests/basic.c +@@ -16892,21 +16892,24 @@ check_pubkey_crypt (int n, gcry_sexp_t skey, gcry_sexp_t pkey, int algo, + "(flags oaep)", + 1, + 0, +- 0 }, ++ 0, ++ FLAG_NOFIPS }, + { GCRY_PK_RSA, + "(data\n (flags oaep)\n (hash-algo sha1)\n" + " (value #11223344556677889900AA#))\n", + "(flags oaep)(hash-algo sha1)", + 1, + 0, +- 0 }, ++ 0, ++ FLAG_NOFIPS }, + { GCRY_PK_RSA, + "(data\n (flags oaep)\n (hash-algo sha1)\n (label \"test\")\n" + " (value #11223344556677889900AA#))\n", + "(flags oaep)(hash-algo sha1)(label \"test\")", + 1, + 0, +- 0 }, ++ 0, ++ FLAG_NOFIPS }, + { GCRY_PK_RSA, + "(data\n (flags oaep)\n (hash-algo sha1)\n (label \"test\")\n" + " (value #11223344556677889900AA#)\n" +@@ -16914,7 +16917,8 @@ check_pubkey_crypt (int n, gcry_sexp_t skey, gcry_sexp_t pkey, int algo, + "(flags oaep)(hash-algo sha1)(label \"test\")", + 1, + 0, +- 0 }, ++ 0, ++ FLAG_NOFIPS }, + { 0, + "(data\n (flags )\n" " (value #11223344556677889900AA#))\n", + NULL, +@@ -16960,7 +16964,7 @@ check_pubkey_crypt (int n, gcry_sexp_t skey, gcry_sexp_t pkey, int algo, + "(flags pkcs1)", + 1, + 0, +- GPG_ERR_ENCODING_PROBLEM, FLAG_SPECIAL }, ++ GPG_ERR_ENCODING_PROBLEM, FLAG_SPECIAL | FLAG_NOFIPS }, + { 0, + "(data\n (flags pss)\n" + " (value #11223344556677889900AA#))\n", +diff --git a/tests/pkcs1v2.c b/tests/pkcs1v2.c +index 6c7f3d81..2fd495d5 100644 +--- a/tests/pkcs1v2.c ++++ b/tests/pkcs1v2.c +@@ -186,11 +186,24 @@ check_oaep (void) + err = gcry_pk_encrypt (&ciph, plain, pub_key); + if (err) + { ++ if (in_fips_mode) ++ { ++ gcry_sexp_release (plain); ++ plain = NULL; ++ continue; ++ } + show_sexp ("plain:\n", ciph); + fail ("gcry_pk_encrypt failed: %s\n", gpg_strerror (err)); + } + else + { ++ if (in_fips_mode) ++ { ++ fail ("The OAEP encryption unexpectedly worked in FIPS mode\n"); ++ gcry_sexp_release (plain); ++ plain = NULL; ++ continue; ++ } + if (extract_cmp_data (ciph, "a", tbl[tno].m[mno].encr, + tbl[tno].m[mno].desc)) + { +-- +2.37.1 + diff --git a/SOURCES/libgcrypt-1.10.0-fips-disable-pkcs1.5.patch b/SOURCES/libgcrypt-1.10.0-fips-disable-pkcs1.5.patch new file mode 100644 index 0000000..325b2fd --- /dev/null +++ b/SOURCES/libgcrypt-1.10.0-fips-disable-pkcs1.5.patch @@ -0,0 +1,219 @@ +From c7709f7b23848abf4ba65cb99cb2a9e9c7ebdefc Mon Sep 17 00:00:00 2001 +From: Jakub Jelen +Date: Fri, 1 Apr 2022 18:29:08 +0200 +Subject: [PATCH 1/3] Do not allow PKCS #1.5 padding for encryption in FIPS + +* cipher/pubkey-util.c (_gcry_pk_util_data_to_mpi): Block PKCS #1.5 + padding for encryption in FIPS mode +* cipher/rsa.c (rsa_decrypt): Block PKCS #1.5 decryption in FIPS mode +-- + +GnuPG-bug-id: 5918 +Signed-off-by: Jakub Jelen +--- + cipher/pubkey-util.c | 5 ++++- + cipher/rsa.c | 5 +++++ + 2 files changed, 9 insertions(+), 1 deletion(-) + +diff --git a/cipher/pubkey-util.c b/cipher/pubkey-util.c +index 68defea6..4953caf3 100644 +--- a/cipher/pubkey-util.c ++++ b/cipher/pubkey-util.c +@@ -957,7 +957,10 @@ _gcry_pk_util_data_to_mpi (gcry_sexp_t input, gcry_mpi_t *ret_mpi, + void *random_override = NULL; + size_t random_override_len = 0; + +- if ( !(value=sexp_nth_data (lvalue, 1, &valuelen)) || !valuelen ) ++ /* The RSA PKCS#1.5 encryption is no longer supported by FIPS */ ++ if (fips_mode ()) ++ rc = GPG_ERR_INV_FLAG; ++ else if ( !(value=sexp_nth_data (lvalue, 1, &valuelen)) || !valuelen ) + rc = GPG_ERR_INV_OBJ; + else + { +diff --git a/cipher/rsa.c b/cipher/rsa.c +index 771413b3..c6319b67 100644 +--- a/cipher/rsa.c ++++ b/cipher/rsa.c +@@ -1391,6 +1391,11 @@ rsa_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t keyparms) + rc = GPG_ERR_INV_DATA; + goto leave; + } ++ if (fips_mode () && (ctx.encoding == PUBKEY_ENC_PKCS1)) ++ { ++ rc = GPG_ERR_INV_FLAG; ++ goto leave; ++ } + + /* Extract the key. */ + rc = sexp_extract_param (keyparms, NULL, "nedp?q?u?", +-- +2.34.1 + + +From 299e2f93415984919181e0ee651719bbf83bdd2f Mon Sep 17 00:00:00 2001 +From: Jakub Jelen +Date: Fri, 1 Apr 2022 18:31:05 +0200 +Subject: [PATCH 2/3] tests: Replace custom bit with more generic flags + +* tests/basic.c (global): New flag FLAG_SPECIAL + (check_pubkey_crypt): Change to use bitfield flags + +-- + +GnuPG-bug-id: 5918 +Signed-off-by: Jakub Jelen +--- + tests/basic.c | 19 ++++++++++--------- + 1 file changed, 10 insertions(+), 9 deletions(-) + +diff --git a/tests/basic.c b/tests/basic.c +index a0ad33eb..1c6cb40b 100644 +--- a/tests/basic.c ++++ b/tests/basic.c +@@ -55,11 +55,12 @@ typedef struct test_spec_pubkey + } + test_spec_pubkey_t; + +-#define FLAG_CRYPT (1 << 0) +-#define FLAG_SIGN (1 << 1) +-#define FLAG_GRIP (1 << 2) +-#define FLAG_NOFIPS (1 << 3) +-#define FLAG_CFB8 (1 << 4) ++#define FLAG_CRYPT (1 << 0) ++#define FLAG_SIGN (1 << 1) ++#define FLAG_GRIP (1 << 2) ++#define FLAG_NOFIPS (1 << 3) ++#define FLAG_CFB8 (1 << 4) ++#define FLAG_SPECIAL (1 << 5) + + static int in_fips_mode; + +@@ -15558,7 +15559,7 @@ check_pubkey_crypt (int n, gcry_sexp_t skey, gcry_sexp_t pkey, int algo, + int unpadded; + int encrypt_expected_rc; + int decrypt_expected_rc; +- int special; ++ int flags; + } datas[] = + { + { GCRY_PK_RSA, +@@ -15642,14 +15643,14 @@ check_pubkey_crypt (int n, gcry_sexp_t skey, gcry_sexp_t pkey, int algo, + "(flags oaep)", + 1, + 0, +- GPG_ERR_ENCODING_PROBLEM, 1 }, ++ GPG_ERR_ENCODING_PROBLEM, FLAG_SPECIAL }, + { GCRY_PK_RSA, + "(data\n (flags oaep)\n" + " (value #11223344556677889900AA#))\n", + "(flags pkcs1)", + 1, + 0, +- GPG_ERR_ENCODING_PROBLEM, 1 }, ++ GPG_ERR_ENCODING_PROBLEM, FLAG_SPECIAL }, + { 0, + "(data\n (flags pss)\n" + " (value #11223344556677889900AA#))\n", +@@ -15725,7 +15726,7 @@ check_pubkey_crypt (int n, gcry_sexp_t skey, gcry_sexp_t pkey, int algo, + ciph = list; + } + rc = gcry_pk_decrypt (&plain, ciph, skey); +- if (!rc && datas[dataidx].special == 1) ++ if (!rc && (datas[dataidx].flags & FLAG_SPECIAL)) + { + /* It may happen that OAEP formatted data which is + decrypted as pkcs#1 data returns a valid pkcs#1 +-- +2.34.1 + + +From f736f3c70182d9c948f9105eb769c47c5578df35 Mon Sep 17 00:00:00 2001 +From: Jakub Jelen +Date: Fri, 1 Apr 2022 18:34:42 +0200 +Subject: [PATCH 3/3] tests: Expect the RSA PKCS #1.5 encryption to fail in + FIPS mode + +* tests/basic.c (check_pubkey_crypt): Expect RSA PKCS #1.5 encryption to + fail in FIPS mode. Expect failure when wrong padding is selected +* tests/pkcs1v2.c (check_v15crypt): Expect RSA PKCS #1.5 encryption to + fail in FIPS mode +-- + +GnuPG-bug-id: 5918 +Signed-off-by: Jakub Jelen +--- + tests/basic.c | 11 +++++++---- + tests/pkcs1v2.c | 14 +++++++++++++- + 2 files changed, 20 insertions(+), 5 deletions(-) + +diff --git a/tests/basic.c b/tests/basic.c +index 1c6cb40b..85764591 100644 +--- a/tests/basic.c ++++ b/tests/basic.c +@@ -15568,14 +15568,16 @@ check_pubkey_crypt (int n, gcry_sexp_t skey, gcry_sexp_t pkey, int algo, + NULL, + 0, + 0, +- 0 }, ++ 0, ++ FLAG_NOFIPS }, + { GCRY_PK_RSA, + "(data\n (flags pkcs1)\n" + " (value #11223344556677889900AA#))\n", + "(flags pkcs1)", + 1, + 0, +- 0 }, ++ 0, ++ FLAG_NOFIPS }, + { GCRY_PK_RSA, + "(data\n (flags oaep)\n" + " (value #11223344556677889900AA#))\n", +@@ -15677,7 +15679,8 @@ check_pubkey_crypt (int n, gcry_sexp_t skey, gcry_sexp_t pkey, int algo, + die ("converting data failed: %s\n", gpg_strerror (rc)); + + rc = gcry_pk_encrypt (&ciph, data, pkey); +- if (in_fips_mode && (flags & FLAG_NOFIPS)) ++ if (in_fips_mode && ((flags & FLAG_NOFIPS) || ++ (datas[dataidx].flags & FLAG_NOFIPS))) + { + if (!rc) + fail ("gcry_pk_encrypt did not fail as expected in FIPS mode\n"); +@@ -15726,7 +15729,7 @@ check_pubkey_crypt (int n, gcry_sexp_t skey, gcry_sexp_t pkey, int algo, + ciph = list; + } + rc = gcry_pk_decrypt (&plain, ciph, skey); +- if (!rc && (datas[dataidx].flags & FLAG_SPECIAL)) ++ if ((!rc || in_fips_mode) && (datas[dataidx].flags & FLAG_SPECIAL)) + { + /* It may happen that OAEP formatted data which is + decrypted as pkcs#1 data returns a valid pkcs#1 +diff --git a/tests/pkcs1v2.c b/tests/pkcs1v2.c +index f26e779b..6c7f3d81 100644 +--- a/tests/pkcs1v2.c ++++ b/tests/pkcs1v2.c +@@ -454,7 +454,19 @@ check_v15crypt (void) + gcry_free (seed); + + err = gcry_pk_encrypt (&ciph, plain, pub_key); +- if (err) ++ if (in_fips_mode) ++ { ++ if (!err) ++ { ++ fail ("gcry_pk_encrypt should have failed in FIPS mode:\n"); ++ } ++ gcry_sexp_release (plain); ++ plain = NULL; ++ gcry_sexp_release (ciph); ++ ciph = NULL; ++ continue; ++ } ++ else if (err) + { + show_sexp ("plain:\n", ciph); + fail ("gcry_pk_encrypt failed: %s\n", gpg_strerror (err)); +-- +2.34.1 + diff --git a/SOURCES/libgcrypt-1.10.0-fips-getrandom.patch b/SOURCES/libgcrypt-1.10.0-fips-getrandom.patch new file mode 100644 index 0000000..39ac59c --- /dev/null +++ b/SOURCES/libgcrypt-1.10.0-fips-getrandom.patch @@ -0,0 +1,41 @@ +From 0a5e608b8b18d4f41e4d7434c6262bf11507f859 Mon Sep 17 00:00:00 2001 +From: Jakub Jelen +Date: Tue, 16 Aug 2022 15:30:43 +0200 +Subject: [PATCH] random: Use getrandom (GRND_RANDOM) in FIPS mode + +The SP800-90C (clarified in IG D.K.) requires the following when +different DRBGs are chained: + * the parent needs to be reseeded before generate operation + * the reseed & generate needs to be atomic + +In RHEL, this is addressed by change in the kernel, that will do this +automatically, when the getentropy () is called with GRND_RANDOM flag. + +* random/rndgetentropy.c (_gcry_rndgetentropy_gather_random): Use + GRND_RANDOM in FIPS Mode +--- + +Signed-off-by: Jakub Jelen +--- + random/rndgetentropy.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/random/rndgetentropy.c b/random/rndgetentropy.c +index 7580873e..db4b09ed 100644 +--- a/random/rndgetentropy.c ++++ b/random/rndgetentropy.c +@@ -82,7 +82,10 @@ _gcry_rndgetentropy_gather_random (void (*add)(const void*, size_t, + { + nbytes = length < sizeof (buffer)? length : sizeof (buffer); + _gcry_pre_syscall (); +- ret = getentropy (buffer, nbytes); ++ if (fips_mode ()) ++ ret = getrandom (buffer, nbytes, GRND_RANDOM); ++ else ++ ret = getentropy (buffer, nbytes); + _gcry_post_syscall (); + } + while (ret == -1 && errno == EINTR); +-- +2.37.1 + diff --git a/SOURCES/libgcrypt-1.10.0-fips-selftest.patch b/SOURCES/libgcrypt-1.10.0-fips-selftest.patch new file mode 100644 index 0000000..6840c07 --- /dev/null +++ b/SOURCES/libgcrypt-1.10.0-fips-selftest.patch @@ -0,0 +1,923 @@ +From e62829a907a7179ec6b0d9f47258185860f0a6c0 Mon Sep 17 00:00:00 2001 +From: Jakub Jelen +Date: Tue, 2 Aug 2022 20:53:31 +0200 +Subject: [PATCH 1/6] Run digest&sign self tests for RSA and ECC in FIPS mode + +* cipher/ecc.c (selftest_hash_sign): Implement digest & sign KAT + (selftests_ecdsa): Run the original basic test only with extended tests + (run_selftests): Pass-through the extended argument +* cipher/rsa.c (selftest_hash_sign_2048): Implement digest & sign KAT + (selftests_rsa): Run the original basic test only with extended tests + (run_selftests): Pass-through the extended argument +--- + +Signed-off-by: Jakub Jelen +--- + cipher/ecc.c | 138 ++++++++++++++++++++++++++++++++++++++++++++++++--- + cipher/rsa.c | 108 +++++++++++++++++++++++++++++++++++++--- + 2 files changed, 234 insertions(+), 12 deletions(-) + +diff --git a/cipher/ecc.c b/cipher/ecc.c +index 9f0e7b11..63b0d05e 100644 +--- a/cipher/ecc.c ++++ b/cipher/ecc.c +@@ -1678,6 +1678,126 @@ _gcry_pk_ecc_get_sexp (gcry_sexp_t *r_sexp, int mode, mpi_ec_t ec) + Self-test section. + */ + ++static const char * ++selftest_hash_sign (gcry_sexp_t pkey, gcry_sexp_t skey) ++{ ++ int md_algo = GCRY_MD_SHA256; ++ gcry_md_hd_t hd = NULL; ++ const char *data_tmpl = "(data (flags rfc6979) (hash %s %b))"; ++ /* Sample data from RFC 6979 section A.2.5, hash is of message "sample" */ ++ static const char sample_data[] = "sample"; ++ static const char sample_data_bad[] = "sbmple"; ++ static const char signature_r[] = ++ "efd48b2aacb6a8fd1140dd9cd45e81d69d2c877b56aaf991c34d0ea84eaf3716"; ++ static const char signature_s[] = ++ "f7cb1c942d657c41d436c7a1b6e29f65f3e900dbb9aff4064dc4ab2f843acda8"; ++ ++ const char *errtxt = NULL; ++ gcry_error_t err; ++ gcry_sexp_t sig = NULL; ++ gcry_sexp_t l1 = NULL; ++ gcry_sexp_t l2 = NULL; ++ gcry_mpi_t r = NULL; ++ gcry_mpi_t s = NULL; ++ gcry_mpi_t calculated_r = NULL; ++ gcry_mpi_t calculated_s = NULL; ++ int cmp; ++ ++ err = _gcry_md_open (&hd, md_algo, 0); ++ if (err) ++ { ++ errtxt = "gcry_md_open failed"; ++ goto leave; ++ } ++ ++ _gcry_md_write (hd, sample_data, strlen(sample_data)); ++ ++ err = _gcry_mpi_scan (&r, GCRYMPI_FMT_HEX, signature_r, 0, NULL); ++ if (!err) ++ err = _gcry_mpi_scan (&s, GCRYMPI_FMT_HEX, signature_s, 0, NULL); ++ ++ if (err) ++ { ++ errtxt = "converting data failed"; ++ goto leave; ++ } ++ ++ err = _gcry_pk_sign_md (&sig, data_tmpl, hd, skey, NULL); ++ if (err) ++ { ++ errtxt = "signing failed"; ++ goto leave; ++ } ++ ++ /* check against known signature */ ++ errtxt = "signature validity failed"; ++ l1 = _gcry_sexp_find_token (sig, "sig-val", 0); ++ if (!l1) ++ goto leave; ++ l2 = _gcry_sexp_find_token (l1, "ecdsa", 0); ++ if (!l2) ++ goto leave; ++ ++ sexp_release (l1); ++ l1 = l2; ++ ++ l2 = _gcry_sexp_find_token (l1, "r", 0); ++ if (!l2) ++ goto leave; ++ calculated_r = _gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG); ++ if (!calculated_r) ++ goto leave; ++ ++ sexp_release (l2); ++ l2 = _gcry_sexp_find_token (l1, "s", 0); ++ if (!l2) ++ goto leave; ++ calculated_s = _gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG); ++ if (!calculated_s) ++ goto leave; ++ ++ errtxt = "known sig check failed"; ++ ++ cmp = _gcry_mpi_cmp (r, calculated_r); ++ if (cmp) ++ goto leave; ++ cmp = _gcry_mpi_cmp (s, calculated_s); ++ if (cmp) ++ goto leave; ++ ++ errtxt = NULL; ++ ++ /* verify generated signature */ ++ err = _gcry_pk_verify_md (sig, data_tmpl, hd, pkey, NULL); ++ if (err) ++ { ++ errtxt = "verify failed"; ++ goto leave; ++ } ++ ++ _gcry_md_reset(hd); ++ _gcry_md_write (hd, sample_data_bad, strlen(sample_data_bad)); ++ err = _gcry_pk_verify_md (sig, data_tmpl, hd, pkey, NULL); ++ if (gcry_err_code (err) != GPG_ERR_BAD_SIGNATURE) ++ { ++ errtxt = "bad signature not detected"; ++ goto leave; ++ } ++ ++ ++ leave: ++ _gcry_md_close (hd); ++ sexp_release (sig); ++ sexp_release (l1); ++ sexp_release (l2); ++ mpi_release (r); ++ mpi_release (s); ++ mpi_release (calculated_r); ++ mpi_release (calculated_s); ++ return errtxt; ++} ++ ++ + static const char * + selftest_sign (gcry_sexp_t pkey, gcry_sexp_t skey) + { +@@ -1798,7 +1918,7 @@ selftest_sign (gcry_sexp_t pkey, gcry_sexp_t skey) + + + static gpg_err_code_t +-selftests_ecdsa (selftest_report_func_t report) ++selftests_ecdsa (selftest_report_func_t report, int extended) + { + const char *what; + const char *errtxt; +@@ -1826,8 +1946,16 @@ selftests_ecdsa (selftest_report_func_t report) + goto failed; + } + +- what = "sign"; +- errtxt = selftest_sign (pkey, skey); ++ if (extended) ++ { ++ what = "sign"; ++ errtxt = selftest_sign (pkey, skey); ++ if (errtxt) ++ goto failed; ++ } ++ ++ what = "digest sign"; ++ errtxt = selftest_hash_sign (pkey, skey); + if (errtxt) + goto failed; + +@@ -1848,12 +1976,10 @@ selftests_ecdsa (selftest_report_func_t report) + static gpg_err_code_t + run_selftests (int algo, int extended, selftest_report_func_t report) + { +- (void)extended; +- + if (algo != GCRY_PK_ECC) + return GPG_ERR_PUBKEY_ALGO; + +- return selftests_ecdsa (report); ++ return selftests_ecdsa (report, extended); + } + + +diff --git a/cipher/rsa.c b/cipher/rsa.c +index 9f2b36e8..34c8e490 100644 +--- a/cipher/rsa.c ++++ b/cipher/rsa.c +@@ -1760,6 +1760,96 @@ compute_keygrip (gcry_md_hd_t md, gcry_sexp_t keyparam) + Self-test section. + */ + ++static const char * ++selftest_hash_sign_2048 (gcry_sexp_t pkey, gcry_sexp_t skey) ++{ ++ int md_algo = GCRY_MD_SHA256; ++ gcry_md_hd_t hd = NULL; ++ const char *data_tmpl = "(data (flags pkcs1) (hash %s %b))"; ++ static const char sample_data[] = ++ "11223344556677889900aabbccddeeff" ++ "102030405060708090a0b0c0d0f01121"; ++ static const char sample_data_bad[] = ++ "11223344556677889900aabbccddeeff" ++ "802030405060708090a0b0c0d0f01121"; ++ ++ const char *errtxt = NULL; ++ gcry_error_t err; ++ gcry_sexp_t sig = NULL; ++ /* raw signature data reference */ ++ const char ref_data[] = ++ "518f41dea3ad884e93eefff8d7ca68a6f4c30d923632e35673651d675cebd652" ++ "a44ed66f6879b18f3d48b2d235b1dd78f6189be1440352cc94231a55c1f93109" ++ "84616b2841c42fe9a6e37be34cd188207209bd028e2fa93e721fbac40c31a068" ++ "1253b312d4e07addb9c7f3d508fa89f218ea7c7f7b9f6a9b1e522c19fa1cd839" ++ "93f9d4ca2f16c3d0b9abafe5e63e848152afc72ce7ee19ea45353116f85209ea" ++ "b9de42129dbccdac8faa461e8e8cc2ae801101cc6add4ba76ccb752030b0e827" ++ "7352b11cdecebae9cdc9a626c4701cd9c85cd287618888c5fae8b4d0ba48915d" ++ "e5cc64e3aee2ba2862d04348ea71f65454f74f9fd1e3108005cc367ca41585a4"; ++ gcry_mpi_t ref_mpi = NULL; ++ gcry_mpi_t sig_mpi = NULL; ++ ++ err = _gcry_md_open (&hd, md_algo, 0); ++ if (err) ++ { ++ errtxt = "gcry_md_open failed"; ++ goto leave; ++ } ++ ++ _gcry_md_write (hd, sample_data, sizeof(sample_data)); ++ ++ err = _gcry_pk_sign_md (&sig, data_tmpl, hd, skey, NULL); ++ if (err) ++ { ++ errtxt = "signing failed"; ++ goto leave; ++ } ++ ++ err = _gcry_mpi_scan(&ref_mpi, GCRYMPI_FMT_HEX, ref_data, 0, NULL); ++ if (err) ++ { ++ errtxt = "converting ref_data to mpi failed"; ++ goto leave; ++ } ++ ++ err = _gcry_sexp_extract_param(sig, "sig-val!rsa", "s", &sig_mpi, NULL); ++ if (err) ++ { ++ errtxt = "extracting signature data failed"; ++ goto leave; ++ } ++ ++ if (mpi_cmp (sig_mpi, ref_mpi)) ++ { ++ errtxt = "signature does not match reference data"; ++ goto leave; ++ } ++ ++ err = _gcry_pk_verify_md (sig, data_tmpl, hd, pkey, NULL); ++ if (err) ++ { ++ errtxt = "verify failed"; ++ goto leave; ++ } ++ ++ _gcry_md_reset(hd); ++ _gcry_md_write (hd, sample_data_bad, sizeof(sample_data_bad)); ++ err = _gcry_pk_verify_md (sig, data_tmpl, hd, pkey, NULL); ++ if (gcry_err_code (err) != GPG_ERR_BAD_SIGNATURE) ++ { ++ errtxt = "bad signature not detected"; ++ goto leave; ++ } ++ ++ ++ leave: ++ sexp_release (sig); ++ _gcry_md_close (hd); ++ _gcry_mpi_release (ref_mpi); ++ _gcry_mpi_release (sig_mpi); ++ return errtxt; ++} ++ + static const char * + selftest_sign_2048 (gcry_sexp_t pkey, gcry_sexp_t skey) + { +@@ -1996,7 +2086,7 @@ selftest_encr_2048 (gcry_sexp_t pkey, gcry_sexp_t skey) + + + static gpg_err_code_t +-selftests_rsa (selftest_report_func_t report) ++selftests_rsa (selftest_report_func_t report, int extended) + { + const char *what; + const char *errtxt; +@@ -2024,8 +2114,16 @@ selftests_rsa (selftest_report_func_t report) + goto failed; + } + +- what = "sign"; +- errtxt = selftest_sign_2048 (pkey, skey); ++ if (extended) ++ { ++ what = "sign"; ++ errtxt = selftest_sign_2048 (pkey, skey); ++ if (errtxt) ++ goto failed; ++ } ++ ++ what = "digest sign"; ++ errtxt = selftest_hash_sign_2048 (pkey, skey); + if (errtxt) + goto failed; + +@@ -2053,12 +2151,10 @@ run_selftests (int algo, int extended, selftest_report_func_t report) + { + gpg_err_code_t ec; + +- (void)extended; +- + switch (algo) + { + case GCRY_PK_RSA: +- ec = selftests_rsa (report); ++ ec = selftests_rsa (report, extended); + break; + default: + ec = GPG_ERR_PUBKEY_ALGO; +-- +2.37.1 + + +From b386e9862e7c3c0f6623fb1c43b0cf0481bbebc7 Mon Sep 17 00:00:00 2001 +From: Jakub Jelen +Date: Mon, 8 Aug 2022 13:50:15 +0200 +Subject: [PATCH 2/6] fips: Add function-name based FIPS indicator + +* doc/gcrypt.texi: Document the new function-based fips indicator + GCRYCTL_FIPS_SERVICE_INDICATOR_FUNCTION +* src/fips.c (_gcry_fips_indicator_function): New function indicating + non-approved functions. +* src/gcrypt.h.in (enum gcry_ctl_cmds): New symbol + GCRYCTL_FIPS_SERVICE_INDICATOR_FUNCTION +* src/global.c (_gcry_vcontrol): Handle new FIPS indicator. +--- + +Signed-off-by: Jakub Jelen +--- + doc/gcrypt.texi | 7 +++++++ + src/fips.c | 12 ++++++++++++ + src/g10lib.h | 1 + + src/gcrypt.h.in | 3 ++- + src/global.c | 7 +++++++ + 5 files changed, 29 insertions(+), 1 deletion(-) + +diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi +index f2c1cc94..b608dba2 100644 +--- a/doc/gcrypt.texi ++++ b/doc/gcrypt.texi +@@ -995,6 +995,13 @@ certification. If the KDF is approved, this function returns + @code{GPG_ERR_NO_ERROR}. Otherwise @code{GPG_ERR_NOT_SUPPORTED} + is returned. + ++@item GCRYCTL_FIPS_SERVICE_INDICATOR_FUNCTION; Arguments: const char * ++ ++Check if the given function is approved under the current FIPS 140-3 ++certification. If the function is approved, this function returns ++@code{GPG_ERR_NO_ERROR} (other restrictions might still apply). ++Otherwise @code{GPG_ERR_NOT_SUPPORTED} is returned. ++ + @end table + + @end deftypefun +diff --git a/src/fips.c b/src/fips.c +index a1958b14..9a524ea4 100644 +--- a/src/fips.c ++++ b/src/fips.c +@@ -390,6 +390,18 @@ _gcry_fips_indicator_kdf (va_list arg_ptr) + } + } + ++int ++_gcry_fips_indicator_function (va_list arg_ptr) ++{ ++ const char *function = va_arg (arg_ptr, const char *); ++ ++ if (strcmp (function, "gcry_sign") == 0 || ++ strcmp (function, "gcry_verify") == 0) ++ return GPG_ERR_NOT_SUPPORTED; ++ ++ return GPG_ERR_NO_ERROR; ++} ++ + + /* This is a test on whether the library is in the error or + operational state. */ +diff --git a/src/g10lib.h b/src/g10lib.h +index 8ba0a5c2..eff6295f 100644 +--- a/src/g10lib.h ++++ b/src/g10lib.h +@@ -468,6 +468,7 @@ void _gcry_fips_signal_error (const char *srcfile, + + int _gcry_fips_indicator_cipher (va_list arg_ptr); + int _gcry_fips_indicator_kdf (va_list arg_ptr); ++int _gcry_fips_indicator_function (va_list arg_ptr); + + int _gcry_fips_is_operational (void); + +diff --git a/src/gcrypt.h.in b/src/gcrypt.h.in +index 299261db..d6a1d516 100644 +--- a/src/gcrypt.h.in ++++ b/src/gcrypt.h.in +@@ -329,7 +329,8 @@ enum gcry_ctl_cmds + GCRYCTL_SET_DECRYPTION_TAG = 80, + GCRYCTL_FIPS_SERVICE_INDICATOR_CIPHER = 81, + GCRYCTL_FIPS_SERVICE_INDICATOR_KDF = 82, +- GCRYCTL_NO_FIPS_MODE = 83 ++ GCRYCTL_NO_FIPS_MODE = 83, ++ GCRYCTL_FIPS_SERVICE_INDICATOR_FUNCTION = 84 + }; + + /* Perform various operations defined by CMD. */ +diff --git a/src/global.c b/src/global.c +index 258ea4d1..debf6194 100644 +--- a/src/global.c ++++ b/src/global.c +@@ -797,6 +797,13 @@ _gcry_vcontrol (enum gcry_ctl_cmds cmd, va_list arg_ptr) + rc = _gcry_fips_indicator_kdf (arg_ptr); + break; + ++ case GCRYCTL_FIPS_SERVICE_INDICATOR_FUNCTION: ++ /* Get FIPS Service Indicator for a given function from the API. ++ * Returns GPG_ERR_NO_ERROR if the function is allowed or ++ * GPG_ERR_NOT_SUPPORTED otherwise */ ++ rc = _gcry_fips_indicator_function (arg_ptr); ++ break; ++ + case PRIV_CTL_INIT_EXTRNG_TEST: /* Init external random test. */ + rc = GPG_ERR_NOT_SUPPORTED; + break; +-- +2.37.1 + + +From 756cdfaf30c2b12d2b2a931591089b1de22444f4 Mon Sep 17 00:00:00 2001 +From: Jakub Jelen +Date: Mon, 8 Aug 2022 15:58:16 +0200 +Subject: [PATCH 4/6] rsa: Run PCT in FIPS mode also with digest step + +Signed-off-by: Jakub Jelen +--- + cipher/rsa.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 68 insertions(+), 1 deletion(-) + +diff --git a/cipher/rsa.c b/cipher/rsa.c +index 6e7be8e8..78c26f2f 100644 +--- a/cipher/rsa.c ++++ b/cipher/rsa.c +@@ -177,6 +177,73 @@ test_keys (RSA_secret_key *sk, unsigned int nbits) + return result; + } + ++static int ++test_keys_fips (RSA_secret_key *sk) ++{ ++ int result = -1; /* Default to failure. */ ++ char plaintext[128]; ++ gcry_sexp_t sig = NULL; ++ gcry_sexp_t skey = NULL, pkey = NULL; ++ const char *data_tmpl = "(data (flags pkcs1) (hash %s %b))"; ++ gcry_md_hd_t hd = NULL; ++ int ec; ++ ++ /* Put the relevant parameters into a public key structure. */ ++ ec = sexp_build (&pkey, NULL, ++ "(key-data" ++ " (public-key" ++ " (rsa(n%m)(e%m))))", ++ sk->n, sk->e); ++ if (ec) ++ goto leave; ++ ++ /* Put the relevant parameters into a secret key structure. */ ++ ec = sexp_build (&skey, NULL, ++ "(key-data" ++ " (public-key" ++ " (rsa(n%m)(e%m)))" ++ " (private-key" ++ " (rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m))))", ++ sk->n, sk->e, ++ sk->n, sk->e, sk->d, sk->p, sk->q, sk->u); ++ if (ec) ++ goto leave; ++ ++ /* Create a random plaintext. */ ++ _gcry_randomize (plaintext, sizeof plaintext, GCRY_WEAK_RANDOM); ++ ++ /* Open MD context and feed the random data in */ ++ ec = _gcry_md_open (&hd, GCRY_MD_SHA256, 0); ++ if (ec) ++ goto leave; ++ _gcry_md_write (hd, plaintext, sizeof(plaintext)); ++ ++ /* Use the RSA secret function to create a signature of the plaintext. */ ++ ec = _gcry_pk_sign_md (&sig, data_tmpl, hd, skey, NULL); ++ if (ec) ++ goto leave; ++ ++ /* Use the RSA public function to verify this signature. */ ++ ec = _gcry_pk_verify_md (sig, data_tmpl, hd, pkey, NULL); ++ if (ec) ++ goto leave; ++ ++ /* Modify the data and check that the signing fails. */ ++ _gcry_md_reset(hd); ++ plaintext[sizeof plaintext / 2] ^= 1; ++ _gcry_md_write (hd, plaintext, sizeof(plaintext)); ++ ec = _gcry_pk_verify_md (sig, data_tmpl, hd, pkey, NULL); ++ if (ec != GPG_ERR_BAD_SIGNATURE) ++ goto leave; /* Signature verification worked on modified data */ ++ ++ result = 0; /* All tests succeeded. */ ++ leave: ++ sexp_release (sig); ++ _gcry_md_close (hd); ++ sexp_release (pkey); ++ sexp_release (skey); ++ return result; ++} + + /* Callback used by the prime generation to test whether the exponent + is suitable. Returns 0 if the test has been passed. */ +@@ -648,7 +715,7 @@ generate_fips (RSA_secret_key *sk, unsigned int nbits, unsigned long use_e, + sk->u = u; + + /* Now we can test our keys. */ +- if (ec || (!testparms && test_keys (sk, nbits - 64))) ++ if (ec || (!testparms && test_keys_fips (sk))) + { + _gcry_mpi_release (sk->n); sk->n = NULL; + _gcry_mpi_release (sk->e); sk->e = NULL; +-- +2.37.1 + + +From de7ad6375be11a0cef45c6e9aa8119c4ce7a3258 Mon Sep 17 00:00:00 2001 +From: Jakub Jelen +Date: Mon, 15 Aug 2022 19:55:33 +0200 +Subject: [PATCH 5/6] ecc: Run PCT also with the digest step + +* cipher/ecc.c (test_keys_fips): New function + (nist_generate_key): In FIPS mode, execute new PCT test +--- + +Signed-off-by: Jakub Jelen +--- + cipher/ecc.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 81 insertions(+) + +diff --git a/cipher/ecc.c b/cipher/ecc.c +index 63b0d05e..783e249d 100644 +--- a/cipher/ecc.c ++++ b/cipher/ecc.c +@@ -101,6 +101,7 @@ static void *progress_cb_data; + + /* Local prototypes. */ + static void test_keys (mpi_ec_t ec, unsigned int nbits); ++static void test_keys_fips (mpi_ec_t ec, gcry_mpi_t x, gcry_mpi_t y); + static void test_ecdh_only_keys (mpi_ec_t ec, unsigned int nbits, int flags); + static unsigned int ecc_get_nbits (gcry_sexp_t parms); + +@@ -255,6 +256,8 @@ nist_generate_key (mpi_ec_t ec, int flags, + ; /* User requested to skip the test. */ + else if (ec->model == MPI_EC_MONTGOMERY) + test_ecdh_only_keys (ec, ec->nbits - 63, flags); ++ else if (fips_mode ()) ++ test_keys_fips (ec, x, y); + else + test_keys (ec, ec->nbits - 64); + +@@ -304,6 +307,84 @@ test_keys (mpi_ec_t ec, unsigned int nbits) + mpi_free (test); + } + ++/* We should get here only with the NIST curves as they are the only ones ++ * having the fips bit set in ecc_domain_parms_t struct so this is slightly ++ * simpler than the whole ecc_generate function */ ++static void ++test_keys_fips (mpi_ec_t ec, gcry_mpi_t Qx, gcry_mpi_t Qy) ++{ ++ gcry_md_hd_t hd = NULL; ++ const char *data_tmpl = "(data (flags rfc6979) (hash %s %b))"; ++ gcry_sexp_t skey = NULL, pkey = NULL; ++ gcry_sexp_t curve_info = NULL; ++ gcry_sexp_t sig = NULL; ++ gcry_mpi_t public = NULL; ++ char plaintext[128]; ++ int rc; ++ ++ /* Build keys structures */ ++ if (ec->name) ++ { ++ rc = sexp_build (&curve_info, NULL, "(curve %s)", ec->name); ++ if (rc) ++ log_fatal ("ECDSA operation: failed to build curve_info\n"); ++ } ++ ++ public = _gcry_ecc_ec2os (Qx, Qy, ec->p); ++ rc = sexp_build (&pkey, NULL, ++ "(key-data" ++ " (public-key" ++ " (ecc%S(q%m)))" ++ " )", ++ curve_info, ++ public); ++ if (rc) ++ log_fatal ("ECDSA operation: failed to build public key: %s\n", gpg_strerror (rc)); ++ rc = sexp_build (&skey, NULL, ++ "(key-data" ++ " (private-key" ++ " (ecc%S(q%m)(d%m)))" ++ " )", ++ curve_info, ++ public, ec->d); ++ if (rc) ++ log_fatal ("ECDSA operation: failed to build private key: %s\n", gpg_strerror (rc)); ++ ++ /* Create a random plaintext. */ ++ _gcry_randomize (plaintext, sizeof plaintext, GCRY_WEAK_RANDOM); ++ ++ /* Open MD context and feed the random data in */ ++ rc = _gcry_md_open (&hd, GCRY_MD_SHA256, 0); ++ if (rc) ++ log_fatal ("ECDSA operation: failed to initialize MD context: %s\n", gpg_strerror (rc)); ++ _gcry_md_write (hd, plaintext, sizeof(plaintext)); ++ ++ /* Sign the data */ ++ rc = _gcry_pk_sign_md (&sig, data_tmpl, hd, skey, NULL); ++ if (rc) ++ log_fatal ("ECDSA operation: signing failed: %s\n", gpg_strerror (rc)); ++ ++ /* Verify this signature. */ ++ rc = _gcry_pk_verify_md (sig, data_tmpl, hd, pkey, NULL); ++ if (rc) ++ log_fatal ("ECDSA operation: verification failed: %s\n", gpg_strerror (rc)); ++ ++ /* Modify the data and check that the signing fails. */ ++ _gcry_md_reset(hd); ++ plaintext[sizeof plaintext / 2] ^= 1; ++ _gcry_md_write (hd, plaintext, sizeof(plaintext)); ++ rc = _gcry_pk_verify_md (sig, data_tmpl, hd, pkey, NULL); ++ if (rc != GPG_ERR_BAD_SIGNATURE) ++ log_fatal ("ECDSA operation: signature verification worked on modified data\n"); ++ ++ mpi_free (public); ++ sexp_release (curve_info); ++ _gcry_md_close (hd); ++ sexp_release (pkey); ++ sexp_release (skey); ++ sexp_release (sig); ++} ++ + + static void + test_ecdh_only_keys (mpi_ec_t ec, unsigned int nbits, int flags) +-- +2.37.1 + + +From 2cca95e488d58ae79975dd867e7782504b155212 Mon Sep 17 00:00:00 2001 +From: Jakub Jelen +Date: Tue, 16 Aug 2022 10:27:46 +0200 +Subject: [PATCH 6/6] Simplify the PCT for RSA and ECDSA + +Could be squashed. + +* cipher/ecc.c (test_keys_fips): Simplify to accept key in SEXP format + (nist_generate_key): Skip call to test keys + (ecc_generate): Call test keys in FIPS mode later, when we have + complete SEXP key structure. +* cipher/rsa.c (test_keys_fips): Simplify to accept key in SEXP format + (generate_fips): Skip selftest at this stage + (rsa_generate): Test the keys later when we already have key in SEXP + format +--- + +Signed-off-by: Jakub Jelen +--- + cipher/ecc.c | 50 ++++++++------------------------------------------ + cipher/rsa.c | 47 ++++++++++++----------------------------------- + 2 files changed, 20 insertions(+), 77 deletions(-) + +diff --git a/cipher/ecc.c b/cipher/ecc.c +index 783e249d..1e80200e 100644 +--- a/cipher/ecc.c ++++ b/cipher/ecc.c +@@ -101,7 +101,7 @@ static void *progress_cb_data; + + /* Local prototypes. */ + static void test_keys (mpi_ec_t ec, unsigned int nbits); +-static void test_keys_fips (mpi_ec_t ec, gcry_mpi_t x, gcry_mpi_t y); ++static void test_keys_fips (gcry_sexp_t skey); + static void test_ecdh_only_keys (mpi_ec_t ec, unsigned int nbits, int flags); + static unsigned int ecc_get_nbits (gcry_sexp_t parms); + +@@ -256,9 +256,7 @@ nist_generate_key (mpi_ec_t ec, int flags, + ; /* User requested to skip the test. */ + else if (ec->model == MPI_EC_MONTGOMERY) + test_ecdh_only_keys (ec, ec->nbits - 63, flags); +- else if (fips_mode ()) +- test_keys_fips (ec, x, y); +- else ++ else if (!fips_mode ()) + test_keys (ec, ec->nbits - 64); + + return 0; +@@ -311,45 +309,14 @@ test_keys (mpi_ec_t ec, unsigned int nbits) + * having the fips bit set in ecc_domain_parms_t struct so this is slightly + * simpler than the whole ecc_generate function */ + static void +-test_keys_fips (mpi_ec_t ec, gcry_mpi_t Qx, gcry_mpi_t Qy) ++test_keys_fips (gcry_sexp_t skey) + { + gcry_md_hd_t hd = NULL; + const char *data_tmpl = "(data (flags rfc6979) (hash %s %b))"; +- gcry_sexp_t skey = NULL, pkey = NULL; +- gcry_sexp_t curve_info = NULL; + gcry_sexp_t sig = NULL; +- gcry_mpi_t public = NULL; + char plaintext[128]; + int rc; + +- /* Build keys structures */ +- if (ec->name) +- { +- rc = sexp_build (&curve_info, NULL, "(curve %s)", ec->name); +- if (rc) +- log_fatal ("ECDSA operation: failed to build curve_info\n"); +- } +- +- public = _gcry_ecc_ec2os (Qx, Qy, ec->p); +- rc = sexp_build (&pkey, NULL, +- "(key-data" +- " (public-key" +- " (ecc%S(q%m)))" +- " )", +- curve_info, +- public); +- if (rc) +- log_fatal ("ECDSA operation: failed to build public key: %s\n", gpg_strerror (rc)); +- rc = sexp_build (&skey, NULL, +- "(key-data" +- " (private-key" +- " (ecc%S(q%m)(d%m)))" +- " )", +- curve_info, +- public, ec->d); +- if (rc) +- log_fatal ("ECDSA operation: failed to build private key: %s\n", gpg_strerror (rc)); +- + /* Create a random plaintext. */ + _gcry_randomize (plaintext, sizeof plaintext, GCRY_WEAK_RANDOM); + +@@ -365,7 +332,7 @@ test_keys_fips (mpi_ec_t ec, gcry_mpi_t Qx, gcry_mpi_t Qy) + log_fatal ("ECDSA operation: signing failed: %s\n", gpg_strerror (rc)); + + /* Verify this signature. */ +- rc = _gcry_pk_verify_md (sig, data_tmpl, hd, pkey, NULL); ++ rc = _gcry_pk_verify_md (sig, data_tmpl, hd, skey, NULL); + if (rc) + log_fatal ("ECDSA operation: verification failed: %s\n", gpg_strerror (rc)); + +@@ -373,15 +340,11 @@ test_keys_fips (mpi_ec_t ec, gcry_mpi_t Qx, gcry_mpi_t Qy) + _gcry_md_reset(hd); + plaintext[sizeof plaintext / 2] ^= 1; + _gcry_md_write (hd, plaintext, sizeof(plaintext)); +- rc = _gcry_pk_verify_md (sig, data_tmpl, hd, pkey, NULL); ++ rc = _gcry_pk_verify_md (sig, data_tmpl, hd, skey, NULL); + if (rc != GPG_ERR_BAD_SIGNATURE) + log_fatal ("ECDSA operation: signature verification worked on modified data\n"); + +- mpi_free (public); +- sexp_release (curve_info); + _gcry_md_close (hd); +- sexp_release (pkey); +- sexp_release (skey); + sexp_release (sig); + } + +@@ -714,6 +677,9 @@ ecc_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey) + log_debug ("ecgen result using Ed25519+EdDSA\n"); + } + ++ if (!(flags & PUBKEY_FLAG_NO_KEYTEST) && fips_mode ()) ++ test_keys_fips (*r_skey); ++ + leave: + mpi_free (public); + mpi_free (base); +diff --git a/cipher/rsa.c b/cipher/rsa.c +index 78c26f2f..9d14a474 100644 +--- a/cipher/rsa.c ++++ b/cipher/rsa.c +@@ -178,37 +178,15 @@ test_keys (RSA_secret_key *sk, unsigned int nbits) + } + + static int +-test_keys_fips (RSA_secret_key *sk) ++test_keys_fips (gcry_sexp_t skey) + { + int result = -1; /* Default to failure. */ + char plaintext[128]; + gcry_sexp_t sig = NULL; +- gcry_sexp_t skey = NULL, pkey = NULL; + const char *data_tmpl = "(data (flags pkcs1) (hash %s %b))"; + gcry_md_hd_t hd = NULL; + int ec; + +- /* Put the relevant parameters into a public key structure. */ +- ec = sexp_build (&pkey, NULL, +- "(key-data" +- " (public-key" +- " (rsa(n%m)(e%m))))", +- sk->n, sk->e); +- if (ec) +- goto leave; +- +- /* Put the relevant parameters into a secret key structure. */ +- ec = sexp_build (&skey, NULL, +- "(key-data" +- " (public-key" +- " (rsa(n%m)(e%m)))" +- " (private-key" +- " (rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m))))", +- sk->n, sk->e, +- sk->n, sk->e, sk->d, sk->p, sk->q, sk->u); +- if (ec) +- goto leave; +- + /* Create a random plaintext. */ + _gcry_randomize (plaintext, sizeof plaintext, GCRY_WEAK_RANDOM); + +@@ -224,7 +202,7 @@ test_keys_fips (RSA_secret_key *sk) + goto leave; + + /* Use the RSA public function to verify this signature. */ +- ec = _gcry_pk_verify_md (sig, data_tmpl, hd, pkey, NULL); ++ ec = _gcry_pk_verify_md (sig, data_tmpl, hd, skey, NULL); + if (ec) + goto leave; + +@@ -232,7 +210,7 @@ test_keys_fips (RSA_secret_key *sk) + _gcry_md_reset(hd); + plaintext[sizeof plaintext / 2] ^= 1; + _gcry_md_write (hd, plaintext, sizeof(plaintext)); +- ec = _gcry_pk_verify_md (sig, data_tmpl, hd, pkey, NULL); ++ ec = _gcry_pk_verify_md (sig, data_tmpl, hd, skey, NULL); + if (ec != GPG_ERR_BAD_SIGNATURE) + goto leave; /* Signature verification worked on modified data */ + +@@ -240,8 +218,6 @@ test_keys_fips (RSA_secret_key *sk) + leave: + sexp_release (sig); + _gcry_md_close (hd); +- sexp_release (pkey); +- sexp_release (skey); + return result; + } + +@@ -714,8 +690,7 @@ generate_fips (RSA_secret_key *sk, unsigned int nbits, unsigned long use_e, + sk->d = d; + sk->u = u; + +- /* Now we can test our keys. */ +- if (ec || (!testparms && test_keys_fips (sk))) ++ if (ec) + { + _gcry_mpi_release (sk->n); sk->n = NULL; + _gcry_mpi_release (sk->e); sk->e = NULL; +@@ -723,11 +698,6 @@ generate_fips (RSA_secret_key *sk, unsigned int nbits, unsigned long use_e, + _gcry_mpi_release (sk->q); sk->q = NULL; + _gcry_mpi_release (sk->d); sk->d = NULL; + _gcry_mpi_release (sk->u); sk->u = NULL; +- if (!ec) +- { +- fips_signal_error ("self-test after key generation failed"); +- return GPG_ERR_SELFTEST_FAILED; +- } + } + + return ec; +@@ -1306,7 +1276,7 @@ rsa_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey) + /**/ : NULL); + + /* Generate. */ +- if (deriveparms || fips_mode()) ++ if (deriveparms || fips_mode ()) + { + ec = generate_fips (&sk, nbits, evalue, deriveparms, + !!(flags & PUBKEY_FLAG_TRANSIENT_KEY)); +@@ -1341,6 +1311,13 @@ rsa_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey) + mpi_free (sk.u); + sexp_release (swap_info); + ++ if (!ec && fips_mode () && test_keys_fips (*r_skey)) ++ { ++ sexp_release (*r_skey); *r_skey = NULL; ++ fips_signal_error ("self-test after key generation failed"); ++ return GPG_ERR_SELFTEST_FAILED; ++ } ++ + return ec; + } + +-- +2.37.1 diff --git a/SOURCES/libgcrypt-1.10.0-ppc-hwf.patch b/SOURCES/libgcrypt-1.10.0-ppc-hwf.patch new file mode 100644 index 0000000..db99240 --- /dev/null +++ b/SOURCES/libgcrypt-1.10.0-ppc-hwf.patch @@ -0,0 +1,29 @@ +From 29bfb3ebbc63d7ed18b916c5c6946790fb3d15df Mon Sep 17 00:00:00 2001 +From: Jussi Kivilinna +Date: Fri, 1 Apr 2022 09:49:20 +0300 +Subject: [PATCH] hwf-ppc: fix missing HWF_PPC_ARCH_3_10 in HW feature + +* src/hwf-ppc.c (ppc_features): Add HWF_PPC_ARCH_3_10. +-- + +GnuPG-bug-id: T5913 +Signed-off-by: Jussi Kivilinna +--- + src/hwf-ppc.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/hwf-ppc.c b/src/hwf-ppc.c +index 7801f8b0..11d14dc1 100644 +--- a/src/hwf-ppc.c ++++ b/src/hwf-ppc.c +@@ -103,6 +103,7 @@ static const struct feature_map_s ppc_features[] = + { 0, PPC_FEATURE2_VEC_CRYPTO, HWF_PPC_VCRYPTO }, + #endif + { 0, PPC_FEATURE2_ARCH_3_00, HWF_PPC_ARCH_3_00 }, ++ { 0, PPC_FEATURE2_ARCH_3_10, HWF_PPC_ARCH_3_10 }, + }; + #endif + +-- +2.34.1 + diff --git a/SPECS/libgcrypt.spec b/SPECS/libgcrypt.spec index 8b97b64..da99e44 100644 --- a/SPECS/libgcrypt.spec +++ b/SPECS/libgcrypt.spec @@ -16,12 +16,19 @@ print(string.sub(hash, 0, 16)) Name: libgcrypt Version: 1.10.0 -Release: 2%{?dist} +Release: 5%{?dist} URL: https://www.gnupg.org/ Source0: https://www.gnupg.org/ftp/gcrypt/libgcrypt/libgcrypt-%{version}.tar.bz2 Source1: https://www.gnupg.org/ftp/gcrypt/libgcrypt/libgcrypt-%{version}.tar.bz2.sig Source2: wk@g10code.com Patch1: libgcrypt-1.10.0-disable-brainpool.patch +Patch2: libgcrypt-1.10.0-fips-disable-pkcs1.5.patch +Patch3: libgcrypt-1.10.0-ppc-hwf.patch +Patch4: libgcrypt-1.10.0-allow-small-RSA-verify.patch +Patch5: libgcrypt-1.10.0-allow-short-salt.patch +Patch6: libgcrypt-1.10.0-fips-getrandom.patch +Patch7: libgcrypt-1.10.0-fips-selftest.patch +Patch8: libgcrypt-1.10.0-fips-disable-oaep.patch %global gcrylibdir %{_libdir} %global gcrysoname libgcrypt.so.20 @@ -58,6 +65,13 @@ applications using libgcrypt. %prep %setup -q %patch1 -p1 +%patch2 -p1 +%patch3 -p1 +%patch4 -p1 +%patch5 -p1 +%patch6 -p1 +%patch7 -p1 +%patch8 -p1 %build # This package has a configure test which uses ASMs, but does not link the @@ -74,7 +88,7 @@ export DIGESTS='crc gostr3411-94 md4 md5 rmd160 sha1 sha256 sha512 sha3 tiger wh export CIPHERS='arcfour blowfish cast5 des aes twofish serpent rfc2268 seed camellia idea salsa20 gost28147 chacha20' eval $(sed -n 's/^\(\(NAME\|VERSION_ID\)=.*\)/OS_\1/p' /etc/os-release) -export FIPS_MODULE_NAME="$OS_NAME $OS_VERSION_ID %name" +export FIPS_MODULE_NAME="$OS_NAME ${OS_VERSION_ID%%.*} %name" autoreconf -f %configure --disable-static \ @@ -176,6 +190,20 @@ mkdir -p -m 755 $RPM_BUILD_ROOT/etc/gcrypt %license COPYING %changelog +* Wed Aug 17 2022 Jakub Jelen - 1.10.0-5 +- Allow signature verification with smaller RSA keys (#2083846) +- Allow short salt for KDF (#2114870) +- Reseed the kernel DRBG by using GRND_RANDOM (#2118695) +- Address FIPS review comments around selftests (#2118695) +- Disable RSA-OAEP in FIPS mode (#2118695) + +* Fri May 06 2022 Jakub Jelen - 1.10.0-4 +- Backport ppc hardware flags detection (#2051307) +- Disable PKCS#1.5 encryption in FIPS mode (#2061328) + +* Thu Mar 31 2022 Jakub Jelen - 1.10.0-3 +- Use correct FIPS module name (#2067123) + * Thu Feb 17 2022 Jakub Jelen - 1.10.0-2 - Systematic FIPS module name with other FIPS modules