diff --git a/.gitignore b/.gitignore index d82cdcb..56e73b9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ SOURCES/gmp-6.2.1.tar.xz SOURCES/gnutls-3.7.6.tar.xz +SOURCES/gnutls-3.7.6.tar.xz.sig SOURCES/gnutls-release-keyring.gpg diff --git a/.gnutls.metadata b/.gnutls.metadata index 0e7b56f..d037fa1 100644 --- a/.gnutls.metadata +++ b/.gnutls.metadata @@ -1,3 +1,4 @@ 0578d48607ec0e272177d175fd1807c30b00fdf2 SOURCES/gmp-6.2.1.tar.xz 47591374259451fe2cd86c5fe7c345e769a6c79b SOURCES/gnutls-3.7.6.tar.xz +0ebda3673eafa2ab34068a7ea798d6e385440d56 SOURCES/gnutls-3.7.6.tar.xz.sig befcf25b9dcd1d36b8bdb754c80c639eca45baa0 SOURCES/gnutls-release-keyring.gpg diff --git a/SOURCES/gnutls-3.7.6-fips-ems.patch b/SOURCES/gnutls-3.7.6-fips-ems.patch new file mode 100644 index 0000000..f844f12 --- /dev/null +++ b/SOURCES/gnutls-3.7.6-fips-ems.patch @@ -0,0 +1,805 @@ +From 4751e1e2d4012404af9bc52535aa73ac88bc7bea Mon Sep 17 00:00:00 2001 +From: rpm-build +Date: Thu, 13 Jul 2023 16:14:08 +0200 +Subject: [PATCH] gnutls-3.7.6-fips-ems.patch + +--- + doc/cha-gtls-app.texi | 5 + + lib/gnutls_int.h | 6 + + lib/handshake.c | 35 ++++- + lib/nettle/int/tls1-prf.c | 19 +++ + lib/priority.c | 41 +++++ + lib/priority_options.gperf | 1 + + tests/Makefile.am | 4 +- + tests/multi-alerts.c | 8 + + tests/no-extensions.c | 7 + + .../ocsp-tests/ocsp-must-staple-connection.sh | 60 +++---- + tests/rehandshake-ext-secret.c | 8 + + tests/resume.c | 26 ++- + tests/status-request.c | 8 +- + tests/system-override-session-hash.sh | 144 +++++++++++++++++ + tests/tls-force-ems.c | 148 ++++++++++++++++++ + 15 files changed, 477 insertions(+), 43 deletions(-) + create mode 100755 tests/system-override-session-hash.sh + create mode 100644 tests/tls-force-ems.c + +diff --git a/doc/cha-gtls-app.texi b/doc/cha-gtls-app.texi +index bd44478..57e7d50 100644 +--- a/doc/cha-gtls-app.texi ++++ b/doc/cha-gtls-app.texi +@@ -1547,6 +1547,11 @@ This is implied by the PFS keyword. + will prevent the advertizing the TLS extended master secret (session hash) + extension. + ++@item %FORCE_SESSION_HASH @tab ++negotiate the TLS extended master secret (session hash) extension. ++Specifying both %NO_SESSION_HASH and %FORCE_SESSION_HASH is not ++supported, and the behavior is undefined. ++ + @item %SERVER_PRECEDENCE @tab + The ciphersuite will be selected according to server priorities + and not the client's. +diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h +index 8c7bdaa..c6bf154 100644 +--- a/lib/gnutls_int.h ++++ b/lib/gnutls_int.h +@@ -926,6 +926,11 @@ typedef struct sign_algo_list_st { + + #include "atomic.h" + ++typedef enum ext_master_secret_t { ++ EMS_REQUEST, ++ EMS_REQUIRE ++} ext_master_secret_t; ++ + /* For the external api */ + struct gnutls_priority_st { + priority_st protocol; +@@ -965,6 +970,7 @@ struct gnutls_priority_st { + bool force_etm; + unsigned int additional_verify_flags; + bool tls13_compat_mode; ++ ext_master_secret_t force_ext_master_secret; + + /* TLS_FALLBACK_SCSV */ + bool fallback; +diff --git a/lib/handshake.c b/lib/handshake.c +index 21edc5e..1e33b84 100644 +--- a/lib/handshake.c ++++ b/lib/handshake.c +@@ -875,6 +875,15 @@ read_client_hello(gnutls_session_t session, uint8_t * data, + if (_gnutls_version_priority(session, vers->id) < 0) + return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_VERSION_PACKET); + ++ /* check if EMS is required */ ++ if (!vers->tls13_sem && vers->id != GNUTLS_SSL3 && ++ vers->id != GNUTLS_DTLS0_9 && ++ session->internals.priorities->force_ext_master_secret == ++ EMS_REQUIRE && ++ !session->security_parameters.ext_master_secret) { ++ return gnutls_assert_val(GNUTLS_E_INSUFFICIENT_SECURITY); ++ } ++ + _gnutls_handshake_log("HSK[%p]: Selected version %s\n", session, vers->name); + + /* select appropriate compression method */ +@@ -2062,11 +2071,27 @@ read_server_hello(gnutls_session_t session, + if (ret < 0) + return gnutls_assert_val(ret); + +- /* check if EtM is required */ +- if (!vers->tls13_sem && session->internals.priorities->force_etm && !session->security_parameters.etm) { +- const cipher_entry_st *cipher = cipher_to_entry(session->security_parameters.cs->block_algorithm); +- if (_gnutls_cipher_type(cipher) == CIPHER_BLOCK) +- return gnutls_assert_val(GNUTLS_E_UNWANTED_ALGORITHM); ++ if (!vers->tls13_sem) { ++ /* check if EtM is required */ ++ if (session->internals.priorities->force_etm && ++ !session->security_parameters.etm) { ++ const cipher_entry_st *cipher = ++ cipher_to_entry(session->security_parameters. ++ cs->block_algorithm); ++ if (_gnutls_cipher_type(cipher) == CIPHER_BLOCK) ++ return ++ gnutls_assert_val ++ (GNUTLS_E_UNWANTED_ALGORITHM); ++ } ++ ++ /* check if EMS is required */ ++ if (vers->id != GNUTLS_SSL3 && vers->id != GNUTLS_DTLS0_9 && ++ session->internals.priorities->force_ext_master_secret == ++ EMS_REQUIRE && ++ !session->security_parameters.ext_master_secret) { ++ return ++ gnutls_assert_val(GNUTLS_E_INSUFFICIENT_SECURITY); ++ } + } + + +diff --git a/lib/nettle/int/tls1-prf.c b/lib/nettle/int/tls1-prf.c +index 19ca5d3..fd9b5a4 100644 +--- a/lib/nettle/int/tls1-prf.c ++++ b/lib/nettle/int/tls1-prf.c +@@ -28,6 +28,7 @@ + #endif + + #include ++#include "fips.h" + + #include + #include +@@ -152,8 +153,26 @@ tls12_prf(void *mac_ctx, + size_t seed_size, const uint8_t *seed, + size_t length, uint8_t *dst) + { ++#define MASTER_SECRET "master secret" ++#define MASTER_SECRET_SIZE (sizeof(MASTER_SECRET) - 1) ++ + P_hash(mac_ctx, update, digest, digest_size, + seed_size, seed, label_size, label, length, dst); + ++ /* Since May 16, 2023, the use of extended master secret is ++ * mandatory according to FIPS 140-3 IG D.Q. Instead of ++ * allowing the "extended master secret" label specifically, ++ * we mark the use of non-EMS label, i.e., "master secret" as ++ * non-approved, because it is still useful to call the ++ * gnutls_prf_raw function with arbitrary label, e.g., in ++ * self-tests. ++ */ ++ if (label_size == MASTER_SECRET_SIZE && ++ memcmp(label, MASTER_SECRET, MASTER_SECRET_SIZE) == 0) { ++ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_NOT_APPROVED); ++ } else { ++ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_APPROVED); ++ } ++ + return 1; + } +diff --git a/lib/priority.c b/lib/priority.c +index d163d81..4adf4c7 100644 +--- a/lib/priority.c ++++ b/lib/priority.c +@@ -906,6 +906,12 @@ static void enable_no_ext_master_secret(gnutls_priority_t c) + { + c->_no_ext_master_secret = 1; + } ++ ++static void enable_force_ext_master_secret(gnutls_priority_t c) ++{ ++ c->force_ext_master_secret = EMS_REQUIRE; ++} ++ + static void enable_no_etm(gnutls_priority_t c) + { + c->_no_etm = 1; +@@ -1040,6 +1046,9 @@ struct cfg { + gnutls_kx_algorithm_t kxs[MAX_ALGOS+1]; + gnutls_sign_algorithm_t sigs[MAX_ALGOS+1]; + gnutls_protocol_t versions[MAX_ALGOS+1]; ++ ++ ext_master_secret_t force_ext_master_secret; ++ bool force_ext_master_secret_set; + }; + + static inline void +@@ -1141,6 +1150,8 @@ cfg_steal(struct cfg *dst, struct cfg *src) + + dst->allowlisting = src->allowlisting; + dst->ktls_enabled = src->ktls_enabled; ++ dst->force_ext_master_secret = src->force_ext_master_secret; ++ dst->force_ext_master_secret_set = src->force_ext_master_secret_set; + memcpy(dst->ciphers, src->ciphers, sizeof(src->ciphers)); + memcpy(dst->macs, src->macs, sizeof(src->macs)); + memcpy(dst->groups, src->groups, sizeof(src->groups)); +@@ -1748,6 +1759,21 @@ static int cfg_ini_handler(void *_ctx, const char *section, const char *name, co + } + cfg->kxs[i] = algo; + cfg->kxs[i+1] = 0; ++ } else if (c_strcasecmp(name, "tls-session-hash") == 0) { ++ if (c_strcasecmp(value, "request") == 0) { ++ cfg->force_ext_master_secret = EMS_REQUEST; ++ cfg->force_ext_master_secret_set = true; ++ } else if (c_strcasecmp(value, "require") == 0) { ++ cfg->force_ext_master_secret = EMS_REQUIRE; ++ cfg->force_ext_master_secret_set = true; ++ } else { ++ _gnutls_debug_log( ++ "cfg: unknown value for %s: %s\n", name, ++ value); ++ if (fail_on_invalid_config) ++ return 0; ++ goto exit; ++ } + } else { + _gnutls_debug_log("unknown parameter %s\n", name); + if (fail_on_invalid_config) +@@ -2744,6 +2770,12 @@ gnutls_priority_init(gnutls_priority_t * priority_cache, + (*priority_cache)->min_record_version = 1; + gnutls_atomic_init(&(*priority_cache)->usage_cnt); + ++ if (_gnutls_fips_mode_enabled()) { ++ (*priority_cache)->force_ext_master_secret = EMS_REQUIRE; ++ } else { ++ (*priority_cache)->force_ext_master_secret = EMS_REQUEST; ++ } ++ + if (system_wide_config.allowlisting && !priorities) { + priorities = "@" LEVEL_SYSTEM; + } +@@ -2997,6 +3029,15 @@ gnutls_priority_init(gnutls_priority_t * priority_cache, + goto error; + } + ++ /* This needs to be done after parsing modifiers, as ++ * tls-session-hash has precedence over modifiers. ++ */ ++ if (system_wide_config.force_ext_master_secret_set) { ++ (*priority_cache)->force_ext_master_secret = ++ system_wide_config.force_ext_master_secret; ++ (*priority_cache)->_no_ext_master_secret = false; ++ } ++ + ret = set_ciphersuite_list(*priority_cache); + if (ret < 0) { + if (err_pos) +diff --git a/lib/priority_options.gperf b/lib/priority_options.gperf +index 5a041b7..5bb250a 100644 +--- a/lib/priority_options.gperf ++++ b/lib/priority_options.gperf +@@ -13,6 +13,7 @@ NO_TICKETS_TLS12, enable_no_tickets_tls12 + NO_ETM, enable_no_etm + FORCE_ETM, enable_force_etm + NO_SESSION_HASH, enable_no_ext_master_secret ++FORCE_SESSION_HASH, enable_force_ext_master_secret + STATELESS_COMPRESSION, dummy_func + VERIFY_ALLOW_BROKEN, enable_verify_allow_broken + VERIFY_ALLOW_SIGN_RSA_MD5, enable_verify_allow_rsa_md5 +diff --git a/tests/Makefile.am b/tests/Makefile.am +index 23d309d..e5f7fa6 100644 +--- a/tests/Makefile.am ++++ b/tests/Makefile.am +@@ -77,7 +77,7 @@ EXTRA_DIST = suppressions.valgrind eagain-common.h cert-common.h test-chains.h \ + testpkcs11-certs/client.key testpkcs11-certs/server.crt testpkcs11-certs/server-tmpl \ + testpkcs11-certs/ca.key testpkcs11-certs/client.crt testpkcs11-certs/client-tmpl testpkcs11-certs/server.key \ + crt_type-neg-common.c \ +- system-override-default-priority-string.bad.config system-override-default-priority-string.none.config system-override-default-priority-string.only-tls13.config \ ++ system-override-default-priority-string.bad.config system-override-default-priority-string.none.config system-override-default-priority-string.only-tls13.config system-override-session-hash.sh \ + client-secrets.h server-secrets.h + + AM_CFLAGS = $(WARN_CFLAGS) $(WERROR_CFLAGS) +@@ -234,7 +234,7 @@ ctests += mini-record-2 simple gnutls_hmac_fast set_pkcs12_cred cert certuniquei + set_x509_ocsp_multi_cli kdf-api keylog-func handshake-write \ + x509cert-dntypes id-on-xmppAddr tls13-compat-mode ciphersuite-name \ + x509-upnconstraint cipher-padding xts-key-check pkcs7-verify-double-free \ +- fips-rsa-sizes tls12-rehandshake-ticket ++ fips-rsa-sizes tls12-rehandshake-ticket tls-force-ems + + ctests += tls-channel-binding + +diff --git a/tests/multi-alerts.c b/tests/multi-alerts.c +index 84a412c..27be63b 100644 +--- a/tests/multi-alerts.c ++++ b/tests/multi-alerts.c +@@ -198,6 +198,14 @@ void doit(void) + int sockets[2]; + int err; + ++ /* This test does not work under FIPS, as extended master ++ * secret extension needs to be negotiated through extensions, ++ * but the fixture does not contain the extension. ++ */ ++ if (gnutls_fips140_mode_enabled()) { ++ exit(77); ++ } ++ + err = socketpair(AF_UNIX, SOCK_STREAM, 0, sockets); + if (err == -1) { + perror("socketpair"); +diff --git a/tests/no-extensions.c b/tests/no-extensions.c +index 3bd9d06..e5b9578 100644 +--- a/tests/no-extensions.c ++++ b/tests/no-extensions.c +@@ -205,6 +205,13 @@ void start(const char *prio, gnutls_protocol_t exp_version) + + void doit(void) + { ++ /* This test does not work under FIPS, as extended master ++ * secret extension needs to be negotiated through extensions. ++ */ ++ if (gnutls_fips140_mode_enabled()) { ++ exit(77); ++ } ++ + start("NORMAL:-VERS-ALL:+VERS-TLS1.0:%NO_EXTENSIONS", GNUTLS_TLS1_0); + start("NORMAL:-VERS-ALL:+VERS-TLS1.1:%NO_EXTENSIONS", GNUTLS_TLS1_1); + start("NORMAL:-VERS-ALL:+VERS-TLS1.2:%NO_EXTENSIONS", GNUTLS_TLS1_2); +diff --git a/tests/ocsp-tests/ocsp-must-staple-connection.sh b/tests/ocsp-tests/ocsp-must-staple-connection.sh +index 049491a..594e854 100755 +--- a/tests/ocsp-tests/ocsp-must-staple-connection.sh ++++ b/tests/ocsp-tests/ocsp-must-staple-connection.sh +@@ -402,39 +402,43 @@ kill "${TLS_SERVER_PID}" + wait "${TLS_SERVER_PID}" + unset TLS_SERVER_PID + +-echo "=== Test 7: OSCP response error - client doesn't send status_request ===" +- +-eval "${GETPORT}" +-# Port for gnutls-serv +-TLS_SERVER_PORT=$PORT +-PORT=${TLS_SERVER_PORT} +-launch_bare_server \ +- datefudge "${TESTDATE}" \ +- "${SERV}" --echo --disable-client-cert \ +- --x509keyfile="${srcdir}/ocsp-tests/certs/server_good.key" \ +- --x509certfile="${SERVER_CERT_FILE}" \ +- --port="${TLS_SERVER_PORT}" \ +- --ocsp-response="${srcdir}/ocsp-tests/response3.der" --ignore-ocsp-response-errors +-TLS_SERVER_PID="${!}" +-wait_server $TLS_SERVER_PID ++if test "${GNUTLS_FORCE_FIPS_MODE}" != 1; then ++ ++ echo "=== Test 7: OSCP response error - client doesn't send status_request ===" ++ ++ eval "${GETPORT}" ++ # Port for gnutls-serv ++ TLS_SERVER_PORT=$PORT ++ PORT=${TLS_SERVER_PORT} ++ launch_bare_server \ ++ datefudge "${TESTDATE}" \ ++ "${SERV}" --echo --disable-client-cert \ ++ --x509keyfile="${srcdir}/ocsp-tests/certs/server_good.key" \ ++ --x509certfile="${SERVER_CERT_FILE}" \ ++ --port="${TLS_SERVER_PORT}" \ ++ --ocsp-response="${srcdir}/ocsp-tests/response3.der" --ignore-ocsp-response-errors ++ TLS_SERVER_PID="${!}" ++ wait_server $TLS_SERVER_PID ++ ++ wait_for_port "${TLS_SERVER_PORT}" ++ ++ echo "test 123456" | \ ++ datefudge -s "${TESTDATE}" \ ++ "${CLI}" --priority "NORMAL:%NO_EXTENSIONS" --ocsp --x509cafile="${srcdir}/ocsp-tests/certs/ca.pem" \ ++ --port="${TLS_SERVER_PORT}" localhost ++ rc=$? + +-wait_for_port "${TLS_SERVER_PORT}" ++ if test "${rc}" != "0"; then ++ echo "Connecting to server with valid certificate and OCSP error response failed" ++ exit ${rc} ++ fi + +-echo "test 123456" | \ +- datefudge -s "${TESTDATE}" \ +- "${CLI}" --priority "NORMAL:%NO_EXTENSIONS" --ocsp --x509cafile="${srcdir}/ocsp-tests/certs/ca.pem" \ +- --port="${TLS_SERVER_PORT}" localhost +-rc=$? ++ kill "${TLS_SERVER_PID}" ++ wait "${TLS_SERVER_PID}" ++ unset TLS_SERVER_PID + +-if test "${rc}" != "0"; then +- echo "Connecting to server with valid certificate and OCSP error response failed" +- exit ${rc} + fi + +-kill "${TLS_SERVER_PID}" +-wait "${TLS_SERVER_PID}" +-unset TLS_SERVER_PID +- + echo "=== Test 8: OSCP response error - client sends status_request, no TLS feature extension ===" + + eval "${GETPORT}" +diff --git a/tests/rehandshake-ext-secret.c b/tests/rehandshake-ext-secret.c +index 94279f0..8d68c9b 100644 +--- a/tests/rehandshake-ext-secret.c ++++ b/tests/rehandshake-ext-secret.c +@@ -142,6 +142,14 @@ static void try(unsigned onclient) + + void doit(void) + { ++ /* This test does not work with TLS 1.2 under FIPS, as ++ * extended master secret extension needs to be negotiated ++ * through extensions, while %NO_SESSION_HASH is set. ++ */ ++ if (gnutls_fips140_mode_enabled()) { ++ exit(77); ++ } ++ + try(0); + reset_buffers(); + try(1); +diff --git a/tests/resume.c b/tests/resume.c +index 93838c0..aa3c60c 100644 +--- a/tests/resume.c ++++ b/tests/resume.c +@@ -91,6 +91,7 @@ struct params_res { + int change_ciphersuite; + int early_start; + int no_early_start; ++ int no_fips; + }; + + pid_t child; +@@ -126,16 +127,18 @@ struct params_res resume_tests[] = { + .enable_session_ticket_client = ST_NONE, + .expect_resume = 0, + .first_no_ext_master = 0, +- .second_no_ext_master = 1}, ++ .second_no_ext_master = 1, ++ .no_fips = 1}, + {.desc = "try to resume from db (none -> ext master secret)", + .enable_db = 1, + .enable_session_ticket_server = ST_NONE, + .enable_session_ticket_client = ST_NONE, + .expect_resume = 0, + .first_no_ext_master = 1, +- .second_no_ext_master = 0}, +-#endif +-#if defined(TLS13) ++ .second_no_ext_master = 0, ++ .no_fips = 1}, ++# endif ++# if defined(TLS13) + /* only makes sense under TLS1.3 as negotiation involves a new + * handshake with different parameters */ + {.desc = "try to resume from session ticket (different cipher order)", +@@ -211,14 +214,17 @@ struct params_res resume_tests[] = { + .enable_session_ticket_client = ST_ALL, + .expect_resume = 0, + .first_no_ext_master = 0, +- .second_no_ext_master = 1}, +- {.desc = "try to resume from session ticket (none -> ext master secret)", ++ .second_no_ext_master = 1, ++ .no_fips = 1}, ++ {.desc = ++ "try to resume from session ticket (none -> ext master secret)", + .enable_db = 0, + .enable_session_ticket_server = ST_ALL, + .enable_session_ticket_client = ST_ALL, + .expect_resume = 0, + .first_no_ext_master = 1, +- .second_no_ext_master = 0}, ++ .second_no_ext_master = 0, ++ .no_fips = 1}, + {.desc = "try to resume from session ticket (server only)", + .enable_db = 0, + .enable_session_ticket_server = ST_ALL, +@@ -942,6 +948,12 @@ void doit(void) + int client_sds[SESSIONS], server_sds[SESSIONS]; + int j; + ++ if (resume_tests[i].no_fips && gnutls_fips140_mode_enabled()) { ++ success("skipping %s under FIPS mode\n", ++ resume_tests[i].desc); ++ continue; ++ } ++ + printf("%s\n", resume_tests[i].desc); + + for (j = 0; j < SESSIONS; j++) { +diff --git a/tests/status-request.c b/tests/status-request.c +index 07c7918..cd2cc54 100644 +--- a/tests/status-request.c ++++ b/tests/status-request.c +@@ -289,7 +289,13 @@ void start(const char *prio) + + void doit(void) + { +- start("NORMAL:-VERS-ALL:+VERS-TLS1.2"); ++ /* This test does not work with TLS 1.2 under FIPS, as ++ * extended master secret extension needs to be negotiated ++ * through extensions. ++ */ ++ if (!gnutls_fips140_mode_enabled()) { ++ start("NORMAL:-VERS-ALL:+VERS-TLS1.2"); ++ } + start("NORMAL:-VERS-ALL:+VERS-TLS1.3"); + start("NORMAL"); + } +diff --git a/tests/system-override-session-hash.sh b/tests/system-override-session-hash.sh +new file mode 100755 +index 0000000..97f11fa +--- /dev/null ++++ b/tests/system-override-session-hash.sh +@@ -0,0 +1,144 @@ ++#!/bin/sh ++ ++# Copyright (C) 2021 Red Hat, Inc. ++# ++# Author: Alexander Sosedkin ++# ++# This file is part of GnuTLS. ++# ++# GnuTLS is free software; you can redistribute it and/or modify it ++# under the terms of the GNU General Public License as published by the ++# Free Software Foundation; either version 3 of the License, or (at ++# your option) any later version. ++# ++# GnuTLS 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 ++# General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with GnuTLS. If not, see . ++ ++: ${srcdir=.} ++: ${SERV=../src/gnutls-serv${EXEEXT}} ++: ${CLI=../src/gnutls-cli${EXEEXT}} ++ ++if ! test -x "${SERV}"; then ++ exit 77 ++fi ++ ++if ! test -x "${CLI}"; then ++ exit 77 ++fi ++ ++${CLI} --fips140-mode ++if test $? = 0;then ++ echo "Cannot run this test in FIPS140 mode" ++ exit 77 ++fi ++ ++. "${srcdir}/scripts/common.sh" ++ ++testdir=`create_testdir cfg` ++ ++cat <<_EOF_ > "$testdir/request.cfg" ++[overrides] ++ ++tls-session-hash = request ++_EOF_ ++ ++cat <<_EOF_ > "$testdir/require.cfg" ++[overrides] ++ ++tls-session-hash = require ++_EOF_ ++ ++eval "${GETPORT}" ++ ++KEY=${srcdir}/../doc/credentials/x509/key-rsa-pss.pem ++CERT=${srcdir}/../doc/credentials/x509/cert-rsa-pss.pem ++CA=${srcdir}/../doc/credentials/x509/ca.pem ++ ++unset GNUTLS_SYSTEM_PRIORITY_FILE ++unset GNUTLS_DEBUG_LEVEL ++ ++launch_server --echo --priority "NORMAL:-VERS-ALL:+VERS-TLS1.2" --x509keyfile ${KEY} --x509certfile ${CERT} ++PID=$! ++wait_server ${PID} ++ ++export GNUTLS_SYSTEM_PRIORITY_FILE="$testdir/request.cfg" ++export GNUTLS_DEBUG_LEVEL=3 ++ ++"${CLI}" -p "${PORT}" 127.0.0.1 --priority "NORMAL:-VERS-ALL:+VERS-TLS1.2" --verify-hostname=localhost --x509cafile ${CA} --logfile="$testdir/client.log" /dev/null || ++ fail "expected connection to succeed (1)" ++ ++# "tls-session-hash" has precedence over %FORCE_SESSION_HASH ++"${CLI}" -p "${PORT}" 127.0.0.1 --priority "NORMAL:-VERS-ALL:+VERS-TLS1.2:%FORCE_SESSION_HASH" --verify-hostname=localhost --x509cafile ${CA} --logfile="$testdir/client.log" /dev/null || ++ fail "expected connection to succeed (2)" ++ ++echo kill ${PID} ++kill ${PID} ++wait ++ ++unset GNUTLS_SYSTEM_PRIORITY_FILE ++unset GNUTLS_DEBUG_LEVEL ++ ++export GNUTLS_SYSTEM_PRIORITY_FILE="$testdir/request.cfg" ++ ++# "tls-session-hash" has precedence over %FORCE_SESSION_HASH ++launch_server --echo --priority "NORMAL:-VERS-ALL:+VERS-TLS1.2:%FORCE_SESSION_HASH" --x509keyfile ${KEY} --x509certfile ${CERT} ++PID=$! ++wait_server ${PID} ++ ++export GNUTLS_DEBUG_LEVEL=3 ++ ++"${CLI}" -p "${PORT}" 127.0.0.1 --priority "NORMAL:-VERS-ALL:+VERS-TLS1.2" --verify-hostname=localhost --x509cafile ${CA} --logfile="$testdir/client.log" /dev/null || ++ fail ${PID} "expected connection to succeed (3)" ++ ++"${CLI}" -p "${PORT}" 127.0.0.1 --priority "NORMAL:-VERS-ALL:+VERS-TLS1.2:%NO_SESSION_HASH" --verify-hostname=localhost --x509cafile ${CA} --logfile="$testdir/client.log" /dev/null || ++ fail ${PID} "expected connection to succeed (4)" ++ ++kill ${PID} ++wait ++ ++unset GNUTLS_SYSTEM_PRIORITY_FILE ++unset GNUTLS_DEBUG_LEVEL ++ ++launch_server --echo --priority "NORMAL:-VERS-ALL:+VERS-TLS1.2" --x509keyfile ${KEY} --x509certfile ${CERT} ++PID=$! ++wait_server ${PID} ++ ++export GNUTLS_SYSTEM_PRIORITY_FILE="$testdir/require.cfg" ++export GNUTLS_DEBUG_LEVEL=3 ++ ++"${CLI}" -p "${PORT}" 127.0.0.1 --priority "NORMAL:-VERS-ALL:+VERS-TLS1.2" --verify-hostname=localhost --x509cafile ${CA} --logfile="$testdir/client.log" /dev/null || ++ fail ${PID} "expected connection to succeed (5)" ++ ++# "tls-session-hash" has precedence over %NO_SESSION_HASH ++"${CLI}" -p "${PORT}" 127.0.0.1 --priority "NORMAL:-VERS-ALL:+VERS-TLS1.2:%NO_SESSION_HASH" --verify-hostname=localhost --x509cafile ${CA} --logfile="$testdir/client.log" /dev/null || ++ fail ${PID} "expected connection to succeed (6)" ++ ++kill ${PID} ++wait ++ ++unset GNUTLS_SYSTEM_PRIORITY_FILE ++unset GNUTLS_DEBUG_LEVEL ++ ++export GNUTLS_SYSTEM_PRIORITY_FILE="$testdir/require.cfg" ++ ++# "tls-session-hash" has precedence over %NO_SESSION_HASH ++launch_server --echo --priority "NORMAL:-VERS-ALL:+VERS-TLS1.2:%NO_SESSION_HASH" --x509keyfile ${KEY} --x509certfile ${CERT} ++PID=$! ++wait_server ${PID} ++ ++"${CLI}" -p "${PORT}" 127.0.0.1 --priority "NORMAL:-VERS-ALL:+VERS-TLS1.2" --verify-hostname=localhost --x509cafile ${CA} --logfile="$testdir/client.log" /dev/null || ++ fail ${PID} "expected connection to succeed (7)" ++ ++# "tls-session-hash" has precedence over %NO_SESSION_HASH ++"${CLI}" -p "${PORT}" 127.0.0.1 --priority "NORMAL:-VERS-ALL:+VERS-TLS1.2:%NO_SESSION_HASH" --verify-hostname=localhost --x509cafile ${CA} --logfile="$testdir/client.log" /dev/null || ++ fail ${PID} "expected connection to succeed (8)" ++ ++kill ${PID} ++wait ++ ++rm -rf "$testdir" +diff --git a/tests/tls-force-ems.c b/tests/tls-force-ems.c +new file mode 100644 +index 0000000..35e7010 +--- /dev/null ++++ b/tests/tls-force-ems.c +@@ -0,0 +1,148 @@ ++/* ++ * Copyright (C) 2023 Red Hat, Inc. ++ * ++ * Author: Daiki Ueno ++ * ++ * This file is part of GnuTLS. ++ * ++ * GnuTLS is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GnuTLS 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 ++ * 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 ++ */ ++ ++#ifdef HAVE_CONFIG_H ++# include ++#endif ++ ++#include ++#include ++ ++#include "utils.h" ++#include "cert-common.h" ++#include "eagain-common.h" ++ ++/* This program tests whether forced extended master secret is ++ * negotiated as expected. ++ */ ++ ++const char *side; ++ ++static void tls_log_func(int level, const char *str) ++{ ++ fprintf(stderr, "%s|<%d>| %s", side, level, str); ++} ++ ++static void ++try(const char *name, const char *sprio, const char *cprio, int serr, int cerr) ++{ ++ int sret, cret; ++ gnutls_certificate_credentials_t scred, ccred; ++ gnutls_session_t server, client; ++ ++ success("Running %s\n", name); ++ ++ assert(gnutls_certificate_allocate_credentials(&scred) >= 0); ++ ++ assert(gnutls_certificate_set_x509_key_mem ++ (scred, &server_ca3_localhost_cert, ++ &server_ca3_key, GNUTLS_X509_FMT_PEM) >= 0); ++ ++ assert(gnutls_certificate_allocate_credentials(&ccred) >= 0); ++ ++ assert(gnutls_certificate_set_x509_trust_mem ++ (ccred, &ca3_cert, GNUTLS_X509_FMT_PEM) >= 0); ++ ++ assert(gnutls_init(&server, GNUTLS_SERVER) >= 0); ++ assert(gnutls_init(&client, GNUTLS_CLIENT) >= 0); ++ ++ gnutls_credentials_set(server, GNUTLS_CRD_CERTIFICATE, scred); ++ gnutls_credentials_set(client, GNUTLS_CRD_CERTIFICATE, ccred); ++ ++ gnutls_transport_set_push_function(server, server_push); ++ gnutls_transport_set_pull_function(server, server_pull); ++ gnutls_transport_set_ptr(server, server); ++ assert(gnutls_priority_set_direct(server, sprio, 0) >= 0); ++ ++ gnutls_transport_set_push_function(client, client_push); ++ gnutls_transport_set_pull_function(client, client_pull); ++ gnutls_transport_set_ptr(client, client); ++ assert(gnutls_priority_set_direct(client, cprio, 0) >= 0); ++ ++ HANDSHAKE_EXPECT(client, server, cerr, serr); ++ ++ gnutls_deinit(server); ++ gnutls_deinit(client); ++ gnutls_certificate_free_credentials(scred); ++ gnutls_certificate_free_credentials(ccred); ++ ++ reset_buffers(); ++} ++ ++#define AES_GCM "NORMAL:-VERS-ALL:+VERS-TLS1.2" ++ ++void doit(void) ++{ ++ gnutls_fips140_context_t fips_context; ++ ++ global_init(); ++ ++ /* General init. */ ++ gnutls_global_set_log_function(tls_log_func); ++ if (debug) ++ gnutls_global_set_log_level(2); ++ ++ assert(gnutls_fips140_context_init(&fips_context) >= 0); ++ ++ /* Default: EMS is requested in non-FIPS mode, while it is ++ * required in FIPS mode. ++ */ ++ FIPS_PUSH_CONTEXT(); ++ try("default", AES_GCM, AES_GCM, 0, 0); ++ FIPS_POP_CONTEXT(APPROVED); ++ ++ FIPS_PUSH_CONTEXT(); ++ try("both force EMS", AES_GCM ":%FORCE_SESSION_HASH", ++ AES_GCM ":%FORCE_SESSION_HASH", 0, 0); ++ FIPS_POP_CONTEXT(APPROVED); ++ ++ if (gnutls_fips140_mode_enabled()) { ++ try("neither negotiates EMS", AES_GCM ":%NO_SESSION_HASH", ++ AES_GCM ":%NO_SESSION_HASH", GNUTLS_E_INSUFFICIENT_SECURITY, ++ GNUTLS_E_AGAIN); ++ } else { ++ try("neither negotiates EMS", AES_GCM ":%NO_SESSION_HASH", ++ AES_GCM ":%NO_SESSION_HASH", 0, 0); ++ } ++ /* Note that the error codes are swapped based on FIPS mode: ++ * in FIPS mode, the server doesn't send the extension which ++ * causes the client to not send the one either, and then the ++ * server doesn't like the situation. On the other hand, in ++ * non-FIPS mode, it's the client to decide to abort the ++ * connection. ++ */ ++ if (gnutls_fips140_mode_enabled()) { ++ try("server doesn't negotiate EMS, client forces EMS", ++ AES_GCM ":%NO_SESSION_HASH", AES_GCM ":%FORCE_SESSION_HASH", ++ GNUTLS_E_INSUFFICIENT_SECURITY, GNUTLS_E_AGAIN); ++ } else { ++ try("server doesn't negotiate EMS, client forces EMS", ++ AES_GCM ":%NO_SESSION_HASH", AES_GCM ":%FORCE_SESSION_HASH", ++ GNUTLS_E_AGAIN, GNUTLS_E_INSUFFICIENT_SECURITY); ++ } ++ try("server forces EMS, client doesn't negotiate EMS", ++ AES_GCM ":%FORCE_SESSION_HASH", AES_GCM ":%NO_SESSION_HASH", ++ GNUTLS_E_INSUFFICIENT_SECURITY, GNUTLS_E_AGAIN); ++ ++ gnutls_fips140_context_deinit(fips_context); ++ ++ gnutls_global_deinit(); ++} +-- +2.41.0 + diff --git a/SOURCES/gnutls-3.7.6.tar.xz.sig b/SOURCES/gnutls-3.7.6.tar.xz.sig deleted file mode 100644 index 70cb359..0000000 Binary files a/SOURCES/gnutls-3.7.6.tar.xz.sig and /dev/null differ diff --git a/SPECS/gnutls.spec b/SPECS/gnutls.spec index ae6987d..7cdca6e 100644 --- a/SPECS/gnutls.spec +++ b/SPECS/gnutls.spec @@ -13,7 +13,7 @@ print(string.sub(hash, 0, 16)) } Version: 3.7.6 -Release: 20%{?dist} +Release: 21%{?dist} # not upstreamed Patch: gnutls-3.6.7-no-now-guile.patch Patch: gnutls-3.2.7-rpath.patch @@ -40,6 +40,7 @@ Patch: gnutls-3.7.6-fips-rsa-pss-saltlen.patch Patch: gnutls-3.7.8-revert-hmac-name.patch Patch: gnutls-3.7.8-rsa-kx-timing.patch Patch: gnutls-3.7.8-fips-pct-dh.patch +Patch: gnutls-3.7.6-fips-ems.patch # not upstreamed Patch: gnutls-3.7.3-disable-config-reload.patch @@ -352,7 +353,20 @@ ln -s ".$fname.hmac" "$RPM_BUILD_ROOT%{_libdir}/.libgnutls.so.30.hmac" %check %if %{with tests} -make check %{?_smp_mflags} GNUTLS_SYSTEM_PRIORITY_FILE=/dev/null + +xfail_tests= + +# With older kernel, key installation fails if the host is x86_64 and +# the package is built with -m32: +%ifarch %{ix86} +case "$(uname -r)" in + 4.*.x86_64) + xfail_tests="$xfail_tests ktls.sh" + ;; +esac +%endif + +make check %{?_smp_mflags} GNUTLS_SYSTEM_PRIORITY_FILE=/dev/null XFAIL_TESTS="$xfail_tests" %endif %files -f gnutls.lang @@ -406,6 +420,10 @@ make check %{?_smp_mflags} GNUTLS_SYSTEM_PRIORITY_FILE=/dev/null %endif %changelog +* Thu Jul 13 2023 Daiki Ueno - 3.7.6-21 +- Require use of extended master secret in FIPS mode by default (#2227257) +- Skip KTLS test on old kernel if host and target arches are different + * Tue Mar 14 2023 Daiki Ueno - 3.7.6-20 - Fix the previous change (#2175214)