diff options
author | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2018-07-09 17:09:11 +0000 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2018-07-09 17:09:11 +0000 |
commit | 596536f12db974e0668effdc5bf3ef6f673c8f54 (patch) | |
tree | 8782e1bb2f0ba4bfc2c39fb709df10262d44d17a | |
parent | 7be78eba6dc33c3ed0787f806c71d75b7c9fe4de (diff) | |
parent | f83156ba49b6b918790dad0452dc7189647cf5e9 (diff) | |
download | gnutls-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.am | 4 | ||||
-rw-r--r-- | doc/cha-gtls-app.texi | 7 | ||||
-rw-r--r-- | doc/examples/ex-client-psk.c | 16 | ||||
-rw-r--r-- | doc/examples/ex-serv-dtls.c | 11 | ||||
-rw-r--r-- | doc/examples/ex-serv-psk.c | 11 | ||||
-rw-r--r-- | doc/examples/ex-serv-x509.c | 11 | ||||
-rw-r--r-- | doc/manpages/Makefile.am | 2 | ||||
-rw-r--r-- | lib/includes/gnutls/gnutls.h.in | 12 | ||||
-rw-r--r-- | lib/libgnutls.map | 2 | ||||
-rw-r--r-- | lib/priority.c | 138 | ||||
-rw-r--r-- | symbols.last | 2 | ||||
-rw-r--r-- | tests/Makefile.am | 4 | ||||
-rw-r--r-- | tests/priority-init2.c | 269 | ||||
-rw-r--r-- | tests/set-default-prio.c | 266 |
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]); + } +} |