From 112336b5f6c8cadfb0f3e82dea8daa7b44811f7d Mon Sep 17 00:00:00 2001 From: Daiki Ueno Date: Tue, 13 Aug 2024 20:32:18 +0900 Subject: [PATCH] Statically link to Nettle libraries Like GMP, this changes the package build process so the libnettle and libhogweed are built and linked statically to libgnutls. That makes it a little simpler to handle FIPS installation, so the users don't need to install a specific version of the nettle package by themselves, at the cost of duplicating cryptography implementation provided by Nettle. Related: RHEL-50011 Signed-off-by: Daiki Ueno --- .gitignore | 1 + gnutls-3.8.6-nettle-static.patch | 13 ++ gnutls.spec | 60 +++++- nettle-3.8-zeroize-stack.patch | 334 +++++++++++++++++++++++++++++++ sources | 1 + 5 files changed, 407 insertions(+), 2 deletions(-) create mode 100644 gnutls-3.8.6-nettle-static.patch create mode 100644 nettle-3.8-zeroize-stack.patch diff --git a/.gitignore b/.gitignore index 86f1a4b..579177f 100644 --- a/.gitignore +++ b/.gitignore @@ -161,3 +161,4 @@ gnutls-2.10.1-nosrp.tar.bz2 /gnutls-3.8.7.tar.xz.sig /gnutls-3.8.7.1.tar.xz /gnutls-3.8.7.1.tar.xz.sig +/nettle-3.10-hobbled.tar.xz diff --git a/gnutls-3.8.6-nettle-static.patch b/gnutls-3.8.6-nettle-static.patch new file mode 100644 index 0000000..837c602 --- /dev/null +++ b/gnutls-3.8.6-nettle-static.patch @@ -0,0 +1,13 @@ +diff --git a/lib/Makefile.am b/lib/Makefile.am +index 0e89fdf..5179858 100644 +--- a/lib/Makefile.am ++++ b/lib/Makefile.am +@@ -269,7 +269,7 @@ thirdparty_libadd += $(LIBTASN1_LIBS) + endif + + if ENABLE_NETTLE +-thirdparty_libadd += $(NETTLE_LIBS) $(HOGWEED_LIBS) $(GMP_LIBS) ++thirdparty_libadd += $(HOGWEED_LIBS) $(NETTLE_LIBS) $(GMP_LIBS) + libgnutls_la_LIBADD += nettle/libcrypto.la + endif + diff --git a/gnutls.spec b/gnutls.spec index 6ee479e..c2db8a0 100644 --- a/gnutls.spec +++ b/gnutls.spec @@ -61,6 +61,12 @@ Patch: gnutls-3.8.7-pkgconf-dlopen.patch %bcond_with bundled_gmp %endif +%if 0%{?rhel} >= 10 && %{with fips} +%bcond_without bundled_nettle +%else +%bcond_with bundled_nettle +%endif + %define fips_requires() %{lua: local f = assert(io.popen("rpm -q --queryformat '%{EVR}' --whatprovides "..rpm.expand("'%1%{?_isa}'"))) @@ -84,7 +90,9 @@ BuildRequires: liboqs-devel %if %{with bootstrap} BuildRequires: automake, autoconf, gperf, libtool, texinfo %endif +%if !%{with bundled_nettle} BuildRequires: nettle-devel >= 3.9.1 +%endif %if %{with tpm12} BuildRequires: trousers-devel >= 0.3.11.2 %endif @@ -102,8 +110,10 @@ BuildRequires: p11-kit-trust, ca-certificates Requires: crypto-policies Requires: p11-kit-trust Requires: libtasn1 >= 4.3 +%if !%{with bundled_nettle} # always bump when a nettle release is packaged Requires: nettle >= 3.9.1 +%endif %if %{with tpm12} Recommends: trousers >= 0.3.11.2 %endif @@ -144,6 +154,12 @@ Source100: gmp-6.2.1.tar.xz Source101: gmp-6.2.1-intel-cet.patch %endif +%if %{with bundled_nettle} +Source200: nettle-3.10-hobbled.tar.xz +# Taken from the main nettle package +Source201: nettle-3.8-zeroize-stack.patch +%endif + # Wildcard bundling exception https://fedorahosted.org/fpc/ticket/174 Provides: bundled(gnulib) = 20130424 @@ -178,7 +194,9 @@ Requires: %{name}%{?_isa} = %{version}-%{release} %package fips Summary: Virtual package to install packages required to use %{name} under FIPS mode Requires: %{name}%{?_isa} = %{version}-%{release} +%if !%{with bundled_nettle} %{fips_requires nettle} +%endif %if !%{with bundled_gmp} %{fips_requires gmp} %endif @@ -275,6 +293,14 @@ patch -p1 < %{SOURCE101} popd %endif +%if %{with bundled_nettle} +mkdir -p bundled_nettle +pushd bundled_nettle +tar --strip-components=1 -xf %{SOURCE200} +patch -p1 < %{SOURCE201} +popd +%endif + %build %define _lto_cflags %{nil} @@ -285,8 +311,38 @@ autoreconf -ifv %make_build popd -export GMP_CFLAGS="-I$PWD/bundled_gmp" -export GMP_LIBS="$PWD/bundled_gmp/.libs/libgmp.a" +export GMP_DIR="$PWD/bundled_gmp" +export GMP_CFLAGS="-I$GMP_DIR" +export GMP_LIBS="$GMP_DIR/.libs/libgmp.a" +%endif + +%if %{with bundled_nettle} +pushd bundled_nettle +./.bootstrap + +# Disable -ggdb3 which makes debugedit unhappy +sed s/ggdb3/g/ -i configure +sed 's/ecc-secp192r1.c//g' -i Makefile.in +sed 's/ecc-secp224r1.c//g' -i Makefile.in + +autoreconf -ifv +# For annocheck +export ASM_FLAGS="-Wa,--generate-missing-build-notes=yes" +%configure --disable-shared --enable-fat --disable-documentation \ + --with-include-path="$GMP_DIR" \ + --with-lib-path="$GMP_DIR/.libs" \ + %{nil} +%make_build +ln -s . nettle +popd + +export NETTLE_DIR="$PWD/bundled_nettle" + +export NETTLE_CFLAGS="-I$NETTLE_DIR" +export NETTLE_LIBS="$NETTLE_DIR/libnettle.a" + +export HOGWEED_CFLAGS="-I$NETTLE_DIR" +export HOGWEED_LIBS="$NETTLE_DIR/libhogweed.a" %endif %if %{with bootstrap} diff --git a/nettle-3.8-zeroize-stack.patch b/nettle-3.8-zeroize-stack.patch new file mode 100644 index 0000000..f93a248 --- /dev/null +++ b/nettle-3.8-zeroize-stack.patch @@ -0,0 +1,334 @@ +From 24a4cb910a51f35dff89842e8cce27f88e8e78c3 Mon Sep 17 00:00:00 2001 +From: Daiki Ueno +Date: Wed, 24 Aug 2022 17:19:57 +0900 +Subject: [PATCH] Clear any intermediate data allocate on stack + +Signed-off-by: Daiki Ueno +--- + cbc.c | 3 +++ + cfb.c | 13 +++++++++++++ + ctr.c | 4 ++++ + ctr16.c | 2 ++ + ecc-random.c | 3 +++ + ecdsa-keygen.c | 2 ++ + ecdsa-sign.c | 2 ++ + ed25519-sha512-sign.c | 2 ++ + ed448-shake256-sign.c | 2 ++ + gostdsa-sign.c | 2 ++ + hmac.c | 10 +++++++--- + nettle-internal.h | 5 +++++ + pbkdf2.c | 5 ++++- + pss-mgf1.c | 5 ++++- + pss.c | 4 ++++ + 15 files changed, 59 insertions(+), 5 deletions(-) + +diff --git a/cbc.c b/cbc.c +index 76b6492d..b9da3aa0 100644 +--- a/cbc.c ++++ b/cbc.c +@@ -128,6 +128,9 @@ cbc_decrypt(const void *ctx, nettle_cipher_func *f, + length - block_size); + /* Writes first block. */ + memxor3(dst, buffer, initial_iv, block_size); ++ ++ TMP_CLEAR(buffer, buffer_size); ++ TMP_CLEAR(initial_iv, block_size); + } + } + +diff --git a/cfb.c b/cfb.c +index b9da3159..b1b01b9e 100644 +--- a/cfb.c ++++ b/cfb.c +@@ -83,6 +83,8 @@ cfb_encrypt(const void *ctx, nettle_cipher_func *f, + /* We do not care about updating IV here. This is the last call in + * message sequence and one has to set IV afterwards anyway */ + } ++ ++ TMP_CLEAR(buffer, block_size); + } + + /* Don't allocate any more space than this on the stack */ +@@ -115,6 +117,8 @@ cfb_decrypt(const void *ctx, nettle_cipher_func *f, + + f(ctx, block_size, buffer, iv); + memxor3(dst + length, src + length, buffer, left); ++ ++ TMP_CLEAR(buffer, block_size); + } + } + else +@@ -160,6 +164,9 @@ cfb_decrypt(const void *ctx, nettle_cipher_func *f, + f(ctx, block_size, buffer, iv); + memxor(dst, buffer, left); + } ++ ++ TMP_CLEAR(buffer, buffer_size); ++ TMP_CLEAR(initial_iv, block_size); + } + } + +@@ -196,6 +203,9 @@ cfb8_encrypt(const void *ctx, nettle_cipher_func *f, + pos ++; + } + memcpy(iv, buffer + pos, block_size); ++ ++ TMP_CLEAR(buffer, block_size * 2); ++ TMP_CLEAR(outbuf, block_size); + } + + void +@@ -235,4 +245,7 @@ cfb8_decrypt(const void *ctx, nettle_cipher_func *f, + } + + memcpy(iv, buffer + i, block_size); ++ ++ TMP_CLEAR(buffer, block_size * 2); ++ TMP_CLEAR(outbuf, block_size * 2); + } +diff --git a/ctr.c b/ctr.c +index 8c6b4626..217d1abb 100644 +--- a/ctr.c ++++ b/ctr.c +@@ -137,6 +137,8 @@ ctr_crypt(const void *ctx, nettle_cipher_func *f, + f(ctx, block_size, block, ctr); + INCREMENT(block_size, ctr); + memxor3(dst + filled, src + filled, block, length - filled); ++ ++ TMP_CLEAR(block, block_size); + } + } + else +@@ -173,5 +175,7 @@ ctr_crypt(const void *ctx, nettle_cipher_func *f, + INCREMENT(block_size, ctr); + memxor(dst, buffer, length); + } ++ ++ TMP_CLEAR(buffer, buffer_size); + } + } +diff --git a/ctr16.c b/ctr16.c +index d744d2a9..ec0abd72 100644 +--- a/ctr16.c ++++ b/ctr16.c +@@ -102,5 +102,7 @@ _nettle_ctr_crypt16(const void *ctx, nettle_cipher_func *f, + done: + memxor3 (dst + i, src + i, buffer->b, length - i); + } ++ ++ TMP_CLEAR(buffer, MIN(blocks, CTR_BUFFER_LIMIT / 16)); + } + } +diff --git a/ecc-random.c b/ecc-random.c +index a7b48d6a..676f5933 100644 +--- a/ecc-random.c ++++ b/ecc-random.c +@@ -36,6 +36,7 @@ + #endif + + #include ++#include + + #include "ecc.h" + #include "ecc-internal.h" +@@ -79,4 +80,6 @@ ecc_scalar_random (struct ecc_scalar *x, + TMP_ALLOC (scratch, ECC_MOD_RANDOM_ITCH (x->ecc->q.size)); + + ecc_mod_random (&x->ecc->q, x->p, random_ctx, random, scratch); ++ ++ TMP_CLEAR (scratch, ECC_MOD_RANDOM_ITCH (x->ecc->q.size)); + } +diff --git a/ecdsa-keygen.c b/ecdsa-keygen.c +index 870282b0..05dd827a 100644 +--- a/ecdsa-keygen.c ++++ b/ecdsa-keygen.c +@@ -59,4 +59,6 @@ ecdsa_generate_keypair (struct ecc_point *pub, + ecc_mod_random (&ecc->q, key->p, random_ctx, random, p); + ecc->mul_g (ecc, p, key->p, p + 3*ecc->p.size); + ecc->h_to_a (ecc, 0, pub->p, p, p + 3*ecc->p.size); ++ ++ TMP_CLEAR (p, itch); + } +diff --git a/ecdsa-sign.c b/ecdsa-sign.c +index e6fb3287..e6b960bf 100644 +--- a/ecdsa-sign.c ++++ b/ecdsa-sign.c +@@ -68,4 +68,6 @@ ecdsa_sign (const struct ecc_scalar *key, + mpz_limbs_finish (signature->s, size); + } + while (mpz_sgn (signature->r) == 0 || mpz_sgn (signature->s) == 0); ++ ++ TMP_CLEAR (k, size + ECC_ECDSA_SIGN_ITCH (size)); + } +diff --git a/ed25519-sha512-sign.c b/ed25519-sha512-sign.c +index 389a157e..52a46ea5 100644 +--- a/ed25519-sha512-sign.c ++++ b/ed25519-sha512-sign.c +@@ -38,6 +38,7 @@ + + #include "ecc-internal.h" + #include "sha2.h" ++#include + + void + ed25519_sha512_sign (const uint8_t *pub, +@@ -61,6 +62,7 @@ ed25519_sha512_sign (const uint8_t *pub, + length, msg, signature, scratch_out); + + gmp_free_limbs (scratch, itch); ++ explicit_bzero (digest, sizeof(digest)); + #undef k1 + #undef k2 + #undef scratch_out +diff --git a/ed448-shake256-sign.c b/ed448-shake256-sign.c +index c524593d..01abf457 100644 +--- a/ed448-shake256-sign.c ++++ b/ed448-shake256-sign.c +@@ -39,6 +39,7 @@ + #include "ecc-internal.h" + #include "eddsa-internal.h" + #include "sha3.h" ++#include + + void + ed448_shake256_sign (const uint8_t *pub, +@@ -63,6 +64,7 @@ ed448_shake256_sign (const uint8_t *pub, + length, msg, signature, scratch_out); + + gmp_free_limbs (scratch, itch); ++ explicit_bzero (digest, sizeof(digest)); + #undef k1 + #undef k2 + #undef scratch_out +diff --git a/gostdsa-sign.c b/gostdsa-sign.c +index 892c0742..a7e0c21d 100644 +--- a/gostdsa-sign.c ++++ b/gostdsa-sign.c +@@ -71,4 +71,6 @@ gostdsa_sign (const struct ecc_scalar *key, + mpz_limbs_finish (signature->s, size); + } + while (mpz_sgn (signature->r) == 0 || mpz_sgn (signature->s) == 0); ++ ++ TMP_CLEAR (k, size + ECC_GOSTDSA_SIGN_ITCH (size)); + } +diff --git a/hmac.c b/hmac.c +index ea356970..6a55551b 100644 +--- a/hmac.c ++++ b/hmac.c +@@ -53,6 +53,8 @@ hmac_set_key(void *outer, void *inner, void *state, + { + TMP_DECL(pad, uint8_t, NETTLE_MAX_HASH_BLOCK_SIZE); + TMP_ALLOC(pad, hash->block_size); ++ TMP_DECL(digest, uint8_t, NETTLE_MAX_HASH_DIGEST_SIZE); ++ TMP_ALLOC(digest, hash->digest_size); + + hash->init(outer); + hash->init(inner); +@@ -62,9 +64,6 @@ hmac_set_key(void *outer, void *inner, void *state, + /* Reduce key to the algorithm's hash size. Use the area pointed + * to by state for the temporary state. */ + +- TMP_DECL(digest, uint8_t, NETTLE_MAX_HASH_DIGEST_SIZE); +- TMP_ALLOC(digest, hash->digest_size); +- + hash->init(state); + hash->update(state, key_length, key); + hash->digest(state, hash->digest_size, digest); +@@ -86,6 +85,9 @@ hmac_set_key(void *outer, void *inner, void *state, + hash->update(inner, hash->block_size, pad); + + memcpy(state, inner, hash->context_size); ++ ++ TMP_CLEAR(pad, hash->block_size); ++ TMP_CLEAR(digest, hash->digest_size); + } + + void +@@ -112,4 +114,6 @@ hmac_digest(const void *outer, const void *inner, void *state, + hash->digest(state, length, dst); + + memcpy(state, inner, hash->context_size); ++ ++ TMP_CLEAR(digest, hash->digest_size); + } +diff --git a/nettle-internal.h b/nettle-internal.h +index c41f3ee0..62b89e11 100644 +--- a/nettle-internal.h ++++ b/nettle-internal.h +@@ -76,6 +76,11 @@ + do { assert((size_t)(size) <= (sizeof(name))); } while (0) + #endif + ++#include /* explicit_bzero */ ++ ++#define TMP_CLEAR(name, size) (explicit_bzero (name, sizeof (*name) * (size))) ++#define TMP_CLEAR_ALIGN(name, size) (explicit_bzero (name, size)) ++ + /* Limits that apply to systems that don't have alloca */ + #define NETTLE_MAX_HASH_BLOCK_SIZE 144 /* For sha3_224*/ + #define NETTLE_MAX_HASH_DIGEST_SIZE 64 +diff --git a/pbkdf2.c b/pbkdf2.c +index 291d138a..a8ecba5b 100644 +--- a/pbkdf2.c ++++ b/pbkdf2.c +@@ -92,8 +92,11 @@ pbkdf2 (void *mac_ctx, + if (length <= digest_size) + { + memcpy (dst, T, length); +- return; ++ break; + } + memcpy (dst, T, digest_size); + } ++ ++ TMP_CLEAR (U, digest_size); ++ TMP_CLEAR (T, digest_size); + } +diff --git a/pss-mgf1.c b/pss-mgf1.c +index 3f5e204b..3644c642 100644 +--- a/pss-mgf1.c ++++ b/pss-mgf1.c +@@ -66,8 +66,11 @@ pss_mgf1(const void *seed, const struct nettle_hash *hash, + if (length <= hash->digest_size) + { + hash->digest(state, length, mask); +- return; ++ break; + } + hash->digest(state, hash->digest_size, mask); + } ++ ++ TMP_CLEAR(h, hash->digest_size); ++ TMP_CLEAR_ALIGN(state, hash->context_size); + } +diff --git a/pss.c b/pss.c +index d28e7b13..8106ebf2 100644 +--- a/pss.c ++++ b/pss.c +@@ -77,6 +77,7 @@ pss_encode_mgf1(mpz_t m, size_t bits, + if (key_size < hash->digest_size + salt_length + 2) + { + TMP_GMP_FREE(em); ++ TMP_CLEAR_ALIGN(state, hash->context_size); + return 0; + } + +@@ -111,6 +112,7 @@ pss_encode_mgf1(mpz_t m, size_t bits, + + nettle_mpz_set_str_256_u(m, key_size, em); + TMP_GMP_FREE(em); ++ TMP_CLEAR_ALIGN(state, hash->context_size); + return 1; + } + +@@ -194,5 +196,7 @@ pss_verify_mgf1(const mpz_t m, size_t bits, + ret = 1; + cleanup: + TMP_GMP_FREE(em); ++ TMP_CLEAR(h2, hash->digest_size); ++ TMP_CLEAR_ALIGN(state, hash->context_size); + return ret; + } +-- +2.41.0 + diff --git a/sources b/sources index 5fcce01..96fb383 100644 --- a/sources +++ b/sources @@ -2,3 +2,4 @@ SHA512 (gnutls-3.8.7.1.tar.xz) = 429cea78e227d838105791b28a18270c3d2418bfb951c32 SHA512 (gnutls-3.8.7.1.tar.xz.sig) = 53ebdaa9775ae22f7eb5e7d6f5411ec667c9c880cea84e23651b6d1994fb1398c09d8efa39b21c96f8be29fa09c2436bdd732a061308956ca1650e3e1878ed57 SHA512 (gnutls-release-keyring.gpg) = 8c2b39239d1d8c5319757fcf669f28a11de7f8ec4a726f9904c57ba8105bea80240083c0de71b747115907bab46569f10cf58004137cc7884ac5c20f8319ae0a SHA512 (gmp-6.2.1.tar.xz) = c99be0950a1d05a0297d65641dd35b75b74466f7bf03c9e8a99895a3b2f9a0856cd17887738fa51cf7499781b65c049769271cbcb77d057d2e9f1ec52e07dd84 +SHA512 (nettle-3.10-hobbled.tar.xz) = 5f2bba913e8ac9c3bef91e59cb7784f609ee6a4549157503583441770fb57782530391906c271316936297ccd691174578a9a584b4a374dfc6214c206b020cb2