blob: 527d01ecfd16e127431cfde704458cd53f524c28 [file] [log] [blame]
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001/*
2 * SSL/TLS interface functions for GnuTLS
Roshan Pius3a1667e2018-07-03 15:17:14 -07003 * Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi>
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07004 *
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007 */
8
9#include "includes.h"
10#include <gnutls/gnutls.h>
11#include <gnutls/x509.h>
12#ifdef PKCS12_FUNCS
13#include <gnutls/pkcs12.h>
14#endif /* PKCS12_FUNCS */
Dmitry Shmidtff787d52015-01-12 13:01:47 -080015#if GNUTLS_VERSION_NUMBER >= 0x030103
16#include <gnutls/ocsp.h>
17#endif /* 3.1.3 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070018
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070019#include "common.h"
Dmitry Shmidtff787d52015-01-12 13:01:47 -080020#include "crypto/crypto.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070021#include "tls.h"
22
23
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070024static int tls_gnutls_ref_count = 0;
25
26struct tls_global {
27 /* Data for session resumption */
28 void *session_data;
29 size_t session_data_size;
30
31 int server;
32
33 int params_set;
34 gnutls_certificate_credentials_t xcred;
Dmitry Shmidtff787d52015-01-12 13:01:47 -080035
36 void (*event_cb)(void *ctx, enum tls_event ev,
37 union tls_event_data *data);
38 void *cb_ctx;
39 int cert_in_cb;
Dmitry Shmidtd97138d2015-12-28 13:27:49 -080040
41 char *ocsp_stapling_response;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070042};
43
44struct tls_connection {
Dmitry Shmidtff787d52015-01-12 13:01:47 -080045 struct tls_global *global;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -080046 gnutls_session_t session;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070047 int read_alerts, write_alerts, failed;
48
49 u8 *pre_shared_secret;
50 size_t pre_shared_secret_len;
51 int established;
52 int verify_peer;
Dmitry Shmidtff787d52015-01-12 13:01:47 -080053 unsigned int disable_time_checks:1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070054
55 struct wpabuf *push_buf;
56 struct wpabuf *pull_buf;
57 const u8 *pull_buf_offset;
58
59 int params_set;
60 gnutls_certificate_credentials_t xcred;
Dmitry Shmidtff787d52015-01-12 13:01:47 -080061
62 char *suffix_match;
Dmitry Shmidt2f74e362015-01-21 13:19:05 -080063 char *domain_match;
Dmitry Shmidtff787d52015-01-12 13:01:47 -080064 unsigned int flags;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070065};
66
67
Dmitry Shmidtff787d52015-01-12 13:01:47 -080068static int tls_connection_verify_peer(gnutls_session_t session);
69
70
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070071static void tls_log_func(int level, const char *msg)
72{
73 char *s, *pos;
74 if (level == 6 || level == 7) {
75 /* These levels seem to be mostly I/O debug and msg dumps */
76 return;
77 }
78
79 s = os_strdup(msg);
80 if (s == NULL)
81 return;
82
83 pos = s;
84 while (*pos != '\0') {
85 if (*pos == '\n') {
86 *pos = '\0';
87 break;
88 }
89 pos++;
90 }
91 wpa_printf(level > 3 ? MSG_MSGDUMP : MSG_DEBUG,
92 "gnutls<%d> %s", level, s);
93 os_free(s);
94}
95
96
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070097void * tls_init(const struct tls_config *conf)
98{
99 struct tls_global *global;
100
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800101 if (tls_gnutls_ref_count == 0) {
102 wpa_printf(MSG_DEBUG,
103 "GnuTLS: Library version %s (runtime) - %s (build)",
104 gnutls_check_version(NULL), GNUTLS_VERSION);
105 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700106
107 global = os_zalloc(sizeof(*global));
108 if (global == NULL)
109 return NULL;
110
111 if (tls_gnutls_ref_count == 0 && gnutls_global_init() < 0) {
112 os_free(global);
113 return NULL;
114 }
115 tls_gnutls_ref_count++;
116
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700117 gnutls_global_set_log_function(tls_log_func);
118 if (wpa_debug_show_keys)
119 gnutls_global_set_log_level(11);
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800120
121 if (conf) {
122 global->event_cb = conf->event_cb;
123 global->cb_ctx = conf->cb_ctx;
124 global->cert_in_cb = conf->cert_in_cb;
125 }
126
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700127 return global;
128}
129
130
131void tls_deinit(void *ssl_ctx)
132{
133 struct tls_global *global = ssl_ctx;
134 if (global) {
135 if (global->params_set)
136 gnutls_certificate_free_credentials(global->xcred);
137 os_free(global->session_data);
Dmitry Shmidtd97138d2015-12-28 13:27:49 -0800138 os_free(global->ocsp_stapling_response);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700139 os_free(global);
140 }
141
142 tls_gnutls_ref_count--;
143 if (tls_gnutls_ref_count == 0)
144 gnutls_global_deinit();
145}
146
147
148int tls_get_errors(void *ssl_ctx)
149{
150 return 0;
151}
152
153
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800154static ssize_t tls_pull_func(gnutls_transport_ptr_t ptr, void *buf,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700155 size_t len)
156{
157 struct tls_connection *conn = (struct tls_connection *) ptr;
158 const u8 *end;
159 if (conn->pull_buf == NULL) {
160 errno = EWOULDBLOCK;
161 return -1;
162 }
163
164 end = wpabuf_head_u8(conn->pull_buf) + wpabuf_len(conn->pull_buf);
165 if ((size_t) (end - conn->pull_buf_offset) < len)
166 len = end - conn->pull_buf_offset;
167 os_memcpy(buf, conn->pull_buf_offset, len);
168 conn->pull_buf_offset += len;
169 if (conn->pull_buf_offset == end) {
170 wpa_printf(MSG_DEBUG, "%s - pull_buf consumed", __func__);
171 wpabuf_free(conn->pull_buf);
172 conn->pull_buf = NULL;
173 conn->pull_buf_offset = NULL;
174 } else {
175 wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in pull_buf",
176 __func__,
177 (unsigned long) (end - conn->pull_buf_offset));
178 }
179 return len;
180}
181
182
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800183static ssize_t tls_push_func(gnutls_transport_ptr_t ptr, const void *buf,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700184 size_t len)
185{
186 struct tls_connection *conn = (struct tls_connection *) ptr;
187
188 if (wpabuf_resize(&conn->push_buf, len) < 0) {
189 errno = ENOMEM;
190 return -1;
191 }
192 wpabuf_put_data(conn->push_buf, buf, len);
193
194 return len;
195}
196
197
198static int tls_gnutls_init_session(struct tls_global *global,
199 struct tls_connection *conn)
200{
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800201 const char *err;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700202 int ret;
203
204 ret = gnutls_init(&conn->session,
205 global->server ? GNUTLS_SERVER : GNUTLS_CLIENT);
206 if (ret < 0) {
207 wpa_printf(MSG_INFO, "TLS: Failed to initialize new TLS "
208 "connection: %s", gnutls_strerror(ret));
209 return -1;
210 }
211
212 ret = gnutls_set_default_priority(conn->session);
213 if (ret < 0)
214 goto fail;
215
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800216 ret = gnutls_priority_set_direct(conn->session, "NORMAL:-VERS-SSL3.0",
217 &err);
218 if (ret < 0) {
219 wpa_printf(MSG_ERROR, "GnuTLS: Priority string failure at "
220 "'%s'", err);
221 goto fail;
222 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700223
224 gnutls_transport_set_pull_function(conn->session, tls_pull_func);
225 gnutls_transport_set_push_function(conn->session, tls_push_func);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800226 gnutls_transport_set_ptr(conn->session, (gnutls_transport_ptr_t) conn);
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800227 gnutls_session_set_ptr(conn->session, conn);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700228
229 return 0;
230
231fail:
232 wpa_printf(MSG_INFO, "TLS: Failed to setup new TLS connection: %s",
233 gnutls_strerror(ret));
234 gnutls_deinit(conn->session);
235 return -1;
236}
237
238
239struct tls_connection * tls_connection_init(void *ssl_ctx)
240{
241 struct tls_global *global = ssl_ctx;
242 struct tls_connection *conn;
243 int ret;
244
245 conn = os_zalloc(sizeof(*conn));
246 if (conn == NULL)
247 return NULL;
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800248 conn->global = global;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700249
250 if (tls_gnutls_init_session(global, conn)) {
251 os_free(conn);
252 return NULL;
253 }
254
255 if (global->params_set) {
256 ret = gnutls_credentials_set(conn->session,
257 GNUTLS_CRD_CERTIFICATE,
258 global->xcred);
259 if (ret < 0) {
260 wpa_printf(MSG_INFO, "Failed to configure "
261 "credentials: %s", gnutls_strerror(ret));
262 os_free(conn);
263 return NULL;
264 }
265 }
266
267 if (gnutls_certificate_allocate_credentials(&conn->xcred)) {
268 os_free(conn);
269 return NULL;
270 }
271
272 return conn;
273}
274
275
276void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
277{
278 if (conn == NULL)
279 return;
280
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700281 gnutls_certificate_free_credentials(conn->xcred);
282 gnutls_deinit(conn->session);
283 os_free(conn->pre_shared_secret);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700284 wpabuf_free(conn->push_buf);
285 wpabuf_free(conn->pull_buf);
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800286 os_free(conn->suffix_match);
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800287 os_free(conn->domain_match);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700288 os_free(conn);
289}
290
291
292int tls_connection_established(void *ssl_ctx, struct tls_connection *conn)
293{
294 return conn ? conn->established : 0;
295}
296
297
Hai Shalom39ba6fc2019-01-22 12:40:38 -0800298char * tls_connection_peer_serial_num(void *tls_ctx,
299 struct tls_connection *conn)
300{
301 /* TODO */
302 return NULL;
303}
304
305
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700306int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
307{
308 struct tls_global *global = ssl_ctx;
309 int ret;
310
311 if (conn == NULL)
312 return -1;
313
314 /* Shutdown previous TLS connection without notifying the peer
315 * because the connection was already terminated in practice
316 * and "close notify" shutdown alert would confuse AS. */
317 gnutls_bye(conn->session, GNUTLS_SHUT_RDWR);
318 wpabuf_free(conn->push_buf);
319 conn->push_buf = NULL;
320 conn->established = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700321
322 gnutls_deinit(conn->session);
323 if (tls_gnutls_init_session(global, conn)) {
324 wpa_printf(MSG_INFO, "GnuTLS: Failed to preparare new session "
325 "for session resumption use");
326 return -1;
327 }
328
329 ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
330 conn->params_set ? conn->xcred :
331 global->xcred);
332 if (ret < 0) {
333 wpa_printf(MSG_INFO, "GnuTLS: Failed to configure credentials "
334 "for session resumption: %s", gnutls_strerror(ret));
335 return -1;
336 }
337
338 if (global->session_data) {
339 ret = gnutls_session_set_data(conn->session,
340 global->session_data,
341 global->session_data_size);
342 if (ret < 0) {
343 wpa_printf(MSG_INFO, "GnuTLS: Failed to set session "
344 "data: %s", gnutls_strerror(ret));
345 return -1;
346 }
347 }
348
349 return 0;
350}
351
352
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700353int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
354 const struct tls_connection_params *params)
355{
356 int ret;
Roshan Pius3a1667e2018-07-03 15:17:14 -0700357 const char *err;
358 char prio_buf[100];
359 const char *prio = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700360
361 if (conn == NULL || params == NULL)
362 return -1;
363
Dmitry Shmidtd97138d2015-12-28 13:27:49 -0800364 if (params->flags & TLS_CONN_REQUIRE_OCSP_ALL) {
365 wpa_printf(MSG_INFO,
366 "GnuTLS: ocsp=3 not supported");
367 return -1;
368 }
369
Dmitry Shmidt1b467752015-12-14 12:45:46 -0800370 if (params->flags & TLS_CONN_EXT_CERT_CHECK) {
371 wpa_printf(MSG_INFO,
372 "GnuTLS: tls_ext_cert_check=1 not supported");
373 return -1;
374 }
375
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700376 if (params->subject_match) {
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800377 wpa_printf(MSG_INFO, "GnuTLS: subject_match not supported");
378 return -1;
379 }
380
381 if (params->altsubject_match) {
382 wpa_printf(MSG_INFO, "GnuTLS: altsubject_match not supported");
383 return -1;
384 }
385
386 os_free(conn->suffix_match);
387 conn->suffix_match = NULL;
388 if (params->suffix_match) {
389 conn->suffix_match = os_strdup(params->suffix_match);
390 if (conn->suffix_match == NULL)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700391 return -1;
392 }
393
Dmitry Shmidt2f74e362015-01-21 13:19:05 -0800394#if GNUTLS_VERSION_NUMBER >= 0x030300
395 os_free(conn->domain_match);
396 conn->domain_match = NULL;
397 if (params->domain_match) {
398 conn->domain_match = os_strdup(params->domain_match);
399 if (conn->domain_match == NULL)
400 return -1;
401 }
402#else /* < 3.3.0 */
403 if (params->domain_match) {
404 wpa_printf(MSG_INFO, "GnuTLS: domain_match not supported");
405 return -1;
406 }
407#endif /* >= 3.3.0 */
408
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800409 conn->flags = params->flags;
410
Roshan Pius3a1667e2018-07-03 15:17:14 -0700411 if (params->flags & (TLS_CONN_DISABLE_TLSv1_0 |
412 TLS_CONN_DISABLE_TLSv1_1 |
413 TLS_CONN_DISABLE_TLSv1_2)) {
414 os_snprintf(prio_buf, sizeof(prio_buf),
415 "NORMAL:-VERS-SSL3.0%s%s%s",
416 params->flags & TLS_CONN_DISABLE_TLSv1_0 ?
417 ":-VERS-TLS1.0" : "",
418 params->flags & TLS_CONN_DISABLE_TLSv1_1 ?
419 ":-VERS-TLS1.1" : "",
420 params->flags & TLS_CONN_DISABLE_TLSv1_2 ?
421 ":-VERS-TLS1.2" : "");
422 prio = prio_buf;
423 }
424
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800425 if (params->openssl_ciphers) {
Roshan Pius3a1667e2018-07-03 15:17:14 -0700426 if (os_strcmp(params->openssl_ciphers, "SUITEB128") == 0) {
427 prio = "SUITEB128";
428 } else if (os_strcmp(params->openssl_ciphers,
429 "SUITEB192") == 0) {
430 prio = "SUITEB192";
431 } else if ((params->flags & TLS_CONN_SUITEB) &&
432 os_strcmp(params->openssl_ciphers,
433 "ECDHE-RSA-AES256-GCM-SHA384") == 0) {
434 prio = "NONE:+VERS-TLS1.2:+AEAD:+ECDHE-RSA:+AES-256-GCM:+SIGN-RSA-SHA384:+CURVE-SECP384R1:+COMP-NULL";
435 } else if (os_strcmp(params->openssl_ciphers,
436 "ECDHE-RSA-AES256-GCM-SHA384") == 0) {
437 prio = "NONE:+VERS-TLS1.2:+AEAD:+ECDHE-RSA:+AES-256-GCM:+SIGN-RSA-SHA384:+CURVE-SECP384R1:+COMP-NULL";
438 } else if (os_strcmp(params->openssl_ciphers,
439 "DHE-RSA-AES256-GCM-SHA384") == 0) {
440 prio = "NONE:+VERS-TLS1.2:+AEAD:+DHE-RSA:+AES-256-GCM:+SIGN-RSA-SHA384:+CURVE-SECP384R1:+COMP-NULL:%PROFILE_HIGH";
441 } else if (os_strcmp(params->openssl_ciphers,
442 "ECDHE-ECDSA-AES256-GCM-SHA384") == 0) {
443 prio = "NONE:+VERS-TLS1.2:+AEAD:+ECDHE-ECDSA:+AES-256-GCM:+SIGN-RSA-SHA384:+CURVE-SECP384R1:+COMP-NULL";
444 } else {
445 wpa_printf(MSG_INFO,
446 "GnuTLS: openssl_ciphers not supported");
447 return -1;
448 }
449 } else if (params->flags & TLS_CONN_SUITEB) {
450 prio = "NONE:+VERS-TLS1.2:+AEAD:+ECDHE-ECDSA:+ECDHE-RSA:+DHE-RSA:+AES-256-GCM:+SIGN-RSA-SHA384:+CURVE-SECP384R1:+COMP-NULL:%PROFILE_HIGH";
451 }
452
453 if (prio) {
454 wpa_printf(MSG_DEBUG, "GnuTLS: Set priority string: %s", prio);
455 ret = gnutls_priority_set_direct(conn->session, prio, &err);
456 if (ret < 0) {
457 wpa_printf(MSG_ERROR,
458 "GnuTLS: Priority string failure at '%s'",
459 err);
460 return -1;
461 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700462 }
463
Hai Shalom74f70d42019-02-11 14:42:39 -0800464 if (params->openssl_ecdh_curves) {
465 wpa_printf(MSG_INFO,
466 "GnuTLS: openssl_ecdh_curves not supported");
467 return -1;
468 }
469
Dmitry Shmidt29333592017-01-09 12:27:11 -0800470 /* TODO: gnutls_certificate_set_verify_flags(xcred, flags);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700471 * to force peer validation(?) */
472
473 if (params->ca_cert) {
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800474 wpa_printf(MSG_DEBUG, "GnuTLS: Try to parse %s in DER format",
475 params->ca_cert);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700476 ret = gnutls_certificate_set_x509_trust_file(
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800477 conn->xcred, params->ca_cert, GNUTLS_X509_FMT_DER);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700478 if (ret < 0) {
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800479 wpa_printf(MSG_DEBUG,
480 "GnuTLS: Failed to read CA cert '%s' in DER format (%s) - try in PEM format",
481 params->ca_cert,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700482 gnutls_strerror(ret));
483 ret = gnutls_certificate_set_x509_trust_file(
484 conn->xcred, params->ca_cert,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800485 GNUTLS_X509_FMT_PEM);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700486 if (ret < 0) {
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800487 wpa_printf(MSG_DEBUG,
488 "Failed to read CA cert '%s' in PEM format: %s",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700489 params->ca_cert,
490 gnutls_strerror(ret));
491 return -1;
492 }
Roshan Pius3a1667e2018-07-03 15:17:14 -0700493 wpa_printf(MSG_DEBUG,
494 "GnuTLS: Successfully read CA cert '%s' in PEM format",
495 params->ca_cert);
496 } else {
497 wpa_printf(MSG_DEBUG,
498 "GnuTLS: Successfully read CA cert '%s' in DER format",
499 params->ca_cert);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700500 }
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800501 } else if (params->ca_cert_blob) {
502 gnutls_datum_t ca;
503
504 ca.data = (unsigned char *) params->ca_cert_blob;
505 ca.size = params->ca_cert_blob_len;
506
507 ret = gnutls_certificate_set_x509_trust_mem(
508 conn->xcred, &ca, GNUTLS_X509_FMT_DER);
509 if (ret < 0) {
510 wpa_printf(MSG_DEBUG,
511 "Failed to parse CA cert in DER format: %s",
512 gnutls_strerror(ret));
513 ret = gnutls_certificate_set_x509_trust_mem(
514 conn->xcred, &ca, GNUTLS_X509_FMT_PEM);
515 if (ret < 0) {
516 wpa_printf(MSG_DEBUG,
517 "Failed to parse CA cert in PEM format: %s",
518 gnutls_strerror(ret));
519 return -1;
520 }
521 }
522 } else if (params->ca_path) {
523 wpa_printf(MSG_INFO, "GnuTLS: ca_path not supported");
524 return -1;
525 }
526
527 conn->disable_time_checks = 0;
528 if (params->ca_cert || params->ca_cert_blob) {
529 conn->verify_peer = 1;
530 gnutls_certificate_set_verify_function(
531 conn->xcred, tls_connection_verify_peer);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700532
533 if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) {
534 gnutls_certificate_set_verify_flags(
535 conn->xcred, GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
536 }
537
538 if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800539 conn->disable_time_checks = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700540 gnutls_certificate_set_verify_flags(
541 conn->xcred,
542 GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
543 }
544 }
545
546 if (params->client_cert && params->private_key) {
Roshan Pius3a1667e2018-07-03 15:17:14 -0700547 wpa_printf(MSG_DEBUG,
548 "GnuTLS: Try to parse client cert '%s' and key '%s' in DER format",
549 params->client_cert, params->private_key);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800550#if GNUTLS_VERSION_NUMBER >= 0x03010b
551 ret = gnutls_certificate_set_x509_key_file2(
552 conn->xcred, params->client_cert, params->private_key,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800553 GNUTLS_X509_FMT_DER, params->private_key_passwd, 0);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800554#else
555 /* private_key_passwd not (easily) supported here */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700556 ret = gnutls_certificate_set_x509_key_file(
557 conn->xcred, params->client_cert, params->private_key,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800558 GNUTLS_X509_FMT_DER);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800559#endif
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700560 if (ret < 0) {
Roshan Pius3a1667e2018-07-03 15:17:14 -0700561 wpa_printf(MSG_DEBUG,
562 "GnuTLS: Failed to read client cert/key in DER format (%s) - try in PEM format",
563 gnutls_strerror(ret));
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800564#if GNUTLS_VERSION_NUMBER >= 0x03010b
565 ret = gnutls_certificate_set_x509_key_file2(
566 conn->xcred, params->client_cert,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800567 params->private_key, GNUTLS_X509_FMT_PEM,
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800568 params->private_key_passwd, 0);
569#else
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700570 ret = gnutls_certificate_set_x509_key_file(
571 conn->xcred, params->client_cert,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800572 params->private_key, GNUTLS_X509_FMT_PEM);
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800573#endif
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700574 if (ret < 0) {
575 wpa_printf(MSG_DEBUG, "Failed to read client "
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800576 "cert/key in PEM format: %s",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700577 gnutls_strerror(ret));
578 return ret;
579 }
Roshan Pius3a1667e2018-07-03 15:17:14 -0700580 wpa_printf(MSG_DEBUG,
581 "GnuTLS: Successfully read client cert/key in PEM format");
582 } else {
583 wpa_printf(MSG_DEBUG,
584 "GnuTLS: Successfully read client cert/key in DER format");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700585 }
586 } else if (params->private_key) {
587 int pkcs12_ok = 0;
588#ifdef PKCS12_FUNCS
589 /* Try to load in PKCS#12 format */
Roshan Pius3a1667e2018-07-03 15:17:14 -0700590 wpa_printf(MSG_DEBUG,
591 "GnuTLS: Try to parse client cert/key '%s'in PKCS#12 DER format",
592 params->private_key);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700593 ret = gnutls_certificate_set_x509_simple_pkcs12_file(
594 conn->xcred, params->private_key, GNUTLS_X509_FMT_DER,
595 params->private_key_passwd);
596 if (ret != 0) {
597 wpa_printf(MSG_DEBUG, "Failed to load private_key in "
598 "PKCS#12 format: %s", gnutls_strerror(ret));
599 return -1;
600 } else
601 pkcs12_ok = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700602#endif /* PKCS12_FUNCS */
603
604 if (!pkcs12_ok) {
605 wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not "
606 "included");
607 return -1;
608 }
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800609 } else if (params->client_cert_blob && params->private_key_blob) {
610 gnutls_datum_t cert, key;
611
612 cert.data = (unsigned char *) params->client_cert_blob;
613 cert.size = params->client_cert_blob_len;
614 key.data = (unsigned char *) params->private_key_blob;
615 key.size = params->private_key_blob_len;
616
617#if GNUTLS_VERSION_NUMBER >= 0x03010b
618 ret = gnutls_certificate_set_x509_key_mem2(
619 conn->xcred, &cert, &key, GNUTLS_X509_FMT_DER,
620 params->private_key_passwd, 0);
621#else
622 /* private_key_passwd not (easily) supported here */
623 ret = gnutls_certificate_set_x509_key_mem(
624 conn->xcred, &cert, &key, GNUTLS_X509_FMT_DER);
625#endif
626 if (ret < 0) {
627 wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
628 "in DER format: %s", gnutls_strerror(ret));
629#if GNUTLS_VERSION_NUMBER >= 0x03010b
630 ret = gnutls_certificate_set_x509_key_mem2(
631 conn->xcred, &cert, &key, GNUTLS_X509_FMT_PEM,
632 params->private_key_passwd, 0);
633#else
634 /* private_key_passwd not (easily) supported here */
635 ret = gnutls_certificate_set_x509_key_mem(
636 conn->xcred, &cert, &key, GNUTLS_X509_FMT_PEM);
637#endif
638 if (ret < 0) {
639 wpa_printf(MSG_DEBUG, "Failed to read client "
640 "cert/key in PEM format: %s",
641 gnutls_strerror(ret));
642 return ret;
643 }
644 }
645 } else if (params->private_key_blob) {
646#ifdef PKCS12_FUNCS
647 gnutls_datum_t key;
648
649 key.data = (unsigned char *) params->private_key_blob;
650 key.size = params->private_key_blob_len;
651
652 /* Try to load in PKCS#12 format */
653 ret = gnutls_certificate_set_x509_simple_pkcs12_mem(
654 conn->xcred, &key, GNUTLS_X509_FMT_DER,
655 params->private_key_passwd);
656 if (ret != 0) {
657 wpa_printf(MSG_DEBUG, "Failed to load private_key in "
658 "PKCS#12 format: %s", gnutls_strerror(ret));
659 return -1;
660 }
661#else /* PKCS12_FUNCS */
662 wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not included");
663 return -1;
664#endif /* PKCS12_FUNCS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700665 }
666
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800667#if GNUTLS_VERSION_NUMBER >= 0x030103
668 if (params->flags & (TLS_CONN_REQUEST_OCSP | TLS_CONN_REQUIRE_OCSP)) {
669 ret = gnutls_ocsp_status_request_enable_client(conn->session,
670 NULL, 0, NULL);
671 if (ret != GNUTLS_E_SUCCESS) {
672 wpa_printf(MSG_INFO,
673 "GnuTLS: Failed to enable OCSP client");
674 return -1;
675 }
676 }
677#else /* 3.1.3 */
678 if (params->flags & TLS_CONN_REQUIRE_OCSP) {
679 wpa_printf(MSG_INFO,
680 "GnuTLS: OCSP not supported by this version of GnuTLS");
681 return -1;
682 }
683#endif /* 3.1.3 */
684
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700685 conn->params_set = 1;
686
687 ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
688 conn->xcred);
689 if (ret < 0) {
690 wpa_printf(MSG_INFO, "Failed to configure credentials: %s",
691 gnutls_strerror(ret));
692 }
693
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700694 return ret;
695}
696
697
Dmitry Shmidtd97138d2015-12-28 13:27:49 -0800698#if GNUTLS_VERSION_NUMBER >= 0x030103
699static int server_ocsp_status_req(gnutls_session_t session, void *ptr,
700 gnutls_datum_t *resp)
701{
702 struct tls_global *global = ptr;
703 char *cached;
704 size_t len;
705
706 if (!global->ocsp_stapling_response) {
707 wpa_printf(MSG_DEBUG, "GnuTLS: OCSP status callback - no response configured");
708 return GNUTLS_E_NO_CERTIFICATE_STATUS;
709 }
710
711 cached = os_readfile(global->ocsp_stapling_response, &len);
712 if (!cached) {
713 wpa_printf(MSG_DEBUG,
714 "GnuTLS: OCSP status callback - could not read response file (%s)",
715 global->ocsp_stapling_response);
716 return GNUTLS_E_NO_CERTIFICATE_STATUS;
717 }
718
719 wpa_printf(MSG_DEBUG,
720 "GnuTLS: OCSP status callback - send cached response");
721 resp->data = gnutls_malloc(len);
722 if (!resp->data) {
723 os_free(resp);
724 return GNUTLS_E_MEMORY_ERROR;
725 }
726
727 os_memcpy(resp->data, cached, len);
728 resp->size = len;
729 os_free(cached);
730
731 return GNUTLS_E_SUCCESS;
732}
733#endif /* 3.1.3 */
734
735
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700736int tls_global_set_params(void *tls_ctx,
737 const struct tls_connection_params *params)
738{
739 struct tls_global *global = tls_ctx;
740 int ret;
741
742 /* Currently, global parameters are only set when running in server
743 * mode. */
744 global->server = 1;
745
746 if (global->params_set) {
747 gnutls_certificate_free_credentials(global->xcred);
748 global->params_set = 0;
749 }
750
751 ret = gnutls_certificate_allocate_credentials(&global->xcred);
752 if (ret) {
753 wpa_printf(MSG_DEBUG, "Failed to allocate global credentials "
754 "%s", gnutls_strerror(ret));
755 return -1;
756 }
757
758 if (params->ca_cert) {
759 ret = gnutls_certificate_set_x509_trust_file(
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800760 global->xcred, params->ca_cert, GNUTLS_X509_FMT_DER);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700761 if (ret < 0) {
762 wpa_printf(MSG_DEBUG, "Failed to read CA cert '%s' "
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800763 "in DER format: %s", params->ca_cert,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700764 gnutls_strerror(ret));
765 ret = gnutls_certificate_set_x509_trust_file(
766 global->xcred, params->ca_cert,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800767 GNUTLS_X509_FMT_PEM);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700768 if (ret < 0) {
769 wpa_printf(MSG_DEBUG, "Failed to read CA cert "
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800770 "'%s' in PEM format: %s",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700771 params->ca_cert,
772 gnutls_strerror(ret));
773 goto fail;
774 }
775 }
776
777 if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) {
778 gnutls_certificate_set_verify_flags(
779 global->xcred,
780 GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
781 }
782
783 if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
784 gnutls_certificate_set_verify_flags(
785 global->xcred,
786 GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
787 }
788 }
789
790 if (params->client_cert && params->private_key) {
791 /* TODO: private_key_passwd? */
792 ret = gnutls_certificate_set_x509_key_file(
793 global->xcred, params->client_cert,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800794 params->private_key, GNUTLS_X509_FMT_DER);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700795 if (ret < 0) {
796 wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800797 "in DER format: %s", gnutls_strerror(ret));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700798 ret = gnutls_certificate_set_x509_key_file(
799 global->xcred, params->client_cert,
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800800 params->private_key, GNUTLS_X509_FMT_PEM);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700801 if (ret < 0) {
802 wpa_printf(MSG_DEBUG, "Failed to read client "
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800803 "cert/key in PEM format: %s",
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700804 gnutls_strerror(ret));
805 goto fail;
806 }
807 }
808 } else if (params->private_key) {
809 int pkcs12_ok = 0;
810#ifdef PKCS12_FUNCS
811 /* Try to load in PKCS#12 format */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700812 ret = gnutls_certificate_set_x509_simple_pkcs12_file(
813 global->xcred, params->private_key,
814 GNUTLS_X509_FMT_DER, params->private_key_passwd);
815 if (ret != 0) {
816 wpa_printf(MSG_DEBUG, "Failed to load private_key in "
817 "PKCS#12 format: %s", gnutls_strerror(ret));
818 goto fail;
819 } else
820 pkcs12_ok = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700821#endif /* PKCS12_FUNCS */
822
823 if (!pkcs12_ok) {
824 wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not "
825 "included");
826 goto fail;
827 }
828 }
829
Dmitry Shmidtd97138d2015-12-28 13:27:49 -0800830#if GNUTLS_VERSION_NUMBER >= 0x030103
831 os_free(global->ocsp_stapling_response);
832 if (params->ocsp_stapling_response)
833 global->ocsp_stapling_response =
834 os_strdup(params->ocsp_stapling_response);
835 else
836 global->ocsp_stapling_response = NULL;
837 gnutls_certificate_set_ocsp_status_request_function(
838 global->xcred, server_ocsp_status_req, global);
839#endif /* 3.1.3 */
840
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700841 global->params_set = 1;
842
843 return 0;
844
845fail:
846 gnutls_certificate_free_credentials(global->xcred);
847 return -1;
848}
849
850
Hai Shalom74f70d42019-02-11 14:42:39 -0800851int tls_global_set_verify(void *ssl_ctx, int check_crl, int strict)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700852{
853 /* TODO */
854 return 0;
855}
856
857
858int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800859 int verify_peer, unsigned int flags,
860 const u8 *session_ctx, size_t session_ctx_len)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700861{
862 if (conn == NULL || conn->session == NULL)
863 return -1;
864
865 conn->verify_peer = verify_peer;
866 gnutls_certificate_server_set_request(conn->session,
867 verify_peer ? GNUTLS_CERT_REQUIRE
868 : GNUTLS_CERT_REQUEST);
869
870 return 0;
871}
872
873
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800874int tls_connection_get_random(void *ssl_ctx, struct tls_connection *conn,
875 struct tls_random *keys)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700876{
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800877#if GNUTLS_VERSION_NUMBER >= 0x030012
878 gnutls_datum_t client, server;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700879
880 if (conn == NULL || conn->session == NULL || keys == NULL)
881 return -1;
882
883 os_memset(keys, 0, sizeof(*keys));
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800884 gnutls_session_get_random(conn->session, &client, &server);
885 keys->client_random = client.data;
886 keys->server_random = server.data;
887 keys->client_random_len = client.size;
888 keys->server_random_len = client.size;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700889
890 return 0;
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800891#else /* 3.0.18 */
892 return -1;
893#endif /* 3.0.18 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700894}
895
896
Dmitry Shmidt849734c2016-05-27 09:59:01 -0700897int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn,
898 const char *label, u8 *out, size_t out_len)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700899{
Dmitry Shmidt849734c2016-05-27 09:59:01 -0700900 if (conn == NULL || conn->session == NULL)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700901 return -1;
902
903 return gnutls_prf(conn->session, os_strlen(label), label,
Dmitry Shmidt849734c2016-05-27 09:59:01 -0700904 0 /* client_random first */, 0, NULL, out_len,
905 (char *) out);
906}
907
908
909int tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn,
910 u8 *out, size_t out_len)
911{
912 return -1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700913}
914
915
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800916static void gnutls_tls_fail_event(struct tls_connection *conn,
917 const gnutls_datum_t *cert, int depth,
918 const char *subject, const char *err_str,
919 enum tls_fail_reason reason)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700920{
Dmitry Shmidtff787d52015-01-12 13:01:47 -0800921 union tls_event_data ev;
922 struct tls_global *global = conn->global;
923 struct wpabuf *cert_buf = NULL;
924
925 if (global->event_cb == NULL)
926 return;
927
928 os_memset(&ev, 0, sizeof(ev));
929 ev.cert_fail.depth = depth;
930 ev.cert_fail.subject = subject ? subject : "";
931 ev.cert_fail.reason = reason;
932 ev.cert_fail.reason_txt = err_str;
933 if (cert) {
934 cert_buf = wpabuf_alloc_copy(cert->data, cert->size);
935 ev.cert_fail.cert = cert_buf;
936 }
937 global->event_cb(global->cb_ctx, TLS_CERT_CHAIN_FAILURE, &ev);
938 wpabuf_free(cert_buf);
939}
940
941
942#if GNUTLS_VERSION_NUMBER < 0x030300
943static int server_eku_purpose(gnutls_x509_crt_t cert)
944{
945 unsigned int i;
946
947 for (i = 0; ; i++) {
948 char oid[128];
949 size_t oid_size = sizeof(oid);
950 int res;
951
952 res = gnutls_x509_crt_get_key_purpose_oid(cert, i, oid,
953 &oid_size, NULL);
954 if (res == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
955 if (i == 0) {
956 /* No EKU - assume any use allowed */
957 return 1;
958 }
959 break;
960 }
961
962 if (res < 0) {
963 wpa_printf(MSG_INFO, "GnuTLS: Failed to get EKU");
964 return 0;
965 }
966
967 wpa_printf(MSG_DEBUG, "GnuTLS: Certificate purpose: %s", oid);
968 if (os_strcmp(oid, GNUTLS_KP_TLS_WWW_SERVER) == 0 ||
969 os_strcmp(oid, GNUTLS_KP_ANY) == 0)
970 return 1;
971 }
972
973 return 0;
974}
975#endif /* < 3.3.0 */
976
977
978static int check_ocsp(struct tls_connection *conn, gnutls_session_t session,
979 gnutls_alert_description_t *err)
980{
981#if GNUTLS_VERSION_NUMBER >= 0x030103
982 gnutls_datum_t response, buf;
983 gnutls_ocsp_resp_t resp;
984 unsigned int cert_status;
985 int res;
986
987 if (!(conn->flags & (TLS_CONN_REQUEST_OCSP | TLS_CONN_REQUIRE_OCSP)))
988 return 0;
989
990 if (!gnutls_ocsp_status_request_is_checked(session, 0)) {
991 if (conn->flags & TLS_CONN_REQUIRE_OCSP) {
992 wpa_printf(MSG_INFO,
993 "GnuTLS: No valid OCSP response received");
994 goto ocsp_error;
995 }
996
997 wpa_printf(MSG_DEBUG,
998 "GnuTLS: Valid OCSP response was not received - continue since OCSP was not required");
999 return 0;
1000 }
1001
1002 /*
1003 * GnuTLS has already verified the OCSP response in
1004 * check_ocsp_response() and rejected handshake if the certificate was
1005 * found to be revoked. However, if the response indicates that the
1006 * status is unknown, handshake continues and reaches here. We need to
1007 * re-import the OCSP response to check for unknown certificate status,
1008 * but we do not need to repeat gnutls_ocsp_resp_check_crt() and
1009 * gnutls_ocsp_resp_verify_direct() calls.
1010 */
1011
1012 res = gnutls_ocsp_status_request_get(session, &response);
1013 if (res != GNUTLS_E_SUCCESS) {
1014 wpa_printf(MSG_INFO,
1015 "GnuTLS: OCSP response was received, but it was not valid");
1016 goto ocsp_error;
1017 }
1018
1019 if (gnutls_ocsp_resp_init(&resp) != GNUTLS_E_SUCCESS)
1020 goto ocsp_error;
1021
1022 res = gnutls_ocsp_resp_import(resp, &response);
1023 if (res != GNUTLS_E_SUCCESS) {
1024 wpa_printf(MSG_INFO,
1025 "GnuTLS: Could not parse received OCSP response: %s",
1026 gnutls_strerror(res));
1027 gnutls_ocsp_resp_deinit(resp);
1028 goto ocsp_error;
1029 }
1030
1031 res = gnutls_ocsp_resp_print(resp, GNUTLS_OCSP_PRINT_FULL, &buf);
1032 if (res == GNUTLS_E_SUCCESS) {
1033 wpa_printf(MSG_DEBUG, "GnuTLS: %s", buf.data);
1034 gnutls_free(buf.data);
1035 }
1036
1037 res = gnutls_ocsp_resp_get_single(resp, 0, NULL, NULL, NULL,
1038 NULL, &cert_status, NULL,
1039 NULL, NULL, NULL);
1040 gnutls_ocsp_resp_deinit(resp);
1041 if (res != GNUTLS_E_SUCCESS) {
1042 wpa_printf(MSG_INFO,
1043 "GnuTLS: Failed to extract OCSP information: %s",
1044 gnutls_strerror(res));
1045 goto ocsp_error;
1046 }
1047
1048 if (cert_status == GNUTLS_OCSP_CERT_GOOD) {
1049 wpa_printf(MSG_DEBUG, "GnuTLS: OCSP cert status: good");
1050 } else if (cert_status == GNUTLS_OCSP_CERT_REVOKED) {
1051 wpa_printf(MSG_DEBUG,
1052 "GnuTLS: OCSP cert status: revoked");
1053 goto ocsp_error;
1054 } else {
1055 wpa_printf(MSG_DEBUG,
1056 "GnuTLS: OCSP cert status: unknown");
1057 if (conn->flags & TLS_CONN_REQUIRE_OCSP)
1058 goto ocsp_error;
1059 wpa_printf(MSG_DEBUG,
1060 "GnuTLS: OCSP was not required, so allow connection to continue");
1061 }
1062
1063 return 0;
1064
1065ocsp_error:
1066 gnutls_tls_fail_event(conn, NULL, 0, NULL,
1067 "bad certificate status response",
1068 TLS_FAIL_REVOKED);
1069 *err = GNUTLS_A_CERTIFICATE_REVOKED;
1070 return -1;
1071#else /* GnuTLS 3.1.3 or newer */
1072 return 0;
1073#endif /* GnuTLS 3.1.3 or newer */
1074}
1075
1076
1077static int tls_connection_verify_peer(gnutls_session_t session)
1078{
1079 struct tls_connection *conn;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001080 unsigned int status, num_certs, i;
1081 struct os_time now;
1082 const gnutls_datum_t *certs;
1083 gnutls_x509_crt_t cert;
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001084 gnutls_alert_description_t err;
1085 int res;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001086
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001087 conn = gnutls_session_get_ptr(session);
1088 if (!conn->verify_peer) {
1089 wpa_printf(MSG_DEBUG,
1090 "GnuTLS: No peer certificate verification enabled");
1091 return 0;
1092 }
1093
1094 wpa_printf(MSG_DEBUG, "GnuTSL: Verifying peer certificate");
1095
1096#if GNUTLS_VERSION_NUMBER >= 0x030300
1097 {
1098 gnutls_typed_vdata_st data[1];
1099 unsigned int elements = 0;
1100
1101 os_memset(data, 0, sizeof(data));
1102 if (!conn->global->server) {
1103 data[elements].type = GNUTLS_DT_KEY_PURPOSE_OID;
1104 data[elements].data = (void *) GNUTLS_KP_TLS_WWW_SERVER;
1105 elements++;
1106 }
1107 res = gnutls_certificate_verify_peers(session, data, 1,
1108 &status);
1109 }
1110#else /* < 3.3.0 */
1111 res = gnutls_certificate_verify_peers2(session, &status);
1112#endif
1113 if (res < 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001114 wpa_printf(MSG_INFO, "TLS: Failed to verify peer "
1115 "certificate chain");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001116 err = GNUTLS_A_INTERNAL_ERROR;
1117 goto out;
1118 }
1119
1120#if GNUTLS_VERSION_NUMBER >= 0x030104
1121 {
1122 gnutls_datum_t info;
1123 int ret, type;
1124
1125 type = gnutls_certificate_type_get(session);
1126 ret = gnutls_certificate_verification_status_print(status, type,
1127 &info, 0);
1128 if (ret < 0) {
1129 wpa_printf(MSG_DEBUG,
1130 "GnuTLS: Failed to print verification status");
1131 err = GNUTLS_A_INTERNAL_ERROR;
1132 goto out;
1133 }
1134 wpa_printf(MSG_DEBUG, "GnuTLS: %s", info.data);
1135 gnutls_free(info.data);
1136 }
1137#endif /* GnuTLS 3.1.4 or newer */
1138
1139 certs = gnutls_certificate_get_peers(session, &num_certs);
1140 if (certs == NULL || num_certs == 0) {
1141 wpa_printf(MSG_INFO, "TLS: No peer certificate chain received");
1142 err = GNUTLS_A_UNKNOWN_CA;
1143 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001144 }
1145
1146 if (conn->verify_peer && (status & GNUTLS_CERT_INVALID)) {
1147 wpa_printf(MSG_INFO, "TLS: Peer certificate not trusted");
1148 if (status & GNUTLS_CERT_INSECURE_ALGORITHM) {
1149 wpa_printf(MSG_INFO, "TLS: Certificate uses insecure "
1150 "algorithm");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001151 gnutls_tls_fail_event(conn, NULL, 0, NULL,
1152 "certificate uses insecure algorithm",
1153 TLS_FAIL_BAD_CERTIFICATE);
1154 err = GNUTLS_A_INSUFFICIENT_SECURITY;
1155 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001156 }
1157 if (status & GNUTLS_CERT_NOT_ACTIVATED) {
1158 wpa_printf(MSG_INFO, "TLS: Certificate not yet "
1159 "activated");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001160 gnutls_tls_fail_event(conn, NULL, 0, NULL,
1161 "certificate not yet valid",
1162 TLS_FAIL_NOT_YET_VALID);
1163 err = GNUTLS_A_CERTIFICATE_EXPIRED;
1164 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001165 }
1166 if (status & GNUTLS_CERT_EXPIRED) {
1167 wpa_printf(MSG_INFO, "TLS: Certificate expired");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001168 gnutls_tls_fail_event(conn, NULL, 0, NULL,
1169 "certificate has expired",
1170 TLS_FAIL_EXPIRED);
1171 err = GNUTLS_A_CERTIFICATE_EXPIRED;
1172 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001173 }
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001174 gnutls_tls_fail_event(conn, NULL, 0, NULL,
1175 "untrusted certificate",
1176 TLS_FAIL_UNTRUSTED);
1177 err = GNUTLS_A_INTERNAL_ERROR;
1178 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001179 }
1180
1181 if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
1182 wpa_printf(MSG_INFO, "TLS: Peer certificate does not have a "
1183 "known issuer");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001184 gnutls_tls_fail_event(conn, NULL, 0, NULL, "signed not found",
1185 TLS_FAIL_UNTRUSTED);
1186 err = GNUTLS_A_UNKNOWN_CA;
1187 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001188 }
1189
1190 if (status & GNUTLS_CERT_REVOKED) {
1191 wpa_printf(MSG_INFO, "TLS: Peer certificate has been revoked");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001192 gnutls_tls_fail_event(conn, NULL, 0, NULL,
1193 "certificate revoked",
1194 TLS_FAIL_REVOKED);
1195 err = GNUTLS_A_CERTIFICATE_REVOKED;
1196 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001197 }
1198
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001199 if (status != 0) {
1200 wpa_printf(MSG_INFO, "TLS: Unknown verification status: %d",
1201 status);
1202 err = GNUTLS_A_INTERNAL_ERROR;
1203 goto out;
1204 }
1205
1206 if (check_ocsp(conn, session, &err))
1207 goto out;
1208
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001209 os_get_time(&now);
1210
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001211 for (i = 0; i < num_certs; i++) {
1212 char *buf;
1213 size_t len;
1214 if (gnutls_x509_crt_init(&cert) < 0) {
1215 wpa_printf(MSG_INFO, "TLS: Certificate initialization "
1216 "failed");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001217 err = GNUTLS_A_BAD_CERTIFICATE;
1218 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001219 }
1220
1221 if (gnutls_x509_crt_import(cert, &certs[i],
1222 GNUTLS_X509_FMT_DER) < 0) {
1223 wpa_printf(MSG_INFO, "TLS: Could not parse peer "
1224 "certificate %d/%d", i + 1, num_certs);
1225 gnutls_x509_crt_deinit(cert);
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001226 err = GNUTLS_A_BAD_CERTIFICATE;
1227 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001228 }
1229
1230 gnutls_x509_crt_get_dn(cert, NULL, &len);
1231 len++;
1232 buf = os_malloc(len + 1);
1233 if (buf) {
1234 buf[0] = buf[len] = '\0';
1235 gnutls_x509_crt_get_dn(cert, buf, &len);
1236 }
1237 wpa_printf(MSG_DEBUG, "TLS: Peer cert chain %d/%d: %s",
1238 i + 1, num_certs, buf);
1239
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001240 if (conn->global->event_cb) {
1241 struct wpabuf *cert_buf = NULL;
1242 union tls_event_data ev;
1243#ifdef CONFIG_SHA256
1244 u8 hash[32];
1245 const u8 *_addr[1];
1246 size_t _len[1];
1247#endif /* CONFIG_SHA256 */
1248
1249 os_memset(&ev, 0, sizeof(ev));
1250 if (conn->global->cert_in_cb) {
1251 cert_buf = wpabuf_alloc_copy(certs[i].data,
1252 certs[i].size);
1253 ev.peer_cert.cert = cert_buf;
1254 }
1255#ifdef CONFIG_SHA256
1256 _addr[0] = certs[i].data;
1257 _len[0] = certs[i].size;
1258 if (sha256_vector(1, _addr, _len, hash) == 0) {
1259 ev.peer_cert.hash = hash;
1260 ev.peer_cert.hash_len = sizeof(hash);
1261 }
1262#endif /* CONFIG_SHA256 */
1263 ev.peer_cert.depth = i;
1264 ev.peer_cert.subject = buf;
1265 conn->global->event_cb(conn->global->cb_ctx,
1266 TLS_PEER_CERTIFICATE, &ev);
1267 wpabuf_free(cert_buf);
1268 }
1269
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001270 if (i == 0) {
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001271 if (conn->suffix_match &&
1272 !gnutls_x509_crt_check_hostname(
1273 cert, conn->suffix_match)) {
1274 wpa_printf(MSG_WARNING,
1275 "TLS: Domain suffix match '%s' not found",
1276 conn->suffix_match);
1277 gnutls_tls_fail_event(
1278 conn, &certs[i], i, buf,
1279 "Domain suffix mismatch",
1280 TLS_FAIL_DOMAIN_SUFFIX_MISMATCH);
1281 err = GNUTLS_A_BAD_CERTIFICATE;
1282 gnutls_x509_crt_deinit(cert);
1283 os_free(buf);
1284 goto out;
1285 }
1286
Dmitry Shmidt2f74e362015-01-21 13:19:05 -08001287#if GNUTLS_VERSION_NUMBER >= 0x030300
1288 if (conn->domain_match &&
1289 !gnutls_x509_crt_check_hostname2(
1290 cert, conn->domain_match,
1291 GNUTLS_VERIFY_DO_NOT_ALLOW_WILDCARDS)) {
1292 wpa_printf(MSG_WARNING,
1293 "TLS: Domain match '%s' not found",
1294 conn->domain_match);
1295 gnutls_tls_fail_event(
1296 conn, &certs[i], i, buf,
1297 "Domain mismatch",
1298 TLS_FAIL_DOMAIN_MISMATCH);
1299 err = GNUTLS_A_BAD_CERTIFICATE;
1300 gnutls_x509_crt_deinit(cert);
1301 os_free(buf);
1302 goto out;
1303 }
1304#endif /* >= 3.3.0 */
1305
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001306 /* TODO: validate altsubject_match.
1307 * For now, any such configuration is rejected in
1308 * tls_connection_set_params() */
1309
1310#if GNUTLS_VERSION_NUMBER < 0x030300
1311 /*
1312 * gnutls_certificate_verify_peers() not available, so
1313 * need to check EKU separately.
1314 */
1315 if (!conn->global->server &&
1316 !server_eku_purpose(cert)) {
1317 wpa_printf(MSG_WARNING,
1318 "GnuTLS: No server EKU");
1319 gnutls_tls_fail_event(
1320 conn, &certs[i], i, buf,
1321 "No server EKU",
1322 TLS_FAIL_BAD_CERTIFICATE);
1323 err = GNUTLS_A_BAD_CERTIFICATE;
1324 gnutls_x509_crt_deinit(cert);
1325 os_free(buf);
1326 goto out;
1327 }
1328#endif /* < 3.3.0 */
1329 }
1330
1331 if (!conn->disable_time_checks &&
1332 (gnutls_x509_crt_get_expiration_time(cert) < now.sec ||
1333 gnutls_x509_crt_get_activation_time(cert) > now.sec)) {
1334 wpa_printf(MSG_INFO, "TLS: Peer certificate %d/%d is "
1335 "not valid at this time",
1336 i + 1, num_certs);
1337 gnutls_tls_fail_event(
1338 conn, &certs[i], i, buf,
1339 "Certificate is not valid at this time",
1340 TLS_FAIL_EXPIRED);
1341 gnutls_x509_crt_deinit(cert);
1342 os_free(buf);
1343 err = GNUTLS_A_CERTIFICATE_EXPIRED;
1344 goto out;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001345 }
1346
1347 os_free(buf);
1348
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001349 gnutls_x509_crt_deinit(cert);
1350 }
1351
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001352 if (conn->global->event_cb != NULL)
1353 conn->global->event_cb(conn->global->cb_ctx,
1354 TLS_CERT_CHAIN_SUCCESS, NULL);
1355
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001356 return 0;
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001357
1358out:
1359 conn->failed++;
1360 gnutls_alert_send(session, GNUTLS_AL_FATAL, err);
1361 return GNUTLS_E_CERTIFICATE_ERROR;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001362}
1363
1364
1365static struct wpabuf * gnutls_get_appl_data(struct tls_connection *conn)
1366{
1367 int res;
1368 struct wpabuf *ad;
1369 wpa_printf(MSG_DEBUG, "GnuTLS: Check for possible Application Data");
1370 ad = wpabuf_alloc((wpabuf_len(conn->pull_buf) + 500) * 3);
1371 if (ad == NULL)
1372 return NULL;
1373
1374 res = gnutls_record_recv(conn->session, wpabuf_mhead(ad),
1375 wpabuf_size(ad));
1376 wpa_printf(MSG_DEBUG, "GnuTLS: gnutls_record_recv: %d", res);
1377 if (res < 0) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001378 wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d "
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001379 "(%s)", __func__, (int) res,
1380 gnutls_strerror(res));
1381 wpabuf_free(ad);
1382 return NULL;
1383 }
1384
1385 wpabuf_put(ad, res);
1386 wpa_printf(MSG_DEBUG, "GnuTLS: Received %d bytes of Application Data",
1387 res);
1388 return ad;
1389}
1390
1391
1392struct wpabuf * tls_connection_handshake(void *tls_ctx,
1393 struct tls_connection *conn,
1394 const struct wpabuf *in_data,
1395 struct wpabuf **appl_data)
1396{
1397 struct tls_global *global = tls_ctx;
1398 struct wpabuf *out_data;
1399 int ret;
1400
1401 if (appl_data)
1402 *appl_data = NULL;
1403
1404 if (in_data && wpabuf_len(in_data) > 0) {
1405 if (conn->pull_buf) {
1406 wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
1407 "pull_buf", __func__,
1408 (unsigned long) wpabuf_len(conn->pull_buf));
1409 wpabuf_free(conn->pull_buf);
1410 }
1411 conn->pull_buf = wpabuf_dup(in_data);
1412 if (conn->pull_buf == NULL)
1413 return NULL;
1414 conn->pull_buf_offset = wpabuf_head(conn->pull_buf);
1415 }
1416
1417 ret = gnutls_handshake(conn->session);
1418 if (ret < 0) {
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001419 gnutls_alert_description_t alert;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001420 union tls_event_data ev;
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001421
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001422 switch (ret) {
1423 case GNUTLS_E_AGAIN:
1424 if (global->server && conn->established &&
1425 conn->push_buf == NULL) {
1426 /* Need to return something to trigger
1427 * completion of EAP-TLS. */
1428 conn->push_buf = wpabuf_alloc(0);
1429 }
1430 break;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001431 case GNUTLS_E_DH_PRIME_UNACCEPTABLE:
1432 wpa_printf(MSG_DEBUG, "GnuTLS: Unacceptable DH prime");
1433 if (conn->global->event_cb) {
1434 os_memset(&ev, 0, sizeof(ev));
1435 ev.alert.is_local = 1;
1436 ev.alert.type = "fatal";
1437 ev.alert.description = "insufficient security";
1438 conn->global->event_cb(conn->global->cb_ctx,
1439 TLS_ALERT, &ev);
1440 }
1441 /*
1442 * Could send a TLS Alert to the server, but for now,
1443 * simply terminate handshake.
1444 */
1445 conn->failed++;
1446 conn->write_alerts++;
1447 break;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001448 case GNUTLS_E_FATAL_ALERT_RECEIVED:
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001449 alert = gnutls_alert_get(conn->session);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001450 wpa_printf(MSG_DEBUG, "%s - received fatal '%s' alert",
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001451 __func__, gnutls_alert_get_name(alert));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001452 conn->read_alerts++;
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001453 if (conn->global->event_cb != NULL) {
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001454 os_memset(&ev, 0, sizeof(ev));
1455 ev.alert.is_local = 0;
1456 ev.alert.type = gnutls_alert_get_name(alert);
1457 ev.alert.description = ev.alert.type;
1458 conn->global->event_cb(conn->global->cb_ctx,
1459 TLS_ALERT, &ev);
1460 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001461 /* continue */
1462 default:
1463 wpa_printf(MSG_DEBUG, "%s - gnutls_handshake failed "
1464 "-> %s", __func__, gnutls_strerror(ret));
1465 conn->failed++;
1466 }
1467 } else {
1468 size_t size;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001469
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001470 wpa_printf(MSG_DEBUG, "TLS: Handshake completed successfully");
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001471
1472#if GNUTLS_VERSION_NUMBER >= 0x03010a
1473 {
1474 char *desc;
1475
1476 desc = gnutls_session_get_desc(conn->session);
1477 if (desc) {
1478 wpa_printf(MSG_DEBUG, "GnuTLS: %s", desc);
1479 gnutls_free(desc);
1480 }
1481 }
1482#endif /* GnuTLS 3.1.10 or newer */
1483
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001484 conn->established = 1;
1485 if (conn->push_buf == NULL) {
1486 /* Need to return something to get final TLS ACK. */
1487 conn->push_buf = wpabuf_alloc(0);
1488 }
1489
1490 gnutls_session_get_data(conn->session, NULL, &size);
1491 if (global->session_data == NULL ||
1492 global->session_data_size < size) {
1493 os_free(global->session_data);
1494 global->session_data = os_malloc(size);
1495 }
1496 if (global->session_data) {
1497 global->session_data_size = size;
1498 gnutls_session_get_data(conn->session,
1499 global->session_data,
1500 &global->session_data_size);
1501 }
1502
1503 if (conn->pull_buf && appl_data)
1504 *appl_data = gnutls_get_appl_data(conn);
1505 }
1506
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001507 out_data = conn->push_buf;
1508 conn->push_buf = NULL;
1509 return out_data;
1510}
1511
1512
1513struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
1514 struct tls_connection *conn,
1515 const struct wpabuf *in_data,
1516 struct wpabuf **appl_data)
1517{
1518 return tls_connection_handshake(tls_ctx, conn, in_data, appl_data);
1519}
1520
1521
1522struct wpabuf * tls_connection_encrypt(void *tls_ctx,
1523 struct tls_connection *conn,
1524 const struct wpabuf *in_data)
1525{
1526 ssize_t res;
1527 struct wpabuf *buf;
1528
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001529 res = gnutls_record_send(conn->session, wpabuf_head(in_data),
1530 wpabuf_len(in_data));
1531 if (res < 0) {
1532 wpa_printf(MSG_INFO, "%s: Encryption failed: %s",
1533 __func__, gnutls_strerror(res));
1534 return NULL;
1535 }
1536
1537 buf = conn->push_buf;
1538 conn->push_buf = NULL;
1539 return buf;
1540}
1541
1542
1543struct wpabuf * tls_connection_decrypt(void *tls_ctx,
1544 struct tls_connection *conn,
1545 const struct wpabuf *in_data)
1546{
1547 ssize_t res;
1548 struct wpabuf *out;
1549
1550 if (conn->pull_buf) {
1551 wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
1552 "pull_buf", __func__,
1553 (unsigned long) wpabuf_len(conn->pull_buf));
1554 wpabuf_free(conn->pull_buf);
1555 }
1556 conn->pull_buf = wpabuf_dup(in_data);
1557 if (conn->pull_buf == NULL)
1558 return NULL;
1559 conn->pull_buf_offset = wpabuf_head(conn->pull_buf);
1560
1561 /*
1562 * Even though we try to disable TLS compression, it is possible that
1563 * this cannot be done with all TLS libraries. Add extra buffer space
1564 * to handle the possibility of the decrypted data being longer than
1565 * input data.
1566 */
1567 out = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
1568 if (out == NULL)
1569 return NULL;
1570
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001571 res = gnutls_record_recv(conn->session, wpabuf_mhead(out),
1572 wpabuf_size(out));
1573 if (res < 0) {
1574 wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d "
1575 "(%s)", __func__, (int) res, gnutls_strerror(res));
1576 wpabuf_free(out);
1577 return NULL;
1578 }
1579 wpabuf_put(out, res);
1580
1581 return out;
1582}
1583
1584
1585int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
1586{
1587 if (conn == NULL)
1588 return 0;
1589 return gnutls_session_is_resumed(conn->session);
1590}
1591
1592
1593int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
1594 u8 *ciphers)
1595{
1596 /* TODO */
1597 return -1;
1598}
1599
1600
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001601int tls_get_version(void *ssl_ctx, struct tls_connection *conn,
1602 char *buf, size_t buflen)
1603{
Roshan Pius3a1667e2018-07-03 15:17:14 -07001604 gnutls_protocol_t ver;
1605
1606 ver = gnutls_protocol_get_version(conn->session);
1607 if (ver == GNUTLS_TLS1_0)
1608 os_strlcpy(buf, "TLSv1", buflen);
1609 else if (ver == GNUTLS_TLS1_1)
1610 os_strlcpy(buf, "TLSv1.1", buflen);
1611 else if (ver == GNUTLS_TLS1_2)
1612 os_strlcpy(buf, "TLSv1.2", buflen);
1613 else
1614 return -1;
1615 return 0;
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001616}
1617
1618
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001619int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
1620 char *buf, size_t buflen)
1621{
Roshan Pius3a1667e2018-07-03 15:17:14 -07001622 gnutls_cipher_algorithm_t cipher;
1623 gnutls_kx_algorithm_t kx;
1624 gnutls_mac_algorithm_t mac;
1625 const char *kx_str, *cipher_str, *mac_str;
1626 int res;
1627
1628 cipher = gnutls_cipher_get(conn->session);
1629 cipher_str = gnutls_cipher_get_name(cipher);
1630 if (!cipher_str)
1631 cipher_str = "";
1632
1633 kx = gnutls_kx_get(conn->session);
1634 kx_str = gnutls_kx_get_name(kx);
1635 if (!kx_str)
1636 kx_str = "";
1637
1638 mac = gnutls_mac_get(conn->session);
1639 mac_str = gnutls_mac_get_name(mac);
1640 if (!mac_str)
1641 mac_str = "";
1642
1643 if (kx == GNUTLS_KX_RSA)
1644 res = os_snprintf(buf, buflen, "%s-%s", cipher_str, mac_str);
1645 else
1646 res = os_snprintf(buf, buflen, "%s-%s-%s",
1647 kx_str, cipher_str, mac_str);
1648 if (os_snprintf_error(buflen, res))
1649 return -1;
1650
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001651 return 0;
1652}
1653
1654
1655int tls_connection_enable_workaround(void *ssl_ctx,
1656 struct tls_connection *conn)
1657{
1658 gnutls_record_disable_padding(conn->session);
1659 return 0;
1660}
1661
1662
1663int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
1664 int ext_type, const u8 *data,
1665 size_t data_len)
1666{
1667 /* TODO */
1668 return -1;
1669}
1670
1671
1672int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
1673{
1674 if (conn == NULL)
1675 return -1;
1676 return conn->failed;
1677}
1678
1679
1680int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn)
1681{
1682 if (conn == NULL)
1683 return -1;
1684 return conn->read_alerts;
1685}
1686
1687
1688int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
1689{
1690 if (conn == NULL)
1691 return -1;
1692 return conn->write_alerts;
1693}
1694
1695
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001696int tls_connection_set_session_ticket_cb(void *tls_ctx,
1697 struct tls_connection *conn,
1698 tls_session_ticket_cb cb, void *ctx)
1699{
1700 return -1;
1701}
Dmitry Shmidtff787d52015-01-12 13:01:47 -08001702
1703
1704int tls_get_library_version(char *buf, size_t buf_len)
1705{
1706 return os_snprintf(buf, buf_len, "GnuTLS build=%s run=%s",
1707 GNUTLS_VERSION, gnutls_check_version(NULL));
1708}
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001709
1710
1711void tls_connection_set_success_data(struct tls_connection *conn,
1712 struct wpabuf *data)
1713{
1714}
1715
1716
1717void tls_connection_set_success_data_resumed(struct tls_connection *conn)
1718{
1719}
1720
1721
1722const struct wpabuf *
1723tls_connection_get_success_data(struct tls_connection *conn)
1724{
1725 return NULL;
1726}
1727
1728
1729void tls_connection_remove_session(struct tls_connection *conn)
1730{
1731}