139beb93cSSam Leffler /*
2e28a4053SRui Paulo * SSL/TLS interface functions for GnuTLS
385732ac8SCy Schubert * Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi>
439beb93cSSam Leffler *
5f05cddf9SRui Paulo * This software may be distributed under the terms of the BSD license.
6f05cddf9SRui Paulo * See README for more details.
739beb93cSSam Leffler */
839beb93cSSam Leffler
939beb93cSSam Leffler #include "includes.h"
1039beb93cSSam Leffler #include <gnutls/gnutls.h>
1139beb93cSSam Leffler #include <gnutls/x509.h>
1239beb93cSSam Leffler #ifdef PKCS12_FUNCS
1339beb93cSSam Leffler #include <gnutls/pkcs12.h>
1439beb93cSSam Leffler #endif /* PKCS12_FUNCS */
155b9c547cSRui Paulo #if GNUTLS_VERSION_NUMBER >= 0x030103
165b9c547cSRui Paulo #include <gnutls/ocsp.h>
175b9c547cSRui Paulo #endif /* 3.1.3 */
1839beb93cSSam Leffler
1939beb93cSSam Leffler #include "common.h"
205b9c547cSRui Paulo #include "crypto/crypto.h"
2139beb93cSSam Leffler #include "tls.h"
2239beb93cSSam Leffler
2339beb93cSSam Leffler
2439beb93cSSam Leffler static int tls_gnutls_ref_count = 0;
2539beb93cSSam Leffler
2639beb93cSSam Leffler struct tls_global {
2739beb93cSSam Leffler /* Data for session resumption */
2839beb93cSSam Leffler void *session_data;
2939beb93cSSam Leffler size_t session_data_size;
3039beb93cSSam Leffler
3139beb93cSSam Leffler int server;
3239beb93cSSam Leffler
3339beb93cSSam Leffler int params_set;
3439beb93cSSam Leffler gnutls_certificate_credentials_t xcred;
355b9c547cSRui Paulo
365b9c547cSRui Paulo void (*event_cb)(void *ctx, enum tls_event ev,
375b9c547cSRui Paulo union tls_event_data *data);
385b9c547cSRui Paulo void *cb_ctx;
395b9c547cSRui Paulo int cert_in_cb;
40780fb4a2SCy Schubert
41780fb4a2SCy Schubert char *ocsp_stapling_response;
4239beb93cSSam Leffler };
4339beb93cSSam Leffler
4439beb93cSSam Leffler struct tls_connection {
455b9c547cSRui Paulo struct tls_global *global;
465b9c547cSRui Paulo gnutls_session_t session;
4739beb93cSSam Leffler int read_alerts, write_alerts, failed;
4839beb93cSSam Leffler
4939beb93cSSam Leffler u8 *pre_shared_secret;
5039beb93cSSam Leffler size_t pre_shared_secret_len;
5139beb93cSSam Leffler int established;
5239beb93cSSam Leffler int verify_peer;
535b9c547cSRui Paulo unsigned int disable_time_checks:1;
5439beb93cSSam Leffler
55e28a4053SRui Paulo struct wpabuf *push_buf;
56e28a4053SRui Paulo struct wpabuf *pull_buf;
57e28a4053SRui Paulo const u8 *pull_buf_offset;
5839beb93cSSam Leffler
5939beb93cSSam Leffler int params_set;
6039beb93cSSam Leffler gnutls_certificate_credentials_t xcred;
615b9c547cSRui Paulo
625b9c547cSRui Paulo char *suffix_match;
635b9c547cSRui Paulo char *domain_match;
645b9c547cSRui Paulo unsigned int flags;
6539beb93cSSam Leffler };
6639beb93cSSam Leffler
6739beb93cSSam Leffler
685b9c547cSRui Paulo static int tls_connection_verify_peer(gnutls_session_t session);
695b9c547cSRui Paulo
705b9c547cSRui Paulo
tls_log_func(int level,const char * msg)7139beb93cSSam Leffler static void tls_log_func(int level, const char *msg)
7239beb93cSSam Leffler {
7339beb93cSSam Leffler char *s, *pos;
7439beb93cSSam Leffler if (level == 6 || level == 7) {
7539beb93cSSam Leffler /* These levels seem to be mostly I/O debug and msg dumps */
7639beb93cSSam Leffler return;
7739beb93cSSam Leffler }
7839beb93cSSam Leffler
7939beb93cSSam Leffler s = os_strdup(msg);
8039beb93cSSam Leffler if (s == NULL)
8139beb93cSSam Leffler return;
8239beb93cSSam Leffler
8339beb93cSSam Leffler pos = s;
8439beb93cSSam Leffler while (*pos != '\0') {
8539beb93cSSam Leffler if (*pos == '\n') {
8639beb93cSSam Leffler *pos = '\0';
8739beb93cSSam Leffler break;
8839beb93cSSam Leffler }
8939beb93cSSam Leffler pos++;
9039beb93cSSam Leffler }
9139beb93cSSam Leffler wpa_printf(level > 3 ? MSG_MSGDUMP : MSG_DEBUG,
9239beb93cSSam Leffler "gnutls<%d> %s", level, s);
9339beb93cSSam Leffler os_free(s);
9439beb93cSSam Leffler }
9539beb93cSSam Leffler
9639beb93cSSam Leffler
tls_init(const struct tls_config * conf)9739beb93cSSam Leffler void * tls_init(const struct tls_config *conf)
9839beb93cSSam Leffler {
9939beb93cSSam Leffler struct tls_global *global;
10039beb93cSSam Leffler
1015b9c547cSRui Paulo if (tls_gnutls_ref_count == 0) {
1025b9c547cSRui Paulo wpa_printf(MSG_DEBUG,
1035b9c547cSRui Paulo "GnuTLS: Library version %s (runtime) - %s (build)",
1045b9c547cSRui Paulo gnutls_check_version(NULL), GNUTLS_VERSION);
1055b9c547cSRui Paulo }
10639beb93cSSam Leffler
10739beb93cSSam Leffler global = os_zalloc(sizeof(*global));
10839beb93cSSam Leffler if (global == NULL)
10939beb93cSSam Leffler return NULL;
11039beb93cSSam Leffler
11139beb93cSSam Leffler if (tls_gnutls_ref_count == 0 && gnutls_global_init() < 0) {
11239beb93cSSam Leffler os_free(global);
11339beb93cSSam Leffler return NULL;
11439beb93cSSam Leffler }
11539beb93cSSam Leffler tls_gnutls_ref_count++;
11639beb93cSSam Leffler
11739beb93cSSam Leffler gnutls_global_set_log_function(tls_log_func);
11839beb93cSSam Leffler if (wpa_debug_show_keys)
11939beb93cSSam Leffler gnutls_global_set_log_level(11);
1205b9c547cSRui Paulo
1215b9c547cSRui Paulo if (conf) {
1225b9c547cSRui Paulo global->event_cb = conf->event_cb;
1235b9c547cSRui Paulo global->cb_ctx = conf->cb_ctx;
1245b9c547cSRui Paulo global->cert_in_cb = conf->cert_in_cb;
1255b9c547cSRui Paulo }
1265b9c547cSRui Paulo
12739beb93cSSam Leffler return global;
12839beb93cSSam Leffler }
12939beb93cSSam Leffler
13039beb93cSSam Leffler
tls_deinit(void * ssl_ctx)13139beb93cSSam Leffler void tls_deinit(void *ssl_ctx)
13239beb93cSSam Leffler {
13339beb93cSSam Leffler struct tls_global *global = ssl_ctx;
13439beb93cSSam Leffler if (global) {
13539beb93cSSam Leffler if (global->params_set)
13639beb93cSSam Leffler gnutls_certificate_free_credentials(global->xcred);
13739beb93cSSam Leffler os_free(global->session_data);
138780fb4a2SCy Schubert os_free(global->ocsp_stapling_response);
13939beb93cSSam Leffler os_free(global);
14039beb93cSSam Leffler }
14139beb93cSSam Leffler
14239beb93cSSam Leffler tls_gnutls_ref_count--;
14339beb93cSSam Leffler if (tls_gnutls_ref_count == 0)
14439beb93cSSam Leffler gnutls_global_deinit();
14539beb93cSSam Leffler }
14639beb93cSSam Leffler
14739beb93cSSam Leffler
tls_get_errors(void * ssl_ctx)14839beb93cSSam Leffler int tls_get_errors(void *ssl_ctx)
14939beb93cSSam Leffler {
15039beb93cSSam Leffler return 0;
15139beb93cSSam Leffler }
15239beb93cSSam Leffler
15339beb93cSSam Leffler
tls_pull_func(gnutls_transport_ptr_t ptr,void * buf,size_t len)1545b9c547cSRui Paulo static ssize_t tls_pull_func(gnutls_transport_ptr_t ptr, void *buf,
15539beb93cSSam Leffler size_t len)
15639beb93cSSam Leffler {
15739beb93cSSam Leffler struct tls_connection *conn = (struct tls_connection *) ptr;
158e28a4053SRui Paulo const u8 *end;
15939beb93cSSam Leffler if (conn->pull_buf == NULL) {
16039beb93cSSam Leffler errno = EWOULDBLOCK;
16139beb93cSSam Leffler return -1;
16239beb93cSSam Leffler }
16339beb93cSSam Leffler
164e28a4053SRui Paulo end = wpabuf_head_u8(conn->pull_buf) + wpabuf_len(conn->pull_buf);
16539beb93cSSam Leffler if ((size_t) (end - conn->pull_buf_offset) < len)
16639beb93cSSam Leffler len = end - conn->pull_buf_offset;
16739beb93cSSam Leffler os_memcpy(buf, conn->pull_buf_offset, len);
16839beb93cSSam Leffler conn->pull_buf_offset += len;
16939beb93cSSam Leffler if (conn->pull_buf_offset == end) {
17039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "%s - pull_buf consumed", __func__);
171e28a4053SRui Paulo wpabuf_free(conn->pull_buf);
172e28a4053SRui Paulo conn->pull_buf = NULL;
173e28a4053SRui Paulo conn->pull_buf_offset = NULL;
17439beb93cSSam Leffler } else {
17539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in pull_buf",
17639beb93cSSam Leffler __func__,
17739beb93cSSam Leffler (unsigned long) (end - conn->pull_buf_offset));
17839beb93cSSam Leffler }
17939beb93cSSam Leffler return len;
18039beb93cSSam Leffler }
18139beb93cSSam Leffler
18239beb93cSSam Leffler
tls_push_func(gnutls_transport_ptr_t ptr,const void * buf,size_t len)1835b9c547cSRui Paulo static ssize_t tls_push_func(gnutls_transport_ptr_t ptr, const void *buf,
18439beb93cSSam Leffler size_t len)
18539beb93cSSam Leffler {
18639beb93cSSam Leffler struct tls_connection *conn = (struct tls_connection *) ptr;
18739beb93cSSam Leffler
188e28a4053SRui Paulo if (wpabuf_resize(&conn->push_buf, len) < 0) {
18939beb93cSSam Leffler errno = ENOMEM;
19039beb93cSSam Leffler return -1;
19139beb93cSSam Leffler }
192e28a4053SRui Paulo wpabuf_put_data(conn->push_buf, buf, len);
19339beb93cSSam Leffler
19439beb93cSSam Leffler return len;
19539beb93cSSam Leffler }
19639beb93cSSam Leffler
19739beb93cSSam Leffler
tls_gnutls_init_session(struct tls_global * global,struct tls_connection * conn)19839beb93cSSam Leffler static int tls_gnutls_init_session(struct tls_global *global,
19939beb93cSSam Leffler struct tls_connection *conn)
20039beb93cSSam Leffler {
201f05cddf9SRui Paulo const char *err;
20239beb93cSSam Leffler int ret;
20339beb93cSSam Leffler
20439beb93cSSam Leffler ret = gnutls_init(&conn->session,
20539beb93cSSam Leffler global->server ? GNUTLS_SERVER : GNUTLS_CLIENT);
20639beb93cSSam Leffler if (ret < 0) {
20739beb93cSSam Leffler wpa_printf(MSG_INFO, "TLS: Failed to initialize new TLS "
20839beb93cSSam Leffler "connection: %s", gnutls_strerror(ret));
20939beb93cSSam Leffler return -1;
21039beb93cSSam Leffler }
21139beb93cSSam Leffler
21239beb93cSSam Leffler ret = gnutls_set_default_priority(conn->session);
21339beb93cSSam Leffler if (ret < 0)
21439beb93cSSam Leffler goto fail;
21539beb93cSSam Leffler
216f05cddf9SRui Paulo ret = gnutls_priority_set_direct(conn->session, "NORMAL:-VERS-SSL3.0",
217f05cddf9SRui Paulo &err);
218f05cddf9SRui Paulo if (ret < 0) {
219f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "GnuTLS: Priority string failure at "
220f05cddf9SRui Paulo "'%s'", err);
221f05cddf9SRui Paulo goto fail;
222f05cddf9SRui Paulo }
22339beb93cSSam Leffler
22439beb93cSSam Leffler gnutls_transport_set_pull_function(conn->session, tls_pull_func);
22539beb93cSSam Leffler gnutls_transport_set_push_function(conn->session, tls_push_func);
2265b9c547cSRui Paulo gnutls_transport_set_ptr(conn->session, (gnutls_transport_ptr_t) conn);
2275b9c547cSRui Paulo gnutls_session_set_ptr(conn->session, conn);
22839beb93cSSam Leffler
22939beb93cSSam Leffler return 0;
23039beb93cSSam Leffler
23139beb93cSSam Leffler fail:
23239beb93cSSam Leffler wpa_printf(MSG_INFO, "TLS: Failed to setup new TLS connection: %s",
23339beb93cSSam Leffler gnutls_strerror(ret));
23439beb93cSSam Leffler gnutls_deinit(conn->session);
23539beb93cSSam Leffler return -1;
23639beb93cSSam Leffler }
23739beb93cSSam Leffler
23839beb93cSSam Leffler
tls_connection_init(void * ssl_ctx)23939beb93cSSam Leffler struct tls_connection * tls_connection_init(void *ssl_ctx)
24039beb93cSSam Leffler {
24139beb93cSSam Leffler struct tls_global *global = ssl_ctx;
24239beb93cSSam Leffler struct tls_connection *conn;
24339beb93cSSam Leffler int ret;
24439beb93cSSam Leffler
24539beb93cSSam Leffler conn = os_zalloc(sizeof(*conn));
24639beb93cSSam Leffler if (conn == NULL)
24739beb93cSSam Leffler return NULL;
2485b9c547cSRui Paulo conn->global = global;
24939beb93cSSam Leffler
25039beb93cSSam Leffler if (tls_gnutls_init_session(global, conn)) {
25139beb93cSSam Leffler os_free(conn);
25239beb93cSSam Leffler return NULL;
25339beb93cSSam Leffler }
25439beb93cSSam Leffler
25539beb93cSSam Leffler if (global->params_set) {
25639beb93cSSam Leffler ret = gnutls_credentials_set(conn->session,
25739beb93cSSam Leffler GNUTLS_CRD_CERTIFICATE,
25839beb93cSSam Leffler global->xcred);
25939beb93cSSam Leffler if (ret < 0) {
26039beb93cSSam Leffler wpa_printf(MSG_INFO, "Failed to configure "
26139beb93cSSam Leffler "credentials: %s", gnutls_strerror(ret));
26239beb93cSSam Leffler os_free(conn);
26339beb93cSSam Leffler return NULL;
26439beb93cSSam Leffler }
26539beb93cSSam Leffler }
26639beb93cSSam Leffler
26739beb93cSSam Leffler if (gnutls_certificate_allocate_credentials(&conn->xcred)) {
26839beb93cSSam Leffler os_free(conn);
26939beb93cSSam Leffler return NULL;
27039beb93cSSam Leffler }
27139beb93cSSam Leffler
27239beb93cSSam Leffler return conn;
27339beb93cSSam Leffler }
27439beb93cSSam Leffler
27539beb93cSSam Leffler
tls_connection_deinit(void * ssl_ctx,struct tls_connection * conn)27639beb93cSSam Leffler void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
27739beb93cSSam Leffler {
27839beb93cSSam Leffler if (conn == NULL)
27939beb93cSSam Leffler return;
28039beb93cSSam Leffler
28139beb93cSSam Leffler gnutls_certificate_free_credentials(conn->xcred);
28239beb93cSSam Leffler gnutls_deinit(conn->session);
28339beb93cSSam Leffler os_free(conn->pre_shared_secret);
284e28a4053SRui Paulo wpabuf_free(conn->push_buf);
285e28a4053SRui Paulo wpabuf_free(conn->pull_buf);
2865b9c547cSRui Paulo os_free(conn->suffix_match);
2875b9c547cSRui Paulo os_free(conn->domain_match);
28839beb93cSSam Leffler os_free(conn);
28939beb93cSSam Leffler }
29039beb93cSSam Leffler
29139beb93cSSam Leffler
tls_connection_established(void * ssl_ctx,struct tls_connection * conn)29239beb93cSSam Leffler int tls_connection_established(void *ssl_ctx, struct tls_connection *conn)
29339beb93cSSam Leffler {
29439beb93cSSam Leffler return conn ? conn->established : 0;
29539beb93cSSam Leffler }
29639beb93cSSam Leffler
29739beb93cSSam Leffler
tls_connection_peer_serial_num(void * tls_ctx,struct tls_connection * conn)29885732ac8SCy Schubert char * tls_connection_peer_serial_num(void *tls_ctx,
29985732ac8SCy Schubert struct tls_connection *conn)
30085732ac8SCy Schubert {
30185732ac8SCy Schubert /* TODO */
30285732ac8SCy Schubert return NULL;
30385732ac8SCy Schubert }
30485732ac8SCy Schubert
30585732ac8SCy Schubert
tls_connection_shutdown(void * ssl_ctx,struct tls_connection * conn)30639beb93cSSam Leffler int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
30739beb93cSSam Leffler {
30839beb93cSSam Leffler struct tls_global *global = ssl_ctx;
30939beb93cSSam Leffler int ret;
31039beb93cSSam Leffler
31139beb93cSSam Leffler if (conn == NULL)
31239beb93cSSam Leffler return -1;
31339beb93cSSam Leffler
31439beb93cSSam Leffler /* Shutdown previous TLS connection without notifying the peer
31539beb93cSSam Leffler * because the connection was already terminated in practice
31639beb93cSSam Leffler * and "close notify" shutdown alert would confuse AS. */
31739beb93cSSam Leffler gnutls_bye(conn->session, GNUTLS_SHUT_RDWR);
318e28a4053SRui Paulo wpabuf_free(conn->push_buf);
31939beb93cSSam Leffler conn->push_buf = NULL;
32039beb93cSSam Leffler conn->established = 0;
32139beb93cSSam Leffler
32239beb93cSSam Leffler gnutls_deinit(conn->session);
32339beb93cSSam Leffler if (tls_gnutls_init_session(global, conn)) {
32439beb93cSSam Leffler wpa_printf(MSG_INFO, "GnuTLS: Failed to preparare new session "
32539beb93cSSam Leffler "for session resumption use");
32639beb93cSSam Leffler return -1;
32739beb93cSSam Leffler }
32839beb93cSSam Leffler
32939beb93cSSam Leffler ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
33039beb93cSSam Leffler conn->params_set ? conn->xcred :
33139beb93cSSam Leffler global->xcred);
33239beb93cSSam Leffler if (ret < 0) {
33339beb93cSSam Leffler wpa_printf(MSG_INFO, "GnuTLS: Failed to configure credentials "
33439beb93cSSam Leffler "for session resumption: %s", gnutls_strerror(ret));
33539beb93cSSam Leffler return -1;
33639beb93cSSam Leffler }
33739beb93cSSam Leffler
33839beb93cSSam Leffler if (global->session_data) {
33939beb93cSSam Leffler ret = gnutls_session_set_data(conn->session,
34039beb93cSSam Leffler global->session_data,
34139beb93cSSam Leffler global->session_data_size);
34239beb93cSSam Leffler if (ret < 0) {
34339beb93cSSam Leffler wpa_printf(MSG_INFO, "GnuTLS: Failed to set session "
34439beb93cSSam Leffler "data: %s", gnutls_strerror(ret));
34539beb93cSSam Leffler return -1;
34639beb93cSSam Leffler }
34739beb93cSSam Leffler }
34839beb93cSSam Leffler
34939beb93cSSam Leffler return 0;
35039beb93cSSam Leffler }
35139beb93cSSam Leffler
35239beb93cSSam Leffler
tls_connection_set_params(void * tls_ctx,struct tls_connection * conn,const struct tls_connection_params * params)35339beb93cSSam Leffler int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
35439beb93cSSam Leffler const struct tls_connection_params *params)
35539beb93cSSam Leffler {
35639beb93cSSam Leffler int ret;
35785732ac8SCy Schubert const char *err;
35885732ac8SCy Schubert char prio_buf[100];
35985732ac8SCy Schubert const char *prio = NULL;
36039beb93cSSam Leffler
36139beb93cSSam Leffler if (conn == NULL || params == NULL)
36239beb93cSSam Leffler return -1;
36339beb93cSSam Leffler
364780fb4a2SCy Schubert if (params->flags & TLS_CONN_REQUIRE_OCSP_ALL) {
365780fb4a2SCy Schubert wpa_printf(MSG_INFO,
366780fb4a2SCy Schubert "GnuTLS: ocsp=3 not supported");
367780fb4a2SCy Schubert return -1;
368780fb4a2SCy Schubert }
369780fb4a2SCy Schubert
370780fb4a2SCy Schubert if (params->flags & TLS_CONN_EXT_CERT_CHECK) {
371780fb4a2SCy Schubert wpa_printf(MSG_INFO,
372780fb4a2SCy Schubert "GnuTLS: tls_ext_cert_check=1 not supported");
373780fb4a2SCy Schubert return -1;
374780fb4a2SCy Schubert }
375780fb4a2SCy Schubert
37639beb93cSSam Leffler if (params->subject_match) {
3775b9c547cSRui Paulo wpa_printf(MSG_INFO, "GnuTLS: subject_match not supported");
37839beb93cSSam Leffler return -1;
37939beb93cSSam Leffler }
38039beb93cSSam Leffler
38139beb93cSSam Leffler if (params->altsubject_match) {
3825b9c547cSRui Paulo wpa_printf(MSG_INFO, "GnuTLS: altsubject_match not supported");
3835b9c547cSRui Paulo return -1;
3845b9c547cSRui Paulo }
3855b9c547cSRui Paulo
3865b9c547cSRui Paulo os_free(conn->suffix_match);
3875b9c547cSRui Paulo conn->suffix_match = NULL;
3885b9c547cSRui Paulo if (params->suffix_match) {
3895b9c547cSRui Paulo conn->suffix_match = os_strdup(params->suffix_match);
3905b9c547cSRui Paulo if (conn->suffix_match == NULL)
3915b9c547cSRui Paulo return -1;
3925b9c547cSRui Paulo }
3935b9c547cSRui Paulo
3945b9c547cSRui Paulo #if GNUTLS_VERSION_NUMBER >= 0x030300
3955b9c547cSRui Paulo os_free(conn->domain_match);
3965b9c547cSRui Paulo conn->domain_match = NULL;
3975b9c547cSRui Paulo if (params->domain_match) {
3985b9c547cSRui Paulo conn->domain_match = os_strdup(params->domain_match);
3995b9c547cSRui Paulo if (conn->domain_match == NULL)
4005b9c547cSRui Paulo return -1;
4015b9c547cSRui Paulo }
4025b9c547cSRui Paulo #else /* < 3.3.0 */
4035b9c547cSRui Paulo if (params->domain_match) {
4045b9c547cSRui Paulo wpa_printf(MSG_INFO, "GnuTLS: domain_match not supported");
4055b9c547cSRui Paulo return -1;
4065b9c547cSRui Paulo }
4075b9c547cSRui Paulo #endif /* >= 3.3.0 */
4085b9c547cSRui Paulo
4095b9c547cSRui Paulo conn->flags = params->flags;
4105b9c547cSRui Paulo
41185732ac8SCy Schubert if (params->flags & (TLS_CONN_DISABLE_TLSv1_0 |
41285732ac8SCy Schubert TLS_CONN_DISABLE_TLSv1_1 |
41385732ac8SCy Schubert TLS_CONN_DISABLE_TLSv1_2)) {
41485732ac8SCy Schubert os_snprintf(prio_buf, sizeof(prio_buf),
41585732ac8SCy Schubert "NORMAL:-VERS-SSL3.0%s%s%s",
41685732ac8SCy Schubert params->flags & TLS_CONN_DISABLE_TLSv1_0 ?
41785732ac8SCy Schubert ":-VERS-TLS1.0" : "",
41885732ac8SCy Schubert params->flags & TLS_CONN_DISABLE_TLSv1_1 ?
41985732ac8SCy Schubert ":-VERS-TLS1.1" : "",
42085732ac8SCy Schubert params->flags & TLS_CONN_DISABLE_TLSv1_2 ?
42185732ac8SCy Schubert ":-VERS-TLS1.2" : "");
42285732ac8SCy Schubert prio = prio_buf;
42385732ac8SCy Schubert }
42485732ac8SCy Schubert
4255b9c547cSRui Paulo if (params->openssl_ciphers) {
42685732ac8SCy Schubert if (os_strcmp(params->openssl_ciphers, "SUITEB128") == 0) {
42785732ac8SCy Schubert prio = "SUITEB128";
42885732ac8SCy Schubert } else if (os_strcmp(params->openssl_ciphers,
42985732ac8SCy Schubert "SUITEB192") == 0) {
43085732ac8SCy Schubert prio = "SUITEB192";
43185732ac8SCy Schubert } else if ((params->flags & TLS_CONN_SUITEB) &&
43285732ac8SCy Schubert os_strcmp(params->openssl_ciphers,
43385732ac8SCy Schubert "ECDHE-RSA-AES256-GCM-SHA384") == 0) {
43485732ac8SCy Schubert prio = "NONE:+VERS-TLS1.2:+AEAD:+ECDHE-RSA:+AES-256-GCM:+SIGN-RSA-SHA384:+CURVE-SECP384R1:+COMP-NULL";
43585732ac8SCy Schubert } else if (os_strcmp(params->openssl_ciphers,
43685732ac8SCy Schubert "ECDHE-RSA-AES256-GCM-SHA384") == 0) {
43785732ac8SCy Schubert prio = "NONE:+VERS-TLS1.2:+AEAD:+ECDHE-RSA:+AES-256-GCM:+SIGN-RSA-SHA384:+CURVE-SECP384R1:+COMP-NULL";
43885732ac8SCy Schubert } else if (os_strcmp(params->openssl_ciphers,
43985732ac8SCy Schubert "DHE-RSA-AES256-GCM-SHA384") == 0) {
44085732ac8SCy Schubert prio = "NONE:+VERS-TLS1.2:+AEAD:+DHE-RSA:+AES-256-GCM:+SIGN-RSA-SHA384:+CURVE-SECP384R1:+COMP-NULL:%PROFILE_HIGH";
44185732ac8SCy Schubert } else if (os_strcmp(params->openssl_ciphers,
44285732ac8SCy Schubert "ECDHE-ECDSA-AES256-GCM-SHA384") == 0) {
44385732ac8SCy Schubert prio = "NONE:+VERS-TLS1.2:+AEAD:+ECDHE-ECDSA:+AES-256-GCM:+SIGN-RSA-SHA384:+CURVE-SECP384R1:+COMP-NULL";
44485732ac8SCy Schubert } else {
44585732ac8SCy Schubert wpa_printf(MSG_INFO,
44685732ac8SCy Schubert "GnuTLS: openssl_ciphers not supported");
44739beb93cSSam Leffler return -1;
44839beb93cSSam Leffler }
44985732ac8SCy Schubert } else if (params->flags & TLS_CONN_SUITEB) {
45085732ac8SCy Schubert prio = "NONE:+VERS-TLS1.2:+AEAD:+ECDHE-ECDSA:+ECDHE-RSA:+DHE-RSA:+AES-256-GCM:+SIGN-RSA-SHA384:+CURVE-SECP384R1:+COMP-NULL:%PROFILE_HIGH";
45185732ac8SCy Schubert }
45285732ac8SCy Schubert
45385732ac8SCy Schubert if (prio) {
45485732ac8SCy Schubert wpa_printf(MSG_DEBUG, "GnuTLS: Set priority string: %s", prio);
45585732ac8SCy Schubert ret = gnutls_priority_set_direct(conn->session, prio, &err);
45685732ac8SCy Schubert if (ret < 0) {
45785732ac8SCy Schubert wpa_printf(MSG_ERROR,
45885732ac8SCy Schubert "GnuTLS: Priority string failure at '%s'",
45985732ac8SCy Schubert err);
46085732ac8SCy Schubert return -1;
46185732ac8SCy Schubert }
46285732ac8SCy Schubert }
46339beb93cSSam Leffler
464*4bc52338SCy Schubert if (params->openssl_ecdh_curves) {
465*4bc52338SCy Schubert wpa_printf(MSG_INFO,
466*4bc52338SCy Schubert "GnuTLS: openssl_ecdh_curves not supported");
467*4bc52338SCy Schubert return -1;
468*4bc52338SCy Schubert }
469*4bc52338SCy Schubert
47039beb93cSSam Leffler /* TODO: gnutls_certificate_set_verify_flags(xcred, flags);
47139beb93cSSam Leffler * to force peer validation(?) */
47239beb93cSSam Leffler
47339beb93cSSam Leffler if (params->ca_cert) {
4745b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "GnuTLS: Try to parse %s in DER format",
4755b9c547cSRui Paulo params->ca_cert);
47639beb93cSSam Leffler ret = gnutls_certificate_set_x509_trust_file(
4775b9c547cSRui Paulo conn->xcred, params->ca_cert, GNUTLS_X509_FMT_DER);
47839beb93cSSam Leffler if (ret < 0) {
4795b9c547cSRui Paulo wpa_printf(MSG_DEBUG,
4805b9c547cSRui Paulo "GnuTLS: Failed to read CA cert '%s' in DER format (%s) - try in PEM format",
4815b9c547cSRui Paulo params->ca_cert,
48239beb93cSSam Leffler gnutls_strerror(ret));
48339beb93cSSam Leffler ret = gnutls_certificate_set_x509_trust_file(
48439beb93cSSam Leffler conn->xcred, params->ca_cert,
4855b9c547cSRui Paulo GNUTLS_X509_FMT_PEM);
48639beb93cSSam Leffler if (ret < 0) {
4875b9c547cSRui Paulo wpa_printf(MSG_DEBUG,
4885b9c547cSRui Paulo "Failed to read CA cert '%s' in PEM format: %s",
48939beb93cSSam Leffler params->ca_cert,
49039beb93cSSam Leffler gnutls_strerror(ret));
49139beb93cSSam Leffler return -1;
49239beb93cSSam Leffler }
49385732ac8SCy Schubert wpa_printf(MSG_DEBUG,
49485732ac8SCy Schubert "GnuTLS: Successfully read CA cert '%s' in PEM format",
49585732ac8SCy Schubert params->ca_cert);
49685732ac8SCy Schubert } else {
49785732ac8SCy Schubert wpa_printf(MSG_DEBUG,
49885732ac8SCy Schubert "GnuTLS: Successfully read CA cert '%s' in DER format",
49985732ac8SCy Schubert params->ca_cert);
50039beb93cSSam Leffler }
5015b9c547cSRui Paulo } else if (params->ca_cert_blob) {
5025b9c547cSRui Paulo gnutls_datum_t ca;
5035b9c547cSRui Paulo
5045b9c547cSRui Paulo ca.data = (unsigned char *) params->ca_cert_blob;
5055b9c547cSRui Paulo ca.size = params->ca_cert_blob_len;
5065b9c547cSRui Paulo
5075b9c547cSRui Paulo ret = gnutls_certificate_set_x509_trust_mem(
5085b9c547cSRui Paulo conn->xcred, &ca, GNUTLS_X509_FMT_DER);
5095b9c547cSRui Paulo if (ret < 0) {
5105b9c547cSRui Paulo wpa_printf(MSG_DEBUG,
5115b9c547cSRui Paulo "Failed to parse CA cert in DER format: %s",
5125b9c547cSRui Paulo gnutls_strerror(ret));
5135b9c547cSRui Paulo ret = gnutls_certificate_set_x509_trust_mem(
5145b9c547cSRui Paulo conn->xcred, &ca, GNUTLS_X509_FMT_PEM);
5155b9c547cSRui Paulo if (ret < 0) {
5165b9c547cSRui Paulo wpa_printf(MSG_DEBUG,
5175b9c547cSRui Paulo "Failed to parse CA cert in PEM format: %s",
5185b9c547cSRui Paulo gnutls_strerror(ret));
5195b9c547cSRui Paulo return -1;
5205b9c547cSRui Paulo }
5215b9c547cSRui Paulo }
5225b9c547cSRui Paulo } else if (params->ca_path) {
5235b9c547cSRui Paulo wpa_printf(MSG_INFO, "GnuTLS: ca_path not supported");
5245b9c547cSRui Paulo return -1;
5255b9c547cSRui Paulo }
5265b9c547cSRui Paulo
5275b9c547cSRui Paulo conn->disable_time_checks = 0;
5285b9c547cSRui Paulo if (params->ca_cert || params->ca_cert_blob) {
5295b9c547cSRui Paulo conn->verify_peer = 1;
5305b9c547cSRui Paulo gnutls_certificate_set_verify_function(
5315b9c547cSRui Paulo conn->xcred, tls_connection_verify_peer);
5323157ba21SRui Paulo
5333157ba21SRui Paulo if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) {
5343157ba21SRui Paulo gnutls_certificate_set_verify_flags(
5353157ba21SRui Paulo conn->xcred, GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
5363157ba21SRui Paulo }
5373157ba21SRui Paulo
5383157ba21SRui Paulo if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
5395b9c547cSRui Paulo conn->disable_time_checks = 1;
5403157ba21SRui Paulo gnutls_certificate_set_verify_flags(
5413157ba21SRui Paulo conn->xcred,
5423157ba21SRui Paulo GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
5433157ba21SRui Paulo }
54439beb93cSSam Leffler }
54539beb93cSSam Leffler
54639beb93cSSam Leffler if (params->client_cert && params->private_key) {
54785732ac8SCy Schubert wpa_printf(MSG_DEBUG,
54885732ac8SCy Schubert "GnuTLS: Try to parse client cert '%s' and key '%s' in DER format",
54985732ac8SCy Schubert params->client_cert, params->private_key);
5505b9c547cSRui Paulo #if GNUTLS_VERSION_NUMBER >= 0x03010b
5515b9c547cSRui Paulo ret = gnutls_certificate_set_x509_key_file2(
5525b9c547cSRui Paulo conn->xcred, params->client_cert, params->private_key,
5535b9c547cSRui Paulo GNUTLS_X509_FMT_DER, params->private_key_passwd, 0);
5545b9c547cSRui Paulo #else
5555b9c547cSRui Paulo /* private_key_passwd not (easily) supported here */
55639beb93cSSam Leffler ret = gnutls_certificate_set_x509_key_file(
55739beb93cSSam Leffler conn->xcred, params->client_cert, params->private_key,
5585b9c547cSRui Paulo GNUTLS_X509_FMT_DER);
5595b9c547cSRui Paulo #endif
56039beb93cSSam Leffler if (ret < 0) {
56185732ac8SCy Schubert wpa_printf(MSG_DEBUG,
56285732ac8SCy Schubert "GnuTLS: Failed to read client cert/key in DER format (%s) - try in PEM format",
56385732ac8SCy Schubert gnutls_strerror(ret));
5645b9c547cSRui Paulo #if GNUTLS_VERSION_NUMBER >= 0x03010b
5655b9c547cSRui Paulo ret = gnutls_certificate_set_x509_key_file2(
5665b9c547cSRui Paulo conn->xcred, params->client_cert,
5675b9c547cSRui Paulo params->private_key, GNUTLS_X509_FMT_PEM,
5685b9c547cSRui Paulo params->private_key_passwd, 0);
5695b9c547cSRui Paulo #else
57039beb93cSSam Leffler ret = gnutls_certificate_set_x509_key_file(
57139beb93cSSam Leffler conn->xcred, params->client_cert,
5725b9c547cSRui Paulo params->private_key, GNUTLS_X509_FMT_PEM);
5735b9c547cSRui Paulo #endif
57439beb93cSSam Leffler if (ret < 0) {
57539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "Failed to read client "
5765b9c547cSRui Paulo "cert/key in PEM format: %s",
57739beb93cSSam Leffler gnutls_strerror(ret));
57839beb93cSSam Leffler return ret;
57939beb93cSSam Leffler }
58085732ac8SCy Schubert wpa_printf(MSG_DEBUG,
58185732ac8SCy Schubert "GnuTLS: Successfully read client cert/key in PEM format");
58285732ac8SCy Schubert } else {
58385732ac8SCy Schubert wpa_printf(MSG_DEBUG,
58485732ac8SCy Schubert "GnuTLS: Successfully read client cert/key in DER format");
58539beb93cSSam Leffler }
58639beb93cSSam Leffler } else if (params->private_key) {
58739beb93cSSam Leffler int pkcs12_ok = 0;
58839beb93cSSam Leffler #ifdef PKCS12_FUNCS
58939beb93cSSam Leffler /* Try to load in PKCS#12 format */
59085732ac8SCy Schubert wpa_printf(MSG_DEBUG,
59185732ac8SCy Schubert "GnuTLS: Try to parse client cert/key '%s'in PKCS#12 DER format",
59285732ac8SCy Schubert params->private_key);
59339beb93cSSam Leffler ret = gnutls_certificate_set_x509_simple_pkcs12_file(
59439beb93cSSam Leffler conn->xcred, params->private_key, GNUTLS_X509_FMT_DER,
59539beb93cSSam Leffler params->private_key_passwd);
59639beb93cSSam Leffler if (ret != 0) {
59739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "Failed to load private_key in "
59839beb93cSSam Leffler "PKCS#12 format: %s", gnutls_strerror(ret));
59939beb93cSSam Leffler return -1;
60039beb93cSSam Leffler } else
60139beb93cSSam Leffler pkcs12_ok = 1;
60239beb93cSSam Leffler #endif /* PKCS12_FUNCS */
60339beb93cSSam Leffler
60439beb93cSSam Leffler if (!pkcs12_ok) {
60539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not "
60639beb93cSSam Leffler "included");
60739beb93cSSam Leffler return -1;
60839beb93cSSam Leffler }
6095b9c547cSRui Paulo } else if (params->client_cert_blob && params->private_key_blob) {
6105b9c547cSRui Paulo gnutls_datum_t cert, key;
6115b9c547cSRui Paulo
6125b9c547cSRui Paulo cert.data = (unsigned char *) params->client_cert_blob;
6135b9c547cSRui Paulo cert.size = params->client_cert_blob_len;
6145b9c547cSRui Paulo key.data = (unsigned char *) params->private_key_blob;
6155b9c547cSRui Paulo key.size = params->private_key_blob_len;
6165b9c547cSRui Paulo
6175b9c547cSRui Paulo #if GNUTLS_VERSION_NUMBER >= 0x03010b
6185b9c547cSRui Paulo ret = gnutls_certificate_set_x509_key_mem2(
6195b9c547cSRui Paulo conn->xcred, &cert, &key, GNUTLS_X509_FMT_DER,
6205b9c547cSRui Paulo params->private_key_passwd, 0);
6215b9c547cSRui Paulo #else
6225b9c547cSRui Paulo /* private_key_passwd not (easily) supported here */
6235b9c547cSRui Paulo ret = gnutls_certificate_set_x509_key_mem(
6245b9c547cSRui Paulo conn->xcred, &cert, &key, GNUTLS_X509_FMT_DER);
6255b9c547cSRui Paulo #endif
6265b9c547cSRui Paulo if (ret < 0) {
6275b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
6285b9c547cSRui Paulo "in DER format: %s", gnutls_strerror(ret));
6295b9c547cSRui Paulo #if GNUTLS_VERSION_NUMBER >= 0x03010b
6305b9c547cSRui Paulo ret = gnutls_certificate_set_x509_key_mem2(
6315b9c547cSRui Paulo conn->xcred, &cert, &key, GNUTLS_X509_FMT_PEM,
6325b9c547cSRui Paulo params->private_key_passwd, 0);
6335b9c547cSRui Paulo #else
6345b9c547cSRui Paulo /* private_key_passwd not (easily) supported here */
6355b9c547cSRui Paulo ret = gnutls_certificate_set_x509_key_mem(
6365b9c547cSRui Paulo conn->xcred, &cert, &key, GNUTLS_X509_FMT_PEM);
6375b9c547cSRui Paulo #endif
6385b9c547cSRui Paulo if (ret < 0) {
6395b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "Failed to read client "
6405b9c547cSRui Paulo "cert/key in PEM format: %s",
6415b9c547cSRui Paulo gnutls_strerror(ret));
6425b9c547cSRui Paulo return ret;
64339beb93cSSam Leffler }
6445b9c547cSRui Paulo }
6455b9c547cSRui Paulo } else if (params->private_key_blob) {
6465b9c547cSRui Paulo #ifdef PKCS12_FUNCS
6475b9c547cSRui Paulo gnutls_datum_t key;
6485b9c547cSRui Paulo
6495b9c547cSRui Paulo key.data = (unsigned char *) params->private_key_blob;
6505b9c547cSRui Paulo key.size = params->private_key_blob_len;
6515b9c547cSRui Paulo
6525b9c547cSRui Paulo /* Try to load in PKCS#12 format */
6535b9c547cSRui Paulo ret = gnutls_certificate_set_x509_simple_pkcs12_mem(
6545b9c547cSRui Paulo conn->xcred, &key, GNUTLS_X509_FMT_DER,
6555b9c547cSRui Paulo params->private_key_passwd);
6565b9c547cSRui Paulo if (ret != 0) {
6575b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "Failed to load private_key in "
6585b9c547cSRui Paulo "PKCS#12 format: %s", gnutls_strerror(ret));
6595b9c547cSRui Paulo return -1;
6605b9c547cSRui Paulo }
6615b9c547cSRui Paulo #else /* PKCS12_FUNCS */
6625b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not included");
6635b9c547cSRui Paulo return -1;
6645b9c547cSRui Paulo #endif /* PKCS12_FUNCS */
6655b9c547cSRui Paulo }
6665b9c547cSRui Paulo
6675b9c547cSRui Paulo #if GNUTLS_VERSION_NUMBER >= 0x030103
6685b9c547cSRui Paulo if (params->flags & (TLS_CONN_REQUEST_OCSP | TLS_CONN_REQUIRE_OCSP)) {
6695b9c547cSRui Paulo ret = gnutls_ocsp_status_request_enable_client(conn->session,
6705b9c547cSRui Paulo NULL, 0, NULL);
6715b9c547cSRui Paulo if (ret != GNUTLS_E_SUCCESS) {
6725b9c547cSRui Paulo wpa_printf(MSG_INFO,
6735b9c547cSRui Paulo "GnuTLS: Failed to enable OCSP client");
6745b9c547cSRui Paulo return -1;
6755b9c547cSRui Paulo }
6765b9c547cSRui Paulo }
6775b9c547cSRui Paulo #else /* 3.1.3 */
6785b9c547cSRui Paulo if (params->flags & TLS_CONN_REQUIRE_OCSP) {
6795b9c547cSRui Paulo wpa_printf(MSG_INFO,
6805b9c547cSRui Paulo "GnuTLS: OCSP not supported by this version of GnuTLS");
6815b9c547cSRui Paulo return -1;
6825b9c547cSRui Paulo }
6835b9c547cSRui Paulo #endif /* 3.1.3 */
68439beb93cSSam Leffler
68539beb93cSSam Leffler conn->params_set = 1;
68639beb93cSSam Leffler
68739beb93cSSam Leffler ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
68839beb93cSSam Leffler conn->xcred);
68939beb93cSSam Leffler if (ret < 0) {
69039beb93cSSam Leffler wpa_printf(MSG_INFO, "Failed to configure credentials: %s",
69139beb93cSSam Leffler gnutls_strerror(ret));
69239beb93cSSam Leffler }
69339beb93cSSam Leffler
69439beb93cSSam Leffler return ret;
69539beb93cSSam Leffler }
69639beb93cSSam Leffler
69739beb93cSSam Leffler
698780fb4a2SCy Schubert #if GNUTLS_VERSION_NUMBER >= 0x030103
server_ocsp_status_req(gnutls_session_t session,void * ptr,gnutls_datum_t * resp)699780fb4a2SCy Schubert static int server_ocsp_status_req(gnutls_session_t session, void *ptr,
700780fb4a2SCy Schubert gnutls_datum_t *resp)
701780fb4a2SCy Schubert {
702780fb4a2SCy Schubert struct tls_global *global = ptr;
703780fb4a2SCy Schubert char *cached;
704780fb4a2SCy Schubert size_t len;
705780fb4a2SCy Schubert
706780fb4a2SCy Schubert if (!global->ocsp_stapling_response) {
707780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "GnuTLS: OCSP status callback - no response configured");
708780fb4a2SCy Schubert return GNUTLS_E_NO_CERTIFICATE_STATUS;
709780fb4a2SCy Schubert }
710780fb4a2SCy Schubert
711780fb4a2SCy Schubert cached = os_readfile(global->ocsp_stapling_response, &len);
712780fb4a2SCy Schubert if (!cached) {
713780fb4a2SCy Schubert wpa_printf(MSG_DEBUG,
714780fb4a2SCy Schubert "GnuTLS: OCSP status callback - could not read response file (%s)",
715780fb4a2SCy Schubert global->ocsp_stapling_response);
716780fb4a2SCy Schubert return GNUTLS_E_NO_CERTIFICATE_STATUS;
717780fb4a2SCy Schubert }
718780fb4a2SCy Schubert
719780fb4a2SCy Schubert wpa_printf(MSG_DEBUG,
720780fb4a2SCy Schubert "GnuTLS: OCSP status callback - send cached response");
721780fb4a2SCy Schubert resp->data = gnutls_malloc(len);
722780fb4a2SCy Schubert if (!resp->data) {
723780fb4a2SCy Schubert os_free(resp);
724780fb4a2SCy Schubert return GNUTLS_E_MEMORY_ERROR;
725780fb4a2SCy Schubert }
726780fb4a2SCy Schubert
727780fb4a2SCy Schubert os_memcpy(resp->data, cached, len);
728780fb4a2SCy Schubert resp->size = len;
729780fb4a2SCy Schubert os_free(cached);
730780fb4a2SCy Schubert
731780fb4a2SCy Schubert return GNUTLS_E_SUCCESS;
732780fb4a2SCy Schubert }
733780fb4a2SCy Schubert #endif /* 3.1.3 */
734780fb4a2SCy Schubert
735780fb4a2SCy Schubert
tls_global_set_params(void * tls_ctx,const struct tls_connection_params * params)73639beb93cSSam Leffler int tls_global_set_params(void *tls_ctx,
73739beb93cSSam Leffler const struct tls_connection_params *params)
73839beb93cSSam Leffler {
73939beb93cSSam Leffler struct tls_global *global = tls_ctx;
74039beb93cSSam Leffler int ret;
74139beb93cSSam Leffler
742*4bc52338SCy Schubert if (params->check_cert_subject)
743*4bc52338SCy Schubert return -1; /* not yet supported */
744*4bc52338SCy Schubert
74539beb93cSSam Leffler /* Currently, global parameters are only set when running in server
74639beb93cSSam Leffler * mode. */
74739beb93cSSam Leffler global->server = 1;
74839beb93cSSam Leffler
74939beb93cSSam Leffler if (global->params_set) {
75039beb93cSSam Leffler gnutls_certificate_free_credentials(global->xcred);
75139beb93cSSam Leffler global->params_set = 0;
75239beb93cSSam Leffler }
75339beb93cSSam Leffler
75439beb93cSSam Leffler ret = gnutls_certificate_allocate_credentials(&global->xcred);
75539beb93cSSam Leffler if (ret) {
75639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "Failed to allocate global credentials "
75739beb93cSSam Leffler "%s", gnutls_strerror(ret));
75839beb93cSSam Leffler return -1;
75939beb93cSSam Leffler }
76039beb93cSSam Leffler
76139beb93cSSam Leffler if (params->ca_cert) {
76239beb93cSSam Leffler ret = gnutls_certificate_set_x509_trust_file(
7635b9c547cSRui Paulo global->xcred, params->ca_cert, GNUTLS_X509_FMT_DER);
76439beb93cSSam Leffler if (ret < 0) {
76539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "Failed to read CA cert '%s' "
7665b9c547cSRui Paulo "in DER format: %s", params->ca_cert,
76739beb93cSSam Leffler gnutls_strerror(ret));
76839beb93cSSam Leffler ret = gnutls_certificate_set_x509_trust_file(
76939beb93cSSam Leffler global->xcred, params->ca_cert,
7705b9c547cSRui Paulo GNUTLS_X509_FMT_PEM);
77139beb93cSSam Leffler if (ret < 0) {
77239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "Failed to read CA cert "
7735b9c547cSRui Paulo "'%s' in PEM format: %s",
77439beb93cSSam Leffler params->ca_cert,
77539beb93cSSam Leffler gnutls_strerror(ret));
77639beb93cSSam Leffler goto fail;
77739beb93cSSam Leffler }
77839beb93cSSam Leffler }
7793157ba21SRui Paulo
7803157ba21SRui Paulo if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) {
7813157ba21SRui Paulo gnutls_certificate_set_verify_flags(
7823157ba21SRui Paulo global->xcred,
7833157ba21SRui Paulo GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
7843157ba21SRui Paulo }
7853157ba21SRui Paulo
7863157ba21SRui Paulo if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
7873157ba21SRui Paulo gnutls_certificate_set_verify_flags(
7883157ba21SRui Paulo global->xcred,
7893157ba21SRui Paulo GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
7903157ba21SRui Paulo }
79139beb93cSSam Leffler }
79239beb93cSSam Leffler
79339beb93cSSam Leffler if (params->client_cert && params->private_key) {
79439beb93cSSam Leffler /* TODO: private_key_passwd? */
79539beb93cSSam Leffler ret = gnutls_certificate_set_x509_key_file(
79639beb93cSSam Leffler global->xcred, params->client_cert,
79739beb93cSSam Leffler params->private_key, GNUTLS_X509_FMT_DER);
79839beb93cSSam Leffler if (ret < 0) {
7995b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
8005b9c547cSRui Paulo "in DER format: %s", gnutls_strerror(ret));
8015b9c547cSRui Paulo ret = gnutls_certificate_set_x509_key_file(
8025b9c547cSRui Paulo global->xcred, params->client_cert,
8035b9c547cSRui Paulo params->private_key, GNUTLS_X509_FMT_PEM);
8045b9c547cSRui Paulo if (ret < 0) {
80539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "Failed to read client "
8065b9c547cSRui Paulo "cert/key in PEM format: %s",
80739beb93cSSam Leffler gnutls_strerror(ret));
80839beb93cSSam Leffler goto fail;
80939beb93cSSam Leffler }
81039beb93cSSam Leffler }
81139beb93cSSam Leffler } else if (params->private_key) {
81239beb93cSSam Leffler int pkcs12_ok = 0;
81339beb93cSSam Leffler #ifdef PKCS12_FUNCS
81439beb93cSSam Leffler /* Try to load in PKCS#12 format */
81539beb93cSSam Leffler ret = gnutls_certificate_set_x509_simple_pkcs12_file(
81639beb93cSSam Leffler global->xcred, params->private_key,
81739beb93cSSam Leffler GNUTLS_X509_FMT_DER, params->private_key_passwd);
81839beb93cSSam Leffler if (ret != 0) {
81939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "Failed to load private_key in "
82039beb93cSSam Leffler "PKCS#12 format: %s", gnutls_strerror(ret));
82139beb93cSSam Leffler goto fail;
82239beb93cSSam Leffler } else
82339beb93cSSam Leffler pkcs12_ok = 1;
82439beb93cSSam Leffler #endif /* PKCS12_FUNCS */
82539beb93cSSam Leffler
82639beb93cSSam Leffler if (!pkcs12_ok) {
82739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not "
82839beb93cSSam Leffler "included");
82939beb93cSSam Leffler goto fail;
83039beb93cSSam Leffler }
83139beb93cSSam Leffler }
83239beb93cSSam Leffler
833780fb4a2SCy Schubert #if GNUTLS_VERSION_NUMBER >= 0x030103
834780fb4a2SCy Schubert os_free(global->ocsp_stapling_response);
835780fb4a2SCy Schubert if (params->ocsp_stapling_response)
836780fb4a2SCy Schubert global->ocsp_stapling_response =
837780fb4a2SCy Schubert os_strdup(params->ocsp_stapling_response);
838780fb4a2SCy Schubert else
839780fb4a2SCy Schubert global->ocsp_stapling_response = NULL;
840780fb4a2SCy Schubert gnutls_certificate_set_ocsp_status_request_function(
841780fb4a2SCy Schubert global->xcred, server_ocsp_status_req, global);
842780fb4a2SCy Schubert #endif /* 3.1.3 */
843780fb4a2SCy Schubert
84439beb93cSSam Leffler global->params_set = 1;
84539beb93cSSam Leffler
84639beb93cSSam Leffler return 0;
84739beb93cSSam Leffler
84839beb93cSSam Leffler fail:
84939beb93cSSam Leffler gnutls_certificate_free_credentials(global->xcred);
85039beb93cSSam Leffler return -1;
85139beb93cSSam Leffler }
85239beb93cSSam Leffler
85339beb93cSSam Leffler
tls_global_set_verify(void * ssl_ctx,int check_crl,int strict)854*4bc52338SCy Schubert int tls_global_set_verify(void *ssl_ctx, int check_crl, int strict)
85539beb93cSSam Leffler {
85639beb93cSSam Leffler /* TODO */
85739beb93cSSam Leffler return 0;
85839beb93cSSam Leffler }
85939beb93cSSam Leffler
86039beb93cSSam Leffler
tls_connection_set_verify(void * ssl_ctx,struct tls_connection * conn,int verify_peer,unsigned int flags,const u8 * session_ctx,size_t session_ctx_len)86139beb93cSSam Leffler int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
862325151a3SRui Paulo int verify_peer, unsigned int flags,
863325151a3SRui Paulo const u8 *session_ctx, size_t session_ctx_len)
86439beb93cSSam Leffler {
86539beb93cSSam Leffler if (conn == NULL || conn->session == NULL)
86639beb93cSSam Leffler return -1;
86739beb93cSSam Leffler
86839beb93cSSam Leffler conn->verify_peer = verify_peer;
86939beb93cSSam Leffler gnutls_certificate_server_set_request(conn->session,
87039beb93cSSam Leffler verify_peer ? GNUTLS_CERT_REQUIRE
87139beb93cSSam Leffler : GNUTLS_CERT_REQUEST);
87239beb93cSSam Leffler
87339beb93cSSam Leffler return 0;
87439beb93cSSam Leffler }
87539beb93cSSam Leffler
87639beb93cSSam Leffler
tls_connection_get_random(void * ssl_ctx,struct tls_connection * conn,struct tls_random * keys)877325151a3SRui Paulo int tls_connection_get_random(void *ssl_ctx, struct tls_connection *conn,
878325151a3SRui Paulo struct tls_random *keys)
87939beb93cSSam Leffler {
8805b9c547cSRui Paulo #if GNUTLS_VERSION_NUMBER >= 0x030012
8815b9c547cSRui Paulo gnutls_datum_t client, server;
88239beb93cSSam Leffler
88339beb93cSSam Leffler if (conn == NULL || conn->session == NULL || keys == NULL)
88439beb93cSSam Leffler return -1;
88539beb93cSSam Leffler
88639beb93cSSam Leffler os_memset(keys, 0, sizeof(*keys));
8875b9c547cSRui Paulo gnutls_session_get_random(conn->session, &client, &server);
8885b9c547cSRui Paulo keys->client_random = client.data;
8895b9c547cSRui Paulo keys->server_random = server.data;
8905b9c547cSRui Paulo keys->client_random_len = client.size;
8915b9c547cSRui Paulo keys->server_random_len = client.size;
89239beb93cSSam Leffler
89339beb93cSSam Leffler return 0;
8945b9c547cSRui Paulo #else /* 3.0.18 */
8955b9c547cSRui Paulo return -1;
8965b9c547cSRui Paulo #endif /* 3.0.18 */
89739beb93cSSam Leffler }
89839beb93cSSam Leffler
89939beb93cSSam Leffler
tls_connection_export_key(void * tls_ctx,struct tls_connection * conn,const char * label,const u8 * context,size_t context_len,u8 * out,size_t out_len)900780fb4a2SCy Schubert int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn,
901*4bc52338SCy Schubert const char *label, const u8 *context,
902*4bc52338SCy Schubert size_t context_len, u8 *out, size_t out_len)
90339beb93cSSam Leffler {
904780fb4a2SCy Schubert if (conn == NULL || conn->session == NULL)
90539beb93cSSam Leffler return -1;
90639beb93cSSam Leffler
907*4bc52338SCy Schubert #if GNUTLS_VERSION_NUMBER >= 0x030404
908*4bc52338SCy Schubert return gnutls_prf_rfc5705(conn->session, os_strlen(label), label,
909*4bc52338SCy Schubert context_len, (const char *) context,
910*4bc52338SCy Schubert out_len, (char *) out);
911*4bc52338SCy Schubert #else /* 3.4.4 */
912*4bc52338SCy Schubert if (context)
913*4bc52338SCy Schubert return -1;
91439beb93cSSam Leffler return gnutls_prf(conn->session, os_strlen(label), label,
915780fb4a2SCy Schubert 0 /* client_random first */, 0, NULL, out_len,
916780fb4a2SCy Schubert (char *) out);
917*4bc52338SCy Schubert #endif /* 3.4.4 */
918780fb4a2SCy Schubert }
919780fb4a2SCy Schubert
920780fb4a2SCy Schubert
tls_connection_get_eap_fast_key(void * tls_ctx,struct tls_connection * conn,u8 * out,size_t out_len)921780fb4a2SCy Schubert int tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn,
922780fb4a2SCy Schubert u8 *out, size_t out_len)
923780fb4a2SCy Schubert {
924780fb4a2SCy Schubert return -1;
92539beb93cSSam Leffler }
92639beb93cSSam Leffler
92739beb93cSSam Leffler
gnutls_tls_fail_event(struct tls_connection * conn,const gnutls_datum_t * cert,int depth,const char * subject,const char * err_str,enum tls_fail_reason reason)9285b9c547cSRui Paulo static void gnutls_tls_fail_event(struct tls_connection *conn,
9295b9c547cSRui Paulo const gnutls_datum_t *cert, int depth,
9305b9c547cSRui Paulo const char *subject, const char *err_str,
9315b9c547cSRui Paulo enum tls_fail_reason reason)
9325b9c547cSRui Paulo {
9335b9c547cSRui Paulo union tls_event_data ev;
9345b9c547cSRui Paulo struct tls_global *global = conn->global;
9355b9c547cSRui Paulo struct wpabuf *cert_buf = NULL;
9365b9c547cSRui Paulo
9375b9c547cSRui Paulo if (global->event_cb == NULL)
9385b9c547cSRui Paulo return;
9395b9c547cSRui Paulo
9405b9c547cSRui Paulo os_memset(&ev, 0, sizeof(ev));
9415b9c547cSRui Paulo ev.cert_fail.depth = depth;
9425b9c547cSRui Paulo ev.cert_fail.subject = subject ? subject : "";
9435b9c547cSRui Paulo ev.cert_fail.reason = reason;
9445b9c547cSRui Paulo ev.cert_fail.reason_txt = err_str;
9455b9c547cSRui Paulo if (cert) {
9465b9c547cSRui Paulo cert_buf = wpabuf_alloc_copy(cert->data, cert->size);
9475b9c547cSRui Paulo ev.cert_fail.cert = cert_buf;
9485b9c547cSRui Paulo }
9495b9c547cSRui Paulo global->event_cb(global->cb_ctx, TLS_CERT_CHAIN_FAILURE, &ev);
9505b9c547cSRui Paulo wpabuf_free(cert_buf);
9515b9c547cSRui Paulo }
9525b9c547cSRui Paulo
9535b9c547cSRui Paulo
9545b9c547cSRui Paulo #if GNUTLS_VERSION_NUMBER < 0x030300
server_eku_purpose(gnutls_x509_crt_t cert)9555b9c547cSRui Paulo static int server_eku_purpose(gnutls_x509_crt_t cert)
9565b9c547cSRui Paulo {
9575b9c547cSRui Paulo unsigned int i;
9585b9c547cSRui Paulo
9595b9c547cSRui Paulo for (i = 0; ; i++) {
9605b9c547cSRui Paulo char oid[128];
9615b9c547cSRui Paulo size_t oid_size = sizeof(oid);
9625b9c547cSRui Paulo int res;
9635b9c547cSRui Paulo
9645b9c547cSRui Paulo res = gnutls_x509_crt_get_key_purpose_oid(cert, i, oid,
9655b9c547cSRui Paulo &oid_size, NULL);
9665b9c547cSRui Paulo if (res == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
9675b9c547cSRui Paulo if (i == 0) {
9685b9c547cSRui Paulo /* No EKU - assume any use allowed */
9695b9c547cSRui Paulo return 1;
9705b9c547cSRui Paulo }
9715b9c547cSRui Paulo break;
9725b9c547cSRui Paulo }
9735b9c547cSRui Paulo
9745b9c547cSRui Paulo if (res < 0) {
9755b9c547cSRui Paulo wpa_printf(MSG_INFO, "GnuTLS: Failed to get EKU");
9765b9c547cSRui Paulo return 0;
9775b9c547cSRui Paulo }
9785b9c547cSRui Paulo
9795b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "GnuTLS: Certificate purpose: %s", oid);
9805b9c547cSRui Paulo if (os_strcmp(oid, GNUTLS_KP_TLS_WWW_SERVER) == 0 ||
9815b9c547cSRui Paulo os_strcmp(oid, GNUTLS_KP_ANY) == 0)
9825b9c547cSRui Paulo return 1;
9835b9c547cSRui Paulo }
9845b9c547cSRui Paulo
9855b9c547cSRui Paulo return 0;
9865b9c547cSRui Paulo }
9875b9c547cSRui Paulo #endif /* < 3.3.0 */
9885b9c547cSRui Paulo
9895b9c547cSRui Paulo
check_ocsp(struct tls_connection * conn,gnutls_session_t session,gnutls_alert_description_t * err)9905b9c547cSRui Paulo static int check_ocsp(struct tls_connection *conn, gnutls_session_t session,
9913157ba21SRui Paulo gnutls_alert_description_t *err)
99239beb93cSSam Leffler {
9935b9c547cSRui Paulo #if GNUTLS_VERSION_NUMBER >= 0x030103
9945b9c547cSRui Paulo gnutls_datum_t response, buf;
9955b9c547cSRui Paulo gnutls_ocsp_resp_t resp;
9965b9c547cSRui Paulo unsigned int cert_status;
9975b9c547cSRui Paulo int res;
9985b9c547cSRui Paulo
9995b9c547cSRui Paulo if (!(conn->flags & (TLS_CONN_REQUEST_OCSP | TLS_CONN_REQUIRE_OCSP)))
10005b9c547cSRui Paulo return 0;
10015b9c547cSRui Paulo
10025b9c547cSRui Paulo if (!gnutls_ocsp_status_request_is_checked(session, 0)) {
10035b9c547cSRui Paulo if (conn->flags & TLS_CONN_REQUIRE_OCSP) {
10045b9c547cSRui Paulo wpa_printf(MSG_INFO,
10055b9c547cSRui Paulo "GnuTLS: No valid OCSP response received");
10065b9c547cSRui Paulo goto ocsp_error;
10075b9c547cSRui Paulo }
10085b9c547cSRui Paulo
10095b9c547cSRui Paulo wpa_printf(MSG_DEBUG,
10105b9c547cSRui Paulo "GnuTLS: Valid OCSP response was not received - continue since OCSP was not required");
10115b9c547cSRui Paulo return 0;
10125b9c547cSRui Paulo }
10135b9c547cSRui Paulo
10145b9c547cSRui Paulo /*
10155b9c547cSRui Paulo * GnuTLS has already verified the OCSP response in
10165b9c547cSRui Paulo * check_ocsp_response() and rejected handshake if the certificate was
10175b9c547cSRui Paulo * found to be revoked. However, if the response indicates that the
10185b9c547cSRui Paulo * status is unknown, handshake continues and reaches here. We need to
10195b9c547cSRui Paulo * re-import the OCSP response to check for unknown certificate status,
10205b9c547cSRui Paulo * but we do not need to repeat gnutls_ocsp_resp_check_crt() and
10215b9c547cSRui Paulo * gnutls_ocsp_resp_verify_direct() calls.
10225b9c547cSRui Paulo */
10235b9c547cSRui Paulo
10245b9c547cSRui Paulo res = gnutls_ocsp_status_request_get(session, &response);
10255b9c547cSRui Paulo if (res != GNUTLS_E_SUCCESS) {
10265b9c547cSRui Paulo wpa_printf(MSG_INFO,
10275b9c547cSRui Paulo "GnuTLS: OCSP response was received, but it was not valid");
10285b9c547cSRui Paulo goto ocsp_error;
10295b9c547cSRui Paulo }
10305b9c547cSRui Paulo
10315b9c547cSRui Paulo if (gnutls_ocsp_resp_init(&resp) != GNUTLS_E_SUCCESS)
10325b9c547cSRui Paulo goto ocsp_error;
10335b9c547cSRui Paulo
10345b9c547cSRui Paulo res = gnutls_ocsp_resp_import(resp, &response);
10355b9c547cSRui Paulo if (res != GNUTLS_E_SUCCESS) {
10365b9c547cSRui Paulo wpa_printf(MSG_INFO,
10375b9c547cSRui Paulo "GnuTLS: Could not parse received OCSP response: %s",
10385b9c547cSRui Paulo gnutls_strerror(res));
10395b9c547cSRui Paulo gnutls_ocsp_resp_deinit(resp);
10405b9c547cSRui Paulo goto ocsp_error;
10415b9c547cSRui Paulo }
10425b9c547cSRui Paulo
10435b9c547cSRui Paulo res = gnutls_ocsp_resp_print(resp, GNUTLS_OCSP_PRINT_FULL, &buf);
10445b9c547cSRui Paulo if (res == GNUTLS_E_SUCCESS) {
10455b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "GnuTLS: %s", buf.data);
10465b9c547cSRui Paulo gnutls_free(buf.data);
10475b9c547cSRui Paulo }
10485b9c547cSRui Paulo
10495b9c547cSRui Paulo res = gnutls_ocsp_resp_get_single(resp, 0, NULL, NULL, NULL,
10505b9c547cSRui Paulo NULL, &cert_status, NULL,
10515b9c547cSRui Paulo NULL, NULL, NULL);
10525b9c547cSRui Paulo gnutls_ocsp_resp_deinit(resp);
10535b9c547cSRui Paulo if (res != GNUTLS_E_SUCCESS) {
10545b9c547cSRui Paulo wpa_printf(MSG_INFO,
10555b9c547cSRui Paulo "GnuTLS: Failed to extract OCSP information: %s",
10565b9c547cSRui Paulo gnutls_strerror(res));
10575b9c547cSRui Paulo goto ocsp_error;
10585b9c547cSRui Paulo }
10595b9c547cSRui Paulo
10605b9c547cSRui Paulo if (cert_status == GNUTLS_OCSP_CERT_GOOD) {
10615b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "GnuTLS: OCSP cert status: good");
10625b9c547cSRui Paulo } else if (cert_status == GNUTLS_OCSP_CERT_REVOKED) {
10635b9c547cSRui Paulo wpa_printf(MSG_DEBUG,
10645b9c547cSRui Paulo "GnuTLS: OCSP cert status: revoked");
10655b9c547cSRui Paulo goto ocsp_error;
10665b9c547cSRui Paulo } else {
10675b9c547cSRui Paulo wpa_printf(MSG_DEBUG,
10685b9c547cSRui Paulo "GnuTLS: OCSP cert status: unknown");
10695b9c547cSRui Paulo if (conn->flags & TLS_CONN_REQUIRE_OCSP)
10705b9c547cSRui Paulo goto ocsp_error;
10715b9c547cSRui Paulo wpa_printf(MSG_DEBUG,
10725b9c547cSRui Paulo "GnuTLS: OCSP was not required, so allow connection to continue");
10735b9c547cSRui Paulo }
10745b9c547cSRui Paulo
10755b9c547cSRui Paulo return 0;
10765b9c547cSRui Paulo
10775b9c547cSRui Paulo ocsp_error:
10785b9c547cSRui Paulo gnutls_tls_fail_event(conn, NULL, 0, NULL,
10795b9c547cSRui Paulo "bad certificate status response",
10805b9c547cSRui Paulo TLS_FAIL_REVOKED);
10815b9c547cSRui Paulo *err = GNUTLS_A_CERTIFICATE_REVOKED;
10825b9c547cSRui Paulo return -1;
10835b9c547cSRui Paulo #else /* GnuTLS 3.1.3 or newer */
10845b9c547cSRui Paulo return 0;
10855b9c547cSRui Paulo #endif /* GnuTLS 3.1.3 or newer */
10865b9c547cSRui Paulo }
10875b9c547cSRui Paulo
10885b9c547cSRui Paulo
tls_match_suffix_helper(gnutls_x509_crt_t cert,const char * match,int full)1089*4bc52338SCy Schubert static int tls_match_suffix_helper(gnutls_x509_crt_t cert, const char *match,
1090*4bc52338SCy Schubert int full)
1091*4bc52338SCy Schubert {
1092*4bc52338SCy Schubert int res = -1;
1093*4bc52338SCy Schubert
1094*4bc52338SCy Schubert #if GNUTLS_VERSION_NUMBER >= 0x030300
1095*4bc52338SCy Schubert if (full)
1096*4bc52338SCy Schubert res = gnutls_x509_crt_check_hostname2(
1097*4bc52338SCy Schubert cert, match,
1098*4bc52338SCy Schubert GNUTLS_VERIFY_DO_NOT_ALLOW_WILDCARDS);
1099*4bc52338SCy Schubert #endif /* >= 3.3.0 */
1100*4bc52338SCy Schubert if (res == -1)
1101*4bc52338SCy Schubert res = gnutls_x509_crt_check_hostname(cert, match);
1102*4bc52338SCy Schubert
1103*4bc52338SCy Schubert wpa_printf(MSG_DEBUG, "TLS: Match domain against %s%s --> res=%d",
1104*4bc52338SCy Schubert full ? "": "suffix ", match, res);
1105*4bc52338SCy Schubert return res;
1106*4bc52338SCy Schubert }
1107*4bc52338SCy Schubert
1108*4bc52338SCy Schubert
tls_match_suffix(gnutls_x509_crt_t cert,const char * match,int full)1109*4bc52338SCy Schubert static int tls_match_suffix(gnutls_x509_crt_t cert, const char *match,
1110*4bc52338SCy Schubert int full)
1111*4bc52338SCy Schubert {
1112*4bc52338SCy Schubert char *values, *token, *context = NULL;
1113*4bc52338SCy Schubert int ret = 0;
1114*4bc52338SCy Schubert
1115*4bc52338SCy Schubert if (!os_strchr(match, ';'))
1116*4bc52338SCy Schubert return tls_match_suffix_helper(cert, match, full);
1117*4bc52338SCy Schubert
1118*4bc52338SCy Schubert values = os_strdup(match);
1119*4bc52338SCy Schubert if (!values)
1120*4bc52338SCy Schubert return 0;
1121*4bc52338SCy Schubert
1122*4bc52338SCy Schubert /* Process each match alternative separately until a match is found */
1123*4bc52338SCy Schubert while ((token = str_token(values, ";", &context))) {
1124*4bc52338SCy Schubert if (tls_match_suffix_helper(cert, token, full)) {
1125*4bc52338SCy Schubert ret = 1;
1126*4bc52338SCy Schubert break;
1127*4bc52338SCy Schubert }
1128*4bc52338SCy Schubert }
1129*4bc52338SCy Schubert
1130*4bc52338SCy Schubert os_free(values);
1131*4bc52338SCy Schubert return ret;
1132*4bc52338SCy Schubert }
1133*4bc52338SCy Schubert
1134*4bc52338SCy Schubert
tls_connection_verify_peer(gnutls_session_t session)11355b9c547cSRui Paulo static int tls_connection_verify_peer(gnutls_session_t session)
11365b9c547cSRui Paulo {
11375b9c547cSRui Paulo struct tls_connection *conn;
113839beb93cSSam Leffler unsigned int status, num_certs, i;
113939beb93cSSam Leffler struct os_time now;
114039beb93cSSam Leffler const gnutls_datum_t *certs;
114139beb93cSSam Leffler gnutls_x509_crt_t cert;
11425b9c547cSRui Paulo gnutls_alert_description_t err;
11435b9c547cSRui Paulo int res;
114439beb93cSSam Leffler
11455b9c547cSRui Paulo conn = gnutls_session_get_ptr(session);
11465b9c547cSRui Paulo if (!conn->verify_peer) {
11475b9c547cSRui Paulo wpa_printf(MSG_DEBUG,
11485b9c547cSRui Paulo "GnuTLS: No peer certificate verification enabled");
11495b9c547cSRui Paulo return 0;
11505b9c547cSRui Paulo }
11515b9c547cSRui Paulo
11525b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "GnuTSL: Verifying peer certificate");
11535b9c547cSRui Paulo
11545b9c547cSRui Paulo #if GNUTLS_VERSION_NUMBER >= 0x030300
11555b9c547cSRui Paulo {
11565b9c547cSRui Paulo gnutls_typed_vdata_st data[1];
11575b9c547cSRui Paulo unsigned int elements = 0;
11585b9c547cSRui Paulo
11595b9c547cSRui Paulo os_memset(data, 0, sizeof(data));
11605b9c547cSRui Paulo if (!conn->global->server) {
11615b9c547cSRui Paulo data[elements].type = GNUTLS_DT_KEY_PURPOSE_OID;
11625b9c547cSRui Paulo data[elements].data = (void *) GNUTLS_KP_TLS_WWW_SERVER;
11635b9c547cSRui Paulo elements++;
11645b9c547cSRui Paulo }
11655b9c547cSRui Paulo res = gnutls_certificate_verify_peers(session, data, 1,
11665b9c547cSRui Paulo &status);
11675b9c547cSRui Paulo }
11685b9c547cSRui Paulo #else /* < 3.3.0 */
11695b9c547cSRui Paulo res = gnutls_certificate_verify_peers2(session, &status);
11705b9c547cSRui Paulo #endif
11715b9c547cSRui Paulo if (res < 0) {
117239beb93cSSam Leffler wpa_printf(MSG_INFO, "TLS: Failed to verify peer "
117339beb93cSSam Leffler "certificate chain");
11745b9c547cSRui Paulo err = GNUTLS_A_INTERNAL_ERROR;
11755b9c547cSRui Paulo goto out;
11765b9c547cSRui Paulo }
11775b9c547cSRui Paulo
11785b9c547cSRui Paulo #if GNUTLS_VERSION_NUMBER >= 0x030104
11795b9c547cSRui Paulo {
11805b9c547cSRui Paulo gnutls_datum_t info;
11815b9c547cSRui Paulo int ret, type;
11825b9c547cSRui Paulo
11835b9c547cSRui Paulo type = gnutls_certificate_type_get(session);
11845b9c547cSRui Paulo ret = gnutls_certificate_verification_status_print(status, type,
11855b9c547cSRui Paulo &info, 0);
11865b9c547cSRui Paulo if (ret < 0) {
11875b9c547cSRui Paulo wpa_printf(MSG_DEBUG,
11885b9c547cSRui Paulo "GnuTLS: Failed to print verification status");
11895b9c547cSRui Paulo err = GNUTLS_A_INTERNAL_ERROR;
11905b9c547cSRui Paulo goto out;
11915b9c547cSRui Paulo }
11925b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "GnuTLS: %s", info.data);
11935b9c547cSRui Paulo gnutls_free(info.data);
11945b9c547cSRui Paulo }
11955b9c547cSRui Paulo #endif /* GnuTLS 3.1.4 or newer */
11965b9c547cSRui Paulo
11975b9c547cSRui Paulo certs = gnutls_certificate_get_peers(session, &num_certs);
11985b9c547cSRui Paulo if (certs == NULL || num_certs == 0) {
11995b9c547cSRui Paulo wpa_printf(MSG_INFO, "TLS: No peer certificate chain received");
12005b9c547cSRui Paulo err = GNUTLS_A_UNKNOWN_CA;
12015b9c547cSRui Paulo goto out;
120239beb93cSSam Leffler }
120339beb93cSSam Leffler
120439beb93cSSam Leffler if (conn->verify_peer && (status & GNUTLS_CERT_INVALID)) {
120539beb93cSSam Leffler wpa_printf(MSG_INFO, "TLS: Peer certificate not trusted");
12063157ba21SRui Paulo if (status & GNUTLS_CERT_INSECURE_ALGORITHM) {
12073157ba21SRui Paulo wpa_printf(MSG_INFO, "TLS: Certificate uses insecure "
12083157ba21SRui Paulo "algorithm");
12095b9c547cSRui Paulo gnutls_tls_fail_event(conn, NULL, 0, NULL,
12105b9c547cSRui Paulo "certificate uses insecure algorithm",
12115b9c547cSRui Paulo TLS_FAIL_BAD_CERTIFICATE);
12125b9c547cSRui Paulo err = GNUTLS_A_INSUFFICIENT_SECURITY;
12135b9c547cSRui Paulo goto out;
12143157ba21SRui Paulo }
12153157ba21SRui Paulo if (status & GNUTLS_CERT_NOT_ACTIVATED) {
12163157ba21SRui Paulo wpa_printf(MSG_INFO, "TLS: Certificate not yet "
12173157ba21SRui Paulo "activated");
12185b9c547cSRui Paulo gnutls_tls_fail_event(conn, NULL, 0, NULL,
12195b9c547cSRui Paulo "certificate not yet valid",
12205b9c547cSRui Paulo TLS_FAIL_NOT_YET_VALID);
12215b9c547cSRui Paulo err = GNUTLS_A_CERTIFICATE_EXPIRED;
12225b9c547cSRui Paulo goto out;
12233157ba21SRui Paulo }
12243157ba21SRui Paulo if (status & GNUTLS_CERT_EXPIRED) {
12253157ba21SRui Paulo wpa_printf(MSG_INFO, "TLS: Certificate expired");
12265b9c547cSRui Paulo gnutls_tls_fail_event(conn, NULL, 0, NULL,
12275b9c547cSRui Paulo "certificate has expired",
12285b9c547cSRui Paulo TLS_FAIL_EXPIRED);
12295b9c547cSRui Paulo err = GNUTLS_A_CERTIFICATE_EXPIRED;
12305b9c547cSRui Paulo goto out;
12313157ba21SRui Paulo }
12325b9c547cSRui Paulo gnutls_tls_fail_event(conn, NULL, 0, NULL,
12335b9c547cSRui Paulo "untrusted certificate",
12345b9c547cSRui Paulo TLS_FAIL_UNTRUSTED);
12355b9c547cSRui Paulo err = GNUTLS_A_INTERNAL_ERROR;
12365b9c547cSRui Paulo goto out;
123739beb93cSSam Leffler }
123839beb93cSSam Leffler
123939beb93cSSam Leffler if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
124039beb93cSSam Leffler wpa_printf(MSG_INFO, "TLS: Peer certificate does not have a "
124139beb93cSSam Leffler "known issuer");
12425b9c547cSRui Paulo gnutls_tls_fail_event(conn, NULL, 0, NULL, "signed not found",
12435b9c547cSRui Paulo TLS_FAIL_UNTRUSTED);
12445b9c547cSRui Paulo err = GNUTLS_A_UNKNOWN_CA;
12455b9c547cSRui Paulo goto out;
124639beb93cSSam Leffler }
124739beb93cSSam Leffler
124839beb93cSSam Leffler if (status & GNUTLS_CERT_REVOKED) {
124939beb93cSSam Leffler wpa_printf(MSG_INFO, "TLS: Peer certificate has been revoked");
12505b9c547cSRui Paulo gnutls_tls_fail_event(conn, NULL, 0, NULL,
12515b9c547cSRui Paulo "certificate revoked",
12525b9c547cSRui Paulo TLS_FAIL_REVOKED);
12535b9c547cSRui Paulo err = GNUTLS_A_CERTIFICATE_REVOKED;
12545b9c547cSRui Paulo goto out;
125539beb93cSSam Leffler }
125639beb93cSSam Leffler
12575b9c547cSRui Paulo if (status != 0) {
12585b9c547cSRui Paulo wpa_printf(MSG_INFO, "TLS: Unknown verification status: %d",
12595b9c547cSRui Paulo status);
12605b9c547cSRui Paulo err = GNUTLS_A_INTERNAL_ERROR;
12615b9c547cSRui Paulo goto out;
12625b9c547cSRui Paulo }
12635b9c547cSRui Paulo
12645b9c547cSRui Paulo if (check_ocsp(conn, session, &err))
12655b9c547cSRui Paulo goto out;
12665b9c547cSRui Paulo
126739beb93cSSam Leffler os_get_time(&now);
126839beb93cSSam Leffler
126939beb93cSSam Leffler for (i = 0; i < num_certs; i++) {
127039beb93cSSam Leffler char *buf;
127139beb93cSSam Leffler size_t len;
127239beb93cSSam Leffler if (gnutls_x509_crt_init(&cert) < 0) {
127339beb93cSSam Leffler wpa_printf(MSG_INFO, "TLS: Certificate initialization "
127439beb93cSSam Leffler "failed");
12755b9c547cSRui Paulo err = GNUTLS_A_BAD_CERTIFICATE;
12765b9c547cSRui Paulo goto out;
127739beb93cSSam Leffler }
127839beb93cSSam Leffler
127939beb93cSSam Leffler if (gnutls_x509_crt_import(cert, &certs[i],
128039beb93cSSam Leffler GNUTLS_X509_FMT_DER) < 0) {
128139beb93cSSam Leffler wpa_printf(MSG_INFO, "TLS: Could not parse peer "
128239beb93cSSam Leffler "certificate %d/%d", i + 1, num_certs);
128339beb93cSSam Leffler gnutls_x509_crt_deinit(cert);
12845b9c547cSRui Paulo err = GNUTLS_A_BAD_CERTIFICATE;
12855b9c547cSRui Paulo goto out;
128639beb93cSSam Leffler }
128739beb93cSSam Leffler
128839beb93cSSam Leffler gnutls_x509_crt_get_dn(cert, NULL, &len);
128939beb93cSSam Leffler len++;
129039beb93cSSam Leffler buf = os_malloc(len + 1);
129139beb93cSSam Leffler if (buf) {
129239beb93cSSam Leffler buf[0] = buf[len] = '\0';
129339beb93cSSam Leffler gnutls_x509_crt_get_dn(cert, buf, &len);
129439beb93cSSam Leffler }
129539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TLS: Peer cert chain %d/%d: %s",
129639beb93cSSam Leffler i + 1, num_certs, buf);
129739beb93cSSam Leffler
12985b9c547cSRui Paulo if (conn->global->event_cb) {
12995b9c547cSRui Paulo struct wpabuf *cert_buf = NULL;
13005b9c547cSRui Paulo union tls_event_data ev;
13015b9c547cSRui Paulo #ifdef CONFIG_SHA256
13025b9c547cSRui Paulo u8 hash[32];
13035b9c547cSRui Paulo const u8 *_addr[1];
13045b9c547cSRui Paulo size_t _len[1];
13055b9c547cSRui Paulo #endif /* CONFIG_SHA256 */
13065b9c547cSRui Paulo
13075b9c547cSRui Paulo os_memset(&ev, 0, sizeof(ev));
13085b9c547cSRui Paulo if (conn->global->cert_in_cb) {
13095b9c547cSRui Paulo cert_buf = wpabuf_alloc_copy(certs[i].data,
13105b9c547cSRui Paulo certs[i].size);
13115b9c547cSRui Paulo ev.peer_cert.cert = cert_buf;
13125b9c547cSRui Paulo }
13135b9c547cSRui Paulo #ifdef CONFIG_SHA256
13145b9c547cSRui Paulo _addr[0] = certs[i].data;
13155b9c547cSRui Paulo _len[0] = certs[i].size;
13165b9c547cSRui Paulo if (sha256_vector(1, _addr, _len, hash) == 0) {
13175b9c547cSRui Paulo ev.peer_cert.hash = hash;
13185b9c547cSRui Paulo ev.peer_cert.hash_len = sizeof(hash);
13195b9c547cSRui Paulo }
13205b9c547cSRui Paulo #endif /* CONFIG_SHA256 */
13215b9c547cSRui Paulo ev.peer_cert.depth = i;
13225b9c547cSRui Paulo ev.peer_cert.subject = buf;
13235b9c547cSRui Paulo conn->global->event_cb(conn->global->cb_ctx,
13245b9c547cSRui Paulo TLS_PEER_CERTIFICATE, &ev);
13255b9c547cSRui Paulo wpabuf_free(cert_buf);
13265b9c547cSRui Paulo }
13275b9c547cSRui Paulo
132839beb93cSSam Leffler if (i == 0) {
13295b9c547cSRui Paulo if (conn->suffix_match &&
1330*4bc52338SCy Schubert !tls_match_suffix(cert, conn->suffix_match, 0)) {
13315b9c547cSRui Paulo wpa_printf(MSG_WARNING,
13325b9c547cSRui Paulo "TLS: Domain suffix match '%s' not found",
13335b9c547cSRui Paulo conn->suffix_match);
13345b9c547cSRui Paulo gnutls_tls_fail_event(
13355b9c547cSRui Paulo conn, &certs[i], i, buf,
13365b9c547cSRui Paulo "Domain suffix mismatch",
13375b9c547cSRui Paulo TLS_FAIL_DOMAIN_SUFFIX_MISMATCH);
13385b9c547cSRui Paulo err = GNUTLS_A_BAD_CERTIFICATE;
13395b9c547cSRui Paulo gnutls_x509_crt_deinit(cert);
13405b9c547cSRui Paulo os_free(buf);
13415b9c547cSRui Paulo goto out;
13425b9c547cSRui Paulo }
13435b9c547cSRui Paulo
13445b9c547cSRui Paulo #if GNUTLS_VERSION_NUMBER >= 0x030300
13455b9c547cSRui Paulo if (conn->domain_match &&
1346*4bc52338SCy Schubert !tls_match_suffix(cert, conn->domain_match, 1)) {
13475b9c547cSRui Paulo wpa_printf(MSG_WARNING,
13485b9c547cSRui Paulo "TLS: Domain match '%s' not found",
13495b9c547cSRui Paulo conn->domain_match);
13505b9c547cSRui Paulo gnutls_tls_fail_event(
13515b9c547cSRui Paulo conn, &certs[i], i, buf,
13525b9c547cSRui Paulo "Domain mismatch",
13535b9c547cSRui Paulo TLS_FAIL_DOMAIN_MISMATCH);
13545b9c547cSRui Paulo err = GNUTLS_A_BAD_CERTIFICATE;
13555b9c547cSRui Paulo gnutls_x509_crt_deinit(cert);
13565b9c547cSRui Paulo os_free(buf);
13575b9c547cSRui Paulo goto out;
13585b9c547cSRui Paulo }
13595b9c547cSRui Paulo #endif /* >= 3.3.0 */
13605b9c547cSRui Paulo
13615b9c547cSRui Paulo /* TODO: validate altsubject_match.
13625b9c547cSRui Paulo * For now, any such configuration is rejected in
13635b9c547cSRui Paulo * tls_connection_set_params() */
13645b9c547cSRui Paulo
13655b9c547cSRui Paulo #if GNUTLS_VERSION_NUMBER < 0x030300
13665b9c547cSRui Paulo /*
13675b9c547cSRui Paulo * gnutls_certificate_verify_peers() not available, so
13685b9c547cSRui Paulo * need to check EKU separately.
13695b9c547cSRui Paulo */
13705b9c547cSRui Paulo if (!conn->global->server &&
13715b9c547cSRui Paulo !server_eku_purpose(cert)) {
13725b9c547cSRui Paulo wpa_printf(MSG_WARNING,
13735b9c547cSRui Paulo "GnuTLS: No server EKU");
13745b9c547cSRui Paulo gnutls_tls_fail_event(
13755b9c547cSRui Paulo conn, &certs[i], i, buf,
13765b9c547cSRui Paulo "No server EKU",
13775b9c547cSRui Paulo TLS_FAIL_BAD_CERTIFICATE);
13785b9c547cSRui Paulo err = GNUTLS_A_BAD_CERTIFICATE;
13795b9c547cSRui Paulo gnutls_x509_crt_deinit(cert);
13805b9c547cSRui Paulo os_free(buf);
13815b9c547cSRui Paulo goto out;
13825b9c547cSRui Paulo }
13835b9c547cSRui Paulo #endif /* < 3.3.0 */
13845b9c547cSRui Paulo }
13855b9c547cSRui Paulo
13865b9c547cSRui Paulo if (!conn->disable_time_checks &&
13875b9c547cSRui Paulo (gnutls_x509_crt_get_expiration_time(cert) < now.sec ||
13885b9c547cSRui Paulo gnutls_x509_crt_get_activation_time(cert) > now.sec)) {
13895b9c547cSRui Paulo wpa_printf(MSG_INFO, "TLS: Peer certificate %d/%d is "
13905b9c547cSRui Paulo "not valid at this time",
13915b9c547cSRui Paulo i + 1, num_certs);
13925b9c547cSRui Paulo gnutls_tls_fail_event(
13935b9c547cSRui Paulo conn, &certs[i], i, buf,
13945b9c547cSRui Paulo "Certificate is not valid at this time",
13955b9c547cSRui Paulo TLS_FAIL_EXPIRED);
13965b9c547cSRui Paulo gnutls_x509_crt_deinit(cert);
13975b9c547cSRui Paulo os_free(buf);
13985b9c547cSRui Paulo err = GNUTLS_A_CERTIFICATE_EXPIRED;
13995b9c547cSRui Paulo goto out;
140039beb93cSSam Leffler }
140139beb93cSSam Leffler
140239beb93cSSam Leffler os_free(buf);
140339beb93cSSam Leffler
140439beb93cSSam Leffler gnutls_x509_crt_deinit(cert);
140539beb93cSSam Leffler }
140639beb93cSSam Leffler
14075b9c547cSRui Paulo if (conn->global->event_cb != NULL)
14085b9c547cSRui Paulo conn->global->event_cb(conn->global->cb_ctx,
14095b9c547cSRui Paulo TLS_CERT_CHAIN_SUCCESS, NULL);
141039beb93cSSam Leffler
141139beb93cSSam Leffler return 0;
14125b9c547cSRui Paulo
14135b9c547cSRui Paulo out:
14145b9c547cSRui Paulo conn->failed++;
14155b9c547cSRui Paulo gnutls_alert_send(session, GNUTLS_AL_FATAL, err);
14165b9c547cSRui Paulo return GNUTLS_E_CERTIFICATE_ERROR;
141739beb93cSSam Leffler }
141839beb93cSSam Leffler
141939beb93cSSam Leffler
gnutls_get_appl_data(struct tls_connection * conn)1420e28a4053SRui Paulo static struct wpabuf * gnutls_get_appl_data(struct tls_connection *conn)
142139beb93cSSam Leffler {
1422e28a4053SRui Paulo int res;
1423e28a4053SRui Paulo struct wpabuf *ad;
1424e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "GnuTLS: Check for possible Application Data");
1425e28a4053SRui Paulo ad = wpabuf_alloc((wpabuf_len(conn->pull_buf) + 500) * 3);
1426e28a4053SRui Paulo if (ad == NULL)
1427e28a4053SRui Paulo return NULL;
1428e28a4053SRui Paulo
1429e28a4053SRui Paulo res = gnutls_record_recv(conn->session, wpabuf_mhead(ad),
1430e28a4053SRui Paulo wpabuf_size(ad));
1431e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "GnuTLS: gnutls_record_recv: %d", res);
1432e28a4053SRui Paulo if (res < 0) {
1433f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d "
1434e28a4053SRui Paulo "(%s)", __func__, (int) res,
1435e28a4053SRui Paulo gnutls_strerror(res));
1436e28a4053SRui Paulo wpabuf_free(ad);
1437e28a4053SRui Paulo return NULL;
1438e28a4053SRui Paulo }
1439e28a4053SRui Paulo
1440e28a4053SRui Paulo wpabuf_put(ad, res);
1441e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "GnuTLS: Received %d bytes of Application Data",
1442e28a4053SRui Paulo res);
1443e28a4053SRui Paulo return ad;
1444e28a4053SRui Paulo }
1445e28a4053SRui Paulo
1446e28a4053SRui Paulo
tls_connection_handshake(void * tls_ctx,struct tls_connection * conn,const struct wpabuf * in_data,struct wpabuf ** appl_data)1447e28a4053SRui Paulo struct wpabuf * tls_connection_handshake(void *tls_ctx,
1448e28a4053SRui Paulo struct tls_connection *conn,
1449e28a4053SRui Paulo const struct wpabuf *in_data,
1450e28a4053SRui Paulo struct wpabuf **appl_data)
1451e28a4053SRui Paulo {
1452e28a4053SRui Paulo struct tls_global *global = tls_ctx;
1453e28a4053SRui Paulo struct wpabuf *out_data;
145439beb93cSSam Leffler int ret;
145539beb93cSSam Leffler
145639beb93cSSam Leffler if (appl_data)
145739beb93cSSam Leffler *appl_data = NULL;
145839beb93cSSam Leffler
1459e28a4053SRui Paulo if (in_data && wpabuf_len(in_data) > 0) {
146039beb93cSSam Leffler if (conn->pull_buf) {
146139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
146239beb93cSSam Leffler "pull_buf", __func__,
1463e28a4053SRui Paulo (unsigned long) wpabuf_len(conn->pull_buf));
1464e28a4053SRui Paulo wpabuf_free(conn->pull_buf);
146539beb93cSSam Leffler }
1466e28a4053SRui Paulo conn->pull_buf = wpabuf_dup(in_data);
146739beb93cSSam Leffler if (conn->pull_buf == NULL)
146839beb93cSSam Leffler return NULL;
1469e28a4053SRui Paulo conn->pull_buf_offset = wpabuf_head(conn->pull_buf);
147039beb93cSSam Leffler }
147139beb93cSSam Leffler
147239beb93cSSam Leffler ret = gnutls_handshake(conn->session);
147339beb93cSSam Leffler if (ret < 0) {
14745b9c547cSRui Paulo gnutls_alert_description_t alert;
147585732ac8SCy Schubert union tls_event_data ev;
14765b9c547cSRui Paulo
147739beb93cSSam Leffler switch (ret) {
147839beb93cSSam Leffler case GNUTLS_E_AGAIN:
147939beb93cSSam Leffler if (global->server && conn->established &&
148039beb93cSSam Leffler conn->push_buf == NULL) {
148139beb93cSSam Leffler /* Need to return something to trigger
148239beb93cSSam Leffler * completion of EAP-TLS. */
1483e28a4053SRui Paulo conn->push_buf = wpabuf_alloc(0);
148439beb93cSSam Leffler }
148539beb93cSSam Leffler break;
148685732ac8SCy Schubert case GNUTLS_E_DH_PRIME_UNACCEPTABLE:
148785732ac8SCy Schubert wpa_printf(MSG_DEBUG, "GnuTLS: Unacceptable DH prime");
148885732ac8SCy Schubert if (conn->global->event_cb) {
148985732ac8SCy Schubert os_memset(&ev, 0, sizeof(ev));
149085732ac8SCy Schubert ev.alert.is_local = 1;
149185732ac8SCy Schubert ev.alert.type = "fatal";
149285732ac8SCy Schubert ev.alert.description = "insufficient security";
149385732ac8SCy Schubert conn->global->event_cb(conn->global->cb_ctx,
149485732ac8SCy Schubert TLS_ALERT, &ev);
149585732ac8SCy Schubert }
149685732ac8SCy Schubert /*
149785732ac8SCy Schubert * Could send a TLS Alert to the server, but for now,
149885732ac8SCy Schubert * simply terminate handshake.
149985732ac8SCy Schubert */
150085732ac8SCy Schubert conn->failed++;
150185732ac8SCy Schubert conn->write_alerts++;
150285732ac8SCy Schubert break;
150339beb93cSSam Leffler case GNUTLS_E_FATAL_ALERT_RECEIVED:
15045b9c547cSRui Paulo alert = gnutls_alert_get(conn->session);
150539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "%s - received fatal '%s' alert",
15065b9c547cSRui Paulo __func__, gnutls_alert_get_name(alert));
150739beb93cSSam Leffler conn->read_alerts++;
15085b9c547cSRui Paulo if (conn->global->event_cb != NULL) {
15095b9c547cSRui Paulo os_memset(&ev, 0, sizeof(ev));
15105b9c547cSRui Paulo ev.alert.is_local = 0;
15115b9c547cSRui Paulo ev.alert.type = gnutls_alert_get_name(alert);
15125b9c547cSRui Paulo ev.alert.description = ev.alert.type;
15135b9c547cSRui Paulo conn->global->event_cb(conn->global->cb_ctx,
15145b9c547cSRui Paulo TLS_ALERT, &ev);
15155b9c547cSRui Paulo }
151639beb93cSSam Leffler /* continue */
151739beb93cSSam Leffler default:
151839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "%s - gnutls_handshake failed "
151939beb93cSSam Leffler "-> %s", __func__, gnutls_strerror(ret));
152039beb93cSSam Leffler conn->failed++;
152139beb93cSSam Leffler }
152239beb93cSSam Leffler } else {
152339beb93cSSam Leffler size_t size;
152439beb93cSSam Leffler
1525f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TLS: Handshake completed successfully");
15265b9c547cSRui Paulo
15275b9c547cSRui Paulo #if GNUTLS_VERSION_NUMBER >= 0x03010a
15285b9c547cSRui Paulo {
15295b9c547cSRui Paulo char *desc;
15305b9c547cSRui Paulo
15315b9c547cSRui Paulo desc = gnutls_session_get_desc(conn->session);
15325b9c547cSRui Paulo if (desc) {
15335b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "GnuTLS: %s", desc);
15345b9c547cSRui Paulo gnutls_free(desc);
15355b9c547cSRui Paulo }
15365b9c547cSRui Paulo }
15375b9c547cSRui Paulo #endif /* GnuTLS 3.1.10 or newer */
15385b9c547cSRui Paulo
153939beb93cSSam Leffler conn->established = 1;
154039beb93cSSam Leffler if (conn->push_buf == NULL) {
154139beb93cSSam Leffler /* Need to return something to get final TLS ACK. */
1542e28a4053SRui Paulo conn->push_buf = wpabuf_alloc(0);
154339beb93cSSam Leffler }
154439beb93cSSam Leffler
154539beb93cSSam Leffler gnutls_session_get_data(conn->session, NULL, &size);
154639beb93cSSam Leffler if (global->session_data == NULL ||
154739beb93cSSam Leffler global->session_data_size < size) {
154839beb93cSSam Leffler os_free(global->session_data);
154939beb93cSSam Leffler global->session_data = os_malloc(size);
155039beb93cSSam Leffler }
155139beb93cSSam Leffler if (global->session_data) {
155239beb93cSSam Leffler global->session_data_size = size;
155339beb93cSSam Leffler gnutls_session_get_data(conn->session,
155439beb93cSSam Leffler global->session_data,
155539beb93cSSam Leffler &global->session_data_size);
155639beb93cSSam Leffler }
1557e28a4053SRui Paulo
1558e28a4053SRui Paulo if (conn->pull_buf && appl_data)
1559e28a4053SRui Paulo *appl_data = gnutls_get_appl_data(conn);
156039beb93cSSam Leffler }
156139beb93cSSam Leffler
156239beb93cSSam Leffler out_data = conn->push_buf;
156339beb93cSSam Leffler conn->push_buf = NULL;
156439beb93cSSam Leffler return out_data;
156539beb93cSSam Leffler }
156639beb93cSSam Leffler
156739beb93cSSam Leffler
tls_connection_server_handshake(void * tls_ctx,struct tls_connection * conn,const struct wpabuf * in_data,struct wpabuf ** appl_data)1568e28a4053SRui Paulo struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
156939beb93cSSam Leffler struct tls_connection *conn,
1570e28a4053SRui Paulo const struct wpabuf *in_data,
1571e28a4053SRui Paulo struct wpabuf **appl_data)
157239beb93cSSam Leffler {
1573e28a4053SRui Paulo return tls_connection_handshake(tls_ctx, conn, in_data, appl_data);
157439beb93cSSam Leffler }
157539beb93cSSam Leffler
157639beb93cSSam Leffler
tls_connection_encrypt(void * tls_ctx,struct tls_connection * conn,const struct wpabuf * in_data)1577e28a4053SRui Paulo struct wpabuf * tls_connection_encrypt(void *tls_ctx,
1578e28a4053SRui Paulo struct tls_connection *conn,
1579e28a4053SRui Paulo const struct wpabuf *in_data)
158039beb93cSSam Leffler {
158139beb93cSSam Leffler ssize_t res;
1582e28a4053SRui Paulo struct wpabuf *buf;
158339beb93cSSam Leffler
1584e28a4053SRui Paulo res = gnutls_record_send(conn->session, wpabuf_head(in_data),
1585e28a4053SRui Paulo wpabuf_len(in_data));
158639beb93cSSam Leffler if (res < 0) {
158739beb93cSSam Leffler wpa_printf(MSG_INFO, "%s: Encryption failed: %s",
158839beb93cSSam Leffler __func__, gnutls_strerror(res));
1589e28a4053SRui Paulo return NULL;
159039beb93cSSam Leffler }
1591e28a4053SRui Paulo
1592e28a4053SRui Paulo buf = conn->push_buf;
159339beb93cSSam Leffler conn->push_buf = NULL;
1594e28a4053SRui Paulo return buf;
159539beb93cSSam Leffler }
159639beb93cSSam Leffler
159739beb93cSSam Leffler
tls_connection_decrypt(void * tls_ctx,struct tls_connection * conn,const struct wpabuf * in_data)1598e28a4053SRui Paulo struct wpabuf * tls_connection_decrypt(void *tls_ctx,
1599e28a4053SRui Paulo struct tls_connection *conn,
1600e28a4053SRui Paulo const struct wpabuf *in_data)
160139beb93cSSam Leffler {
160239beb93cSSam Leffler ssize_t res;
1603e28a4053SRui Paulo struct wpabuf *out;
160439beb93cSSam Leffler
160539beb93cSSam Leffler if (conn->pull_buf) {
160639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
160739beb93cSSam Leffler "pull_buf", __func__,
1608e28a4053SRui Paulo (unsigned long) wpabuf_len(conn->pull_buf));
1609e28a4053SRui Paulo wpabuf_free(conn->pull_buf);
161039beb93cSSam Leffler }
1611e28a4053SRui Paulo conn->pull_buf = wpabuf_dup(in_data);
161239beb93cSSam Leffler if (conn->pull_buf == NULL)
1613e28a4053SRui Paulo return NULL;
1614e28a4053SRui Paulo conn->pull_buf_offset = wpabuf_head(conn->pull_buf);
1615e28a4053SRui Paulo
1616e28a4053SRui Paulo /*
1617e28a4053SRui Paulo * Even though we try to disable TLS compression, it is possible that
1618e28a4053SRui Paulo * this cannot be done with all TLS libraries. Add extra buffer space
1619e28a4053SRui Paulo * to handle the possibility of the decrypted data being longer than
1620e28a4053SRui Paulo * input data.
1621e28a4053SRui Paulo */
1622e28a4053SRui Paulo out = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
1623e28a4053SRui Paulo if (out == NULL)
1624e28a4053SRui Paulo return NULL;
162539beb93cSSam Leffler
1626e28a4053SRui Paulo res = gnutls_record_recv(conn->session, wpabuf_mhead(out),
1627e28a4053SRui Paulo wpabuf_size(out));
162839beb93cSSam Leffler if (res < 0) {
162939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d "
163039beb93cSSam Leffler "(%s)", __func__, (int) res, gnutls_strerror(res));
1631e28a4053SRui Paulo wpabuf_free(out);
1632e28a4053SRui Paulo return NULL;
163339beb93cSSam Leffler }
1634e28a4053SRui Paulo wpabuf_put(out, res);
163539beb93cSSam Leffler
1636e28a4053SRui Paulo return out;
163739beb93cSSam Leffler }
163839beb93cSSam Leffler
163939beb93cSSam Leffler
tls_connection_resumed(void * ssl_ctx,struct tls_connection * conn)164039beb93cSSam Leffler int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
164139beb93cSSam Leffler {
164239beb93cSSam Leffler if (conn == NULL)
164339beb93cSSam Leffler return 0;
164439beb93cSSam Leffler return gnutls_session_is_resumed(conn->session);
164539beb93cSSam Leffler }
164639beb93cSSam Leffler
164739beb93cSSam Leffler
tls_connection_set_cipher_list(void * tls_ctx,struct tls_connection * conn,u8 * ciphers)164839beb93cSSam Leffler int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
164939beb93cSSam Leffler u8 *ciphers)
165039beb93cSSam Leffler {
165139beb93cSSam Leffler /* TODO */
165239beb93cSSam Leffler return -1;
165339beb93cSSam Leffler }
165439beb93cSSam Leffler
165539beb93cSSam Leffler
tls_get_version(void * ssl_ctx,struct tls_connection * conn,char * buf,size_t buflen)1656325151a3SRui Paulo int tls_get_version(void *ssl_ctx, struct tls_connection *conn,
1657325151a3SRui Paulo char *buf, size_t buflen)
1658325151a3SRui Paulo {
165985732ac8SCy Schubert gnutls_protocol_t ver;
166085732ac8SCy Schubert
166185732ac8SCy Schubert ver = gnutls_protocol_get_version(conn->session);
166285732ac8SCy Schubert if (ver == GNUTLS_TLS1_0)
166385732ac8SCy Schubert os_strlcpy(buf, "TLSv1", buflen);
166485732ac8SCy Schubert else if (ver == GNUTLS_TLS1_1)
166585732ac8SCy Schubert os_strlcpy(buf, "TLSv1.1", buflen);
166685732ac8SCy Schubert else if (ver == GNUTLS_TLS1_2)
166785732ac8SCy Schubert os_strlcpy(buf, "TLSv1.2", buflen);
166885732ac8SCy Schubert else
1669325151a3SRui Paulo return -1;
167085732ac8SCy Schubert return 0;
1671325151a3SRui Paulo }
1672325151a3SRui Paulo
1673325151a3SRui Paulo
tls_get_cipher(void * ssl_ctx,struct tls_connection * conn,char * buf,size_t buflen)167439beb93cSSam Leffler int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
167539beb93cSSam Leffler char *buf, size_t buflen)
167639beb93cSSam Leffler {
167785732ac8SCy Schubert gnutls_cipher_algorithm_t cipher;
167885732ac8SCy Schubert gnutls_kx_algorithm_t kx;
167985732ac8SCy Schubert gnutls_mac_algorithm_t mac;
168085732ac8SCy Schubert const char *kx_str, *cipher_str, *mac_str;
168185732ac8SCy Schubert int res;
168285732ac8SCy Schubert
168385732ac8SCy Schubert cipher = gnutls_cipher_get(conn->session);
168485732ac8SCy Schubert cipher_str = gnutls_cipher_get_name(cipher);
168585732ac8SCy Schubert if (!cipher_str)
168685732ac8SCy Schubert cipher_str = "";
168785732ac8SCy Schubert
168885732ac8SCy Schubert kx = gnutls_kx_get(conn->session);
168985732ac8SCy Schubert kx_str = gnutls_kx_get_name(kx);
169085732ac8SCy Schubert if (!kx_str)
169185732ac8SCy Schubert kx_str = "";
169285732ac8SCy Schubert
169385732ac8SCy Schubert mac = gnutls_mac_get(conn->session);
169485732ac8SCy Schubert mac_str = gnutls_mac_get_name(mac);
169585732ac8SCy Schubert if (!mac_str)
169685732ac8SCy Schubert mac_str = "";
169785732ac8SCy Schubert
169885732ac8SCy Schubert if (kx == GNUTLS_KX_RSA)
169985732ac8SCy Schubert res = os_snprintf(buf, buflen, "%s-%s", cipher_str, mac_str);
170085732ac8SCy Schubert else
170185732ac8SCy Schubert res = os_snprintf(buf, buflen, "%s-%s-%s",
170285732ac8SCy Schubert kx_str, cipher_str, mac_str);
170385732ac8SCy Schubert if (os_snprintf_error(buflen, res))
170485732ac8SCy Schubert return -1;
170585732ac8SCy Schubert
170639beb93cSSam Leffler return 0;
170739beb93cSSam Leffler }
170839beb93cSSam Leffler
170939beb93cSSam Leffler
tls_connection_enable_workaround(void * ssl_ctx,struct tls_connection * conn)171039beb93cSSam Leffler int tls_connection_enable_workaround(void *ssl_ctx,
171139beb93cSSam Leffler struct tls_connection *conn)
171239beb93cSSam Leffler {
1713e28a4053SRui Paulo gnutls_record_disable_padding(conn->session);
171439beb93cSSam Leffler return 0;
171539beb93cSSam Leffler }
171639beb93cSSam Leffler
171739beb93cSSam Leffler
tls_connection_client_hello_ext(void * ssl_ctx,struct tls_connection * conn,int ext_type,const u8 * data,size_t data_len)171839beb93cSSam Leffler int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
171939beb93cSSam Leffler int ext_type, const u8 *data,
172039beb93cSSam Leffler size_t data_len)
172139beb93cSSam Leffler {
172239beb93cSSam Leffler /* TODO */
172339beb93cSSam Leffler return -1;
172439beb93cSSam Leffler }
172539beb93cSSam Leffler
172639beb93cSSam Leffler
tls_connection_get_failed(void * ssl_ctx,struct tls_connection * conn)172739beb93cSSam Leffler int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
172839beb93cSSam Leffler {
172939beb93cSSam Leffler if (conn == NULL)
173039beb93cSSam Leffler return -1;
173139beb93cSSam Leffler return conn->failed;
173239beb93cSSam Leffler }
173339beb93cSSam Leffler
173439beb93cSSam Leffler
tls_connection_get_read_alerts(void * ssl_ctx,struct tls_connection * conn)173539beb93cSSam Leffler int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn)
173639beb93cSSam Leffler {
173739beb93cSSam Leffler if (conn == NULL)
173839beb93cSSam Leffler return -1;
173939beb93cSSam Leffler return conn->read_alerts;
174039beb93cSSam Leffler }
174139beb93cSSam Leffler
174239beb93cSSam Leffler
tls_connection_get_write_alerts(void * ssl_ctx,struct tls_connection * conn)174339beb93cSSam Leffler int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
174439beb93cSSam Leffler {
174539beb93cSSam Leffler if (conn == NULL)
174639beb93cSSam Leffler return -1;
174739beb93cSSam Leffler return conn->write_alerts;
174839beb93cSSam Leffler }
174939beb93cSSam Leffler
175039beb93cSSam Leffler
tls_connection_set_session_ticket_cb(void * tls_ctx,struct tls_connection * conn,tls_session_ticket_cb cb,void * ctx)1751e28a4053SRui Paulo int tls_connection_set_session_ticket_cb(void *tls_ctx,
1752e28a4053SRui Paulo struct tls_connection *conn,
1753e28a4053SRui Paulo tls_session_ticket_cb cb, void *ctx)
1754e28a4053SRui Paulo {
1755e28a4053SRui Paulo return -1;
1756e28a4053SRui Paulo }
17575b9c547cSRui Paulo
17585b9c547cSRui Paulo
tls_get_library_version(char * buf,size_t buf_len)17595b9c547cSRui Paulo int tls_get_library_version(char *buf, size_t buf_len)
17605b9c547cSRui Paulo {
17615b9c547cSRui Paulo return os_snprintf(buf, buf_len, "GnuTLS build=%s run=%s",
17625b9c547cSRui Paulo GNUTLS_VERSION, gnutls_check_version(NULL));
17635b9c547cSRui Paulo }
1764325151a3SRui Paulo
1765325151a3SRui Paulo
tls_connection_set_success_data(struct tls_connection * conn,struct wpabuf * data)1766325151a3SRui Paulo void tls_connection_set_success_data(struct tls_connection *conn,
1767325151a3SRui Paulo struct wpabuf *data)
1768325151a3SRui Paulo {
1769325151a3SRui Paulo }
1770325151a3SRui Paulo
1771325151a3SRui Paulo
tls_connection_set_success_data_resumed(struct tls_connection * conn)1772325151a3SRui Paulo void tls_connection_set_success_data_resumed(struct tls_connection *conn)
1773325151a3SRui Paulo {
1774325151a3SRui Paulo }
1775325151a3SRui Paulo
1776325151a3SRui Paulo
1777325151a3SRui Paulo const struct wpabuf *
tls_connection_get_success_data(struct tls_connection * conn)1778325151a3SRui Paulo tls_connection_get_success_data(struct tls_connection *conn)
1779325151a3SRui Paulo {
1780325151a3SRui Paulo return NULL;
1781325151a3SRui Paulo }
1782325151a3SRui Paulo
1783325151a3SRui Paulo
tls_connection_remove_session(struct tls_connection * conn)1784325151a3SRui Paulo void tls_connection_remove_session(struct tls_connection *conn)
1785325151a3SRui Paulo {
1786325151a3SRui Paulo }
1787