summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@gnutls.org>2018-07-09 17:09:11 +0000
committerNikos Mavrogiannopoulos <nmav@gnutls.org>2018-07-09 17:09:11 +0000
commit596536f12db974e0668effdc5bf3ef6f673c8f54 (patch)
tree8782e1bb2f0ba4bfc2c39fb709df10262d44d17a
parent7be78eba6dc33c3ed0787f806c71d75b7c9fe4de (diff)
parentf83156ba49b6b918790dad0452dc7189647cf5e9 (diff)
downloadgnutls-596536f12db974e0668effdc5bf3ef6f673c8f54.tar.gz
Merge branch 'tmp-def-priority2' into 'master'
gnutls_set_default_priority2: introduced See merge request gnutls/gnutls!680
-rw-r--r--doc/Makefile.am4
-rw-r--r--doc/cha-gtls-app.texi7
-rw-r--r--doc/examples/ex-client-psk.c16
-rw-r--r--doc/examples/ex-serv-dtls.c11
-rw-r--r--doc/examples/ex-serv-psk.c11
-rw-r--r--doc/examples/ex-serv-x509.c11
-rw-r--r--doc/manpages/Makefile.am2
-rw-r--r--lib/includes/gnutls/gnutls.h.in12
-rw-r--r--lib/libgnutls.map2
-rw-r--r--lib/priority.c138
-rw-r--r--symbols.last2
-rw-r--r--tests/Makefile.am4
-rw-r--r--tests/priority-init2.c269
-rw-r--r--tests/set-default-prio.c266
14 files changed, 730 insertions, 25 deletions
diff --git a/doc/Makefile.am b/doc/Makefile.am
index ed6ee8371c..de4a7711b4 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -1542,6 +1542,8 @@ FUNCS += functions/gnutls_priority_group_list
FUNCS += functions/gnutls_priority_group_list.short
FUNCS += functions/gnutls_priority_init
FUNCS += functions/gnutls_priority_init.short
+FUNCS += functions/gnutls_priority_init2
+FUNCS += functions/gnutls_priority_init2.short
FUNCS += functions/gnutls_priority_kx_list
FUNCS += functions/gnutls_priority_kx_list.short
FUNCS += functions/gnutls_priority_mac_list
@@ -1902,6 +1904,8 @@ FUNCS += functions/gnutls_session_ticket_send
FUNCS += functions/gnutls_session_ticket_send.short
FUNCS += functions/gnutls_set_default_priority
FUNCS += functions/gnutls_set_default_priority.short
+FUNCS += functions/gnutls_set_default_priority_append
+FUNCS += functions/gnutls_set_default_priority_append.short
FUNCS += functions/gnutls_sign_algorithm_get
FUNCS += functions/gnutls_sign_algorithm_get.short
FUNCS += functions/gnutls_sign_algorithm_get_client
diff --git a/doc/cha-gtls-app.texi b/doc/cha-gtls-app.texi
index 59b448547c..f6710a0a16 100644
--- a/doc/cha-gtls-app.texi
+++ b/doc/cha-gtls-app.texi
@@ -1071,7 +1071,8 @@ algorithms and options in a compact, easy-to-use format. These
strings are intended as a user-specified override of the library defaults.
That is, we recommend applications using the default settings
-(c.f. @funcref{gnutls_set_default_priority}), and provide the user
+(c.f. @funcref{gnutls_set_default_priority} or
+@funcref{gnutls_set_default_priority_append}), and provide the user
with access to priority strings for overriding the default behavior,
on configuration files, or other UI. Following such a principle,
makes the GnuTLS library as the default settings provider. That is
@@ -1079,7 +1080,7 @@ necessary and a good practice, because TLS protocol hardening and
phasing out of legacy algorithms, is easier to co-ordinate when happens
in a single library.
-@showfuncB{gnutls_set_default_priority,gnutls_priority_set_direct}
+@showfuncC{gnutls_set_default_priority,gnutls_set_default_priority_append,gnutls_priority_set_direct}
The priority string translation to the internal GnuTLS form requires
processing and the generated internal form also occupies some memory.
@@ -1088,7 +1089,7 @@ and share the generated data across sessions. The following functions
allow the generation of a "priority cache" and the sharing of it across
sessions.
-@showfuncC{gnutls_priority_init,gnutls_priority_set,gnutls_priority_deinit}
+@showfuncD{gnutls_priority_init2,gnutls_priority_init,gnutls_priority_set,gnutls_priority_deinit}
@subheading Using Priority Strings
diff --git a/doc/examples/ex-client-psk.c b/doc/examples/ex-client-psk.c
index 5658cb0ce0..4b393d877f 100644
--- a/doc/examples/ex-client-psk.c
+++ b/doc/examples/ex-client-psk.c
@@ -34,6 +34,11 @@ int main(void)
gnutls_psk_client_credentials_t pskcred;
const gnutls_datum_t key = { (void *) "DEADBEEF", 8 };
+ if (gnutls_check_version("3.6.3") == NULL) {
+ fprintf(stderr, "GnuTLS 3.6.3 or later is required for this example\n");
+ exit(1);
+ }
+
CHECK(gnutls_global_init());
CHECK(gnutls_psk_allocate_client_credentials(&pskcred));
@@ -44,11 +49,14 @@ int main(void)
*/
CHECK(gnutls_init(&session, GNUTLS_CLIENT));
- /* Use default priorities */
ret =
- gnutls_priority_set_direct(session,
- "PERFORMANCE:+ECDHE-PSK:+DHE-PSK:+PSK",
- &err);
+ gnutls_set_default_priority_append(session,
+ "-KX-ALL:+ECDHE-PSK:+DHE-PSK:+PSK",
+ &err, 0);
+
+ /* Alternative for pre-3.6.3 versions:
+ * gnutls_priority_set_direct(session, "NORMAL:+ECDHE-PSK:+DHE-PSK:+PSK", &err)
+ */
if (ret < 0) {
if (ret == GNUTLS_E_INVALID_REQUEST) {
fprintf(stderr, "Syntax error at: %s\n", err);
diff --git a/doc/examples/ex-serv-dtls.c b/doc/examples/ex-serv-dtls.c
index 23b51a1781..40b4f4728f 100644
--- a/doc/examples/ex-serv-dtls.c
+++ b/doc/examples/ex-serv-dtls.c
@@ -88,9 +88,14 @@ int main(void)
gnutls_certificate_set_known_dh_params(x509_cred, GNUTLS_SEC_PARAM_MEDIUM);
- gnutls_priority_init(&priority_cache,
- "PERFORMANCE:-VERS-TLS-ALL:+VERS-DTLS1.0:%SERVER_PRECEDENCE",
- NULL);
+ /* pre-3.6.3 equivalent:
+ * gnutls_priority_init(&priority_cache,
+ * "NORMAL:-VERS-TLS-ALL:+VERS-DTLS1.0:%SERVER_PRECEDENCE",
+ * NULL);
+ */
+ gnutls_priority_init2(&priority_cache,
+ "%SERVER_PRECEDENCE",
+ NULL, GNUTLS_PRIORITY_INIT_DEF_APPEND);
gnutls_key_generate(&cookie_key, GNUTLS_COOKIE_KEY_SIZE);
diff --git a/doc/examples/ex-serv-psk.c b/doc/examples/ex-serv-psk.c
index 26aad02f47..4c469819be 100644
--- a/doc/examples/ex-serv-psk.c
+++ b/doc/examples/ex-serv-psk.c
@@ -79,9 +79,14 @@ int main(void)
gnutls_psk_allocate_server_credentials(&psk_cred);
gnutls_psk_set_server_credentials_function(psk_cred, pskfunc);
- gnutls_priority_init(&priority_cache,
- "NORMAL:+PSK:+ECDHE-PSK:+DHE-PSK",
- NULL);
+ /* pre-3.6.3 equivalent:
+ * gnutls_priority_init(&priority_cache,
+ * "NORMAL:+PSK:+ECDHE-PSK:+DHE-PSK",
+ * NULL);
+ */
+ gnutls_priority_init2(&priority_cache,
+ "+ECDHE-PSK:+DHE-PSK:+PSK",
+ NULL, GNUTLS_PRIORITY_INIT_DEF_APPEND);
gnutls_certificate_set_known_dh_params(x509_cred, GNUTLS_SEC_PARAM_MEDIUM);
diff --git a/doc/examples/ex-serv-x509.c b/doc/examples/ex-serv-x509.c
index caf2a0c120..c2545a6688 100644
--- a/doc/examples/ex-serv-x509.c
+++ b/doc/examples/ex-serv-x509.c
@@ -77,11 +77,16 @@ int main(void)
OCSP_STATUS_FILE,
0));
- /* One could use specific priority strings such as "PERFORMANCE:%SERVER_PRECEDENCE"
- * especially if they are read from a configuration file; otherwise, it
- * is recommended to use the defaults as shown here. */
CHECK(gnutls_priority_init(&priority_cache, NULL, NULL));
+ /* Instead of the default options as shown above one could specify
+ * additional options such as server precedence in ciphersuite selection
+ * as follows:
+ * gnutls_priority_init2(&priority_cache,
+ * "%SERVER_PRECEDENCE",
+ * NULL, GNUTLS_PRIORITY_INIT_DEF_APPEND);
+ */
+
#if GNUTLS_VERSION_NUMBER >= 0x030506
/* only available since GnuTLS 3.5.6, on previous versions see
* gnutls_certificate_set_dh_params(). */
diff --git a/doc/manpages/Makefile.am b/doc/manpages/Makefile.am
index 7513e610e5..6a802077b0 100644
--- a/doc/manpages/Makefile.am
+++ b/doc/manpages/Makefile.am
@@ -566,6 +566,7 @@ APIMANS += gnutls_priority_ecc_curve_list.3
APIMANS += gnutls_priority_get_cipher_suite_index.3
APIMANS += gnutls_priority_group_list.3
APIMANS += gnutls_priority_init.3
+APIMANS += gnutls_priority_init2.3
APIMANS += gnutls_priority_kx_list.3
APIMANS += gnutls_priority_mac_list.3
APIMANS += gnutls_priority_protocol_list.3
@@ -746,6 +747,7 @@ APIMANS += gnutls_session_ticket_enable_server.3
APIMANS += gnutls_session_ticket_key_generate.3
APIMANS += gnutls_session_ticket_send.3
APIMANS += gnutls_set_default_priority.3
+APIMANS += gnutls_set_default_priority_append.3
APIMANS += gnutls_sign_algorithm_get.3
APIMANS += gnutls_sign_algorithm_get_client.3
APIMANS += gnutls_sign_algorithm_get_requested.3
diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in
index 7187e9df93..b675035f3e 100644
--- a/lib/includes/gnutls/gnutls.h.in
+++ b/lib/includes/gnutls/gnutls.h.in
@@ -1548,11 +1548,13 @@ int gnutls_alpn_set_protocols(gnutls_session_t session,
int gnutls_key_generate(gnutls_datum_t * key, unsigned int key_size);
-/* if you just want some defaults, use the following.
- */
+#define GNUTLS_PRIORITY_INIT_DEF_APPEND 1
int gnutls_priority_init(gnutls_priority_t * priority_cache,
const char *priorities, const char **err_pos);
+int gnutls_priority_init2(gnutls_priority_t * priority_cache,
+ const char *priorities, const char **err_pos,
+ unsigned flags);
void gnutls_priority_deinit(gnutls_priority_t priority_cache);
int gnutls_priority_get_cipher_suite_index(gnutls_priority_t pcache,
unsigned int idx,
@@ -1589,9 +1591,11 @@ int gnutls_priority_cipher_list(gnutls_priority_t pcache,
int gnutls_priority_mac_list(gnutls_priority_t pcache,
const unsigned int **list);
- /* for compatibility
- */
int gnutls_set_default_priority(gnutls_session_t session);
+int gnutls_set_default_priority_append(gnutls_session_t session,
+ const char *add_prio,
+ const char **err_pos,
+ unsigned flags);
/* Returns the name of a cipher suite */
const char *
diff --git a/lib/libgnutls.map b/lib/libgnutls.map
index 597ebc1ebd..91c44faf5f 100644
--- a/lib/libgnutls.map
+++ b/lib/libgnutls.map
@@ -1233,6 +1233,8 @@ GNUTLS_3_6_3
gnutls_privkey_import_gost_raw;
gnutls_x509_privkey_export_gost_raw;
gnutls_x509_privkey_import_gost_raw;
+ gnutls_set_default_priority_append;
+ gnutls_priority_init2;
} GNUTLS_3_6_2;
GNUTLS_FIPS140_3_4 {
diff --git a/lib/priority.c b/lib/priority.c
index cb162a12fe..4027042b33 100644
--- a/lib/priority.c
+++ b/lib/priority.c
@@ -1385,10 +1385,11 @@ static int set_ciphersuite_list(gnutls_priority_t priority_cache)
}
/**
- * gnutls_priority_init:
+ * gnutls_priority_init2:
* @priority_cache: is a #gnutls_prioritity_t type.
* @priorities: is a string describing priorities (may be %NULL)
* @err_pos: In case of an error this will have the position in the string the error occurred
+ * @flags: zero or %GNUTLS_PRIORITY_INIT_DEF_APPEND
*
* Sets priorities for the ciphers, key exchange methods, and macs.
* The @priority_cache should be deinitialized
@@ -1399,6 +1400,9 @@ static int set_ciphersuite_list(gnutls_priority_t priority_cache)
* Some keywords are defined to provide quick access
* to common preferences.
*
+ * When @flags is set to %GNUTLS_PRIORITY_INIT_DEF_APPEND then the @priorities
+ * specified will be appended to the default options.
+ *
* Unless there is a special need, use the "NORMAL" keyword to
* apply a reasonable security level, or "NORMAL:%%COMPAT" for compatibility.
*
@@ -1478,6 +1482,80 @@ static int set_ciphersuite_list(gnutls_priority_t priority_cache)
*
* Returns: On syntax error %GNUTLS_E_INVALID_REQUEST is returned,
* %GNUTLS_E_SUCCESS on success, or an error code.
+ *
+ * Since: 3.6.3
+ **/
+int
+gnutls_priority_init2(gnutls_priority_t * priority_cache,
+ const char *priorities, const char **err_pos,
+ unsigned flags)
+{
+ gnutls_buffer_st buf;
+ const char *ep;
+ int ret;
+
+ if (flags & GNUTLS_PRIORITY_INIT_DEF_APPEND) {
+ if (priorities == NULL)
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
+ if (err_pos)
+ *err_pos = priorities;
+
+ _gnutls_buffer_init(&buf);
+
+ ret = _gnutls_buffer_append_str(&buf, DEFAULT_PRIORITY_STRING);
+ if (ret < 0) {
+ _gnutls_buffer_clear(&buf);
+ return gnutls_assert_val(ret);
+ }
+
+ ret = _gnutls_buffer_append_str(&buf, ":");
+ if (ret < 0) {
+ _gnutls_buffer_clear(&buf);
+ return gnutls_assert_val(ret);
+ }
+
+ ret = _gnutls_buffer_append_str(&buf, priorities);
+ if (ret < 0) {
+ _gnutls_buffer_clear(&buf);
+ return gnutls_assert_val(ret);
+ }
+
+ ret = gnutls_priority_init(priority_cache, (const char*)buf.data, &ep);
+ if (ret < 0 && ep != (const char*)buf.data && ep != NULL) {
+ ptrdiff_t diff = (ptrdiff_t)ep-(ptrdiff_t)buf.data;
+ unsigned hlen = strlen(DEFAULT_PRIORITY_STRING)+1;
+
+ if (err_pos && diff > hlen) {
+ *err_pos = priorities + diff - hlen;
+ }
+ }
+ _gnutls_buffer_clear(&buf);
+ return ret;
+ } else {
+ return gnutls_priority_init(priority_cache, priorities, err_pos);
+ }
+}
+
+/**
+ * gnutls_priority_init:
+ * @priority_cache: is a #gnutls_prioritity_t type.
+ * @priorities: is a string describing priorities (may be %NULL)
+ * @err_pos: In case of an error this will have the position in the string the error occurred
+ *
+ * For applications that do not modify their crypto settings per release, consider
+ * using gnutls_priority_init2() with %GNUTLS_PRIORITY_INIT_DEF_APPEND flag
+ * instead. We suggest to use centralized crypto settings handled by the GnuTLS
+ * library, and applications modifying the default settings to their needs.
+ *
+ * This function is identical to gnutls_priority_init2() with zero
+ * flags.
+ *
+ * A %NULL @priorities string indicates the default priorities to be
+ * used (this is available since GnuTLS 3.3.0).
+ *
+ * Returns: On syntax error %GNUTLS_E_INVALID_REQUEST is returned,
+ * %GNUTLS_E_SUCCESS on success, or an error code.
**/
int
gnutls_priority_init(gnutls_priority_t * priority_cache,
@@ -1734,7 +1812,6 @@ gnutls_priority_init(gnutls_priority_t * priority_cache,
*priority_cache = NULL;
return ret;
-
}
/**
@@ -1778,7 +1855,7 @@ void gnutls_priority_deinit(gnutls_priority_t priority_cache)
* TLS session. For documentation check the gnutls_priority_init().
*
* To use a reasonable default, consider using gnutls_set_default_priority(),
- * instead of this function.
+ * or gnutls_set_default_priority_append() instead of this function.
*
* Returns: On syntax error %GNUTLS_E_INVALID_REQUEST is returned,
* %GNUTLS_E_SUCCESS on success, or an error code.
@@ -1849,6 +1926,9 @@ break_list(char *list,
* maximum compatibility consider calling gnutls_session_enable_compatibility_mode()
* after this function.
*
+ * For an application to specify additional options to priority string
+ * consider using gnutls_set_default_priority_append().
+ *
* To allow a user to override the defaults (e.g., when a user interface
* or configuration file is available), the functions
* gnutls_priority_set_direct() or gnutls_priority_set() can
@@ -1864,6 +1944,58 @@ int gnutls_set_default_priority(gnutls_session_t session)
}
/**
+ * gnutls_set_default_priority_append:
+ * @session: is a #gnutls_session_t type.
+ * @add_prio: is a string describing priorities to be appended to default
+ * @err_pos: In case of an error this will have the position in the string the error occurred
+ * @flags: must be zero
+ *
+ * Sets the default priority on the ciphers, key exchange methods,
+ * and macs with the additional options in @add_prio. This is the recommended method of
+ * setting the defaults when only few additional options are to be added. This promotes
+ * consistency between applications using GnuTLS, and allows GnuTLS using applications
+ * to update settings in par with the library.
+ *
+ * The @add_prio string should start as a normal priority string, e.g.,
+ * '-VERS-TLS-ALL:+VERS-TLS1.3:%%COMPAT' or '%%FORCE_ETM'. That is, it must not start
+ * with ':'.
+ *
+ * To allow a user to override the defaults (e.g., when a user interface
+ * or configuration file is available), the functions
+ * gnutls_priority_set_direct() or gnutls_priority_set() can
+ * be used.
+ *
+ * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
+ *
+ * Since: 3.6.3
+ **/
+int gnutls_set_default_priority_append(gnutls_session_t session,
+ const char *add_prio,
+ const char **err_pos,
+ unsigned flags)
+{
+ gnutls_priority_t prio;
+ int ret;
+
+ ret = gnutls_priority_init2(&prio, add_prio, err_pos, GNUTLS_PRIORITY_INIT_DEF_APPEND);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ ret = gnutls_priority_set(session, prio);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ /* ensure that the session holds the only reference for the struct */
+ gnutls_priority_deinit(prio);
+
+ return 0;
+}
+
+/**
* gnutls_priority_ecc_curve_list:
* @pcache: is a #gnutls_prioritity_t type.
* @list: will point to an integer list
diff --git a/symbols.last b/symbols.last
index cadbd97014..cf609caf43 100644
--- a/symbols.last
+++ b/symbols.last
@@ -544,6 +544,7 @@ gnutls_priority_deinit@GNUTLS_3_4
gnutls_priority_ecc_curve_list@GNUTLS_3_4
gnutls_priority_get_cipher_suite_index@GNUTLS_3_4
gnutls_priority_group_list@GNUTLS_3_6_0
+gnutls_priority_init2@GNUTLS_3_6_3
gnutls_priority_init@GNUTLS_3_4
gnutls_priority_kx_list@GNUTLS_3_4
gnutls_priority_mac_list@GNUTLS_3_4
@@ -726,6 +727,7 @@ gnutls_session_ticket_enable_server@GNUTLS_3_4
gnutls_session_ticket_key_generate@GNUTLS_3_4
gnutls_session_ticket_send@GNUTLS_3_6_3
gnutls_set_default_priority@GNUTLS_3_4
+gnutls_set_default_priority_append@GNUTLS_3_6_3
gnutls_sign_algorithm_get@GNUTLS_3_4
gnutls_sign_algorithm_get_client@GNUTLS_3_4
gnutls_sign_algorithm_get_requested@GNUTLS_3_4
diff --git a/tests/Makefile.am b/tests/Makefile.am
index a8e72b6051..c12887d4eb 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -161,11 +161,11 @@ ctests += mini-record-2 simple gnutls_hmac_fast set_pkcs12_cred cert certuniquei
tls13-cert-key-exchange x509-cert-callback-ocsp gnutls_ocsp_resp_list_import2 \
server-sign-md5-rep privkey-keygen mini-tls-nonblock no-signal pkcs7-gen dtls-etm \
x509sign-verify-rsa x509sign-verify-ecdsa x509sign-verify-gost \
- mini-alignment oids atfork prf psk-file \
+ mini-alignment oids atfork prf psk-file priority-init2 \
status-request status-request-ok status-request-missing sign-verify-ext \
fallback-scsv pkcs8-key-decode urls dtls-rehandshake-cert \
key-usage-rsa key-usage-ecdhe-rsa mini-session-verify-function auto-verify \
- record-timeouts mini-dtls-hello-verify-48 mini-x509-default-prio \
+ record-timeouts mini-dtls-hello-verify-48 set-default-prio \
tls12-anon-upgrade global-init-override tlsext-decoding rsa-psk-cb \
rehandshake-switch-cert rehandshake-switch-cert-allow rehandshake-switch-cert-client \
rehandshake-switch-cert-client-allow handshake-versions dtls-handshake-versions \
diff --git a/tests/priority-init2.c b/tests/priority-init2.c
new file mode 100644
index 0000000000..850a6d9bdf
--- /dev/null
+++ b/tests/priority-init2.c
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2008-2012 Free Software Foundation, Inc.
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Author: Simon Josefsson, Nikos Mavrogiannopoulos
+ *
+ * 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 <http://www.gnu.org/licenses/>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <gnutls/gnutls.h>
+#include "utils.h"
+#include "eagain-common.h"
+#include "cert-common.h"
+
+const char *side;
+
+static void tls_log_func(int level, const char *str)
+{
+ fprintf(stderr, "%s|<%d>| %s", side, level, str);
+}
+
+struct test_st {
+ const char *name;
+ const char *add_prio;
+ int exp_err;
+ int exp_etm;
+ unsigned err_pos;
+ unsigned exp_vers;
+};
+
+static void start(struct test_st *test)
+{
+ int ret;
+ /* Server stuff. */
+ gnutls_priority_t cache;
+ gnutls_certificate_credentials_t serverx509cred;
+ gnutls_session_t server;
+ int sret = GNUTLS_E_AGAIN;
+ /* Client stuff. */
+ gnutls_certificate_credentials_t clientx509cred;
+ gnutls_session_t client;
+ const char *ep;
+ int cret = GNUTLS_E_AGAIN;
+
+ if (test == NULL)
+ success("running gnutls_set_default_priority test\n");
+ else
+ success("running %s\n", test->name);
+
+ /* General init. */
+ global_init();
+ gnutls_global_set_log_function(tls_log_func);
+ if (debug)
+ gnutls_global_set_log_level(6);
+
+ assert(gnutls_certificate_allocate_credentials(&serverx509cred)>=0);
+ assert(gnutls_certificate_set_x509_key_mem(serverx509cred,
+ &server_cert, &server_key,
+ GNUTLS_X509_FMT_PEM)>=0);
+
+ assert(gnutls_init(&server, GNUTLS_SERVER) >= 0);
+ gnutls_credentials_set(server, GNUTLS_CRD_CERTIFICATE,
+ serverx509cred);
+ if (test == NULL)
+ ret = gnutls_priority_init(&cache, NULL, NULL);
+ else
+ ret = gnutls_priority_init2(&cache, test->add_prio, &ep, GNUTLS_PRIORITY_INIT_DEF_APPEND);
+ if (ret < 0) {
+ if (test->exp_err == ret) {
+ if (ep-test->add_prio != test->err_pos) {
+ fprintf(stderr, "diff: %d\n", (int)(ep-test->add_prio));
+ fail("error expected error on different position[%d]: %s\n",
+ test->err_pos, test->add_prio);
+ }
+ goto cleanup;
+ }
+ fail("error: %s\n", gnutls_strerror(ret));
+ }
+ gnutls_priority_set(server, cache);
+
+ gnutls_transport_set_push_function(server, server_push);
+ gnutls_transport_set_pull_function(server, server_pull);
+ gnutls_transport_set_ptr(server, server);
+
+ /* Init client */
+ ret = gnutls_certificate_allocate_credentials(&clientx509cred);
+ if (ret < 0)
+ exit(1);
+
+ ret = gnutls_certificate_set_x509_trust_mem(clientx509cred, &ca_cert, GNUTLS_X509_FMT_PEM);
+ if (ret < 0)
+ exit(1);
+
+ ret = gnutls_init(&client, GNUTLS_CLIENT);
+ if (ret < 0)
+ exit(1);
+
+ ret = gnutls_credentials_set(client, GNUTLS_CRD_CERTIFICATE,
+ clientx509cred);
+ if (ret < 0)
+ exit(1);
+
+ ret = gnutls_set_default_priority(client);
+ if (ret < 0)
+ exit(1);
+
+ gnutls_transport_set_push_function(client, client_push);
+ gnutls_transport_set_pull_function(client, client_pull);
+ gnutls_transport_set_ptr(client, client);
+
+ HANDSHAKE(client, server);
+
+ /* check gnutls_certificate_get_ours() - client side */
+ {
+ const gnutls_datum_t *mcert;
+
+ mcert = gnutls_certificate_get_ours(client);
+ if (mcert != NULL) {
+ fail("gnutls_certificate_get_ours(): failed\n");
+ exit(1);
+ }
+ }
+
+ if (test && test->exp_vers != 0) {
+ if (test->exp_vers != gnutls_protocol_get_version(server)) {
+ fail("expected version %s, got %s\n",
+ gnutls_protocol_get_name(test->exp_vers),
+ gnutls_protocol_get_name(gnutls_protocol_get_version(server)));
+ }
+ }
+
+ /* check the number of certificates received */
+ {
+ unsigned cert_list_size = 0;
+ gnutls_typed_vdata_st data[2];
+ unsigned status;
+
+ memset(data, 0, sizeof(data));
+
+ data[0].type = GNUTLS_DT_DNS_HOSTNAME;
+ data[0].data = (void*)"localhost1";
+
+ data[1].type = GNUTLS_DT_KEY_PURPOSE_OID;
+ data[1].data = (void*)GNUTLS_KP_TLS_WWW_SERVER;
+
+ gnutls_certificate_get_peers(client, &cert_list_size);
+ if (cert_list_size < 2) {
+ fprintf(stderr, "received a certificate list of %d!\n", cert_list_size);
+ exit(1);
+ }
+
+ ret = gnutls_certificate_verify_peers(client, data, 2, &status);
+ if (ret < 0) {
+ fprintf(stderr, "could not verify certificate: %s\n", gnutls_strerror(ret));
+ exit(1);
+ }
+
+ if (status == 0) {
+ fprintf(stderr, "should not have accepted!\n");
+ exit(1);
+ }
+
+ data[0].type = GNUTLS_DT_DNS_HOSTNAME;
+ data[0].data = (void*)"localhost";
+
+ ret = gnutls_certificate_verify_peers(client, data, 2, &status);
+ if (ret < 0) {
+ fprintf(stderr, "could not verify certificate: %s\n", gnutls_strerror(ret));
+ exit(1);
+ }
+
+ if (status != 0) {
+ fprintf(stderr, "could not verify certificate: %.4x\n", status);
+ exit(1);
+ }
+ }
+
+ if (test && test->exp_etm) {
+ ret = gnutls_session_ext_master_secret_status(client);
+ if (ret != 1) {
+ fprintf(stderr, "Extended master secret wasn't negotiated by default (client ret: %d)\n", ret);
+ exit(1);
+ }
+
+ ret = gnutls_session_ext_master_secret_status(server);
+ if (ret != 1) {
+ fprintf(stderr, "Extended master secret wasn't negotiated by default (server ret: %d)\n", ret);
+ exit(1);
+ }
+ }
+
+ gnutls_bye(client, GNUTLS_SHUT_RDWR);
+ gnutls_bye(server, GNUTLS_SHUT_RDWR);
+
+ gnutls_deinit(client);
+ gnutls_certificate_free_credentials(clientx509cred);
+ cleanup:
+ gnutls_priority_deinit(cache);
+ gnutls_deinit(server);
+
+ gnutls_certificate_free_credentials(serverx509cred);
+
+ gnutls_global_deinit();
+ reset_buffers();
+}
+
+struct test_st tests[] = {
+ {
+ .name = "additional flag",
+ .add_prio = "%FORCE_ETM",
+ .exp_err = 0
+ },
+ {
+ .name = "additional flag typo1",
+ .add_prio = ":%FORCE_ETM",
+ .exp_err = GNUTLS_E_INVALID_REQUEST,
+ .err_pos = 0
+ },
+ {
+ .name = "additional flag typo2",
+ .add_prio = "%FORCE_ETM::%NO_TICKETS",
+ .exp_err = GNUTLS_E_INVALID_REQUEST,
+ .err_pos = 11
+ },
+ {
+ .name = "additional flag typo3",
+ .add_prio = "%FORCE_ETM:%%NO_TICKETS",
+ .exp_err = GNUTLS_E_INVALID_REQUEST,
+ .err_pos = 11
+ },
+ {
+ .name = "additional flag for version (functional)",
+ .add_prio = "-VERS-ALL:+VERS-TLS1.1",
+ .exp_etm = 1,
+ .exp_err = 0,
+ .exp_vers = GNUTLS_TLS1_1
+ }
+};
+
+
+void doit(void)
+{
+ start(NULL);
+ for (unsigned i=0;i<sizeof(tests)/sizeof(tests[0]);i++) {
+ start(&tests[i]);
+ }
+}
diff --git a/tests/set-default-prio.c b/tests/set-default-prio.c
new file mode 100644
index 0000000000..48e8bf19ae
--- /dev/null
+++ b/tests/set-default-prio.c
@@ -0,0 +1,266 @@
+/*
+ * Copyright (C) 2008-2012 Free Software Foundation, Inc.
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Author: Simon Josefsson, Nikos Mavrogiannopoulos
+ *
+ * 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 <http://www.gnu.org/licenses/>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <gnutls/gnutls.h>
+#include "utils.h"
+#include "eagain-common.h"
+#include "cert-common.h"
+
+const char *side;
+
+static void tls_log_func(int level, const char *str)
+{
+ fprintf(stderr, "%s|<%d>| %s", side, level, str);
+}
+
+struct test_st {
+ const char *name;
+ const char *add_prio;
+ int exp_err;
+ unsigned err_pos;
+ unsigned exp_vers;
+ int exp_etm;
+};
+
+static void start(struct test_st *test)
+{
+ int ret;
+ /* Server stuff. */
+ gnutls_certificate_credentials_t serverx509cred;
+ gnutls_session_t server;
+ int sret = GNUTLS_E_AGAIN;
+ /* Client stuff. */
+ gnutls_certificate_credentials_t clientx509cred;
+ gnutls_session_t client;
+ const char *ep;
+ int cret = GNUTLS_E_AGAIN;
+
+ if (test == NULL)
+ success("running gnutls_set_default_priority test\n");
+ else
+ success("running %s\n", test->name);
+
+ /* General init. */
+ global_init();
+ gnutls_global_set_log_function(tls_log_func);
+ if (debug)
+ gnutls_global_set_log_level(6);
+
+ assert(gnutls_certificate_allocate_credentials(&serverx509cred)>=0);
+ assert(gnutls_certificate_set_x509_key_mem(serverx509cred,
+ &server_cert, &server_key,
+ GNUTLS_X509_FMT_PEM)>=0);
+
+ assert(gnutls_init(&server, GNUTLS_SERVER) >= 0);
+ gnutls_credentials_set(server, GNUTLS_CRD_CERTIFICATE,
+ serverx509cred);
+ if (test == NULL)
+ ret = gnutls_set_default_priority(server);
+ else
+ ret = gnutls_set_default_priority_append(server, test->add_prio, &ep, 0);
+ if (ret < 0) {
+ if (test->exp_err == ret) {
+ if (ep-test->add_prio != test->err_pos) {
+ fprintf(stderr, "diff: %d\n", (int)(ep-test->add_prio));
+ fail("error expected error on different position[%d]: %s\n",
+ test->err_pos, test->add_prio);
+ }
+ goto cleanup;
+ }
+ fail("error: %s\n", gnutls_strerror(ret));
+ }
+
+ gnutls_transport_set_push_function(server, server_push);
+ gnutls_transport_set_pull_function(server, server_pull);
+ gnutls_transport_set_ptr(server, server);
+
+ /* Init client */
+ ret = gnutls_certificate_allocate_credentials(&clientx509cred);
+ if (ret < 0)
+ exit(1);
+
+ ret = gnutls_certificate_set_x509_trust_mem(clientx509cred, &ca_cert, GNUTLS_X509_FMT_PEM);
+ if (ret < 0)
+ exit(1);
+
+ ret = gnutls_init(&client, GNUTLS_CLIENT);
+ if (ret < 0)
+ exit(1);
+
+ ret = gnutls_credentials_set(client, GNUTLS_CRD_CERTIFICATE,
+ clientx509cred);
+ if (ret < 0)
+ exit(1);
+
+ ret = gnutls_set_default_priority(client);
+ if (ret < 0)
+ exit(1);
+
+ gnutls_transport_set_push_function(client, client_push);
+ gnutls_transport_set_pull_function(client, client_pull);
+ gnutls_transport_set_ptr(client, client);
+
+ HANDSHAKE(client, server);
+
+ /* check gnutls_certificate_get_ours() - client side */
+ {
+ const gnutls_datum_t *mcert;
+
+ mcert = gnutls_certificate_get_ours(client);
+ if (mcert != NULL) {
+ fail("gnutls_certificate_get_ours(): failed\n");
+ exit(1);
+ }
+ }
+
+ if (test && test->exp_vers != 0) {
+ if (test->exp_vers != gnutls_protocol_get_version(server)) {
+ fail("expected version %s, got %s\n",
+ gnutls_protocol_get_name(test->exp_vers),
+ gnutls_protocol_get_name(gnutls_protocol_get_version(server)));
+ }
+ }
+
+ /* check the number of certificates received */
+ {
+ unsigned cert_list_size = 0;
+ gnutls_typed_vdata_st data[2];
+ unsigned status;
+
+ memset(data, 0, sizeof(data));
+
+ data[0].type = GNUTLS_DT_DNS_HOSTNAME;
+ data[0].data = (void*)"localhost1";
+
+ data[1].type = GNUTLS_DT_KEY_PURPOSE_OID;
+ data[1].data = (void*)GNUTLS_KP_TLS_WWW_SERVER;
+
+ gnutls_certificate_get_peers(client, &cert_list_size);
+ if (cert_list_size < 2) {
+ fprintf(stderr, "received a certificate list of %d!\n", cert_list_size);
+ exit(1);
+ }
+
+ ret = gnutls_certificate_verify_peers(client, data, 2, &status);
+ if (ret < 0) {
+ fprintf(stderr, "could not verify certificate: %s\n", gnutls_strerror(ret));
+ exit(1);
+ }
+
+ if (status == 0) {
+ fprintf(stderr, "should not have accepted!\n");
+ exit(1);
+ }
+
+ data[0].type = GNUTLS_DT_DNS_HOSTNAME;
+ data[0].data = (void*)"localhost";
+
+ ret = gnutls_certificate_verify_peers(client, data, 2, &status);
+ if (ret < 0) {
+ fprintf(stderr, "could not verify certificate: %s\n", gnutls_strerror(ret));
+ exit(1);
+ }
+
+ if (status != 0) {
+ fprintf(stderr, "could not verify certificate: %.4x\n", status);
+ exit(1);
+ }
+ }
+
+ if (test && test->exp_etm) {
+ ret = gnutls_session_ext_master_secret_status(client);
+ if (ret != 1) {
+ fprintf(stderr, "Extended master secret wasn't negotiated by default (client ret: %d)\n", ret);
+ exit(1);
+ }
+
+ ret = gnutls_session_ext_master_secret_status(server);
+ if (ret != 1) {
+ fprintf(stderr, "Extended master secret wasn't negotiated by default (server ret: %d)\n", ret);
+ exit(1);
+ }
+ }
+
+ gnutls_bye(client, GNUTLS_SHUT_RDWR);
+ gnutls_bye(server, GNUTLS_SHUT_RDWR);
+
+ gnutls_deinit(client);
+ gnutls_certificate_free_credentials(clientx509cred);
+ cleanup:
+ gnutls_deinit(server);
+
+ gnutls_certificate_free_credentials(serverx509cred);
+
+ gnutls_global_deinit();
+ reset_buffers();
+}
+
+struct test_st tests[] = {
+ {
+ .name = "additional flag",
+ .add_prio = "%FORCE_ETM",
+ .exp_err = 0
+ },
+ {
+ .name = "additional flag typo1",
+ .add_prio = ":%FORCE_ETM",
+ .exp_err = GNUTLS_E_INVALID_REQUEST,
+ .err_pos = 0
+ },
+ {
+ .name = "additional flag typo2",
+ .add_prio = "%FORCE_ETM::%NO_TICKETS",
+ .exp_err = GNUTLS_E_INVALID_REQUEST,
+ .err_pos = 11
+ },
+ {
+ .name = "additional flag typo3",
+ .add_prio = "%FORCE_ETM:%%NO_TICKETS",
+ .exp_err = GNUTLS_E_INVALID_REQUEST,
+ .err_pos = 11
+ },
+ {
+ .name = "additional flag for version (functional)",
+ .add_prio = "-VERS-ALL:+VERS-TLS1.1",
+ .exp_err = 0,
+ .exp_etm = 1,
+ .exp_vers = GNUTLS_TLS1_1
+ }
+};
+
+
+void doit(void)
+{
+ start(NULL);
+ for (unsigned i=0;i<sizeof(tests)/sizeof(tests[0]);i++) {
+ start(&tests[i]);
+ }
+}