]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
priority: add config keyword "tls-session-hash"
authorDaiki Ueno <ueno@gnu.org>
Tue, 4 Jul 2023 07:47:52 +0000 (09:47 +0200)
committerDaiki Ueno <ueno@gnu.org>
Mon, 10 Jul 2023 12:57:40 +0000 (14:57 +0200)
This adds a new keyword in the configuration file, "tls-session-hash",
which shall appear in the [overrides] section and takes either
"request" or "require" as the argument.  This is particularly useful
when reverting the EMS requirement in FIPS mode for interoperability
reasons.

Signed-off-by: Daiki Ueno <ueno@gnu.org>
lib/gnutls_int.h
lib/handshake.c
lib/priority.c
tests/Makefile.am
tests/system-override-session-hash.sh [new file with mode: 0755]

index 5d7ff9bff9e654b9ffbc3bff669d50bfb177adbd..5b9c95fac2d94b9bf97d7331dd2dd4c6c2fe5fbf 100644 (file)
@@ -1023,6 +1023,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;
@@ -1065,7 +1070,7 @@ struct gnutls_priority_st {
        bool force_etm;
        unsigned int additional_verify_flags;
        bool tls13_compat_mode;
-       bool force_ext_master_secret;
+       ext_master_secret_t force_ext_master_secret;
 
        /* TLS_FALLBACK_SCSV */
        bool fallback;
index e50cfa0af7531763cda0dcb3e4fb5dd4c1407290..ebc8e90b54bc7bee68cb23b95cc300bb89d03376 100644 (file)
@@ -880,7 +880,8 @@ static int read_client_hello(gnutls_session_t session, uint8_t *data,
        /* 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 &&
+           session->internals.priorities->force_ext_master_secret ==
+                   EMS_REQUIRE &&
            !session->security_parameters.ext_master_secret) {
                return gnutls_assert_val(GNUTLS_E_INSUFFICIENT_SECURITY);
        }
@@ -2061,7 +2062,8 @@ static int read_server_hello(gnutls_session_t session, uint8_t *data,
 
                /* check if EMS is required */
                if (vers->id != GNUTLS_SSL3 && vers->id != GNUTLS_DTLS0_9 &&
-                   session->internals.priorities->force_ext_master_secret &&
+                   session->internals.priorities->force_ext_master_secret ==
+                           EMS_REQUIRE &&
                    !session->security_parameters.ext_master_secret) {
                        return gnutls_assert_val(
                                GNUTLS_E_INSUFFICIENT_SECURITY);
index f5ac656e57425aae7b5a15f7c3258afaf7017870..fff04220163df45376b0c39cdae5f1e54a5df3d7 100644 (file)
@@ -845,7 +845,7 @@ static void enable_no_ext_master_secret(gnutls_priority_t c)
 
 static void enable_force_ext_master_secret(gnutls_priority_t c)
 {
-       c->force_ext_master_secret = 1;
+       c->force_ext_master_secret = EMS_REQUIRE;
 }
 
 static void enable_no_etm(gnutls_priority_t c)
@@ -1013,6 +1013,9 @@ struct cfg {
        gnutls_digest_algorithm_t hashes[MAX_ALGOS + 1];
        gnutls_ecc_curve_t ecc_curves[MAX_ALGOS + 1];
        gnutls_sign_algorithm_t sigs_for_cert[MAX_ALGOS + 1];
+
+       ext_master_secret_t force_ext_master_secret;
+       bool force_ext_master_secret_set;
 };
 
 static inline void cfg_deinit(struct cfg *cfg)
@@ -1117,6 +1120,8 @@ static inline void 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));
@@ -2032,6 +2037,21 @@ static int cfg_ini_handler(void *_ctx, const char *section, const char *name,
                        }
                        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)
@@ -3106,7 +3126,9 @@ int gnutls_priority_init(gnutls_priority_t *priority_cache,
        gnutls_atomic_init(&(*priority_cache)->usage_cnt);
 
        if (_gnutls_fips_mode_enabled()) {
-               (*priority_cache)->force_ext_master_secret = true;
+               (*priority_cache)->force_ext_master_secret = EMS_REQUIRE;
+       } else {
+               (*priority_cache)->force_ext_master_secret = EMS_REQUEST;
        }
 
        if (system_wide_config.allowlisting && !priorities) {
@@ -3384,6 +3406,15 @@ int 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)
index 86acb4c27710af493e537d76e8281a16fa9d34d1..e4bf3de3aeeb83cc66bd9b8f07e317ef5c743a7f 100644 (file)
@@ -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)
diff --git a/tests/system-override-session-hash.sh b/tests/system-override-session-hash.sh
new file mode 100755 (executable)
index 0000000..97f11fa
--- /dev/null
@@ -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 <https://www.gnu.org/licenses/>.
+
+: ${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 >/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 >/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 >/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 >/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 >/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 >/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 >/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 >/dev/null ||
+       fail ${PID} "expected connection to succeed (8)"
+
+kill ${PID}
+wait
+
+rm -rf "$testdir"