--- /dev/null
+/*
+ * 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, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/*
+ * This test isn't meant for direct execution.
+ * It is the significant part of the test
+ * invoked from system-override-curves-allowlist.sh that covers:
+ * - generating a key using the curve enabled in the config succeeds
+ * - disabling the previously enabled curve results in blocking it
+ * - reenabling it back is also possible after disabling
+ * - enabling a different curve unblocks key generation using it
+ * - disabling the originally enabled curve results in blocking it
+ * - redisabling it back is also possible after enabling
+ * Inputs (passed through environment variables):
+ * - INITIALLY_ENABLED_CURVES - space-separated string
+ * - INITIALLY_DISABLED_CURVES - space-separated string
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+
+#include <gnutls/gnutls.h>
+#include <gnutls/abstract.h>
+
+#include "utils.h"
+
+#define _assert(cond, format, ...) if (!(cond)) \
+ _fail("Assertion `" #cond "` failed: " format "\n", ##__VA_ARGS__)
+#define _check(cond) if (!(cond)) _fail("Assertion `" #cond "` failed.\n")
+
+gnutls_ecc_curve_t unlocked_ecc_curve_get_id(const char* curve);
+gnutls_pk_algorithm_t curve_name_to_pk(const char* curve);
+void assert_unblocked(const char* curve);
+void assert_blocked(const char* curve);
+char* envvarcpy(const char* envvar);
+
+
+gnutls_ecc_curve_t unlocked_ecc_curve_get_id(const char* curve) {
+ if (!strcasecmp(curve, "SECP192R1")) return GNUTLS_ECC_CURVE_SECP192R1;
+ if (!strcasecmp(curve, "SECP256R1")) return GNUTLS_ECC_CURVE_SECP256R1;
+ if (!strcasecmp(curve, "SECP384R1")) return GNUTLS_ECC_CURVE_SECP384R1;
+ if (!strcasecmp(curve, "SECP521R1")) return GNUTLS_ECC_CURVE_SECP521R1;
+ if (!strcasecmp(curve, "X448")) return GNUTLS_ECC_CURVE_X448;
+ if (!strcasecmp(curve, "X25519")) return GNUTLS_ECC_CURVE_X25519;
+ fprintf(stderr, "unknown curve %s\n", curve);
+ return GNUTLS_ECC_CURVE_INVALID;
+}
+
+
+gnutls_pk_algorithm_t curve_name_to_pk(const char* curve) {
+ if (!strcasecmp(curve, "X448")) return GNUTLS_PK_ECDH_X448;
+ if (!strcasecmp(curve, "X25519")) return GNUTLS_PK_ECDH_X25519;
+ return GNUTLS_PK_ECDSA;
+}
+
+
+void assert_unblocked(const char* curve_name) {
+ gnutls_privkey_t priv;
+ gnutls_ecc_curve_t curve;
+ gnutls_pk_algorithm_t pk;
+
+ unsigned int bits;
+
+ fprintf(stderr, "generating a key using non-blocked %s curve...\n",
+ curve_name);
+ _check(curve = gnutls_ecc_curve_get_id(curve_name));
+ _check(curve == unlocked_ecc_curve_get_id(curve_name));
+ _check(gnutls_privkey_init(&priv) == GNUTLS_E_SUCCESS);
+ bits = GNUTLS_CURVE_TO_BITS(curve);
+ pk = curve_name_to_pk(curve_name);
+ _check(gnutls_privkey_generate(priv, pk, bits, 0) == GNUTLS_E_SUCCESS);
+ gnutls_privkey_deinit(priv);
+ fprintf(stderr, "%s succeeds as expected\n", curve_name);
+}
+
+
+void assert_blocked(const char* curve_name) {
+ gnutls_privkey_t priv;
+ gnutls_ecc_curve_t curve;
+ unsigned int bits;
+ gnutls_pk_algorithm_t pk;
+
+ fprintf(stderr, "generating a key using blocked %s curve...\n",
+ curve_name);
+ _check(gnutls_ecc_curve_get_id(curve_name) == GNUTLS_ECC_CURVE_INVALID);
+ _check((curve = unlocked_ecc_curve_get_id(curve_name)) !=
+ GNUTLS_ECC_CURVE_INVALID);
+ _check(!strcasecmp(curve_name, gnutls_ecc_curve_get_name(curve)));
+ _check(gnutls_privkey_init(&priv) == GNUTLS_E_SUCCESS);
+ bits = GNUTLS_CURVE_TO_BITS(curve);
+ pk = curve_name_to_pk(curve_name);
+ _check(gnutls_privkey_generate(priv, pk, bits, 0) < 0);
+ gnutls_privkey_deinit(priv);
+ fprintf(stderr, "%s is blocked as expected\n", curve_name);
+}
+
+
+char* envvarcpy(const char* envvar) {
+ char* s;
+ _assert(s = getenv(envvar), "variable %s is not set", envvar);
+ return gnutls_strdup(s);
+}
+
+
+void doit(void) {
+ char* curves;
+ const char* curve;
+ gnutls_ecc_curve_t curve_id;
+
+ curves = envvarcpy("INITIALLY_ENABLED_CURVES");
+ for (curve = strtok(curves, " "); curve; curve = strtok(NULL, " ")) {
+ curve_id = unlocked_ecc_curve_get_id(curve);
+
+ assert_unblocked(curve);
+
+ gnutls_ecc_curve_set_enabled(curve_id, 0);
+ assert_blocked(curve);
+
+ gnutls_ecc_curve_set_enabled(curve_id, 1);
+ assert_unblocked(curve);
+
+ printf("disableable: %s\n", curve);
+ }
+ free(curves);
+
+ curves = envvarcpy("INITIALLY_DISABLED_CURVES");
+ for (curve = strtok(curves, " "); curve; curve = strtok(NULL, " ")) {
+ curve_id = unlocked_ecc_curve_get_id(curve);
+
+ assert_blocked(curve);
+
+ gnutls_ecc_curve_set_enabled(curve_id, 1);
+ assert_unblocked(curve);
+
+ gnutls_ecc_curve_set_enabled(curve_id, 0);
+ assert_blocked(curve);
+
+ printf("reenableable: %s\n", curve);
+ }
+ free(curves);
+
+ exit(0);
+}
# along with this program. If not, see <https://www.gnu.org/licenses/>
: ${srcdir=.}
+: ${builddir=.}
: ${SERV=../src/gnutls-serv${EXEEXT}}
: ${CLI=../src/gnutls-cli${EXEEXT}}
: ${CERTTOOL=../src/certtool${EXEEXT}}
[overrides]
enabled-curve= seCp384r1
+enabled-curve =X448
_EOF_
export GNUTLS_SYSTEM_PRIORITY_FILE="${TMPFILE_CONFIG}"
export GNUTLS_SYSTEM_PRIORITY_FAIL_ON_INVALID=1
-INITIALLY_ENABLED_CURVES="SECP384R1"
-INITIALLY_DISABLED_CURVES="SECP256R1 SECP521R1 X25519 X448"
-EXAMPLE_DISABLED_PRIORITY=NORMAL:-CURVE-ALL:+CURVE-SECP256R1:+CURVE-SECP521R1
+export INITIALLY_ENABLED_CURVES="SECP384R1 X448"
+export INITIALLY_DISABLED_CURVES="SECP256R1 SECP521R1 X25519"
+EXAMPLE_DISABLED_PRIORITY=NORMAL:-CURVE-ALL:+CURVE-SECP256R1:+CURVE-SECP521R1:+CURVE-X25519
export GNUTLS_DEBUG_LEVEL=3
+
+# --list output
+
"${CLI}" --list|grep ^Groups >"${TMPFILE_OBSERVED_LOG}"
cat "${TMPFILE_OBSERVED_LOG}"
for curve in ${INITIALLY_DISABLED_CURVES}; do
fi
done
-# Try whether a client connection with a disabled curve will succeed.
+
+# TLS: try whether a client connection with a disabled curve will succeed
KEY1=${srcdir}/../doc/credentials/x509/key-rsa.pem
CERT1=${srcdir}/../doc/credentials/x509/cert-rsa.pem
kill ${PID}
wait
-# Try whether a server connection with a disabled curve will succeed.
+# TLS: try whether a server connection with a disabled curve will succeed
KEY1=${srcdir}/../doc/credentials/x509/key-rsa.pem
CERT1=${srcdir}/../doc/credentials/x509/cert-rsa.pem
kill ${PID}
wait
+export GNUTLS_SYSTEM_PRIORITY_FILE="${TMPFILE_CONFIG}"
+
+
+# Key generation using certtool
+
+for curve in ${INITIALLY_ENABLED_CURVES}; do
+ key_type=ecdsa
+ test $curve = X448 && key_type=x448
+ test $curve = X25519 && key_type=x25519
+ ${VALGRIND} ${CERTTOOL} \
+ --generate-privkey --key-type=$key_type --curve=$curve \
+ --outfile "${TMPFILE_KEY}"
+ EX=$?
+ if test $EX != 0; then
+ echo "key generation using $curve has failed ($EX)"
+ exit $EX
+ fi
+done
+
+for curve in ${INITIALLY_DISABLED_CURVES}; do
+ key_type=ecdsa
+ test $curve = X448 && key_type=x448
+ test $curve = X25519 && key_type=x25519
+ ${VALGRIND} ${CERTTOOL} \
+ --generate-privkey --key-type=$key_type --curve=$curve \
+ --outfile "${TMPFILE_KEY}" &> ${TMPFILE_OBSERVED_LOG}
+ EX=$?
+ if test $EX != 1; then
+ echo "key generation using $curve has succeeded unexpectedly"
+ exit $EX
+ fi
+ if ! ${GREP} -Fqx "Unsupported curve: $curve" "${TMPFILE_OBSERVED_LOG}"
+ then
+ ${CAT} "${TMPFILE_OBSERVED_LOG}"
+ echo "'Unsupported curve: $curve' not found in the output"
+ exit 1
+ fi
+done
+
+
+# Test key generation and gnutls_ecc_curve_set_enabled
+# using system-override-curves-allowlist.c
+
+${CAT} > "${TMPFILE_EXPECTED_LOG}" <<EOF
+disableable: SECP384R1
+disableable: X448
+reenableable: SECP256R1
+reenableable: SECP521R1
+reenableable: X25519
+EOF
+
+${VALGRIND} "${builddir}/system-override-curves-allowlist" \
+ > ${TMPFILE_OBSERVED_LOG}
+EX=$?
+if test $EX != 0; then
+ ${CAT} ${TMPFILE_OBSERVED_LOG}
+ echo "system-override-curves-allowlist(.c) failed with $EX"
+ exit $EX
+fi
+${DIFF} "${TMPFILE_EXPECTED_LOG}" "${TMPFILE_OBSERVED_LOG}"
+EX=$?
+if test $EX != 0; then
+ echo "system-override-curves-allowlist(.c) produced unexpected output"
+ exit 1
+fi
+
exit 0