From 3f33b83ad8700159e0a9ece1119d56da1168bc0c Mon Sep 17 00:00:00 2001 From: orange-snn Date: Mon, 11 May 2020 22:32:03 +0800 Subject: [PATCH] update to 1.8.5 --- CVE-2019-13627-1.patch | 67 - CVE-2019-13627-2.patch | 123 - ...-in-secmem-in-out-of-core-conditions.patch | 34 - curves.c | 144 -- ...eak-in-the-error-case-of-ecc_encrypt.patch | 64 - ...-memory-leakage-in-parameter-check-o.patch | 34 - ecc-curves.c | 1207 ---------- hobble-libgcrypt | 11 - libgcrypt-1.8.3-cmac-selftest.patch | 322 +++ libgcrypt-1.8.3-fips-enttest.patch | 113 + libgcrypt-1.8.3-md-fips-enforce.patch | 12 + ...patch => libgcrypt-1.8.4-fips-keygen.patch | 80 +- ...m.patch => libgcrypt-1.8.4-getrandom.patch | 87 +- libgcrypt-1.8.4-tests-fipsmode.patch | 184 ++ ...ll.patch => libgcrypt-1.8.4-use-poll.patch | 14 +- libgcrypt-1.8.5-build.patch | 14 + libgcrypt-1.8.5-intel-cet.patch | 348 +++ ...ypt-1.8.3.tar.gz => libgcrypt-1.8.5.tar.gz | Bin 3601948 -> 3603649 bytes libgcrypt.spec | 53 +- ...alized-use-of-a-var-in-the-error-cas.patch | 45 - t-mpi-point.c | 1225 ---------- wk@g10code.com | 2007 ----------------- 22 files changed, 1093 insertions(+), 5095 deletions(-) delete mode 100644 CVE-2019-13627-1.patch delete mode 100644 CVE-2019-13627-2.patch delete mode 100644 Fix-memory-leak-in-secmem-in-out-of-core-conditions.patch delete mode 100644 curves.c delete mode 100644 ecc-Fix-memory-leak-in-the-error-case-of-ecc_encrypt.patch delete mode 100644 ecc-Fix-possible-memory-leakage-in-parameter-check-o.patch delete mode 100644 ecc-curves.c delete mode 100644 hobble-libgcrypt create mode 100644 libgcrypt-1.8.3-cmac-selftest.patch create mode 100644 libgcrypt-1.8.3-fips-enttest.patch create mode 100644 libgcrypt-1.8.3-md-fips-enforce.patch rename libgcrypt-1.8.0-tests.patch => libgcrypt-1.8.4-fips-keygen.patch (42%) rename libgcrypt-1.8.3-getrandom.patch => libgcrypt-1.8.4-getrandom.patch (47%) create mode 100644 libgcrypt-1.8.4-tests-fipsmode.patch rename libgcrypt-1.8.0-use-poll.patch => libgcrypt-1.8.4-use-poll.patch (80%) create mode 100644 libgcrypt-1.8.5-build.patch create mode 100644 libgcrypt-1.8.5-intel-cet.patch rename libgcrypt-1.8.3.tar.gz => libgcrypt-1.8.5.tar.gz (33%) delete mode 100644 sexp-Fix-uninitialized-use-of-a-var-in-the-error-cas.patch delete mode 100644 t-mpi-point.c delete mode 100644 wk@g10code.com diff --git a/CVE-2019-13627-1.patch b/CVE-2019-13627-1.patch deleted file mode 100644 index de190f4..0000000 --- a/CVE-2019-13627-1.patch +++ /dev/null @@ -1,67 +0,0 @@ -From d5407b78cca9f9d318a4f4d2f6ba2b8388584cd9 Mon Sep 17 00:00:00 2001 -From: NIIBE Yutaka -Date: Wed, 17 Jul 2019 12:44:50 +0900 -Subject: [PATCH] ecc: Add mitigation against timing attack. -MIME-Version: 1.0 -Content-Type: text/plain; charset=utf8 -Content-Transfer-Encoding: 8bit - -* cipher/ecc-ecdsa.c (_gcry_ecc_ecdsa_sign): Add the order N to K. -* mpi/ec.c (_gcry_mpi_ec_mul_point): Compute with NBITS of P or larger. - --- - -Cherry-picked master commit of: - b9577f7c89b4327edc09f2231bc8b31521102c79 - -CVE-id: CVE-2019-13627 -GnuPG-bug-id: 4626 -Co-authored-by: Ján JanÄár -Signed-off-by: NIIBE Yutaka ---- - cipher/ecc-ecdsa.c | 10 ++++++++++ - mpi/ec.c | 6 +++++- - 2 files changed, 15 insertions(+), 1 deletion(-) - -diff --git a/cipher/ecc-ecdsa.c b/cipher/ecc-ecdsa.c -index 140e8c09..84a1cf84 100644 ---- a/cipher/ecc-ecdsa.c -+++ b/cipher/ecc-ecdsa.c -@@ -114,6 +114,16 @@ _gcry_ecc_ecdsa_sign (gcry_mpi_t input, ECC_secret_key *skey, - else - k = _gcry_dsa_gen_k (skey->E.n, GCRY_STRONG_RANDOM); - -+ /* Originally, ECDSA computation requires k where 0 < k < n. -+ * Here, we add n (the order of curve), to keep k in a -+ * range: n < k < 2*n, or, addming more n, keep k in a range: -+ * 2*n < k < 3*n, so that timing difference of the EC -+ * multiply operation can be small. The result is same. -+ */ -+ mpi_add (k, k, skey->E.n); -+ if (!mpi_test_bit (k, qbits)) -+ mpi_add (k, k, skey->E.n); -+ - _gcry_mpi_ec_mul_point (&I, k, &skey->E.G, ctx); - if (_gcry_mpi_ec_get_affine (x, NULL, &I, ctx)) - { -diff --git a/mpi/ec.c b/mpi/ec.c -index 89077cd9..adb02600 100644 ---- a/mpi/ec.c -+++ b/mpi/ec.c -@@ -1309,7 +1309,11 @@ _gcry_mpi_ec_mul_point (mpi_point_t result, - unsigned int nbits; - int j; - -- nbits = mpi_get_nbits (scalar); -+ if (mpi_cmp (scalar, ctx->p) >= 0) -+ nbits = mpi_get_nbits (scalar); -+ else -+ nbits = mpi_get_nbits (ctx->p); -+ - if (ctx->model == MPI_EC_WEIERSTRASS) - { - mpi_set_ui (result->x, 1); --- -2.11.0 - - diff --git a/CVE-2019-13627-2.patch b/CVE-2019-13627-2.patch deleted file mode 100644 index b33a7b2..0000000 --- a/CVE-2019-13627-2.patch +++ /dev/null @@ -1,123 +0,0 @@ -From db4e9976cc31b314aafad6626b2894e86ee44d60 Mon Sep 17 00:00:00 2001 -From: NIIBE Yutaka -Date: Thu, 8 Aug 2019 17:42:02 +0900 -Subject: [PATCH] dsa,ecdsa: Fix use of nonce, use larger one. - -* cipher/dsa-common.c (_gcry_dsa_modify_k): New. -* cipher/pubkey-internal.h (_gcry_dsa_modify_k): New. -* cipher/dsa.c (sign): Use _gcry_dsa_modify_k. -* cipher/ecc-ecdsa.c (_gcry_ecc_ecdsa_sign): Likewise. -* cipher/ecc-gost.c (_gcry_ecc_gost_sign): Likewise. - --- - -Cherry-picked master commit of: - 7c2943309d14407b51c8166c4dcecb56a3628567 - -CVE-id: CVE-2019-13627 -GnuPG-bug-id: 4626 -Signed-off-by: NIIBE Yutaka ---- - cipher/dsa-common.c | 24 ++++++++++++++++++++++++ - cipher/dsa.c | 2 ++ - cipher/ecc-ecdsa.c | 10 +--------- - cipher/ecc-gost.c | 2 ++ - cipher/pubkey-internal.h | 1 + - 5 files changed, 30 insertions(+), 9 deletions(-) - -diff --git a/cipher/dsa-common.c b/cipher/dsa-common.c -index 8c0a6843..fe49248d 100644 ---- a/cipher/dsa-common.c -+++ b/cipher/dsa-common.c -@@ -30,6 +30,30 @@ - - - /* -+ * Modify K, so that computation time difference can be small, -+ * by making K large enough. -+ * -+ * Originally, (EC)DSA computation requires k where 0 < k < q. Here, -+ * we add q (the order), to keep k in a range: q < k < 2*q (or, -+ * addming more q, to keep k in a range: 2*q < k < 3*q), so that -+ * timing difference of the EC multiply (or exponentiation) operation -+ * can be small. The result of (EC)DSA computation is same. -+ */ -+void -+_gcry_dsa_modify_k (gcry_mpi_t k, gcry_mpi_t q, int qbits) -+{ -+ gcry_mpi_t k1 = mpi_new (qbits+2); -+ -+ mpi_resize (k, (qbits+2+BITS_PER_MPI_LIMB-1) / BITS_PER_MPI_LIMB); -+ k->nlimbs = k->alloced; -+ mpi_add (k, k, q); -+ mpi_add (k1, k, q); -+ mpi_set_cond (k, k1, !mpi_test_bit (k, qbits)); -+ -+ mpi_free (k1); -+} -+ -+/* - * Generate a random secret exponent K less than Q. - * Note that ECDSA uses this code also to generate D. - */ -diff --git a/cipher/dsa.c b/cipher/dsa.c -index 22d8d782..24a53528 100644 ---- a/cipher/dsa.c -+++ b/cipher/dsa.c -@@ -635,6 +635,8 @@ sign (gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t input, DSA_secret_key *skey, - k = _gcry_dsa_gen_k (skey->q, GCRY_STRONG_RANDOM); - } - -+ _gcry_dsa_modify_k (k, skey->q, qbits); -+ - /* r = (a^k mod p) mod q */ - mpi_powm( r, skey->g, k, skey->p ); - mpi_fdiv_r( r, r, skey->q ); -diff --git a/cipher/ecc-ecdsa.c b/cipher/ecc-ecdsa.c -index 84a1cf84..97966c3a 100644 ---- a/cipher/ecc-ecdsa.c -+++ b/cipher/ecc-ecdsa.c -@@ -114,15 +114,7 @@ _gcry_ecc_ecdsa_sign (gcry_mpi_t input, ECC_secret_key *skey, - else - k = _gcry_dsa_gen_k (skey->E.n, GCRY_STRONG_RANDOM); - -- /* Originally, ECDSA computation requires k where 0 < k < n. -- * Here, we add n (the order of curve), to keep k in a -- * range: n < k < 2*n, or, addming more n, keep k in a range: -- * 2*n < k < 3*n, so that timing difference of the EC -- * multiply operation can be small. The result is same. -- */ -- mpi_add (k, k, skey->E.n); -- if (!mpi_test_bit (k, qbits)) -- mpi_add (k, k, skey->E.n); -+ _gcry_dsa_modify_k (k, skey->E.n, qbits); - - _gcry_mpi_ec_mul_point (&I, k, &skey->E.G, ctx); - if (_gcry_mpi_ec_get_affine (x, NULL, &I, ctx)) -diff --git a/cipher/ecc-gost.c b/cipher/ecc-gost.c -index a34fa084..0362a6c7 100644 ---- a/cipher/ecc-gost.c -+++ b/cipher/ecc-gost.c -@@ -94,6 +94,8 @@ _gcry_ecc_gost_sign (gcry_mpi_t input, ECC_secret_key *skey, - mpi_free (k); - k = _gcry_dsa_gen_k (skey->E.n, GCRY_STRONG_RANDOM); - -+ _gcry_dsa_modify_k (k, skey->E.n, qbits); -+ - _gcry_mpi_ec_mul_point (&I, k, &skey->E.G, ctx); - if (_gcry_mpi_ec_get_affine (x, NULL, &I, ctx)) - { -diff --git a/cipher/pubkey-internal.h b/cipher/pubkey-internal.h -index b8167c77..d31e26f3 100644 ---- a/cipher/pubkey-internal.h -+++ b/cipher/pubkey-internal.h -@@ -84,6 +84,7 @@ _gcry_rsa_pss_verify (gcry_mpi_t value, gcry_mpi_t encoded, - - - /*-- dsa-common.c --*/ -+void _gcry_dsa_modify_k (gcry_mpi_t k, gcry_mpi_t q, int qbits); - gcry_mpi_t _gcry_dsa_gen_k (gcry_mpi_t q, int security_level); - gpg_err_code_t _gcry_dsa_gen_rfc6979_k (gcry_mpi_t *r_k, - gcry_mpi_t dsa_q, gcry_mpi_t dsa_x, --- -2.11.0 diff --git a/Fix-memory-leak-in-secmem-in-out-of-core-conditions.patch b/Fix-memory-leak-in-secmem-in-out-of-core-conditions.patch deleted file mode 100644 index d6411f2..0000000 --- a/Fix-memory-leak-in-secmem-in-out-of-core-conditions.patch +++ /dev/null @@ -1,34 +0,0 @@ -From f74687fd43f5772a372f54031d5a9527597f4ce4 Mon Sep 17 00:00:00 2001 -From: Werner Koch -Date: Wed, 24 Oct 2018 11:55:34 +0200 -Subject: [PATCH 098/152] Fix memory leak in secmem in out of core conditions. - -* src/secmem.c (_gcry_secmem_malloc_internal): Release pool descriptor -if the pool could not be allocated. --- - -GnuPG-bug-id: 4211 -Signed-off-by: Werner Koch ---- - src/secmem.c | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -diff --git a/src/secmem.c b/src/secmem.c -index 79c135f..3e091d8 100644 ---- a/src/secmem.c -+++ b/src/secmem.c -@@ -658,7 +658,10 @@ _gcry_secmem_malloc_internal (size_t size, int xhint) - pool->size = auto_expand? auto_expand : STANDARD_POOL_SIZE; - pool->mem = malloc (pool->size); - if (!pool->mem) -- return NULL; /* Not enough memory available for a new pool. */ -+ { -+ free (pool); -+ return NULL; /* Not enough memory available for a new pool. */ -+ } - /* Initialize first memory block. */ - mb = (memblock_t *) pool->mem; - mb->size = pool->size - BLOCK_HEAD_SIZE; --- -1.8.3.1 - diff --git a/curves.c b/curves.c deleted file mode 100644 index b68e0e2..0000000 --- a/curves.c +++ /dev/null @@ -1,144 +0,0 @@ -/* curves.c - ECC curves regression tests - * Copyright (C) 2011 Free Software Foundation, Inc. - * - * This file is part of Libgcrypt. - * - * Libgcrypt is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * Libgcrypt is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#ifdef HAVE_CONFIG_H -#include -#endif -#include -#include -#include -#include - -#include "../src/gcrypt-int.h" - - -#define PGM "curves" -#include "t-common.h" - -/* Number of curves defined in ../cipger/ecc.c */ -#define N_CURVES 14 - -/* A real world sample public key. */ -static char const sample_key_1[] = -"(public-key\n" -" (ecdsa\n" -" (p #00FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF#)\n" -" (a #00FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC#)\n" -" (b #5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B#)\n" -" (g #046B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296" - "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5#)\n" -" (n #00FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551#)\n" -" (h #000000000000000000000000000000000000000000000000000000000000000001#)\n" -" (q #0442B927242237639A36CE9221B340DB1A9AB76DF2FE3E171277F6A4023DED146EE" - "86525E38CCECFF3FB8D152CC6334F70D23A525175C1BCBDDE6E023B2228770E#)\n" -" ))"; -static char const sample_key_1_curve[] = "NIST P-256"; -static unsigned int sample_key_1_nbits = 256; - - - -static void -list_curves (void) -{ - int idx; - const char *name; - unsigned int nbits; - - for (idx=0; (name = gcry_pk_get_curve (NULL, idx, &nbits)); idx++) - { - if (verbose) - printf ("%s - %u bits\n", name, nbits); - } - if (idx != N_CURVES) - fail ("expected %d curves but got %d\n", N_CURVES, idx); - if (gcry_pk_get_curve (NULL, -1, NULL)) - fail ("curve iteration failed\n"); -} - - -static void -check_matching (void) -{ - gpg_error_t err; - gcry_sexp_t key; - const char *name; - unsigned int nbits; - - err = gcry_sexp_new (&key, sample_key_1, 0, 1); - if (err) - die ("parsing s-expression string failed: %s\n", gpg_strerror (err)); - name = gcry_pk_get_curve (key, 0, &nbits); - if (!name) - fail ("curve name not found for sample_key_1\n"); - else if (strcmp (name, sample_key_1_curve)) - fail ("expected curve name %s but got %s for sample_key_1\n", - sample_key_1_curve, name); - else if (nbits != sample_key_1_nbits) - fail ("expected curve size %u but got %u for sample_key_1\n", - sample_key_1_nbits, nbits); - - gcry_sexp_release (key); - -} - - -static void -check_get_params (void) -{ - gcry_sexp_t param; - const char *name; - - param = gcry_pk_get_param (GCRY_PK_ECDSA, sample_key_1_curve); - if (!param) - fail ("error gerring parameters for `%s'\n", sample_key_1_curve); - - name = gcry_pk_get_curve (param, 0, NULL); - if (!name) - fail ("get_param: curve name not found for sample_key_1\n"); - else if (strcmp (name, sample_key_1_curve)) - fail ("get_param: expected curve name %s but got %s for sample_key_1\n", - sample_key_1_curve, name); - - gcry_sexp_release (param); - -} - - -int -main (int argc, char **argv) -{ - if (argc > 1 && !strcmp (argv[1], "--verbose")) - verbose = 1; - else if (argc > 1 && !strcmp (argv[1], "--debug")) - verbose = debug = 1; - - if (!gcry_check_version (GCRYPT_VERSION)) - die ("version mismatch\n"); - - xgcry_control (GCRYCTL_DISABLE_SECMEM, 0); - xgcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0); - if (debug) - xgcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u, 0); - list_curves (); - check_matching (); - check_get_params (); - - return error_count ? 1 : 0; -} diff --git a/ecc-Fix-memory-leak-in-the-error-case-of-ecc_encrypt.patch b/ecc-Fix-memory-leak-in-the-error-case-of-ecc_encrypt.patch deleted file mode 100644 index b4ab929..0000000 --- a/ecc-Fix-memory-leak-in-the-error-case-of-ecc_encrypt.patch +++ /dev/null @@ -1,64 +0,0 @@ -From e57e75ea517f32109b508113f18298fc69fd1192 Mon Sep 17 00:00:00 2001 -From: Werner Koch -Date: Wed, 24 Oct 2018 11:50:46 +0200 -Subject: [PATCH 097/152] ecc: Fix memory leak in the error case of - ecc_encrypt_raw - -* cipher/ecc.c (ecc_encrypt_raw): Add proper error cleanup in the main -block. --- - -GnuPG-bug-id: 4210 -Signed-off-by: Werner Koch ---- - cipher/ecc.c | 10 ++++++---- - 1 file changed, 6 insertions(+), 4 deletions(-) - -diff --git a/cipher/ecc.c b/cipher/ecc.c -index 4e3e5b1..3f221a2 100644 ---- a/cipher/ecc.c -+++ b/cipher/ecc.c -@@ -1392,6 +1392,7 @@ ecc_encrypt_raw (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t keyparms) - unsigned char *rawmpi; - unsigned int rawmpilen; - -+ rc = 0; - x = mpi_new (0); - if (ec->model == MPI_EC_MONTGOMERY) - y = NULL; -@@ -1418,7 +1419,7 @@ ecc_encrypt_raw (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t keyparms) - if (!(flags & PUBKEY_FLAG_DJB_TWEAK)) - { /* It's not for X25519, then, the input data was simply wrong. */ - rc = GPG_ERR_INV_DATA; -- goto leave; -+ goto leave_main; - } - } - if (y) -@@ -1443,7 +1444,7 @@ ecc_encrypt_raw (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t keyparms) - if (_gcry_mpi_ec_get_affine (x, y, &R, ec)) - { - rc = GPG_ERR_INV_DATA; -- goto leave; -+ goto leave_main; - } - if (y) - mpi_e = _gcry_ecc_ec2os (x, y, pk.E.p); -@@ -1461,11 +1462,12 @@ ecc_encrypt_raw (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t keyparms) - } - } - -- -+ leave_main: - mpi_free (x); - mpi_free (y); -- - point_free (&R); -+ if (rc) -+ goto leave; - } - - if (!rc) --- -1.8.3.1 - diff --git a/ecc-Fix-possible-memory-leakage-in-parameter-check-o.patch b/ecc-Fix-possible-memory-leakage-in-parameter-check-o.patch deleted file mode 100644 index 51e0283..0000000 --- a/ecc-Fix-possible-memory-leakage-in-parameter-check-o.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 149ceb3cae03d0385341d32430aa5ae57de90007 Mon Sep 17 00:00:00 2001 -From: Werner Koch -Date: Wed, 24 Oct 2018 09:50:17 +0200 -Subject: [PATCH 096/152] ecc: Fix possible memory leakage in parameter check - of eddsa. - -* cipher/ecc-eddsa.c (_gcry_ecc_eddsa_verify): Fix mem leak. --- - -GnuPG-bug-id: 4209 -Signed-off-by: Werner Koch ---- - cipher/ecc-eddsa.c | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -diff --git a/cipher/ecc-eddsa.c b/cipher/ecc-eddsa.c -index 813e030..89b708a 100644 ---- a/cipher/ecc-eddsa.c -+++ b/cipher/ecc-eddsa.c -@@ -760,7 +760,10 @@ _gcry_ecc_eddsa_verify (gcry_mpi_t input, ECC_public_key *pkey, - pkey->E.p, pkey->E.a, pkey->E.b); - b = ctx->nbits/8; - if (b != 256/8) -- return GPG_ERR_INTERNAL; /* We only support 256 bit. */ -+ { -+ rc = GPG_ERR_INTERNAL; /* We only support 256 bit. */ -+ goto leave; -+ } - - /* Decode and check the public key. */ - rc = _gcry_ecc_eddsa_decodepoint (pk, ctx, &Q, &encpk, &encpklen); --- -1.8.3.1 - diff --git a/ecc-curves.c b/ecc-curves.c deleted file mode 100644 index 7378bae..0000000 --- a/ecc-curves.c +++ /dev/null @@ -1,1207 +0,0 @@ -/* ecc-curves.c - Elliptic Curve parameter mangement - * Copyright (C) 2007, 2008, 2010, 2011 Free Software Foundation, Inc. - * Copyright (C) 2013 g10 Code GmbH - * - * This file is part of Libgcrypt. - * - * Libgcrypt is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * Libgcrypt is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, see . - */ - -#include -#include -#include -#include -#include - -#include "g10lib.h" -#include "mpi.h" -#include "cipher.h" -#include "context.h" -#include "ec-context.h" -#include "pubkey-internal.h" -#include "ecc-common.h" - - -/* This tables defines aliases for curve names. */ -static const struct -{ - const char *name; /* Our name. */ - const char *other; /* Other name. */ -} curve_aliases[] = - { - { "Curve25519", "1.3.6.1.4.1.3029.1.5.1" }, - { "Ed25519", "1.3.6.1.4.1.11591.15.1" }, - - { "NIST P-224", "secp224r1" }, - { "NIST P-224", "1.3.132.0.33" }, /* SECP OID. */ - { "NIST P-224", "nistp224" }, /* rfc5656. */ - - { "NIST P-256", "1.2.840.10045.3.1.7" }, /* From NIST SP 800-78-1. */ - { "NIST P-256", "prime256v1" }, - { "NIST P-256", "secp256r1" }, - { "NIST P-256", "nistp256" }, /* rfc5656. */ - - { "NIST P-384", "secp384r1" }, - { "NIST P-384", "1.3.132.0.34" }, - { "NIST P-384", "nistp384" }, /* rfc5656. */ - - { "NIST P-521", "secp521r1" }, - { "NIST P-521", "1.3.132.0.35" }, - { "NIST P-521", "nistp521" }, /* rfc5656. */ - - { "GOST2001-test", "1.2.643.2.2.35.0" }, - { "GOST2001-CryptoPro-A", "1.2.643.2.2.35.1" }, - { "GOST2001-CryptoPro-B", "1.2.643.2.2.35.2" }, - { "GOST2001-CryptoPro-C", "1.2.643.2.2.35.3" }, - { "GOST2001-CryptoPro-A", "GOST2001-CryptoPro-XchA" }, - { "GOST2001-CryptoPro-C", "GOST2001-CryptoPro-XchB" }, - { "GOST2001-CryptoPro-A", "1.2.643.2.2.36.0" }, - { "GOST2001-CryptoPro-C", "1.2.643.2.2.36.1" }, - - { "GOST2012-tc26-A", "1.2.643.7.1.2.1.2.1" }, - { "GOST2012-tc26-B", "1.2.643.7.1.2.1.2.2" }, - - { "secp256k1", "1.3.132.0.10" }, - - { NULL, NULL} - }; - - -typedef struct -{ - const char *desc; /* Description of the curve. */ - unsigned int nbits; /* Number of bits. */ - unsigned int fips:1; /* True if this is a FIPS140-2 approved curve. */ - - /* The model describing this curve. This is mainly used to select - the group equation. */ - enum gcry_mpi_ec_models model; - - /* The actual ECC dialect used. This is used for curve specific - optimizations and to select encodings etc. */ - enum ecc_dialects dialect; - - const char *p; /* The prime defining the field. */ - const char *a, *b; /* The coefficients. For Twisted Edwards - Curves b is used for d. For Montgomery - Curves (a,b) has ((A-2)/4,B^-1). */ - const char *n; /* The order of the base point. */ - const char *g_x, *g_y; /* Base point. */ - const char *h; /* Cofactor. */ -} ecc_domain_parms_t; - - -/* This static table defines all available curves. */ -static const ecc_domain_parms_t domain_parms[] = - { - { - /* (-x^2 + y^2 = 1 + dx^2y^2) */ - "Ed25519", 256, 0, - MPI_EC_EDWARDS, ECC_DIALECT_ED25519, - "0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED", - "-0x01", - "-0x2DFC9311D490018C7338BF8688861767FF8FF5B2BEBE27548A14B235ECA6874A", - "0x1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED", - "0x216936D3CD6E53FEC0A4E231FDD6DC5C692CC7609525A7B2C9562D608F25D51A", - "0x6666666666666666666666666666666666666666666666666666666666666658", - "0x08" - }, - { - /* (y^2 = x^3 + 486662*x^2 + x) */ - "Curve25519", 256, 0, - MPI_EC_MONTGOMERY, ECC_DIALECT_STANDARD, - "0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED", - "0x01DB41", - "0x01", - "0x1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED", - "0x0000000000000000000000000000000000000000000000000000000000000009", - "0x20AE19A1B8A086B4E01EDD2C7748D14C923D4D7E6D7C61B229E9C5A27ECED3D9", - "0x08" - }, - { - "NIST P-224", 224, 1, - MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, - "0xffffffffffffffffffffffffffffffff000000000000000000000001", - "0xfffffffffffffffffffffffffffffffefffffffffffffffffffffffe", - "0xb4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4", - "0xffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3d" , - - "0xb70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21", - "0xbd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34", - "0x01" - }, - { - "NIST P-256", 256, 1, - MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, - "0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff", - "0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc", - "0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", - "0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", - - "0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296", - "0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5", - "0x01" - }, - { - "NIST P-384", 384, 1, - MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, - "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe" - "ffffffff0000000000000000ffffffff", - "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe" - "ffffffff0000000000000000fffffffc", - "0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875a" - "c656398d8a2ed19d2a85c8edd3ec2aef", - "0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf" - "581a0db248b0a77aecec196accc52973", - - "0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a38" - "5502f25dbf55296c3a545e3872760ab7", - "0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c0" - "0a60b1ce1d7e819d7a431d7c90ea0e5f", - "0x01" - }, - { - "NIST P-521", 521, 1, - MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, - "0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" - "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc", - "0x051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef10" - "9e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00", - "0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" - "ffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409", - - "0x00c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d" - "3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66", - "0x011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e" - "662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650", - "0x01" - }, - - { - "GOST2001-test", 256, 0, - MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, - "0x8000000000000000000000000000000000000000000000000000000000000431", - "0x0000000000000000000000000000000000000000000000000000000000000007", - "0x5fbff498aa938ce739b8e022fbafef40563f6e6a3472fc2a514c0ce9dae23b7e", - "0x8000000000000000000000000000000150fe8a1892976154c59cfc193accf5b3", - - "0x0000000000000000000000000000000000000000000000000000000000000002", - "0x08e2a8a0e65147d4bd6316030e16d19c85c97f0a9ca267122b96abbcea7e8fc8", - "0x01" - }, - { - "GOST2001-CryptoPro-A", 256, 0, - MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, - "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd97", - "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd94", - "0x00000000000000000000000000000000000000000000000000000000000000a6", - "0xffffffffffffffffffffffffffffffff6c611070995ad10045841b09b761b893", - "0x0000000000000000000000000000000000000000000000000000000000000001", - "0x8d91e471e0989cda27df505a453f2b7635294f2ddf23e3b122acc99c9e9f1e14", - "0x01" - }, - { - "GOST2001-CryptoPro-B", 256, 0, - MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, - "0x8000000000000000000000000000000000000000000000000000000000000c99", - "0x8000000000000000000000000000000000000000000000000000000000000c96", - "0x3e1af419a269a5f866a7d3c25c3df80ae979259373ff2b182f49d4ce7e1bbc8b", - "0x800000000000000000000000000000015f700cfff1a624e5e497161bcc8a198f", - "0x0000000000000000000000000000000000000000000000000000000000000001", - "0x3fa8124359f96680b83d1c3eb2c070e5c545c9858d03ecfb744bf8d717717efc", - "0x01" - }, - { - "GOST2001-CryptoPro-C", 256, 0, - MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, - "0x9b9f605f5a858107ab1ec85e6b41c8aacf846e86789051d37998f7b9022d759b", - "0x9b9f605f5a858107ab1ec85e6b41c8aacf846e86789051d37998f7b9022d7598", - "0x000000000000000000000000000000000000000000000000000000000000805a", - "0x9b9f605f5a858107ab1ec85e6b41c8aa582ca3511eddfb74f02f3a6598980bb9", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x41ece55743711a8c3cbf3783cd08c0ee4d4dc440d4641a8f366e550dfdb3bb67", - "0x01" - }, - { - "GOST2012-test", 511, 0, - MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, - "0x4531acd1fe0023c7550d267b6b2fee80922b14b2ffb90f04d4eb7c09b5d2d15d" - "f1d852741af4704a0458047e80e4546d35b8336fac224dd81664bbf528be6373", - "0x0000000000000000000000000000000000000000000000000000000000000007", - "0x1cff0806a31116da29d8cfa54e57eb748bc5f377e49400fdd788b649eca1ac4" - "361834013b2ad7322480a89ca58e0cf74bc9e540c2add6897fad0a3084f302adc", - "0x4531acd1fe0023c7550d267b6b2fee80922b14b2ffb90f04d4eb7c09b5d2d15d" - "a82f2d7ecb1dbac719905c5eecc423f1d86e25edbe23c595d644aaf187e6e6df", - - "0x24d19cc64572ee30f396bf6ebbfd7a6c5213b3b3d7057cc825f91093a68cd762" - "fd60611262cd838dc6b60aa7eee804e28bc849977fac33b4b530f1b120248a9a", - "0x2bb312a43bd2ce6e0d020613c857acddcfbf061e91e5f2c3f32447c259f39b2" - "c83ab156d77f1496bf7eb3351e1ee4e43dc1a18b91b24640b6dbb92cb1add371e", - "0x01" - }, - { - "GOST2012-tc26-A", 512, 0, - MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, - "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" - "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc7", - "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" - "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc4", - "0xe8c2505dedfc86ddc1bd0b2b6667f1da34b82574761cb0e879bd081cfd0b6265" - "ee3cb090f30d27614cb4574010da90dd862ef9d4ebee4761503190785a71c760", - "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" - "27e69532f48d89116ff22b8d4e0560609b4b38abfad2b85dcacdb1411f10b275", - "0x0000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000003", - "0x7503cfe87a836ae3a61b8816e25450e6ce5e1c93acf1abc1778064fdcbefa921" - "df1626be4fd036e93d75e6a50e3a41e98028fe5fc235f5b889a589cb5215f2a4", - "0x01" - }, - { - "GOST2012-tc26-B", 512, 0, - MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, - "0x8000000000000000000000000000000000000000000000000000000000000000" - "000000000000000000000000000000000000000000000000000000000000006f", - "0x8000000000000000000000000000000000000000000000000000000000000000" - "000000000000000000000000000000000000000000000000000000000000006c", - "0x687d1b459dc841457e3e06cf6f5e2517b97c7d614af138bcbf85dc806c4b289f" - "3e965d2db1416d217f8b276fad1ab69c50f78bee1fa3106efb8ccbc7c5140116", - "0x8000000000000000000000000000000000000000000000000000000000000001" - "49a1ec142565a545acfdb77bd9d40cfa8b996712101bea0ec6346c54374f25bd", - "0x0000000000000000000000000000000000000000000000000000000000000000" - "0000000000000000000000000000000000000000000000000000000000000002", - "0x1a8f7eda389b094c2c071e3647a8940f3c123b697578c213be6dd9e6c8ec7335" - "dcb228fd1edf4a39152cbcaaf8c0398828041055f94ceeec7e21340780fe41bd", - "0x01" - }, - - { - "secp256k1", 256, 0, - MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, - "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000007", - "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", - "0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", - "0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8", - "0x01" - }, - - { NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL } - }; - - - - -/* Return a copy of POINT. */ -static gcry_mpi_point_t -point_copy (gcry_mpi_point_t point) -{ - gcry_mpi_point_t newpoint; - - if (point) - { - newpoint = mpi_point_new (0); - point_set (newpoint, point); - } - else - newpoint = NULL; - return newpoint; -} - - -/* Helper to scan a hex string. */ -static gcry_mpi_t -scanval (const char *string) -{ - gpg_err_code_t rc; - gcry_mpi_t val; - - rc = _gcry_mpi_scan (&val, GCRYMPI_FMT_HEX, string, 0, NULL); - if (rc) - log_fatal ("scanning ECC parameter failed: %s\n", gpg_strerror (rc)); - return val; -} - - -/* Return the index of the domain_parms table for a curve with NAME. - Return -1 if not found. */ -static int -find_domain_parms_idx (const char *name) -{ - int idx, aliasno; - - /* First check our native curves. */ - for (idx = 0; domain_parms[idx].desc; idx++) - if (!strcmp (name, domain_parms[idx].desc)) - return idx; - - /* If not found consult the alias table. */ - if (!domain_parms[idx].desc) - { - for (aliasno = 0; curve_aliases[aliasno].name; aliasno++) - if (!strcmp (name, curve_aliases[aliasno].other)) - break; - if (curve_aliases[aliasno].name) - { - for (idx = 0; domain_parms[idx].desc; idx++) - if (!strcmp (curve_aliases[aliasno].name, domain_parms[idx].desc)) - return idx; - } - } - - return -1; -} - - -/* Generate the crypto system setup. This function takes the NAME of - a curve or the desired number of bits and stores at R_CURVE the - parameters of the named curve or those of a suitable curve. If - R_NBITS is not NULL, the chosen number of bits is stored there. - NULL may be given for R_CURVE, if the value is not required and for - example only a quick test for availability is desired. Note that - the curve fields should be initialized to zero because fields which - are not NULL are skipped. */ -gpg_err_code_t -_gcry_ecc_fill_in_curve (unsigned int nbits, const char *name, - elliptic_curve_t *curve, unsigned int *r_nbits) -{ - int idx; - const char *resname = NULL; /* Set to a found curve name. */ - - if (name) - idx = find_domain_parms_idx (name); - else - { - for (idx = 0; domain_parms[idx].desc; idx++) - if (nbits == domain_parms[idx].nbits - && domain_parms[idx].model == MPI_EC_WEIERSTRASS) - break; - if (!domain_parms[idx].desc) - idx = -1; - } - if (idx < 0) - return GPG_ERR_UNKNOWN_CURVE; - - resname = domain_parms[idx].desc; - - /* In fips mode we only support NIST curves. Note that it is - possible to bypass this check by specifying the curve parameters - directly. */ - if (fips_mode () && !domain_parms[idx].fips ) - return GPG_ERR_NOT_SUPPORTED; - - switch (domain_parms[idx].model) - { - case MPI_EC_WEIERSTRASS: - case MPI_EC_EDWARDS: - case MPI_EC_MONTGOMERY: - break; - default: - return GPG_ERR_BUG; - } - - - if (r_nbits) - *r_nbits = domain_parms[idx].nbits; - - if (curve) - { - curve->model = domain_parms[idx].model; - curve->dialect = domain_parms[idx].dialect; - if (!curve->p) - curve->p = scanval (domain_parms[idx].p); - if (!curve->a) - { - curve->a = scanval (domain_parms[idx].a); - if (curve->a->sign) - mpi_add (curve->a, curve->p, curve->a); - } - if (!curve->b) - { - curve->b = scanval (domain_parms[idx].b); - if (curve->b->sign) - mpi_add (curve->b, curve->p, curve->b); - } - if (!curve->n) - curve->n = scanval (domain_parms[idx].n); - if (!curve->h) - curve->h = scanval (domain_parms[idx].h); - if (!curve->G.x) - curve->G.x = scanval (domain_parms[idx].g_x); - if (!curve->G.y) - curve->G.y = scanval (domain_parms[idx].g_y); - if (!curve->G.z) - curve->G.z = mpi_alloc_set_ui (1); - if (!curve->name) - curve->name = resname; - } - - return 0; -} - - -/* Give the name of the curve NAME, store the curve parameters into P, - A, B, G, N, and H if they point to NULL value. Note that G is returned - in standard uncompressed format. Also update MODEL and DIALECT if - they are not NULL. */ -gpg_err_code_t -_gcry_ecc_update_curve_param (const char *name, - enum gcry_mpi_ec_models *model, - enum ecc_dialects *dialect, - gcry_mpi_t *p, gcry_mpi_t *a, gcry_mpi_t *b, - gcry_mpi_t *g, gcry_mpi_t *n, gcry_mpi_t *h) -{ - int idx; - - idx = find_domain_parms_idx (name); - if (idx < 0) - return GPG_ERR_UNKNOWN_CURVE; - - if (g) - { - char *buf; - size_t len; - - len = 4; - len += strlen (domain_parms[idx].g_x+2); - len += strlen (domain_parms[idx].g_y+2); - len++; - buf = xtrymalloc (len); - if (!buf) - return gpg_err_code_from_syserror (); - strcpy (stpcpy (stpcpy (buf, "0x04"), domain_parms[idx].g_x+2), - domain_parms[idx].g_y+2); - _gcry_mpi_release (*g); - *g = scanval (buf); - xfree (buf); - } - if (model) - *model = domain_parms[idx].model; - if (dialect) - *dialect = domain_parms[idx].dialect; - if (p) - { - _gcry_mpi_release (*p); - *p = scanval (domain_parms[idx].p); - } - if (a) - { - _gcry_mpi_release (*a); - *a = scanval (domain_parms[idx].a); - } - if (b) - { - _gcry_mpi_release (*b); - *b = scanval (domain_parms[idx].b); - } - if (n) - { - _gcry_mpi_release (*n); - *n = scanval (domain_parms[idx].n); - } - if (h) - { - _gcry_mpi_release (*h); - *h = scanval (domain_parms[idx].h); - } - return 0; -} - - -/* Return the name matching the parameters in PKEY. This works only - with curves described by the Weierstrass equation. */ -const char * -_gcry_ecc_get_curve (gcry_sexp_t keyparms, int iterator, unsigned int *r_nbits) -{ - gpg_err_code_t rc; - const char *result = NULL; - elliptic_curve_t E; - gcry_mpi_t mpi_g = NULL; - gcry_mpi_t tmp = NULL; - int idx; - - memset (&E, 0, sizeof E); - - if (r_nbits) - *r_nbits = 0; - - if (!keyparms) - { - idx = iterator; - if (idx >= 0 && idx < DIM (domain_parms)) - { - result = domain_parms[idx].desc; - if (r_nbits) - *r_nbits = domain_parms[idx].nbits; - } - return result; - } - - - /* - * Extract the curve parameters.. - */ - rc = gpg_err_code (sexp_extract_param (keyparms, NULL, "-pabgnh", - &E.p, &E.a, &E.b, &mpi_g, &E.n, &E.h, - NULL)); - if (rc == GPG_ERR_NO_OBJ) - { - /* This might be the second use case of checking whether a - specific curve given by name is supported. */ - gcry_sexp_t l1; - char *name; - - l1 = sexp_find_token (keyparms, "curve", 5); - if (!l1) - goto leave; /* No curve name parameter. */ - - name = sexp_nth_string (l1, 1); - sexp_release (l1); - if (!name) - goto leave; /* Name missing or out of core. */ - - idx = find_domain_parms_idx (name); - xfree (name); - if (idx >= 0) /* Curve found. */ - { - result = domain_parms[idx].desc; - if (r_nbits) - *r_nbits = domain_parms[idx].nbits; - } - return result; - } - - if (rc) - goto leave; - - if (mpi_g) - { - _gcry_mpi_point_init (&E.G); - if (_gcry_ecc_os2ec (&E.G, mpi_g)) - goto leave; - } - - for (idx = 0; domain_parms[idx].desc; idx++) - { - mpi_free (tmp); - tmp = scanval (domain_parms[idx].p); - if (!mpi_cmp (tmp, E.p)) - { - mpi_free (tmp); - tmp = scanval (domain_parms[idx].a); - if (!mpi_cmp (tmp, E.a)) - { - mpi_free (tmp); - tmp = scanval (domain_parms[idx].b); - if (!mpi_cmp (tmp, E.b)) - { - mpi_free (tmp); - tmp = scanval (domain_parms[idx].n); - if (!mpi_cmp (tmp, E.n)) - { - mpi_free (tmp); - tmp = scanval (domain_parms[idx].h); - if (!mpi_cmp (tmp, E.h)) - { - mpi_free (tmp); - tmp = scanval (domain_parms[idx].g_x); - if (!mpi_cmp (tmp, E.G.x)) - { - mpi_free (tmp); - tmp = scanval (domain_parms[idx].g_y); - if (!mpi_cmp (tmp, E.G.y)) - { - result = domain_parms[idx].desc; - if (r_nbits) - *r_nbits = domain_parms[idx].nbits; - goto leave; - } - } - } - } - } - } - } - } - - leave: - _gcry_mpi_release (tmp); - _gcry_mpi_release (E.p); - _gcry_mpi_release (E.a); - _gcry_mpi_release (E.b); - _gcry_mpi_release (mpi_g); - _gcry_mpi_point_free_parts (&E.G); - _gcry_mpi_release (E.n); - _gcry_mpi_release (E.h); - return result; -} - - -/* Helper to extract an MPI from key parameters. */ -static gpg_err_code_t -mpi_from_keyparam (gcry_mpi_t *r_a, gcry_sexp_t keyparam, const char *name) -{ - gcry_err_code_t ec = 0; - gcry_sexp_t l1; - - l1 = sexp_find_token (keyparam, name, 0); - if (l1) - { - *r_a = sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG); - sexp_release (l1); - if (!*r_a) - ec = GPG_ERR_INV_OBJ; - } - return ec; -} - -/* Helper to extract a point from key parameters. If no parameter - with NAME is found, the functions tries to find a non-encoded point - by appending ".x", ".y" and ".z" to NAME. ".z" is in this case - optional and defaults to 1. EC is the context which at this point - may not be fully initialized. */ -static gpg_err_code_t -point_from_keyparam (gcry_mpi_point_t *r_a, - gcry_sexp_t keyparam, const char *name, mpi_ec_t ec) -{ - gcry_err_code_t rc; - gcry_sexp_t l1; - gcry_mpi_point_t point; - - l1 = sexp_find_token (keyparam, name, 0); - if (l1) - { - gcry_mpi_t a; - - a = sexp_nth_mpi (l1, 1, GCRYMPI_FMT_OPAQUE); - sexp_release (l1); - if (!a) - return GPG_ERR_INV_OBJ; - - point = mpi_point_new (0); - if (ec && ec->dialect == ECC_DIALECT_ED25519) - rc = _gcry_ecc_eddsa_decodepoint (a, ec, point, NULL, NULL); - else - rc = _gcry_ecc_os2ec (point, a); - mpi_free (a); - if (rc) - { - mpi_point_release (point); - return rc; - } - } - else - { - char *tmpname; - gcry_mpi_t x = NULL; - gcry_mpi_t y = NULL; - gcry_mpi_t z = NULL; - - tmpname = xtrymalloc (strlen (name) + 2 + 1); - if (!tmpname) - return gpg_err_code_from_syserror (); - strcpy (stpcpy (tmpname, name), ".x"); - rc = mpi_from_keyparam (&x, keyparam, tmpname); - if (rc) - { - xfree (tmpname); - return rc; - } - strcpy (stpcpy (tmpname, name), ".y"); - rc = mpi_from_keyparam (&y, keyparam, tmpname); - if (rc) - { - mpi_free (x); - xfree (tmpname); - return rc; - } - strcpy (stpcpy (tmpname, name), ".z"); - rc = mpi_from_keyparam (&z, keyparam, tmpname); - if (rc) - { - mpi_free (y); - mpi_free (x); - xfree (tmpname); - return rc; - } - if (!z) - z = mpi_set_ui (NULL, 1); - if (x && y) - point = mpi_point_snatch_set (NULL, x, y, z); - else - { - mpi_free (x); - mpi_free (y); - mpi_free (z); - point = NULL; - } - xfree (tmpname); - } - - if (point) - *r_a = point; - return 0; -} - - -/* This function creates a new context for elliptic curve operations. - Either KEYPARAM or CURVENAME must be given. If both are given and - KEYPARAM has no curve parameter, CURVENAME is used to add missing - parameters. On success 0 is returned and the new context stored at - R_CTX. On error NULL is stored at R_CTX and an error code is - returned. The context needs to be released using - gcry_ctx_release. */ -gpg_err_code_t -_gcry_mpi_ec_new (gcry_ctx_t *r_ctx, - gcry_sexp_t keyparam, const char *curvename) -{ - gpg_err_code_t errc; - gcry_ctx_t ctx = NULL; - enum gcry_mpi_ec_models model = MPI_EC_WEIERSTRASS; - enum ecc_dialects dialect = ECC_DIALECT_STANDARD; - gcry_mpi_t p = NULL; - gcry_mpi_t a = NULL; - gcry_mpi_t b = NULL; - gcry_mpi_point_t G = NULL; - gcry_mpi_t n = NULL; - gcry_mpi_t h = NULL; - gcry_mpi_point_t Q = NULL; - gcry_mpi_t d = NULL; - int flags = 0; - gcry_sexp_t l1; - - *r_ctx = NULL; - - if (keyparam) - { - /* Parse an optional flags list. */ - l1 = sexp_find_token (keyparam, "flags", 0); - if (l1) - { - errc = _gcry_pk_util_parse_flaglist (l1, &flags, NULL); - sexp_release (l1); - l1 = NULL; - if (errc) - goto leave; - } - - /* Check whether a curve name was given. */ - l1 = sexp_find_token (keyparam, "curve", 5); - - /* If we don't have a curve name or if override parameters have - explicitly been requested, parse them. */ - if (!l1 || (flags & PUBKEY_FLAG_PARAM)) - { - errc = mpi_from_keyparam (&p, keyparam, "p"); - if (errc) - goto leave; - errc = mpi_from_keyparam (&a, keyparam, "a"); - if (errc) - goto leave; - errc = mpi_from_keyparam (&b, keyparam, "b"); - if (errc) - goto leave; - errc = point_from_keyparam (&G, keyparam, "g", NULL); - if (errc) - goto leave; - errc = mpi_from_keyparam (&n, keyparam, "n"); - if (errc) - goto leave; - errc = mpi_from_keyparam (&h, keyparam, "h"); - if (errc) - goto leave; - } - } - else - l1 = NULL; /* No curvename. */ - - /* Check whether a curve parameter is available and use that to fill - in missing values. If no curve parameter is available try an - optional provided curvename. If only the curvename has been - given use that one. */ - if (l1 || curvename) - { - char *name; - elliptic_curve_t *E; - - if (l1) - { - name = sexp_nth_string (l1, 1); - sexp_release (l1); - if (!name) - { - errc = GPG_ERR_INV_OBJ; /* Name missing or out of core. */ - goto leave; - } - } - else - name = NULL; - - E = xtrycalloc (1, sizeof *E); - if (!E) - { - errc = gpg_err_code_from_syserror (); - xfree (name); - goto leave; - } - - errc = _gcry_ecc_fill_in_curve (0, name? name : curvename, E, NULL); - xfree (name); - if (errc) - { - xfree (E); - goto leave; - } - - model = E->model; - dialect = E->dialect; - - if (!p) - { - p = E->p; - E->p = NULL; - } - if (!a) - { - a = E->a; - E->a = NULL; - } - if (!b) - { - b = E->b; - E->b = NULL; - } - if (!G) - { - G = mpi_point_snatch_set (NULL, E->G.x, E->G.y, E->G.z); - E->G.x = NULL; - E->G.y = NULL; - E->G.z = NULL; - } - if (!n) - { - n = E->n; - E->n = NULL; - } - if (!h) - { - h = E->h; - E->h = NULL; - } - _gcry_ecc_curve_free (E); - xfree (E); - } - - - errc = _gcry_mpi_ec_p_new (&ctx, model, dialect, flags, p, a, b); - if (!errc) - { - mpi_ec_t ec = _gcry_ctx_get_pointer (ctx, CONTEXT_TYPE_EC); - - if (b) - { - mpi_free (ec->b); - ec->b = b; - b = NULL; - } - if (G) - { - ec->G = G; - G = NULL; - } - if (n) - { - ec->n = n; - n = NULL; - } - if (h) - { - ec->h = h; - h = NULL; - } - - /* Now that we know the curve name we can look for the public key - Q. point_from_keyparam needs to know the curve parameters so - that it is able to use the correct decompression. Parsing - the private key D could have been done earlier but it is less - surprising if we do it here as well. */ - if (keyparam) - { - errc = point_from_keyparam (&Q, keyparam, "q", ec); - if (errc) - goto leave; - errc = mpi_from_keyparam (&d, keyparam, "d"); - if (errc) - goto leave; - } - - if (Q) - { - ec->Q = Q; - Q = NULL; - } - if (d) - { - ec->d = d; - d = NULL; - } - - *r_ctx = ctx; - ctx = NULL; - } - - leave: - _gcry_ctx_release (ctx); - mpi_free (p); - mpi_free (a); - mpi_free (b); - _gcry_mpi_point_release (G); - mpi_free (n); - mpi_free (h); - _gcry_mpi_point_release (Q); - mpi_free (d); - return errc; -} - - -/* Return the parameters of the curve NAME as an S-expression. */ -gcry_sexp_t -_gcry_ecc_get_param_sexp (const char *name) -{ - unsigned int nbits; - elliptic_curve_t E; - mpi_ec_t ctx; - gcry_mpi_t g_x, g_y; - gcry_mpi_t pkey[7]; - gcry_sexp_t result; - int i; - - memset (&E, 0, sizeof E); - if (_gcry_ecc_fill_in_curve (0, name, &E, &nbits)) - return NULL; - - g_x = mpi_new (0); - g_y = mpi_new (0); - ctx = _gcry_mpi_ec_p_internal_new (MPI_EC_WEIERSTRASS, - ECC_DIALECT_STANDARD, - 0, - E.p, E.a, NULL); - if (_gcry_mpi_ec_get_affine (g_x, g_y, &E.G, ctx)) - log_fatal ("ecc get param: Failed to get affine coordinates\n"); - _gcry_mpi_ec_free (ctx); - _gcry_mpi_point_free_parts (&E.G); - - pkey[0] = E.p; - pkey[1] = E.a; - pkey[2] = E.b; - pkey[3] = _gcry_ecc_ec2os (g_x, g_y, E.p); - pkey[4] = E.n; - pkey[5] = E.h; - pkey[6] = NULL; - - mpi_free (g_x); - mpi_free (g_y); - - if (sexp_build (&result, NULL, - "(public-key(ecc(p%m)(a%m)(b%m)(g%m)(n%m)(h%m)))", - pkey[0], pkey[1], pkey[2], pkey[3], pkey[4], pkey[5])) - result = NULL; - - for (i=0; pkey[i]; i++) - _gcry_mpi_release (pkey[i]); - - return result; -} - - -/* Return an MPI (or opaque MPI) described by NAME and the context EC. - If COPY is true a copy is returned, if not a const MPI may be - returned. In any case mpi_free must be used. */ -gcry_mpi_t -_gcry_ecc_get_mpi (const char *name, mpi_ec_t ec, int copy) -{ - if (!*name) - return NULL; - - if (!strcmp (name, "p") && ec->p) - return mpi_is_const (ec->p) && !copy? ec->p : mpi_copy (ec->p); - if (!strcmp (name, "a") && ec->a) - return mpi_is_const (ec->a) && !copy? ec->a : mpi_copy (ec->a); - if (!strcmp (name, "b") && ec->b) - return mpi_is_const (ec->b) && !copy? ec->b : mpi_copy (ec->b); - if (!strcmp (name, "n") && ec->n) - return mpi_is_const (ec->n) && !copy? ec->n : mpi_copy (ec->n); - if (!strcmp (name, "h") && ec->h) - return mpi_is_const (ec->h) && !copy? ec->h : mpi_copy (ec->h); - if (!strcmp (name, "d") && ec->d) - return mpi_is_const (ec->d) && !copy? ec->d : mpi_copy (ec->d); - - /* Return a requested point coordinate. */ - if (!strcmp (name, "g.x") && ec->G && ec->G->x) - return mpi_is_const (ec->G->x) && !copy? ec->G->x : mpi_copy (ec->G->x); - if (!strcmp (name, "g.y") && ec->G && ec->G->y) - return mpi_is_const (ec->G->y) && !copy? ec->G->y : mpi_copy (ec->G->y); - if (!strcmp (name, "q.x") && ec->Q && ec->Q->x) - return mpi_is_const (ec->Q->x) && !copy? ec->Q->x : mpi_copy (ec->Q->x); - if (!strcmp (name, "q.y") && ec->Q && ec->Q->y) - return mpi_is_const (ec->Q->y) && !copy? ec->Q->y : mpi_copy (ec->Q->y); - - /* If the base point has been requested, return it in standard - encoding. */ - if (!strcmp (name, "g") && ec->G) - return _gcry_mpi_ec_ec2os (ec->G, ec); - - /* If the public key has been requested, return it by default in - standard uncompressed encoding or if requested in other - encodings. */ - if (*name == 'q' && (!name[1] || name[1] == '@')) - { - /* If only the private key is given, compute the public key. */ - if (!ec->Q) - ec->Q = _gcry_ecc_compute_public (NULL, ec, NULL, NULL); - - if (!ec->Q) - return NULL; - - if (name[1] != '@') - return _gcry_mpi_ec_ec2os (ec->Q, ec); - - if (!strcmp (name+2, "eddsa") && ec->model == MPI_EC_EDWARDS) - { - unsigned char *encpk; - unsigned int encpklen; - - if (!_gcry_ecc_eddsa_encodepoint (ec->Q, ec, NULL, NULL, 0, - &encpk, &encpklen)) - return mpi_set_opaque (NULL, encpk, encpklen*8); - } - } - - return NULL; -} - - -/* Return a point described by NAME and the context EC. */ -gcry_mpi_point_t -_gcry_ecc_get_point (const char *name, mpi_ec_t ec) -{ - if (!strcmp (name, "g") && ec->G) - return point_copy (ec->G); - if (!strcmp (name, "q")) - { - /* If only the private key is given, compute the public key. */ - if (!ec->Q) - ec->Q = _gcry_ecc_compute_public (NULL, ec, NULL, NULL); - - if (ec->Q) - return point_copy (ec->Q); - } - - return NULL; -} - - -/* Store the MPI NEWVALUE into the context EC under NAME. */ -gpg_err_code_t -_gcry_ecc_set_mpi (const char *name, gcry_mpi_t newvalue, mpi_ec_t ec) -{ - gpg_err_code_t rc = 0; - - if (!*name) - ; - else if (!strcmp (name, "p")) - { - mpi_free (ec->p); - ec->p = mpi_copy (newvalue); - _gcry_mpi_ec_get_reset (ec); - } - else if (!strcmp (name, "a")) - { - mpi_free (ec->a); - ec->a = mpi_copy (newvalue); - _gcry_mpi_ec_get_reset (ec); - } - else if (!strcmp (name, "b")) - { - mpi_free (ec->b); - ec->b = mpi_copy (newvalue); - } - else if (!strcmp (name, "n")) - { - mpi_free (ec->n); - ec->n = mpi_copy (newvalue); - } - else if (!strcmp (name, "h")) - { - mpi_free (ec->h); - ec->h = mpi_copy (newvalue); - } - else if (*name == 'q' && (!name[1] || name[1] == '@')) - { - if (newvalue) - { - if (!ec->Q) - ec->Q = mpi_point_new (0); - if (ec->dialect == ECC_DIALECT_ED25519) - rc = _gcry_ecc_eddsa_decodepoint (newvalue, ec, ec->Q, NULL, NULL); - else - rc = _gcry_ecc_os2ec (ec->Q, newvalue); - } - if (rc || !newvalue) - { - _gcry_mpi_point_release (ec->Q); - ec->Q = NULL; - } - /* Note: We assume that Q matches d and thus do not reset d. */ - } - else if (!strcmp (name, "d")) - { - mpi_free (ec->d); - ec->d = mpi_copy (newvalue); - if (ec->d) - { - /* We need to reset the public key because it may not - anymore match. */ - _gcry_mpi_point_release (ec->Q); - ec->Q = NULL; - } - } - else - rc = GPG_ERR_UNKNOWN_NAME; - - return rc; -} - - -/* Store the point NEWVALUE into the context EC under NAME. */ -gpg_err_code_t -_gcry_ecc_set_point (const char *name, gcry_mpi_point_t newvalue, mpi_ec_t ec) -{ - if (!strcmp (name, "g")) - { - _gcry_mpi_point_release (ec->G); - ec->G = point_copy (newvalue); - } - else if (!strcmp (name, "q")) - { - _gcry_mpi_point_release (ec->Q); - ec->Q = point_copy (newvalue); - } - else - return GPG_ERR_UNKNOWN_NAME; - - return 0; -} diff --git a/hobble-libgcrypt b/hobble-libgcrypt deleted file mode 100644 index cc53cc1..0000000 --- a/hobble-libgcrypt +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh - -# Quit out if anything fails. -set -e -x - -# Clean out patent-or-otherwise-encumbered code. -# EC: ????????? ??/??/2015 - -rm -f cipher/ecc-curves.c -rm -f tests/curves.c -rm -f tests/t-mpi-point.c diff --git a/libgcrypt-1.8.3-cmac-selftest.patch b/libgcrypt-1.8.3-cmac-selftest.patch new file mode 100644 index 0000000..d480092 --- /dev/null +++ b/libgcrypt-1.8.3-cmac-selftest.patch @@ -0,0 +1,322 @@ +diff -up libgcrypt-1.8.3/cipher/cipher-cmac.c.cmac-selftest libgcrypt-1.8.3/cipher/cipher-cmac.c +--- libgcrypt-1.8.3/cipher/cipher-cmac.c.cmac-selftest 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.3/cipher/cipher-cmac.c 2019-05-31 17:33:35.594407152 +0200 +@@ -251,3 +251,246 @@ _gcry_cipher_cmac_set_subkeys (gcry_ciph + + return GPG_ERR_NO_ERROR; + } ++ ++/* CMAC selftests. ++ * Copyright (C) 2008 Free Software Foundation, Inc. ++ * Copyright (C) 2019 Red Hat, Inc. ++ */ ++ ++ ++ ++/* Check one MAC with MAC ALGO using the regular MAC ++ * API. (DATA,DATALEN) is the data to be MACed, (KEY,KEYLEN) the key ++ * and (EXPECT,EXPECTLEN) the expected result. If TRUNC is set, the ++ * EXPECTLEN may be less than the digest length. Returns NULL on ++ * success or a string describing the failure. */ ++static const char * ++check_one (int algo, ++ const void *data, size_t datalen, ++ const void *key, size_t keylen, ++ const void *expect, size_t expectlen) ++{ ++ gcry_mac_hd_t hd; ++ unsigned char mac[512]; /* hardcoded to avoid allocation */ ++ size_t macoutlen = expectlen; ++ ++/* printf ("MAC algo %d\n", algo); */ ++ if (_gcry_mac_get_algo_maclen (algo) != expectlen || ++ expectlen > sizeof (mac)) ++ return "invalid tests data"; ++ if (_gcry_mac_open (&hd, algo, 0, NULL)) ++ return "gcry_mac_open failed"; ++ if (_gcry_mac_setkey (hd, key, keylen)) ++ { ++ _gcry_mac_close (hd); ++ return "gcry_md_setkey failed"; ++ } ++ if (_gcry_mac_write (hd, data, datalen)) ++ { ++ _gcry_mac_close (hd); ++ return "gcry_mac_write failed"; ++ } ++ if (_gcry_mac_read (hd, mac, &macoutlen)) ++ { ++ _gcry_mac_close (hd); ++ return "gcry_mac_read failed"; ++ } ++ _gcry_mac_close (hd); ++ if (macoutlen != expectlen || memcmp (mac, expect, expectlen)) ++ { ++/* int i; */ ++ ++/* fputs (" {", stdout); */ ++/* for (i=0; i < expectlen-1; i++) */ ++/* { */ ++/* if (i && !(i % 8)) */ ++/* fputs ("\n ", stdout); */ ++/* printf (" 0x%02x,", mac[i]); */ ++/* } */ ++/* printf (" 0x%02x } },\n", mac[i]); */ ++ ++ return "does not match"; ++ } ++ return NULL; ++} ++ ++ ++static gpg_err_code_t ++selftests_cmac_tdes (int extended, selftest_report_func_t report) ++{ ++ const char *what; ++ const char *errtxt; ++ ++ what = "Basic TDES"; ++ errtxt = check_one (GCRY_MAC_CMAC_3DES, ++ "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a" ++ "\xae\x2d\x8a\x57", 20, ++ "\x8a\xa8\x3b\xf8\xcb\xda\x10\x62\x0b\xc1\xbf\x19\xfb\xb6\xcd\x58" ++ "\xbc\x31\x3d\x4a\x37\x1c\xa8\xb5", 24, ++ "\x74\x3d\xdb\xe0\xce\x2d\xc2\xed", 8); ++ if (errtxt) ++ goto failed; ++ ++ if (extended) ++ { ++ what = "Extended TDES #1"; ++ errtxt = check_one (GCRY_MAC_CMAC_3DES, ++ "", 0, ++ "\x8a\xa8\x3b\xf8\xcb\xda\x10\x62\x0b\xc1\xbf\x19\xfb\xb6\xcd\x58" ++ "\xbc\x31\x3d\x4a\x37\x1c\xa8\xb5", 24, ++ "\xb7\xa6\x88\xe1\x22\xff\xaf\x95", 8); ++ if (errtxt) ++ goto failed; ++ ++ what = "Extended TDES #2"; ++ errtxt = check_one (GCRY_MAC_CMAC_3DES, ++ "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96", 8, ++ "\x8a\xa8\x3b\xf8\xcb\xda\x10\x62\x0b\xc1\xbf\x19\xfb\xb6\xcd\x58" ++ "\xbc\x31\x3d\x4a\x37\x1c\xa8\xb5", 24, ++ "\x8e\x8f\x29\x31\x36\x28\x37\x97", 8); ++ if (errtxt) ++ goto failed; ++ ++ what = "Extended TDES #3"; ++ errtxt = check_one (GCRY_MAC_CMAC_3DES, ++ "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a" ++ "\xae\x2d\x8a\x57\x1e\x03\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e\x51", 32, ++ "\x8a\xa8\x3b\xf8\xcb\xda\x10\x62\x0b\xc1\xbf\x19\xfb\xb6\xcd\x58" ++ "\xbc\x31\x3d\x4a\x37\x1c\xa8\xb5", 24, ++ "\x33\xe6\xb1\x09\x24\x00\xea\xe5", 8); ++ if (errtxt) ++ goto failed; ++ } ++ ++ return 0; /* Succeeded. */ ++ ++ failed: ++ if (report) ++ report ("cmac", GCRY_MAC_CMAC_3DES, what, errtxt); ++ return GPG_ERR_SELFTEST_FAILED; ++} ++ ++ ++ ++static gpg_err_code_t ++selftests_cmac_aes (int extended, selftest_report_func_t report) ++{ ++ const char *what; ++ const char *errtxt; ++ ++ what = "Basic AES128"; ++ errtxt = check_one (GCRY_MAC_CMAC_AES, ++ "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a" ++ "\xae\x2d\x8a\x57\x1e\x03\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e\x51" ++ "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11", 40, ++ "\x2b\x7e\x15\x16\x28\xae\xd2\xa6\xab\xf7\x15\x88\x09\xcf\x4f\x3c", 16, ++ "\xdf\xa6\x67\x47\xde\x9a\xe6\x30\x30\xca\x32\x61\x14\x97\xc8\x27", 16); ++ if (errtxt) ++ goto failed; ++ ++ what = "Basic AES192"; ++ errtxt = check_one (GCRY_MAC_CMAC_AES, ++ "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a" ++ "\xae\x2d\x8a\x57\x1e\x03\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e\x51" ++ "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11", 40, ++ "\x8e\x73\xb0\xf7\xda\x0e\x64\x52\xc8\x10\xf3\x2b\x80\x90\x79\xe5" ++ "\x62\xf8\xea\xd2\x52\x2c\x6b\x7b", 24, ++ "\x8a\x1d\xe5\xbe\x2e\xb3\x1a\xad\x08\x9a\x82\xe6\xee\x90\x8b\x0e", 16); ++ if (errtxt) ++ goto failed; ++ ++ what = "Basic AES256"; ++ errtxt = check_one (GCRY_MAC_CMAC_AES, ++ "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a" ++ "\xae\x2d\x8a\x57\x1e\x03\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e\x51" ++ "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11", 40, ++ "\x60\x3d\xeb\x10\x15\xca\x71\xbe\x2b\x73\xae\xf0\x85\x7d\x77\x81" ++ "\x1f\x35\x2c\x07\x3b\x61\x08\xd7\x2d\x98\x10\xa3\x09\x14\xdf\xf4", 32, ++ "\xaa\xf3\xd8\xf1\xde\x56\x40\xc2\x32\xf5\xb1\x69\xb9\xc9\x11\xe6", 16); ++ if (errtxt) ++ goto failed; ++ if (extended) ++ { ++ what = "Extended AES #1"; ++ errtxt = check_one (GCRY_MAC_CMAC_AES, ++ "", 0, ++ "\x2b\x7e\x15\x16\x28\xae\xd2\xa6\xab\xf7\x15\x88\x09\xcf\x4f\x3c", 16, ++ "\xbb\x1d\x69\x29\xe9\x59\x37\x28\x7f\xa3\x7d\x12\x9b\x75\x67\x46", 16); ++ if (errtxt) ++ goto failed; ++ ++ what = "Extended AES #2"; ++ errtxt = check_one (GCRY_MAC_CMAC_AES, ++ "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a", 16, ++ "\x8e\x73\xb0\xf7\xda\x0e\x64\x52\xc8\x10\xf3\x2b\x80\x90\x79\xe5" ++ "\x62\xf8\xea\xd2\x52\x2c\x6b\x7b", 24, ++ "\x9e\x99\xa7\xbf\x31\xe7\x10\x90\x06\x62\xf6\x5e\x61\x7c\x51\x84", 16); ++ if (errtxt) ++ goto failed; ++ ++ what = "Extended AES #3"; ++ errtxt = check_one (GCRY_MAC_CMAC_AES, ++ "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a" ++ "\xae\x2d\x8a\x57\x1e\x03\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e\x51" ++ "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11\xe5\xfb\xc1\x19\x1a\x0a\x52\xef" ++ "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17\xad\x2b\x41\x7b\xe6\x6c\x37\x10", 64, ++ "\x60\x3d\xeb\x10\x15\xca\x71\xbe\x2b\x73\xae\xf0\x85\x7d\x77\x81" ++ "\x1f\x35\x2c\x07\x3b\x61\x08\xd7\x2d\x98\x10\xa3\x09\x14\xdf\xf4", 32, ++ "\xe1\x99\x21\x90\x54\x9f\x6e\xd5\x69\x6a\x2c\x05\x6c\x31\x54\x10", 16 ); ++ if (errtxt) ++ goto failed; ++ } ++ ++ return 0; /* Succeeded. */ ++ ++ failed: ++ if (report) ++ report ("cmac", GCRY_MAC_CMAC_AES, what, errtxt); ++ return GPG_ERR_SELFTEST_FAILED; ++} ++ ++ ++/* Run a full self-test for ALGO and return 0 on success. */ ++static gpg_err_code_t ++run_cmac_selftests (int algo, int extended, selftest_report_func_t report) ++{ ++ gpg_err_code_t ec; ++ ++ switch (algo) ++ { ++ case GCRY_MAC_CMAC_3DES: ++ ec = selftests_cmac_tdes (extended, report); ++ break; ++ case GCRY_MAC_CMAC_AES: ++ ec = selftests_cmac_aes (extended, report); ++ break; ++ ++ default: ++ ec = GPG_ERR_MAC_ALGO; ++ break; ++ } ++ return ec; ++} ++ ++ ++ ++ ++/* Run the selftests for CMAC with CMAC algorithm ALGO with optional ++ reporting function REPORT. */ ++gpg_error_t ++_gcry_cmac_selftest (int algo, int extended, selftest_report_func_t report) ++{ ++ gcry_err_code_t ec = 0; ++ ++ if (!_gcry_mac_algo_info( algo, GCRYCTL_TEST_ALGO, NULL, NULL )) ++ { ++ ec = run_cmac_selftests (algo, extended, report); ++ } ++ else ++ { ++ ec = GPG_ERR_MAC_ALGO; ++ if (report) ++ report ("mac", algo, "module", "algorithm not available"); ++ } ++ return gpg_error (ec); ++} +diff -up libgcrypt-1.8.3/src/cipher-proto.h.cmac-selftest libgcrypt-1.8.3/src/cipher-proto.h +--- libgcrypt-1.8.3/src/cipher-proto.h.cmac-selftest 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.3/src/cipher-proto.h 2019-05-31 17:29:34.574588234 +0200 +@@ -256,6 +256,8 @@ gcry_error_t _gcry_pk_selftest (int algo + selftest_report_func_t report); + gcry_error_t _gcry_hmac_selftest (int algo, int extended, + selftest_report_func_t report); ++gcry_error_t _gcry_cmac_selftest (int algo, int extended, ++ selftest_report_func_t report); + + gcry_error_t _gcry_random_selftest (selftest_report_func_t report); + +diff -up libgcrypt-1.8.3/src/fips.c.cmac-selftest libgcrypt-1.8.3/src/fips.c +--- libgcrypt-1.8.3/src/fips.c.cmac-selftest 2018-11-01 15:40:36.051865535 +0100 ++++ libgcrypt-1.8.3/src/fips.c 2019-05-31 17:31:20.157756640 +0200 +@@ -521,29 +521,32 @@ run_digest_selftests (int extended) + + /* Run self-tests for all HMAC algorithms. Return 0 on success. */ + static int +-run_hmac_selftests (int extended) ++run_mac_selftests (int extended) + { +- static int algos[] = ++ static int algos[][2] = + { +- GCRY_MD_SHA1, +- GCRY_MD_SHA224, +- GCRY_MD_SHA256, +- GCRY_MD_SHA384, +- GCRY_MD_SHA512, +- GCRY_MD_SHA3_224, +- GCRY_MD_SHA3_256, +- GCRY_MD_SHA3_384, +- GCRY_MD_SHA3_512, +- 0 ++ { GCRY_MD_SHA1, 0 }, ++ { GCRY_MD_SHA224, 0 }, ++ { GCRY_MD_SHA256, 0 }, ++ { GCRY_MD_SHA384, 0 }, ++ { GCRY_MD_SHA512, 0 }, ++ { GCRY_MD_SHA3_224, 0 }, ++ { GCRY_MD_SHA3_256, 0 }, ++ { GCRY_MD_SHA3_384, 0 }, ++ { GCRY_MD_SHA3_512, 0 }, ++ { GCRY_MAC_CMAC_3DES, 1 }, ++ { GCRY_MAC_CMAC_AES, 1 }, ++ { 0, 0 } + }; + int idx; + gpg_error_t err; + int anyerr = 0; + +- for (idx=0; algos[idx]; idx++) ++ for (idx=0; algos[idx][0]; idx++) + { +- err = _gcry_hmac_selftest (algos[idx], extended, reporter); +- reporter ("hmac", algos[idx], NULL, ++ err = algos[idx][1] ? _gcry_cmac_selftest (algos[idx][0], extended, reporter) : ++ _gcry_hmac_selftest (algos[idx][0], extended, reporter); ++ reporter (algos[idx][1] ? "cmac" : "hmac", algos[idx][0], NULL, + err? gpg_strerror (err):NULL); + if (err) + anyerr = 1; +@@ -747,7 +750,7 @@ _gcry_fips_run_selftests (int extended) + if (run_digest_selftests (extended)) + goto leave; + +- if (run_hmac_selftests (extended)) ++ if (run_mac_selftests (extended)) + goto leave; + + /* Run random tests before the pubkey tests because the latter diff --git a/libgcrypt-1.8.3-fips-enttest.patch b/libgcrypt-1.8.3-fips-enttest.patch new file mode 100644 index 0000000..b6b09ba --- /dev/null +++ b/libgcrypt-1.8.3-fips-enttest.patch @@ -0,0 +1,113 @@ +diff -up libgcrypt-1.8.3/random/random-drbg.c.fips-enttest libgcrypt-1.8.3/random/random-drbg.c +--- libgcrypt-1.8.3/random/random-drbg.c.fips-enttest 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.3/random/random-drbg.c 2019-06-24 10:04:23.219547141 +0200 +@@ -317,6 +317,7 @@ struct drbg_state_s + unsigned char *ctr_null; /* CTR mode zero buffer */ + int seeded:1; /* DRBG fully seeded? */ + int pr:1; /* Prediction resistance enabled? */ ++ int ent_primed:1; /* Previous entropy data primed? */ + /* Taken from libgcrypt ANSI X9.31 DRNG: We need to keep track of the + * process which did the initialization so that we can detect a fork. + * The volatile modifier is required so that the compiler does not +@@ -324,6 +325,7 @@ struct drbg_state_s + pid_t seed_init_pid; + const struct drbg_state_ops_s *d_ops; + const struct drbg_core_s *core; ++ unsigned char ent_hash[64]; /* Hash of previous entropy data */ + struct drbg_test_data_s *test_data; + }; + +@@ -610,11 +612,13 @@ drbg_get_entropy (drbg_state_t drbg, uns + size_t len) + { + int rc = 0; ++ unsigned char newhash[64]; + + /* Perform testing as defined in 11.3.2 */ + if (drbg->test_data && drbg->test_data->fail_seed_source) + return -1; + ++redo: + read_cb_buffer = buffer; + read_cb_size = len; + read_cb_len = 0; +@@ -634,6 +638,27 @@ drbg_get_entropy (drbg_state_t drbg, uns + #else + rc = -1; + #endif ++ ++ /* to avoid storing the actual entropy obtained for indefinite ++ time, we just store the SHA-512 hash of the entropy gathered ++ */ ++ _gcry_md_hash_buffer (GCRY_MD_SHA512, newhash, buffer, len); ++ ++ if (!drbg->ent_primed) ++ { ++ memcpy (drbg->ent_hash, newhash, sizeof (drbg->ent_hash)); ++ drbg->ent_primed = 1; ++ goto redo; ++ } ++ ++ if (memcmp (newhash, drbg->ent_hash, sizeof (drbg->ent_hash)) == 0) ++ { ++ fips_signal_error ("Entropy source failed the continuous test"); ++ return -1; /* continuous entropy test failed */ ++ } ++ ++ memcpy (drbg->ent_hash, newhash, sizeof (drbg->ent_hash)); ++ + return rc; + } + +@@ -1341,26 +1366,38 @@ drbg_seed (drbg_state_t drbg, drbg_strin + } + else + { ++ int nonce = 0; + /* Gather entropy equal to the security strength of the DRBG. + * With a derivation function, a nonce is required in addition + * to the entropy. A nonce must be at least 1/2 of the security + * strength of the DRBG in size. Thus, entropy * nonce is 3/2 + * of the strength. The consideration of a nonce is only +- * applicable during initial seeding. */ ++ * applicable during initial seeding. ++ * To avoid pulling different length of data from entropy ++ * source, we use 2 * strength for initial seeding. */ + entropylen = drbg_sec_strength (drbg->core->flags); + if (!entropylen) + return GPG_ERR_GENERAL; + if (0 == reseed) +- /* make sure we round up strength/2 in +- * case it is not divisible by 2 */ +- entropylen = ((entropylen + 1) / 2) * 3; ++ { ++ nonce = 1; ++ } + dbg (("DRBG: (re)seeding with %lu bytes of entropy\n", entropylen)); +- entropy = xcalloc_secure (1, entropylen); ++ entropy = xcalloc_secure (nonce + 1, entropylen); + if (!entropy) + return GPG_ERR_ENOMEM; + ret = drbg_get_entropy (drbg, entropy, entropylen); + if (ret) + goto out; ++ if (nonce) ++ { ++ ret = drbg_get_entropy (drbg, entropy + entropylen, entropylen); ++ if (ret) ++ goto out; ++ /* make sure we round up strength/2 in ++ * case it is not divisible by 2 */ ++ entropylen = 2 * entropylen; ++ } + drbg_string_fill (&data1, entropy, entropylen); + } + +@@ -1597,6 +1634,7 @@ drbg_instantiate (drbg_state_t drbg, + drbg->core = &drbg_cores[coreref]; + drbg->pr = pr; + drbg->seeded = 0; ++ drbg->ent_primed = 0; + if (drbg->core->flags & DRBG_HMAC) + drbg->d_ops = &drbg_hmac_ops; + else if (drbg->core->flags & DRBG_HASH_MASK) diff --git a/libgcrypt-1.8.3-md-fips-enforce.patch b/libgcrypt-1.8.3-md-fips-enforce.patch new file mode 100644 index 0000000..d040bfb --- /dev/null +++ b/libgcrypt-1.8.3-md-fips-enforce.patch @@ -0,0 +1,12 @@ +diff -up libgcrypt-1.8.3/cipher/md.c.fips-enforce libgcrypt-1.8.3/cipher/md.c +--- libgcrypt-1.8.3/cipher/md.c.fips-enforce 2018-11-01 15:40:36.051865535 +0100 ++++ libgcrypt-1.8.3/cipher/md.c 2019-06-03 11:50:21.435401753 +0200 +@@ -409,7 +409,7 @@ md_enable (gcry_md_hd_t hd, int algorith + } + + +- if (!err && algorithm == GCRY_MD_MD5 && fips_mode ()) ++ if (!err && !spec->flags.fips && fips_mode ()) + { + if (_gcry_enforced_fips_mode () ) + { diff --git a/libgcrypt-1.8.0-tests.patch b/libgcrypt-1.8.4-fips-keygen.patch similarity index 42% rename from libgcrypt-1.8.0-tests.patch rename to libgcrypt-1.8.4-fips-keygen.patch index f3dfe96..9d3a647 100644 --- a/libgcrypt-1.8.0-tests.patch +++ b/libgcrypt-1.8.4-fips-keygen.patch @@ -1,6 +1,6 @@ -diff -up libgcrypt-1.8.0/cipher/dsa.c.tests libgcrypt-1.8.0/cipher/dsa.c ---- libgcrypt-1.8.0/cipher/dsa.c.tests 2016-04-07 17:30:08.000000000 +0200 -+++ libgcrypt-1.8.0/cipher/dsa.c 2017-08-15 15:10:39.551600227 +0200 +diff -up libgcrypt-1.8.4/cipher/dsa.c.fips-keygen libgcrypt-1.8.4/cipher/dsa.c +--- libgcrypt-1.8.4/cipher/dsa.c.fips-keygen 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.4/cipher/dsa.c 2019-02-12 14:29:25.629513989 +0100 @@ -457,11 +457,22 @@ generate_fips186 (DSA_secret_key *sk, un &prime_q, &prime_p, r_counter, @@ -42,9 +42,18 @@ diff -up libgcrypt-1.8.0/cipher/dsa.c.tests libgcrypt-1.8.0/cipher/dsa.c return GPG_ERR_MISSING_VALUE; } -diff -up libgcrypt-1.8.0/cipher/rsa.c.tests libgcrypt-1.8.0/cipher/rsa.c ---- libgcrypt-1.8.0/cipher/rsa.c.tests 2017-07-06 10:21:36.000000000 +0200 -+++ libgcrypt-1.8.0/cipher/rsa.c 2017-08-15 15:10:39.551600227 +0200 +diff -up libgcrypt-1.8.4/cipher/rsa.c.fips-keygen libgcrypt-1.8.4/cipher/rsa.c +--- libgcrypt-1.8.4/cipher/rsa.c.fips-keygen 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.4/cipher/rsa.c 2019-02-12 14:29:25.630513971 +0100 +@@ -389,7 +389,7 @@ generate_fips (RSA_secret_key *sk, unsig + + if (nbits < 1024 || (nbits & 0x1FF)) + return GPG_ERR_INV_VALUE; +- if (_gcry_enforced_fips_mode() && nbits != 2048 && nbits != 3072) ++ if (fips_mode() && nbits < 2048) + return GPG_ERR_INV_VALUE; + + /* The random quality depends on the transient_key flag. */ @@ -696,7 +696,7 @@ generate_x931 (RSA_secret_key *sk, unsig *swapped = 0; @@ -54,62 +63,3 @@ diff -up libgcrypt-1.8.0/cipher/rsa.c.tests libgcrypt-1.8.0/cipher/rsa.c e_value = 65537; /* Point 1 of section 4.1: k = 1024 + 256s with S >= 0 */ -diff -up libgcrypt-1.8.0/tests/keygen.c.tests libgcrypt-1.8.0/tests/keygen.c ---- libgcrypt-1.8.0/tests/keygen.c.tests 2017-08-15 15:10:39.551600227 +0200 -+++ libgcrypt-1.8.0/tests/keygen.c 2017-08-15 15:16:05.433176171 +0200 -@@ -200,11 +200,11 @@ check_rsa_keys (void) - - - if (verbose) -- info ("creating 512 bit RSA key with e=257\n"); -+ info ("creating 1024 bit RSA key with e=257\n"); - rc = gcry_sexp_new (&keyparm, - "(genkey\n" - " (rsa\n" -- " (nbits 3:512)\n" -+ " (nbits 4:1024)\n" - " (rsa-use-e 3:257)\n" - " ))", 0, 1); - if (rc) -@@ -225,11 +225,11 @@ check_rsa_keys (void) - gcry_sexp_release (key); - - if (verbose) -- info ("creating 512 bit RSA key with default e\n"); -+ info ("creating 1024 bit RSA key with default e\n"); - rc = gcry_sexp_new (&keyparm, - "(genkey\n" - " (rsa\n" -- " (nbits 3:512)\n" -+ " (nbits 4:1024)\n" - " (rsa-use-e 1:0)\n" - " ))", 0, 1); - if (rc) -@@ -309,12 +309,12 @@ check_dsa_keys (void) - } - - if (verbose) -- info ("creating 1536 bit DSA key\n"); -+ info ("creating 2048 bit DSA key\n"); - rc = gcry_sexp_new (&keyparm, - "(genkey\n" - " (dsa\n" -- " (nbits 4:1536)\n" -- " (qbits 3:224)\n" -+ " (nbits 4:2048)\n" -+ " (qbits 3:256)\n" - " ))", 0, 1); - if (rc) - die ("error creating S-expression: %s\n", gpg_strerror (rc)); -diff -up libgcrypt-1.8.0/tests/pubkey.c.tests libgcrypt-1.8.0/tests/pubkey.c ---- libgcrypt-1.8.0/tests/pubkey.c.tests 2017-01-18 15:24:25.000000000 +0100 -+++ libgcrypt-1.8.0/tests/pubkey.c 2017-08-15 15:10:39.552600207 +0200 -@@ -595,7 +595,7 @@ get_dsa_key_fips186_with_seed_new (gcry_ - " (use-fips186)" - " (transient-key)" - " (derive-parms" -- " (seed #0cb1990c1fd3626055d7a0096f8fa99807399871#))))", -+ " (seed #8b4c4d671fff82e8ed932260206d0571e3a1c2cee8cd94cb73fe58f9b67488fa#))))", - 0, 1); - if (rc) - die ("error creating S-expression: %s\n", gcry_strerror (rc)); diff --git a/libgcrypt-1.8.3-getrandom.patch b/libgcrypt-1.8.4-getrandom.patch similarity index 47% rename from libgcrypt-1.8.3-getrandom.patch rename to libgcrypt-1.8.4-getrandom.patch index 7428dfb..a2fb7b9 100644 --- a/libgcrypt-1.8.3-getrandom.patch +++ b/libgcrypt-1.8.4-getrandom.patch @@ -1,6 +1,6 @@ -diff -up libgcrypt-1.8.3/random/random.c.getrandom libgcrypt-1.8.3/random/random.c ---- libgcrypt-1.8.3/random/random.c.getrandom 2017-11-23 19:16:58.000000000 +0100 -+++ libgcrypt-1.8.3/random/random.c 2018-07-10 15:38:34.303855808 +0200 +diff -up libgcrypt-1.8.4/random/random.c.getrandom libgcrypt-1.8.4/random/random.c +--- libgcrypt-1.8.4/random/random.c.getrandom 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.4/random/random.c 2018-11-20 15:52:41.738708554 +0100 @@ -110,8 +110,8 @@ _gcry_random_read_conf (void) unsigned int result = 0; @@ -12,9 +12,9 @@ diff -up libgcrypt-1.8.3/random/random.c.getrandom libgcrypt-1.8.3/random/random for (;;) { -diff -up libgcrypt-1.8.3/random/random-csprng.c.getrandom libgcrypt-1.8.3/random/random-csprng.c ---- libgcrypt-1.8.3/random/random-csprng.c.getrandom 2017-11-23 19:16:58.000000000 +0100 -+++ libgcrypt-1.8.3/random/random-csprng.c 2018-06-14 16:31:04.731179208 +0200 +diff -up libgcrypt-1.8.4/random/random-csprng.c.getrandom libgcrypt-1.8.4/random/random-csprng.c +--- libgcrypt-1.8.4/random/random-csprng.c.getrandom 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.4/random/random-csprng.c 2018-11-20 15:52:41.738708554 +0100 @@ -55,6 +55,10 @@ #ifdef __MINGW32__ #include @@ -49,9 +49,9 @@ diff -up libgcrypt-1.8.3/random/random-csprng.c.getrandom libgcrypt-1.8.3/random if ( !access (NAME_OF_DEV_RANDOM, R_OK) && !access (NAME_OF_DEV_URANDOM, R_OK)) { -diff -up libgcrypt-1.8.3/random/rndlinux.c.getrandom libgcrypt-1.8.3/random/rndlinux.c ---- libgcrypt-1.8.3/random/rndlinux.c.getrandom 2018-06-14 16:31:04.722178971 +0200 -+++ libgcrypt-1.8.3/random/rndlinux.c 2018-07-10 15:55:03.301075155 +0200 +diff -up libgcrypt-1.8.4/random/rndlinux.c.getrandom libgcrypt-1.8.4/random/rndlinux.c +--- libgcrypt-1.8.4/random/rndlinux.c.getrandom 2018-11-20 15:52:41.731708393 +0100 ++++ libgcrypt-1.8.4/random/rndlinux.c 2018-11-20 16:06:45.431207374 +0100 @@ -35,6 +35,7 @@ #include #if defined(__linux__) && defined(HAVE_SYSCALL) @@ -60,40 +60,73 @@ diff -up libgcrypt-1.8.3/random/rndlinux.c.getrandom libgcrypt-1.8.3/random/rndl #endif #include "types.h" -@@ -204,6 +205,18 @@ _gcry_rndlinux_gather_random (void (*add +@@ -147,12 +148,12 @@ _gcry_rndlinux_gather_random (void (*add + if (!add) { - if (fd_urandom == -1) + /* Special mode to close the descriptors. */ +- if (fd_random != -1) ++ if (fd_random >= 0) { + close (fd_random); + fd_random = -1; + } +- if (fd_urandom != -1) ++ if (fd_urandom >= 0) + { + close (fd_urandom); + fd_urandom = -1; +@@ -166,12 +167,12 @@ _gcry_rndlinux_gather_random (void (*add + apid = getpid (); + if (my_pid != apid) + { +- if (fd_random != -1) ++ if (fd_random >= 0) + { + close (fd_random); + fd_random = -1; + } +- if (fd_urandom != -1) ++ if (fd_urandom >= 0) + { + close (fd_urandom); + fd_urandom = -1; +@@ -216,6 +217,22 @@ _gcry_rndlinux_gather_random (void (*add + that we always require the device to be existent but want a more + graceful behaviour if the rarely needed close operation has been + used and the device needs to be re-opened later. */ +#if defined(__linux__) && defined(HAVE_SYSCALL) && defined(__NR_getrandom) -+ long ret; ++ if (fd_urandom != -2) ++ { ++ long ret; + -+ _gcry_pre_syscall (); -+ ret = syscall (__NR_getrandom, -+ (void*)buffer, (size_t)1, (unsigned int)GRND_NONBLOCK); -+ _gcry_post_syscall (); -+ if (ret > -1 || errno == EAGAIN || errno == EINTR) -+ fd_urandom = -2; -+ else -+ /* The syscall is not supported - fallback to /dev/urandom. */ ++ _gcry_pre_syscall (); ++ ret = syscall (__NR_getrandom, ++ (void*)buffer, (size_t)1, (unsigned int)GRND_NONBLOCK); ++ _gcry_post_syscall (); ++ if (ret > -1 || errno == EAGAIN || errno == EINTR) ++ { ++ fd_urandom = -2; ++ fd_random = -2; ++ } ++ } +#endif - fd_urandom = open_device (NAME_OF_DEV_URANDOM, (ever_opened & 2)); - ever_opened |= 2; - } -@@ -230,7 +243,7 @@ _gcry_rndlinux_gather_random (void (*add + if (level >= GCRY_VERY_STRONG_RANDOM && !only_urandom) + { + if (fd_random == -1) +@@ -255,6 +272,7 @@ _gcry_rndlinux_gather_random (void (*add * syscall and not a new device and thus we are not able to use * select(2) to have a timeout. */ #if defined(__linux__) && defined(HAVE_SYSCALL) && defined(__NR_getrandom) -- if (fd == fd_urandom) + if (fd == -2) { long ret; size_t nbytes; -@@ -246,9 +259,7 @@ _gcry_rndlinux_gather_random (void (*add +@@ -270,9 +288,7 @@ _gcry_rndlinux_gather_random (void (*add _gcry_post_syscall (); } while (ret == -1 && errno == EINTR); - if (ret == -1 && errno == ENOSYS) -- ; /* The syscall is not supported - fallback to /dev/urandom. */ +- ; /* The syscall is not supported - fallback to pulling from fd. */ - else + if (1) { /* The syscall is supported. Some sanity checks. */ diff --git a/libgcrypt-1.8.4-tests-fipsmode.patch b/libgcrypt-1.8.4-tests-fipsmode.patch new file mode 100644 index 0000000..1442a0b --- /dev/null +++ b/libgcrypt-1.8.4-tests-fipsmode.patch @@ -0,0 +1,184 @@ +diff -up libgcrypt-1.8.4/tests/basic.c.tests-fipsmode libgcrypt-1.8.4/tests/basic.c +--- libgcrypt-1.8.4/tests/basic.c.tests-fipsmode 2018-04-17 17:29:40.000000000 +0200 ++++ libgcrypt-1.8.4/tests/basic.c 2019-02-12 13:30:48.935791024 +0100 +@@ -6964,7 +6964,7 @@ check_ciphers (void) + check_one_cipher (algos[i], GCRY_CIPHER_MODE_CTR, 0); + if (gcry_cipher_get_algo_blklen (algos[i]) == GCRY_CCM_BLOCK_LEN) + check_one_cipher (algos[i], GCRY_CIPHER_MODE_CCM, 0); +- if (gcry_cipher_get_algo_blklen (algos[i]) == GCRY_GCM_BLOCK_LEN) ++ if (!in_fips_mode && gcry_cipher_get_algo_blklen (algos[i]) == GCRY_GCM_BLOCK_LEN) + check_one_cipher (algos[i], GCRY_CIPHER_MODE_GCM, 0); + if (gcry_cipher_get_algo_blklen (algos[i]) == GCRY_OCB_BLOCK_LEN) + check_one_cipher (algos[i], GCRY_CIPHER_MODE_OCB, 0); +@@ -7010,11 +7010,17 @@ check_cipher_modes(void) + check_cfb_cipher (); + check_ofb_cipher (); + check_ccm_cipher (); +- check_gcm_cipher (); +- check_poly1305_cipher (); +- check_ocb_cipher (); ++ if (!in_fips_mode) ++ { ++ check_gcm_cipher (); ++ check_poly1305_cipher (); ++ check_ocb_cipher (); ++ } + check_xts_cipher (); +- check_gost28147_cipher (); ++ if (!in_fips_mode) ++ { ++ check_gost28147_cipher (); ++ } + check_stream_cipher (); + check_stream_cipher_large_block (); + +@@ -10001,7 +10007,7 @@ check_mac (void) + show_mac_not_available (algos[i].algo); + continue; + } +- if (gcry_mac_test_algo (algos[i].algo) && in_fips_mode) ++ if ((algos[i].algo == GCRY_MAC_GMAC_AES || gcry_mac_test_algo (algos[i].algo)) && in_fips_mode) + { + if (verbose) + fprintf (stderr, " algorithm %d not available in fips mode\n", +@@ -11095,8 +11101,6 @@ main (int argc, char **argv) + /* If we are in fips mode do some more tests. */ + gcry_md_hd_t md; + +- /* First trigger a self-test. */ +- xgcry_control (GCRYCTL_FORCE_FIPS_MODE, 0); + if (!gcry_control (GCRYCTL_OPERATIONAL_P, 0)) + fail ("not in operational state after self-test\n"); + +@@ -11121,15 +11125,6 @@ main (int argc, char **argv) + gcry_md_close (md); + if (gcry_control (GCRYCTL_OPERATIONAL_P, 0)) + fail ("expected error state but still in operational state\n"); +- else +- { +- /* Now run a self-test and to get back into +- operational state. */ +- xgcry_control (GCRYCTL_FORCE_FIPS_MODE, 0); +- if (!gcry_control (GCRYCTL_OPERATIONAL_P, 0)) +- fail ("did not reach operational after error " +- "and self-test\n"); +- } + } + } + +diff -up libgcrypt-1.8.4/tests/benchmark.c.tests-fipsmode libgcrypt-1.8.4/tests/benchmark.c +--- libgcrypt-1.8.4/tests/benchmark.c.tests-fipsmode 2019-02-12 11:31:44.859603883 +0100 ++++ libgcrypt-1.8.4/tests/benchmark.c 2019-02-12 14:10:40.271999352 +0100 +@@ -872,8 +872,10 @@ cipher_bench ( const char *algoname ) + || (blklen == 1 && modes[modeidx].mode != GCRY_CIPHER_MODE_STREAM)) + continue; + +- if (modes[modeidx].req_blocksize > 0 +- && blklen != modes[modeidx].req_blocksize) ++ if ((modes[modeidx].req_blocksize > 0 ++ && blklen != modes[modeidx].req_blocksize) ++ || (in_fips_mode ++ && modes[modeidx].mode == GCRY_CIPHER_MODE_GCM)) + { + printf (" %7s %7s", "-", "-" ); + continue; +diff -up libgcrypt-1.8.4/tests/bench-slope.c.tests-fipsmode libgcrypt-1.8.4/tests/bench-slope.c +--- libgcrypt-1.8.4/tests/bench-slope.c.tests-fipsmode 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.4/tests/bench-slope.c 2019-02-12 14:14:33.618763325 +0100 +@@ -1338,7 +1338,7 @@ cipher_bench_one (int algo, struct bench + return; + + /* GCM has restrictions for block-size */ +- if (mode.mode == GCRY_CIPHER_MODE_GCM && blklen != GCRY_GCM_BLOCK_LEN) ++ if (mode.mode == GCRY_CIPHER_MODE_GCM && (gcry_fips_mode_active () || blklen != GCRY_GCM_BLOCK_LEN)) + return; + + /* XTS has restrictions for block-size */ +diff -up libgcrypt-1.8.4/tests/pubkey.c.tests-fipsmode libgcrypt-1.8.4/tests/pubkey.c +--- libgcrypt-1.8.4/tests/pubkey.c.tests-fipsmode 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.4/tests/pubkey.c 2019-02-12 13:52:25.658746415 +0100 +@@ -504,15 +504,30 @@ get_dsa_key_with_domain_new (gcry_sexp_t + rc = gcry_sexp_new + (&key_spec, + "(genkey (dsa (transient-key)(domain" +- "(p #d3aed1876054db831d0c1348fbb1ada72507e5fbf9a62cbd47a63aeb7859d6921" +- "4adeb9146a6ec3f43520f0fd8e3125dd8bbc5d87405d1ac5f82073cd762a3f8d7" +- "74322657c9da88a7d2f0e1a9ceb84a39cb40876179e6a76e400498de4bb9379b0" +- "5f5feb7b91eb8fea97ee17a955a0a8a37587a272c4719d6feb6b54ba4ab69#)" +- "(q #9c916d121de9a03f71fb21bc2e1c0d116f065a4f#)" +- "(g #8157c5f68ca40b3ded11c353327ab9b8af3e186dd2e8dade98761a0996dda99ab" +- "0250d3409063ad99efae48b10c6ab2bba3ea9a67b12b911a372a2bba260176fad" +- "b4b93247d9712aad13aa70216c55da9858f7a298deb670a403eb1e7c91b847f1e" +- "ccfbd14bd806fd42cf45dbb69cd6d6b43add2a78f7d16928eaa04458dea44#)" ++ " (p #a85378d8fd3f8d72ec7418080da21317e43ec4b62ba8c862" ++ " 3b7e4d04441dd1a0658662596493ca8e9e8fbb7e34aaddb6" ++ " 2e5d67b6d09a6e61b769e7c352aa2b10e20ca0636963b552" ++ " 3e86470decbbeda027e797e7b67635d4d49c30700e74af8a" ++ " 0ff156a801af57a26e7078f1d82f74908ecb6d07e70b3503" ++ " eed94fa32cf17a7fc3d6cf40dc7b00830e6a2566dc073e34" ++ " 3312517c6aa5152b4bfecd2e551fee346318a153423c996b" ++ " 0d5dcb9102aedd38798616f1f1e0d6c403525b1f9b3d4dc7" ++ " 66de2dfc4a56d7b8ba5963d60f3e16318870ad436952e557" ++ " 65374eab85e8ec17d6b9a4547b9b5f2752f3105be809b23a" ++ " 2c8d7469db02e24d592394a7dba069e9#)" ++ " (q #d277044e50f5a4e3f510a50a0b84fdffbca047ed27602056" ++ " 7441a0a5#)" ++ " (g #13d754e21fd241655da891c522a65a72a89bdc64ec9b54a8" ++ " 21ed4a898b490e0c4fcb72192a4a20f541f3f2925399f0ba" ++ " ecf929aafbf79dfe4332393b32cd2e2fcf272f32a627434a" ++ " 0df242b75b414df372121e53a553f222f836b000f016485b" ++ " 6bd0898451801dcd8de64cd5365696ffc532d528c506620a" ++ " 942a0305046d8f1876341f1e570bc3974ba6b9a438e97023" ++ " 02a2e6e67bfd06d32bc679962271d7b40cd72f386e64e0d7" ++ " ef86ca8ca5d14228dc2a4f16e3189886b5990674f4200f3a" ++ " 4cf65a3f0ddba1fa672dff2f5e143d10e4e97ae84f6da095" ++ " 35d5b9df259181a79b63b069e949972b02ba36b3586aab7e" ++ " 45f322f82e4e85ca3ab85591b3c2a966#)" + ")))", 0, 1); + if (rc) + die ("error creating S-expression: %s\n", gcry_strerror (rc)); +@@ -595,7 +610,7 @@ get_dsa_key_fips186_with_seed_new (gcry_ + " (use-fips186)" + " (transient-key)" + " (derive-parms" +- " (seed #0cb1990c1fd3626055d7a0096f8fa99807399871#))))", ++ " (seed #8b4c4d671fff82e8ed932260206d0571e3a1c2cee8cd94cb73fe58f9b67488fa#))))", + 0, 1); + if (rc) + die ("error creating S-expression: %s\n", gcry_strerror (rc)); +diff -up libgcrypt-1.8.4/tests/t-cv25519.c.tests-fipsmode libgcrypt-1.8.4/tests/t-cv25519.c +--- libgcrypt-1.8.4/tests/t-cv25519.c.tests-fipsmode 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.4/tests/t-cv25519.c 2019-02-12 14:02:35.935705390 +0100 +@@ -560,6 +560,9 @@ main (int argc, char **argv) + xgcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u , 0); + xgcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0); + xgcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0); ++ /* Curve25519 isn't supported in fips mode */ ++ if (gcry_fips_mode_active()) ++ return 77; + + start_timer (); + check_cv25519 (); +diff -up libgcrypt-1.8.4/tests/t-secmem.c.tests-fipsmode libgcrypt-1.8.4/tests/t-secmem.c +--- libgcrypt-1.8.4/tests/t-secmem.c.tests-fipsmode 2017-11-23 19:19:54.000000000 +0100 ++++ libgcrypt-1.8.4/tests/t-secmem.c 2019-02-12 11:51:02.462190538 +0100 +@@ -174,7 +174,8 @@ main (int argc, char **argv) + xgcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u , 0); + xgcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0); + xgcry_control (GCRYCTL_INIT_SECMEM, pool_size, 0); +- gcry_set_outofcore_handler (outofcore_handler, NULL); ++ if (!gcry_fips_mode_active ()) ++ gcry_set_outofcore_handler (outofcore_handler, NULL); + xgcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0); + + /* Libgcrypt prints a warning when the first overflow is allocated; +@@ -184,7 +185,8 @@ main (int argc, char **argv) + + + test_secmem (); +- test_secmem_overflow (); ++ if (!gcry_fips_mode_active ()) ++ test_secmem_overflow (); + /* FIXME: We need to improve the tests, for example by registering + * our own log handler and comparing the output of + * PRIV_CTL_DUMP_SECMEM_STATS to expected pattern. */ diff --git a/libgcrypt-1.8.0-use-poll.patch b/libgcrypt-1.8.4-use-poll.patch similarity index 80% rename from libgcrypt-1.8.0-use-poll.patch rename to libgcrypt-1.8.4-use-poll.patch index 07df8dd..b96c6ce 100644 --- a/libgcrypt-1.8.0-use-poll.patch +++ b/libgcrypt-1.8.4-use-poll.patch @@ -1,6 +1,6 @@ -diff -up libgcrypt-1.8.0/random/rndlinux.c.use-poll libgcrypt-1.8.0/random/rndlinux.c ---- libgcrypt-1.8.0/random/rndlinux.c.use-poll 2017-06-24 13:34:29.000000000 +0200 -+++ libgcrypt-1.8.0/random/rndlinux.c 2017-08-15 15:37:37.604629377 +0200 +diff -up libgcrypt-1.8.4/random/rndlinux.c.use-poll libgcrypt-1.8.4/random/rndlinux.c +--- libgcrypt-1.8.4/random/rndlinux.c.use-poll 2018-10-26 13:50:20.000000000 +0200 ++++ libgcrypt-1.8.4/random/rndlinux.c 2018-11-20 15:51:56.760669058 +0100 @@ -32,6 +32,7 @@ #include #include @@ -9,7 +9,7 @@ diff -up libgcrypt-1.8.0/random/rndlinux.c.use-poll libgcrypt-1.8.0/random/rndli #if defined(__linux__) && defined(HAVE_SYSCALL) # include #endif -@@ -216,9 +217,8 @@ _gcry_rndlinux_gather_random (void (*add +@@ -241,9 +242,8 @@ _gcry_rndlinux_gather_random (void (*add return with something we will actually use 100ms. */ while (length) { @@ -18,9 +18,9 @@ diff -up libgcrypt-1.8.0/random/rndlinux.c.use-poll libgcrypt-1.8.0/random/rndli int rc; + struct pollfd pfd; - /* If we have a modern Linux kernel and we want to read from the - * the non-blocking /dev/urandom, we first try to use the new -@@ -276,36 +276,25 @@ _gcry_rndlinux_gather_random (void (*add + /* If we have a modern Linux kernel, we first try to use the new + * getrandom syscall. That call guarantees that the kernel's +@@ -300,36 +300,25 @@ _gcry_rndlinux_gather_random (void (*add any_need_entropy = 1; } diff --git a/libgcrypt-1.8.5-build.patch b/libgcrypt-1.8.5-build.patch new file mode 100644 index 0000000..3e71238 --- /dev/null +++ b/libgcrypt-1.8.5-build.patch @@ -0,0 +1,14 @@ +diff -up libgcrypt-1.8.5/cipher/poly1305-armv7-neon.S.build libgcrypt-1.8.5/cipher/poly1305-armv7-neon.S +--- libgcrypt-1.8.5/cipher/poly1305-armv7-neon.S.build 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.5/cipher/poly1305-armv7-neon.S 2020-01-30 17:26:12.026404286 +0100 +@@ -87,9 +87,8 @@ _gcry_poly1305_armv7_neon_init_ext: + .Lpoly1305_init_ext_neon_local: + stmfd sp!, {r4-r11, lr} + sub sp, sp, #32 +- mov r14, r2 ++ mov r14, #-1 + and r2, r2, r2 +- moveq r14, #-1 + UNALIGNED_LDMIA4(r1, r2, r3, r4, r5) + GET_DATA_POINTER(r7,.Lpoly1305_init_constants_neon,r8) + mov r6, r2 diff --git a/libgcrypt-1.8.5-intel-cet.patch b/libgcrypt-1.8.5-intel-cet.patch new file mode 100644 index 0000000..f58084e --- /dev/null +++ b/libgcrypt-1.8.5-intel-cet.patch @@ -0,0 +1,348 @@ +diff -up libgcrypt-1.8.5/cipher/camellia-aesni-avx2-amd64.S.intel-cet libgcrypt-1.8.5/cipher/camellia-aesni-avx2-amd64.S +--- libgcrypt-1.8.5/cipher/camellia-aesni-avx2-amd64.S.intel-cet 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.5/cipher/camellia-aesni-avx2-amd64.S 2020-01-23 15:36:44.148972045 +0100 +@@ -18,8 +18,9 @@ + * License along with this program; if not, see . + */ + +-#ifdef __x86_64 + #include ++ ++#ifdef __x86_64 + #if (defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) || \ + defined(HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS)) && \ + defined(ENABLE_AESNI_SUPPORT) && defined(ENABLE_AVX2_SUPPORT) +diff -up libgcrypt-1.8.5/cipher/camellia-aesni-avx-amd64.S.intel-cet libgcrypt-1.8.5/cipher/camellia-aesni-avx-amd64.S +--- libgcrypt-1.8.5/cipher/camellia-aesni-avx-amd64.S.intel-cet 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.5/cipher/camellia-aesni-avx-amd64.S 2020-01-23 15:36:44.145972088 +0100 +@@ -18,8 +18,9 @@ + * License along with this program; if not, see . + */ + +-#ifdef __x86_64 + #include ++ ++#ifdef __x86_64 + #if (defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) || \ + defined(HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS)) && \ + defined(ENABLE_AESNI_SUPPORT) && defined(ENABLE_AVX_SUPPORT) +diff -up libgcrypt-1.8.5/cipher/chacha20-avx2-amd64.S.intel-cet libgcrypt-1.8.5/cipher/chacha20-avx2-amd64.S +--- libgcrypt-1.8.5/cipher/chacha20-avx2-amd64.S.intel-cet 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.5/cipher/chacha20-avx2-amd64.S 2020-01-23 15:36:16.780250066 +0100 +@@ -48,6 +48,9 @@ + .globl _gcry_chacha20_amd64_avx2_blocks + ELF(.type _gcry_chacha20_amd64_avx2_blocks,@function;) + _gcry_chacha20_amd64_avx2_blocks: ++#ifdef _CET_ENDBR ++ _CET_ENDBR ++#endif + .Lchacha_blocks_avx2_local: + vzeroupper + pushq %rbx +diff -up libgcrypt-1.8.5/cipher/chacha20-sse2-amd64.S.intel-cet libgcrypt-1.8.5/cipher/chacha20-sse2-amd64.S +--- libgcrypt-1.8.5/cipher/chacha20-sse2-amd64.S.intel-cet 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.5/cipher/chacha20-sse2-amd64.S 2020-01-23 15:36:16.783250095 +0100 +@@ -41,6 +41,9 @@ + .globl _gcry_chacha20_amd64_sse2_blocks + ELF(.type _gcry_chacha20_amd64_sse2_blocks,@function;) + _gcry_chacha20_amd64_sse2_blocks: ++#ifdef _CET_ENDBR ++ _CET_ENDBR ++#endif + .Lchacha_blocks_sse2_local: + pushq %rbx + pushq %rbp +diff -up libgcrypt-1.8.5/cipher/poly1305-avx2-amd64.S.intel-cet libgcrypt-1.8.5/cipher/poly1305-avx2-amd64.S +--- libgcrypt-1.8.5/cipher/poly1305-avx2-amd64.S.intel-cet 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.5/cipher/poly1305-avx2-amd64.S 2020-01-23 15:36:16.784250105 +0100 +@@ -43,6 +43,9 @@ + .globl _gcry_poly1305_amd64_avx2_init_ext + ELF(.type _gcry_poly1305_amd64_avx2_init_ext,@function;) + _gcry_poly1305_amd64_avx2_init_ext: ++#ifdef _CET_ENDBR ++ _CET_ENDBR ++#endif + .Lpoly1305_init_ext_avx2_local: + xor %edx, %edx + vzeroupper +@@ -406,6 +409,9 @@ ELF(.size _gcry_poly1305_amd64_avx2_init + .globl _gcry_poly1305_amd64_avx2_blocks + ELF(.type _gcry_poly1305_amd64_avx2_blocks,@function;) + _gcry_poly1305_amd64_avx2_blocks: ++#ifdef _CET_ENDBR ++ _CET_ENDBR ++#endif + .Lpoly1305_blocks_avx2_local: + vzeroupper + pushq %rbp +@@ -732,6 +738,9 @@ ELF(.size _gcry_poly1305_amd64_avx2_bloc + .globl _gcry_poly1305_amd64_avx2_finish_ext + ELF(.type _gcry_poly1305_amd64_avx2_finish_ext,@function;) + _gcry_poly1305_amd64_avx2_finish_ext: ++#ifdef _CET_ENDBR ++ _CET_ENDBR ++#endif + .Lpoly1305_finish_ext_avx2_local: + vzeroupper + pushq %rbp +diff -up libgcrypt-1.8.5/cipher/poly1305-sse2-amd64.S.intel-cet libgcrypt-1.8.5/cipher/poly1305-sse2-amd64.S +--- libgcrypt-1.8.5/cipher/poly1305-sse2-amd64.S.intel-cet 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.5/cipher/poly1305-sse2-amd64.S 2020-01-23 15:36:16.787250134 +0100 +@@ -42,6 +42,9 @@ + .globl _gcry_poly1305_amd64_sse2_init_ext + ELF(.type _gcry_poly1305_amd64_sse2_init_ext,@function;) + _gcry_poly1305_amd64_sse2_init_ext: ++#ifdef _CET_ENDBR ++ _CET_ENDBR ++#endif + .Lpoly1305_init_ext_x86_local: + xor %edx, %edx + pushq %r12 +@@ -288,6 +291,9 @@ ELF(.size _gcry_poly1305_amd64_sse2_init + .globl _gcry_poly1305_amd64_sse2_finish_ext + ELF(.type _gcry_poly1305_amd64_sse2_finish_ext,@function;) + _gcry_poly1305_amd64_sse2_finish_ext: ++#ifdef _CET_ENDBR ++ _CET_ENDBR ++#endif + .Lpoly1305_finish_ext_x86_local: + pushq %rbp + movq %rsp, %rbp +@@ -439,6 +445,9 @@ ELF(.size _gcry_poly1305_amd64_sse2_fini + .globl _gcry_poly1305_amd64_sse2_blocks + ELF(.type _gcry_poly1305_amd64_sse2_blocks,@function;) + _gcry_poly1305_amd64_sse2_blocks: ++#ifdef _CET_ENDBR ++ _CET_ENDBR ++#endif + .Lpoly1305_blocks_x86_local: + pushq %rbp + movq %rsp, %rbp +diff -up libgcrypt-1.8.5/cipher/serpent-avx2-amd64.S.intel-cet libgcrypt-1.8.5/cipher/serpent-avx2-amd64.S +--- libgcrypt-1.8.5/cipher/serpent-avx2-amd64.S.intel-cet 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.5/cipher/serpent-avx2-amd64.S 2020-01-23 15:36:44.151972003 +0100 +@@ -18,8 +18,9 @@ + * License along with this program; if not, see . + */ + +-#ifdef __x86_64 + #include ++ ++#ifdef __x86_64 + #if (defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) || \ + defined(HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS)) && defined(USE_SERPENT) && \ + defined(ENABLE_AVX2_SUPPORT) +diff -up libgcrypt-1.8.5/configure.ac.intel-cet libgcrypt-1.8.5/configure.ac +--- libgcrypt-1.8.5/configure.ac.intel-cet 2019-08-29 15:00:08.000000000 +0200 ++++ libgcrypt-1.8.5/configure.ac 2020-01-23 15:35:28.147774463 +0100 +@@ -95,6 +95,12 @@ AH_TOP([ + AH_BOTTOM([ + #define _GCRYPT_IN_LIBGCRYPT 1 + ++/* Add .note.gnu.property section for Intel CET in assembler sources ++ when CET is enabled. */ ++#if defined(__ASSEMBLER__) && defined(__CET__) ++# include ++#endif ++ + /* If the configure check for endianness has been disabled, get it from + OS macros. This is intended for making fat binary builds on OS X. */ + #ifdef DISABLED_ENDIAN_CHECK +diff -up libgcrypt-1.8.5/mpi/config.links.intel-cet libgcrypt-1.8.5/mpi/config.links +--- libgcrypt-1.8.5/mpi/config.links.intel-cet 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.5/mpi/config.links 2020-01-23 15:35:46.398952954 +0100 +@@ -382,6 +382,16 @@ if test x"$mpi_cpu_arch" = x ; then + mpi_cpu_arch="unknown" + fi + ++# Add .note.gnu.property section for Intel CET in assembler sources ++# when CET is enabled. */ ++if test x"$mpi_cpu_arch" = xx86 ; then ++ cat <> ./mpi/asm-syntax.h ++ ++#if defined(__ASSEMBLER__) && defined(__CET__) ++# include ++#endif ++EOF ++fi + + # Make sysdep.h + echo '/* created by config.links - do not edit */' >./mpi/sysdep.h +diff -up libgcrypt-1.8.5/mpi/i386/mpih-add1.S.intel-cet libgcrypt-1.8.5/mpi/i386/mpih-add1.S +--- libgcrypt-1.8.5/mpi/i386/mpih-add1.S.intel-cet 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.5/mpi/i386/mpih-add1.S 2020-01-23 15:37:40.470175379 +0100 +@@ -52,6 +52,10 @@ C_SYMBOL_NAME(_gcry_mpih_add_n:) + movl 20(%esp),%edx /* s2_ptr */ + movl 24(%esp),%ecx /* size */ + ++#if defined __CET__ && (__CET__ & 1) != 0 ++ pushl %ebx ++#endif ++ + movl %ecx,%eax + shrl $3,%ecx /* compute count for unrolled loop */ + negl %eax +@@ -63,6 +67,9 @@ C_SYMBOL_NAME(_gcry_mpih_add_n:) + subl %eax,%esi /* ... by a constant when we ... */ + subl %eax,%edx /* ... enter the loop */ + shrl $2,%eax /* restore previous value */ ++#if defined __CET__ && (__CET__ & 1) != 0 ++ leal -4(,%eax,4),%ebx /* Count for 4-byte endbr32 */ ++#endif + #ifdef PIC + /* Calculate start address in loop for PIC. Due to limitations in some + assemblers, Loop-L0-3 cannot be put into the leal */ +@@ -75,29 +82,53 @@ L0: leal (%eax,%eax,8),%eax + /* Calculate start address in loop for non-PIC. */ + leal (Loop - 3)(%eax,%eax,8),%eax + #endif ++#if defined __CET__ && (__CET__ & 1) != 0 ++ addl %ebx,%eax /* Adjust for endbr32 */ ++#endif + jmp *%eax /* jump into loop */ + ALIGN (3) + Loop: movl (%esi),%eax + adcl (%edx),%eax + movl %eax,(%edi) ++#ifdef _CET_ENDBR ++ _CET_ENDBR ++#endif + movl 4(%esi),%eax + adcl 4(%edx),%eax + movl %eax,4(%edi) ++#ifdef _CET_ENDBR ++ _CET_ENDBR ++#endif + movl 8(%esi),%eax + adcl 8(%edx),%eax + movl %eax,8(%edi) ++#ifdef _CET_ENDBR ++ _CET_ENDBR ++#endif + movl 12(%esi),%eax + adcl 12(%edx),%eax + movl %eax,12(%edi) ++#ifdef _CET_ENDBR ++ _CET_ENDBR ++#endif + movl 16(%esi),%eax + adcl 16(%edx),%eax + movl %eax,16(%edi) ++#ifdef _CET_ENDBR ++ _CET_ENDBR ++#endif + movl 20(%esi),%eax + adcl 20(%edx),%eax + movl %eax,20(%edi) ++#ifdef _CET_ENDBR ++ _CET_ENDBR ++#endif + movl 24(%esi),%eax + adcl 24(%edx),%eax + movl %eax,24(%edi) ++#ifdef _CET_ENDBR ++ _CET_ENDBR ++#endif + movl 28(%esi),%eax + adcl 28(%edx),%eax + movl %eax,28(%edi) +@@ -110,6 +141,10 @@ Loop: movl (%esi),%eax + sbbl %eax,%eax + negl %eax + ++#if defined __CET__ && (__CET__ & 1) != 0 ++ popl %ebx ++#endif ++ + popl %esi + popl %edi + ret +diff -up libgcrypt-1.8.5/mpi/i386/mpih-sub1.S.intel-cet libgcrypt-1.8.5/mpi/i386/mpih-sub1.S +--- libgcrypt-1.8.5/mpi/i386/mpih-sub1.S.intel-cet 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.5/mpi/i386/mpih-sub1.S 2020-01-23 15:37:40.472175351 +0100 +@@ -53,6 +53,10 @@ C_SYMBOL_NAME(_gcry_mpih_sub_n:) + movl 20(%esp),%edx /* s2_ptr */ + movl 24(%esp),%ecx /* size */ + ++#if defined __CET__ && (__CET__ & 1) != 0 ++ pushl %ebx ++#endif ++ + movl %ecx,%eax + shrl $3,%ecx /* compute count for unrolled loop */ + negl %eax +@@ -64,6 +68,9 @@ C_SYMBOL_NAME(_gcry_mpih_sub_n:) + subl %eax,%esi /* ... by a constant when we ... */ + subl %eax,%edx /* ... enter the loop */ + shrl $2,%eax /* restore previous value */ ++#if defined __CET__ && (__CET__ & 1) != 0 ++ leal -4(,%eax,4),%ebx /* Count for 4-byte endbr32 */ ++#endif + #ifdef PIC + /* Calculate start address in loop for PIC. Due to limitations in some + assemblers, Loop-L0-3 cannot be put into the leal */ +@@ -76,29 +83,53 @@ L0: leal (%eax,%eax,8),%eax + /* Calculate start address in loop for non-PIC. */ + leal (Loop - 3)(%eax,%eax,8),%eax + #endif ++#if defined __CET__ && (__CET__ & 1) != 0 ++ addl %ebx,%eax /* Adjust for endbr32 */ ++#endif + jmp *%eax /* jump into loop */ + ALIGN (3) + Loop: movl (%esi),%eax + sbbl (%edx),%eax + movl %eax,(%edi) ++#ifdef _CET_ENDBR ++ _CET_ENDBR ++#endif + movl 4(%esi),%eax + sbbl 4(%edx),%eax + movl %eax,4(%edi) ++#ifdef _CET_ENDBR ++ _CET_ENDBR ++#endif + movl 8(%esi),%eax + sbbl 8(%edx),%eax + movl %eax,8(%edi) ++#ifdef _CET_ENDBR ++ _CET_ENDBR ++#endif + movl 12(%esi),%eax + sbbl 12(%edx),%eax + movl %eax,12(%edi) ++#ifdef _CET_ENDBR ++ _CET_ENDBR ++#endif + movl 16(%esi),%eax + sbbl 16(%edx),%eax + movl %eax,16(%edi) ++#ifdef _CET_ENDBR ++ _CET_ENDBR ++#endif + movl 20(%esi),%eax + sbbl 20(%edx),%eax + movl %eax,20(%edi) ++#ifdef _CET_ENDBR ++ _CET_ENDBR ++#endif + movl 24(%esi),%eax + sbbl 24(%edx),%eax + movl %eax,24(%edi) ++#ifdef _CET_ENDBR ++ _CET_ENDBR ++#endif + movl 28(%esi),%eax + sbbl 28(%edx),%eax + movl %eax,28(%edi) +@@ -111,6 +142,10 @@ Loop: movl (%esi),%eax + sbbl %eax,%eax + negl %eax + ++#if defined __CET__ && (__CET__ & 1) != 0 ++ popl %ebx ++#endif ++ + popl %esi + popl %edi + ret diff --git a/libgcrypt-1.8.3.tar.gz b/libgcrypt-1.8.5.tar.gz similarity index 33% rename from libgcrypt-1.8.3.tar.gz rename to libgcrypt-1.8.5.tar.gz index 7596989b3c59ce7eaa3e17155057b9fc52df9374..1308d707420823bf6c365883b96917b00a50a30c 100644 GIT binary patch delta 3565544 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