]> git.ipfire.org Git - thirdparty/hostap.git/blob - src/crypto/tls_gnutls.c
GnuTLS: Add support for OCSP stapling as a client
[thirdparty/hostap.git] / src / crypto / tls_gnutls.c
1 /*
2 * SSL/TLS interface functions for GnuTLS
3 * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
4 *
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
7 */
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 */
15 #if GNUTLS_VERSION_NUMBER >= 0x030103
16 #include <gnutls/ocsp.h>
17 #endif /* 3.1.3 */
18
19 #include "common.h"
20 #include "tls.h"
21
22
23 static int tls_gnutls_ref_count = 0;
24
25 struct tls_global {
26 /* Data for session resumption */
27 void *session_data;
28 size_t session_data_size;
29
30 int server;
31
32 int params_set;
33 gnutls_certificate_credentials_t xcred;
34
35 void (*event_cb)(void *ctx, enum tls_event ev,
36 union tls_event_data *data);
37 void *cb_ctx;
38 int cert_in_cb;
39 };
40
41 struct tls_connection {
42 struct tls_global *global;
43 gnutls_session_t session;
44 int read_alerts, write_alerts, failed;
45
46 u8 *pre_shared_secret;
47 size_t pre_shared_secret_len;
48 int established;
49 int verify_peer;
50 unsigned int disable_time_checks:1;
51
52 struct wpabuf *push_buf;
53 struct wpabuf *pull_buf;
54 const u8 *pull_buf_offset;
55
56 int params_set;
57 gnutls_certificate_credentials_t xcred;
58
59 char *suffix_match;
60 unsigned int flags;
61 };
62
63
64 static int tls_connection_verify_peer(gnutls_session_t session);
65
66
67 static void tls_log_func(int level, const char *msg)
68 {
69 char *s, *pos;
70 if (level == 6 || level == 7) {
71 /* These levels seem to be mostly I/O debug and msg dumps */
72 return;
73 }
74
75 s = os_strdup(msg);
76 if (s == NULL)
77 return;
78
79 pos = s;
80 while (*pos != '\0') {
81 if (*pos == '\n') {
82 *pos = '\0';
83 break;
84 }
85 pos++;
86 }
87 wpa_printf(level > 3 ? MSG_MSGDUMP : MSG_DEBUG,
88 "gnutls<%d> %s", level, s);
89 os_free(s);
90 }
91
92
93 void * tls_init(const struct tls_config *conf)
94 {
95 struct tls_global *global;
96
97 if (tls_gnutls_ref_count == 0) {
98 wpa_printf(MSG_DEBUG,
99 "GnuTLS: Library version %s (runtime) - %s (build)",
100 gnutls_check_version(NULL), GNUTLS_VERSION);
101 }
102
103 global = os_zalloc(sizeof(*global));
104 if (global == NULL)
105 return NULL;
106
107 if (tls_gnutls_ref_count == 0 && gnutls_global_init() < 0) {
108 os_free(global);
109 return NULL;
110 }
111 tls_gnutls_ref_count++;
112
113 gnutls_global_set_log_function(tls_log_func);
114 if (wpa_debug_show_keys)
115 gnutls_global_set_log_level(11);
116
117 if (conf) {
118 global->event_cb = conf->event_cb;
119 global->cb_ctx = conf->cb_ctx;
120 global->cert_in_cb = conf->cert_in_cb;
121 }
122
123 return global;
124 }
125
126
127 void tls_deinit(void *ssl_ctx)
128 {
129 struct tls_global *global = ssl_ctx;
130 if (global) {
131 if (global->params_set)
132 gnutls_certificate_free_credentials(global->xcred);
133 os_free(global->session_data);
134 os_free(global);
135 }
136
137 tls_gnutls_ref_count--;
138 if (tls_gnutls_ref_count == 0)
139 gnutls_global_deinit();
140 }
141
142
143 int tls_get_errors(void *ssl_ctx)
144 {
145 return 0;
146 }
147
148
149 static ssize_t tls_pull_func(gnutls_transport_ptr_t ptr, void *buf,
150 size_t len)
151 {
152 struct tls_connection *conn = (struct tls_connection *) ptr;
153 const u8 *end;
154 if (conn->pull_buf == NULL) {
155 errno = EWOULDBLOCK;
156 return -1;
157 }
158
159 end = wpabuf_head_u8(conn->pull_buf) + wpabuf_len(conn->pull_buf);
160 if ((size_t) (end - conn->pull_buf_offset) < len)
161 len = end - conn->pull_buf_offset;
162 os_memcpy(buf, conn->pull_buf_offset, len);
163 conn->pull_buf_offset += len;
164 if (conn->pull_buf_offset == end) {
165 wpa_printf(MSG_DEBUG, "%s - pull_buf consumed", __func__);
166 wpabuf_free(conn->pull_buf);
167 conn->pull_buf = NULL;
168 conn->pull_buf_offset = NULL;
169 } else {
170 wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in pull_buf",
171 __func__,
172 (unsigned long) (end - conn->pull_buf_offset));
173 }
174 return len;
175 }
176
177
178 static ssize_t tls_push_func(gnutls_transport_ptr_t ptr, const void *buf,
179 size_t len)
180 {
181 struct tls_connection *conn = (struct tls_connection *) ptr;
182
183 if (wpabuf_resize(&conn->push_buf, len) < 0) {
184 errno = ENOMEM;
185 return -1;
186 }
187 wpabuf_put_data(conn->push_buf, buf, len);
188
189 return len;
190 }
191
192
193 static int tls_gnutls_init_session(struct tls_global *global,
194 struct tls_connection *conn)
195 {
196 const char *err;
197 int ret;
198
199 ret = gnutls_init(&conn->session,
200 global->server ? GNUTLS_SERVER : GNUTLS_CLIENT);
201 if (ret < 0) {
202 wpa_printf(MSG_INFO, "TLS: Failed to initialize new TLS "
203 "connection: %s", gnutls_strerror(ret));
204 return -1;
205 }
206
207 ret = gnutls_set_default_priority(conn->session);
208 if (ret < 0)
209 goto fail;
210
211 ret = gnutls_priority_set_direct(conn->session, "NORMAL:-VERS-SSL3.0",
212 &err);
213 if (ret < 0) {
214 wpa_printf(MSG_ERROR, "GnuTLS: Priority string failure at "
215 "'%s'", err);
216 goto fail;
217 }
218
219 gnutls_transport_set_pull_function(conn->session, tls_pull_func);
220 gnutls_transport_set_push_function(conn->session, tls_push_func);
221 gnutls_transport_set_ptr(conn->session, (gnutls_transport_ptr_t) conn);
222 gnutls_session_set_ptr(conn->session, conn);
223
224 return 0;
225
226 fail:
227 wpa_printf(MSG_INFO, "TLS: Failed to setup new TLS connection: %s",
228 gnutls_strerror(ret));
229 gnutls_deinit(conn->session);
230 return -1;
231 }
232
233
234 struct tls_connection * tls_connection_init(void *ssl_ctx)
235 {
236 struct tls_global *global = ssl_ctx;
237 struct tls_connection *conn;
238 int ret;
239
240 conn = os_zalloc(sizeof(*conn));
241 if (conn == NULL)
242 return NULL;
243 conn->global = global;
244
245 if (tls_gnutls_init_session(global, conn)) {
246 os_free(conn);
247 return NULL;
248 }
249
250 if (global->params_set) {
251 ret = gnutls_credentials_set(conn->session,
252 GNUTLS_CRD_CERTIFICATE,
253 global->xcred);
254 if (ret < 0) {
255 wpa_printf(MSG_INFO, "Failed to configure "
256 "credentials: %s", gnutls_strerror(ret));
257 os_free(conn);
258 return NULL;
259 }
260 }
261
262 if (gnutls_certificate_allocate_credentials(&conn->xcred)) {
263 os_free(conn);
264 return NULL;
265 }
266
267 return conn;
268 }
269
270
271 void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
272 {
273 if (conn == NULL)
274 return;
275
276 gnutls_certificate_free_credentials(conn->xcred);
277 gnutls_deinit(conn->session);
278 os_free(conn->pre_shared_secret);
279 wpabuf_free(conn->push_buf);
280 wpabuf_free(conn->pull_buf);
281 os_free(conn->suffix_match);
282 os_free(conn);
283 }
284
285
286 int tls_connection_established(void *ssl_ctx, struct tls_connection *conn)
287 {
288 return conn ? conn->established : 0;
289 }
290
291
292 int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
293 {
294 struct tls_global *global = ssl_ctx;
295 int ret;
296
297 if (conn == NULL)
298 return -1;
299
300 /* Shutdown previous TLS connection without notifying the peer
301 * because the connection was already terminated in practice
302 * and "close notify" shutdown alert would confuse AS. */
303 gnutls_bye(conn->session, GNUTLS_SHUT_RDWR);
304 wpabuf_free(conn->push_buf);
305 conn->push_buf = NULL;
306 conn->established = 0;
307
308 gnutls_deinit(conn->session);
309 if (tls_gnutls_init_session(global, conn)) {
310 wpa_printf(MSG_INFO, "GnuTLS: Failed to preparare new session "
311 "for session resumption use");
312 return -1;
313 }
314
315 ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
316 conn->params_set ? conn->xcred :
317 global->xcred);
318 if (ret < 0) {
319 wpa_printf(MSG_INFO, "GnuTLS: Failed to configure credentials "
320 "for session resumption: %s", gnutls_strerror(ret));
321 return -1;
322 }
323
324 if (global->session_data) {
325 ret = gnutls_session_set_data(conn->session,
326 global->session_data,
327 global->session_data_size);
328 if (ret < 0) {
329 wpa_printf(MSG_INFO, "GnuTLS: Failed to set session "
330 "data: %s", gnutls_strerror(ret));
331 return -1;
332 }
333 }
334
335 return 0;
336 }
337
338
339 int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
340 const struct tls_connection_params *params)
341 {
342 int ret;
343
344 if (conn == NULL || params == NULL)
345 return -1;
346
347 if (params->subject_match) {
348 wpa_printf(MSG_INFO, "GnuTLS: subject_match not supported");
349 return -1;
350 }
351
352 if (params->altsubject_match) {
353 wpa_printf(MSG_INFO, "GnuTLS: altsubject_match not supported");
354 return -1;
355 }
356
357 os_free(conn->suffix_match);
358 conn->suffix_match = NULL;
359 if (params->suffix_match) {
360 conn->suffix_match = os_strdup(params->suffix_match);
361 if (conn->suffix_match == NULL)
362 return -1;
363 }
364
365 conn->flags = params->flags;
366
367 if (params->openssl_ciphers) {
368 wpa_printf(MSG_INFO, "GnuTLS: openssl_ciphers not supported");
369 return -1;
370 }
371
372 /* TODO: gnutls_certificate_set_verify_flags(xcred, flags);
373 * to force peer validation(?) */
374
375 if (params->ca_cert) {
376 wpa_printf(MSG_DEBUG, "GnuTLS: Try to parse %s in DER format",
377 params->ca_cert);
378 ret = gnutls_certificate_set_x509_trust_file(
379 conn->xcred, params->ca_cert, GNUTLS_X509_FMT_DER);
380 if (ret < 0) {
381 wpa_printf(MSG_DEBUG,
382 "GnuTLS: Failed to read CA cert '%s' in DER format (%s) - try in PEM format",
383 params->ca_cert,
384 gnutls_strerror(ret));
385 ret = gnutls_certificate_set_x509_trust_file(
386 conn->xcred, params->ca_cert,
387 GNUTLS_X509_FMT_PEM);
388 if (ret < 0) {
389 wpa_printf(MSG_DEBUG,
390 "Failed to read CA cert '%s' in PEM format: %s",
391 params->ca_cert,
392 gnutls_strerror(ret));
393 return -1;
394 }
395 }
396 } else if (params->ca_cert_blob) {
397 gnutls_datum_t ca;
398
399 ca.data = (unsigned char *) params->ca_cert_blob;
400 ca.size = params->ca_cert_blob_len;
401
402 ret = gnutls_certificate_set_x509_trust_mem(
403 conn->xcred, &ca, GNUTLS_X509_FMT_DER);
404 if (ret < 0) {
405 wpa_printf(MSG_DEBUG,
406 "Failed to parse CA cert in DER format: %s",
407 gnutls_strerror(ret));
408 ret = gnutls_certificate_set_x509_trust_mem(
409 conn->xcred, &ca, GNUTLS_X509_FMT_PEM);
410 if (ret < 0) {
411 wpa_printf(MSG_DEBUG,
412 "Failed to parse CA cert in PEM format: %s",
413 gnutls_strerror(ret));
414 return -1;
415 }
416 }
417 } else if (params->ca_path) {
418 wpa_printf(MSG_INFO, "GnuTLS: ca_path not supported");
419 return -1;
420 }
421
422 conn->disable_time_checks = 0;
423 if (params->ca_cert || params->ca_cert_blob) {
424 conn->verify_peer = 1;
425 gnutls_certificate_set_verify_function(
426 conn->xcred, tls_connection_verify_peer);
427
428 if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) {
429 gnutls_certificate_set_verify_flags(
430 conn->xcred, GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
431 }
432
433 if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
434 conn->disable_time_checks = 1;
435 gnutls_certificate_set_verify_flags(
436 conn->xcred,
437 GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
438 }
439 }
440
441 if (params->client_cert && params->private_key) {
442 #if GNUTLS_VERSION_NUMBER >= 0x03010b
443 ret = gnutls_certificate_set_x509_key_file2(
444 conn->xcred, params->client_cert, params->private_key,
445 GNUTLS_X509_FMT_DER, params->private_key_passwd, 0);
446 #else
447 /* private_key_passwd not (easily) supported here */
448 ret = gnutls_certificate_set_x509_key_file(
449 conn->xcred, params->client_cert, params->private_key,
450 GNUTLS_X509_FMT_DER);
451 #endif
452 if (ret < 0) {
453 wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
454 "in DER format: %s", gnutls_strerror(ret));
455 #if GNUTLS_VERSION_NUMBER >= 0x03010b
456 ret = gnutls_certificate_set_x509_key_file2(
457 conn->xcred, params->client_cert,
458 params->private_key, GNUTLS_X509_FMT_PEM,
459 params->private_key_passwd, 0);
460 #else
461 ret = gnutls_certificate_set_x509_key_file(
462 conn->xcred, params->client_cert,
463 params->private_key, GNUTLS_X509_FMT_PEM);
464 #endif
465 if (ret < 0) {
466 wpa_printf(MSG_DEBUG, "Failed to read client "
467 "cert/key in PEM format: %s",
468 gnutls_strerror(ret));
469 return ret;
470 }
471 }
472 } else if (params->private_key) {
473 int pkcs12_ok = 0;
474 #ifdef PKCS12_FUNCS
475 /* Try to load in PKCS#12 format */
476 ret = gnutls_certificate_set_x509_simple_pkcs12_file(
477 conn->xcred, params->private_key, GNUTLS_X509_FMT_DER,
478 params->private_key_passwd);
479 if (ret != 0) {
480 wpa_printf(MSG_DEBUG, "Failed to load private_key in "
481 "PKCS#12 format: %s", gnutls_strerror(ret));
482 return -1;
483 } else
484 pkcs12_ok = 1;
485 #endif /* PKCS12_FUNCS */
486
487 if (!pkcs12_ok) {
488 wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not "
489 "included");
490 return -1;
491 }
492 } else if (params->client_cert_blob && params->private_key_blob) {
493 gnutls_datum_t cert, key;
494
495 cert.data = (unsigned char *) params->client_cert_blob;
496 cert.size = params->client_cert_blob_len;
497 key.data = (unsigned char *) params->private_key_blob;
498 key.size = params->private_key_blob_len;
499
500 #if GNUTLS_VERSION_NUMBER >= 0x03010b
501 ret = gnutls_certificate_set_x509_key_mem2(
502 conn->xcred, &cert, &key, GNUTLS_X509_FMT_DER,
503 params->private_key_passwd, 0);
504 #else
505 /* private_key_passwd not (easily) supported here */
506 ret = gnutls_certificate_set_x509_key_mem(
507 conn->xcred, &cert, &key, GNUTLS_X509_FMT_DER);
508 #endif
509 if (ret < 0) {
510 wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
511 "in DER format: %s", gnutls_strerror(ret));
512 #if GNUTLS_VERSION_NUMBER >= 0x03010b
513 ret = gnutls_certificate_set_x509_key_mem2(
514 conn->xcred, &cert, &key, GNUTLS_X509_FMT_PEM,
515 params->private_key_passwd, 0);
516 #else
517 /* private_key_passwd not (easily) supported here */
518 ret = gnutls_certificate_set_x509_key_mem(
519 conn->xcred, &cert, &key, GNUTLS_X509_FMT_PEM);
520 #endif
521 if (ret < 0) {
522 wpa_printf(MSG_DEBUG, "Failed to read client "
523 "cert/key in PEM format: %s",
524 gnutls_strerror(ret));
525 return ret;
526 }
527 }
528 } else if (params->private_key_blob) {
529 #ifdef PKCS12_FUNCS
530 gnutls_datum_t key;
531
532 key.data = (unsigned char *) params->private_key_blob;
533 key.size = params->private_key_blob_len;
534
535 /* Try to load in PKCS#12 format */
536 ret = gnutls_certificate_set_x509_simple_pkcs12_mem(
537 conn->xcred, &key, GNUTLS_X509_FMT_DER,
538 params->private_key_passwd);
539 if (ret != 0) {
540 wpa_printf(MSG_DEBUG, "Failed to load private_key in "
541 "PKCS#12 format: %s", gnutls_strerror(ret));
542 return -1;
543 }
544 #else /* PKCS12_FUNCS */
545 wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not included");
546 return -1;
547 #endif /* PKCS12_FUNCS */
548 }
549
550 #if GNUTLS_VERSION_NUMBER >= 0x030103
551 if (params->flags & (TLS_CONN_REQUEST_OCSP | TLS_CONN_REQUIRE_OCSP)) {
552 ret = gnutls_ocsp_status_request_enable_client(conn->session,
553 NULL, 0, NULL);
554 if (ret != GNUTLS_E_SUCCESS) {
555 wpa_printf(MSG_INFO,
556 "GnuTLS: Failed to enable OCSP client");
557 return -1;
558 }
559 }
560 #else /* 3.1.3 */
561 if (params->flags & TLS_CONN_REQUIRE_OCSP) {
562 wpa_printf(MSG_INFO,
563 "GnuTLS: OCSP not supported by this version of GnuTLS");
564 return -1;
565 }
566 #endif /* 3.1.3 */
567
568 conn->params_set = 1;
569
570 ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
571 conn->xcred);
572 if (ret < 0) {
573 wpa_printf(MSG_INFO, "Failed to configure credentials: %s",
574 gnutls_strerror(ret));
575 }
576
577 return ret;
578 }
579
580
581 int tls_global_set_params(void *tls_ctx,
582 const struct tls_connection_params *params)
583 {
584 struct tls_global *global = tls_ctx;
585 int ret;
586
587 /* Currently, global parameters are only set when running in server
588 * mode. */
589 global->server = 1;
590
591 if (global->params_set) {
592 gnutls_certificate_free_credentials(global->xcred);
593 global->params_set = 0;
594 }
595
596 ret = gnutls_certificate_allocate_credentials(&global->xcred);
597 if (ret) {
598 wpa_printf(MSG_DEBUG, "Failed to allocate global credentials "
599 "%s", gnutls_strerror(ret));
600 return -1;
601 }
602
603 if (params->ca_cert) {
604 ret = gnutls_certificate_set_x509_trust_file(
605 global->xcred, params->ca_cert, GNUTLS_X509_FMT_DER);
606 if (ret < 0) {
607 wpa_printf(MSG_DEBUG, "Failed to read CA cert '%s' "
608 "in DER format: %s", params->ca_cert,
609 gnutls_strerror(ret));
610 ret = gnutls_certificate_set_x509_trust_file(
611 global->xcred, params->ca_cert,
612 GNUTLS_X509_FMT_PEM);
613 if (ret < 0) {
614 wpa_printf(MSG_DEBUG, "Failed to read CA cert "
615 "'%s' in PEM format: %s",
616 params->ca_cert,
617 gnutls_strerror(ret));
618 goto fail;
619 }
620 }
621
622 if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) {
623 gnutls_certificate_set_verify_flags(
624 global->xcred,
625 GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
626 }
627
628 if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
629 gnutls_certificate_set_verify_flags(
630 global->xcred,
631 GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
632 }
633 }
634
635 if (params->client_cert && params->private_key) {
636 /* TODO: private_key_passwd? */
637 ret = gnutls_certificate_set_x509_key_file(
638 global->xcred, params->client_cert,
639 params->private_key, GNUTLS_X509_FMT_DER);
640 if (ret < 0) {
641 wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
642 "in DER format: %s", gnutls_strerror(ret));
643 ret = gnutls_certificate_set_x509_key_file(
644 global->xcred, params->client_cert,
645 params->private_key, GNUTLS_X509_FMT_PEM);
646 if (ret < 0) {
647 wpa_printf(MSG_DEBUG, "Failed to read client "
648 "cert/key in PEM format: %s",
649 gnutls_strerror(ret));
650 goto fail;
651 }
652 }
653 } else if (params->private_key) {
654 int pkcs12_ok = 0;
655 #ifdef PKCS12_FUNCS
656 /* Try to load in PKCS#12 format */
657 ret = gnutls_certificate_set_x509_simple_pkcs12_file(
658 global->xcred, params->private_key,
659 GNUTLS_X509_FMT_DER, params->private_key_passwd);
660 if (ret != 0) {
661 wpa_printf(MSG_DEBUG, "Failed to load private_key in "
662 "PKCS#12 format: %s", gnutls_strerror(ret));
663 goto fail;
664 } else
665 pkcs12_ok = 1;
666 #endif /* PKCS12_FUNCS */
667
668 if (!pkcs12_ok) {
669 wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not "
670 "included");
671 goto fail;
672 }
673 }
674
675 global->params_set = 1;
676
677 return 0;
678
679 fail:
680 gnutls_certificate_free_credentials(global->xcred);
681 return -1;
682 }
683
684
685 int tls_global_set_verify(void *ssl_ctx, int check_crl)
686 {
687 /* TODO */
688 return 0;
689 }
690
691
692 int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
693 int verify_peer)
694 {
695 if (conn == NULL || conn->session == NULL)
696 return -1;
697
698 conn->verify_peer = verify_peer;
699 gnutls_certificate_server_set_request(conn->session,
700 verify_peer ? GNUTLS_CERT_REQUIRE
701 : GNUTLS_CERT_REQUEST);
702
703 return 0;
704 }
705
706
707 int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
708 struct tls_keys *keys)
709 {
710 #if GNUTLS_VERSION_NUMBER >= 0x030012
711 gnutls_datum_t client, server;
712
713 if (conn == NULL || conn->session == NULL || keys == NULL)
714 return -1;
715
716 os_memset(keys, 0, sizeof(*keys));
717 gnutls_session_get_random(conn->session, &client, &server);
718 keys->client_random = client.data;
719 keys->server_random = server.data;
720 keys->client_random_len = client.size;
721 keys->server_random_len = client.size;
722
723 return 0;
724 #else /* 3.0.18 */
725 return -1;
726 #endif /* 3.0.18 */
727 }
728
729
730 int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
731 const char *label, int server_random_first,
732 u8 *out, size_t out_len)
733 {
734 if (conn == NULL || conn->session == NULL)
735 return -1;
736
737 return gnutls_prf(conn->session, os_strlen(label), label,
738 server_random_first, 0, NULL, out_len, (char *) out);
739 }
740
741
742 static void gnutls_tls_fail_event(struct tls_connection *conn,
743 const gnutls_datum_t *cert, int depth,
744 const char *subject, const char *err_str,
745 enum tls_fail_reason reason)
746 {
747 union tls_event_data ev;
748 struct tls_global *global = conn->global;
749 struct wpabuf *cert_buf = NULL;
750
751 if (global->event_cb == NULL)
752 return;
753
754 os_memset(&ev, 0, sizeof(ev));
755 ev.cert_fail.depth = depth;
756 ev.cert_fail.subject = subject ? subject : "";
757 ev.cert_fail.reason = reason;
758 ev.cert_fail.reason_txt = err_str;
759 if (cert) {
760 cert_buf = wpabuf_alloc_copy(cert->data, cert->size);
761 ev.cert_fail.cert = cert_buf;
762 }
763 global->event_cb(global->cb_ctx, TLS_CERT_CHAIN_FAILURE, &ev);
764 wpabuf_free(cert_buf);
765 }
766
767
768 #if GNUTLS_VERSION_NUMBER < 0x030300
769 static int server_eku_purpose(gnutls_x509_crt_t cert)
770 {
771 unsigned int i;
772
773 for (i = 0; ; i++) {
774 char oid[128];
775 size_t oid_size = sizeof(oid);
776 int res;
777
778 res = gnutls_x509_crt_get_key_purpose_oid(cert, i, oid,
779 &oid_size, NULL);
780 if (res == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
781 if (i == 0) {
782 /* No EKU - assume any use allowed */
783 return 1;
784 }
785 break;
786 }
787
788 if (res < 0) {
789 wpa_printf(MSG_INFO, "GnuTLS: Failed to get EKU");
790 return 0;
791 }
792
793 wpa_printf(MSG_DEBUG, "GnuTLS: Certificate purpose: %s", oid);
794 if (os_strcmp(oid, GNUTLS_KP_TLS_WWW_SERVER) == 0 ||
795 os_strcmp(oid, GNUTLS_KP_ANY) == 0)
796 return 1;
797 }
798
799 return 0;
800 }
801 #endif /* < 3.3.0 */
802
803
804 static int check_ocsp(struct tls_connection *conn, gnutls_session_t session,
805 gnutls_alert_description_t *err)
806 {
807 #if GNUTLS_VERSION_NUMBER >= 0x030103
808 gnutls_datum_t response, buf;
809 gnutls_ocsp_resp_t resp;
810 unsigned int cert_status;
811 int res;
812
813 if (!(conn->flags & (TLS_CONN_REQUEST_OCSP | TLS_CONN_REQUIRE_OCSP)))
814 return 0;
815
816 if (!gnutls_ocsp_status_request_is_checked(session, 0)) {
817 if (conn->flags & TLS_CONN_REQUIRE_OCSP) {
818 wpa_printf(MSG_INFO,
819 "GnuTLS: No valid OCSP response received");
820 goto ocsp_error;
821 }
822
823 wpa_printf(MSG_DEBUG,
824 "GnuTLS: Valid OCSP response was not received - continue since OCSP was not required");
825 return 0;
826 }
827
828 /*
829 * GnuTLS has already verified the OCSP response in
830 * check_ocsp_response() and rejected handshake if the certificate was
831 * found to be revoked. However, if the response indicates that the
832 * status is unknown, handshake continues and reaches here. We need to
833 * re-import the OCSP response to check for unknown certificate status,
834 * but we do not need to repeat gnutls_ocsp_resp_check_crt() and
835 * gnutls_ocsp_resp_verify_direct() calls.
836 */
837
838 res = gnutls_ocsp_status_request_get(session, &response);
839 if (res != GNUTLS_E_SUCCESS) {
840 wpa_printf(MSG_INFO,
841 "GnuTLS: OCSP response was received, but it was not valid");
842 goto ocsp_error;
843 }
844
845 if (gnutls_ocsp_resp_init(&resp) != GNUTLS_E_SUCCESS)
846 goto ocsp_error;
847
848 res = gnutls_ocsp_resp_import(resp, &response);
849 if (res != GNUTLS_E_SUCCESS) {
850 wpa_printf(MSG_INFO,
851 "GnuTLS: Could not parse received OCSP response: %s",
852 gnutls_strerror(res));
853 gnutls_ocsp_resp_deinit(resp);
854 goto ocsp_error;
855 }
856
857 res = gnutls_ocsp_resp_print(resp, GNUTLS_OCSP_PRINT_FULL, &buf);
858 if (res == GNUTLS_E_SUCCESS) {
859 wpa_printf(MSG_DEBUG, "GnuTLS: %s", buf.data);
860 gnutls_free(buf.data);
861 }
862
863 res = gnutls_ocsp_resp_get_single(resp, 0, NULL, NULL, NULL,
864 NULL, &cert_status, NULL,
865 NULL, NULL, NULL);
866 gnutls_ocsp_resp_deinit(resp);
867 if (res != GNUTLS_E_SUCCESS) {
868 wpa_printf(MSG_INFO,
869 "GnuTLS: Failed to extract OCSP information: %s",
870 gnutls_strerror(res));
871 goto ocsp_error;
872 }
873
874 if (cert_status == GNUTLS_OCSP_CERT_GOOD) {
875 wpa_printf(MSG_DEBUG, "GnuTLS: OCSP cert status: good");
876 } else if (cert_status == GNUTLS_OCSP_CERT_REVOKED) {
877 wpa_printf(MSG_DEBUG,
878 "GnuTLS: OCSP cert status: revoked");
879 goto ocsp_error;
880 } else {
881 wpa_printf(MSG_DEBUG,
882 "GnuTLS: OCSP cert status: unknown");
883 if (conn->flags & TLS_CONN_REQUIRE_OCSP)
884 goto ocsp_error;
885 wpa_printf(MSG_DEBUG,
886 "GnuTLS: OCSP was not required, so allow connection to continue");
887 }
888
889 return 0;
890
891 ocsp_error:
892 gnutls_tls_fail_event(conn, NULL, 0, NULL,
893 "bad certificate status response",
894 TLS_FAIL_REVOKED);
895 *err = GNUTLS_A_CERTIFICATE_REVOKED;
896 return -1;
897 #else /* GnuTLS 3.1.3 or newer */
898 return 0;
899 #endif /* GnuTLS 3.1.3 or newer */
900 }
901
902
903 static int tls_connection_verify_peer(gnutls_session_t session)
904 {
905 struct tls_connection *conn;
906 unsigned int status, num_certs, i;
907 struct os_time now;
908 const gnutls_datum_t *certs;
909 gnutls_x509_crt_t cert;
910 gnutls_alert_description_t err;
911 int res;
912
913 conn = gnutls_session_get_ptr(session);
914 if (!conn->verify_peer) {
915 wpa_printf(MSG_DEBUG,
916 "GnuTLS: No peer certificate verification enabled");
917 return 0;
918 }
919
920 wpa_printf(MSG_DEBUG, "GnuTSL: Verifying peer certificate");
921
922 #if GNUTLS_VERSION_NUMBER >= 0x030300
923 {
924 gnutls_typed_vdata_st data[1];
925 unsigned int elements = 0;
926
927 os_memset(data, 0, sizeof(data));
928 if (!conn->global->server) {
929 data[elements].type = GNUTLS_DT_KEY_PURPOSE_OID;
930 data[elements].data = (void *) GNUTLS_KP_TLS_WWW_SERVER;
931 elements++;
932 }
933 res = gnutls_certificate_verify_peers(session, data, 1,
934 &status);
935 }
936 #else /* < 3.3.0 */
937 res = gnutls_certificate_verify_peers2(session, &status);
938 #endif
939 if (res < 0) {
940 wpa_printf(MSG_INFO, "TLS: Failed to verify peer "
941 "certificate chain");
942 err = GNUTLS_A_INTERNAL_ERROR;
943 goto out;
944 }
945
946 #if GNUTLS_VERSION_NUMBER >= 0x030104
947 {
948 gnutls_datum_t info;
949 int ret, type;
950
951 type = gnutls_certificate_type_get(session);
952 ret = gnutls_certificate_verification_status_print(status, type,
953 &info, 0);
954 if (ret < 0) {
955 wpa_printf(MSG_DEBUG,
956 "GnuTLS: Failed to print verification status");
957 err = GNUTLS_A_INTERNAL_ERROR;
958 goto out;
959 }
960 wpa_printf(MSG_DEBUG, "GnuTLS: %s", info.data);
961 gnutls_free(info.data);
962 }
963 #endif /* GnuTLS 3.1.4 or newer */
964
965 certs = gnutls_certificate_get_peers(session, &num_certs);
966 if (certs == NULL || num_certs == 0) {
967 wpa_printf(MSG_INFO, "TLS: No peer certificate chain received");
968 err = GNUTLS_A_UNKNOWN_CA;
969 goto out;
970 }
971
972 if (conn->verify_peer && (status & GNUTLS_CERT_INVALID)) {
973 wpa_printf(MSG_INFO, "TLS: Peer certificate not trusted");
974 if (status & GNUTLS_CERT_INSECURE_ALGORITHM) {
975 wpa_printf(MSG_INFO, "TLS: Certificate uses insecure "
976 "algorithm");
977 gnutls_tls_fail_event(conn, NULL, 0, NULL,
978 "certificate uses insecure algorithm",
979 TLS_FAIL_BAD_CERTIFICATE);
980 err = GNUTLS_A_INSUFFICIENT_SECURITY;
981 goto out;
982 }
983 if (status & GNUTLS_CERT_NOT_ACTIVATED) {
984 wpa_printf(MSG_INFO, "TLS: Certificate not yet "
985 "activated");
986 gnutls_tls_fail_event(conn, NULL, 0, NULL,
987 "certificate not yet valid",
988 TLS_FAIL_NOT_YET_VALID);
989 err = GNUTLS_A_CERTIFICATE_EXPIRED;
990 goto out;
991 }
992 if (status & GNUTLS_CERT_EXPIRED) {
993 wpa_printf(MSG_INFO, "TLS: Certificate expired");
994 gnutls_tls_fail_event(conn, NULL, 0, NULL,
995 "certificate has expired",
996 TLS_FAIL_EXPIRED);
997 err = GNUTLS_A_CERTIFICATE_EXPIRED;
998 goto out;
999 }
1000 gnutls_tls_fail_event(conn, NULL, 0, NULL,
1001 "untrusted certificate",
1002 TLS_FAIL_UNTRUSTED);
1003 err = GNUTLS_A_INTERNAL_ERROR;
1004 goto out;
1005 }
1006
1007 if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
1008 wpa_printf(MSG_INFO, "TLS: Peer certificate does not have a "
1009 "known issuer");
1010 gnutls_tls_fail_event(conn, NULL, 0, NULL, "signed not found",
1011 TLS_FAIL_UNTRUSTED);
1012 err = GNUTLS_A_UNKNOWN_CA;
1013 goto out;
1014 }
1015
1016 if (status & GNUTLS_CERT_REVOKED) {
1017 wpa_printf(MSG_INFO, "TLS: Peer certificate has been revoked");
1018 gnutls_tls_fail_event(conn, NULL, 0, NULL,
1019 "certificate revoked",
1020 TLS_FAIL_REVOKED);
1021 err = GNUTLS_A_CERTIFICATE_REVOKED;
1022 goto out;
1023 }
1024
1025 if (status != 0) {
1026 wpa_printf(MSG_INFO, "TLS: Unknown verification status: %d",
1027 status);
1028 err = GNUTLS_A_INTERNAL_ERROR;
1029 goto out;
1030 }
1031
1032 if (check_ocsp(conn, session, &err))
1033 goto out;
1034
1035 os_get_time(&now);
1036
1037 for (i = 0; i < num_certs; i++) {
1038 char *buf;
1039 size_t len;
1040 if (gnutls_x509_crt_init(&cert) < 0) {
1041 wpa_printf(MSG_INFO, "TLS: Certificate initialization "
1042 "failed");
1043 err = GNUTLS_A_BAD_CERTIFICATE;
1044 goto out;
1045 }
1046
1047 if (gnutls_x509_crt_import(cert, &certs[i],
1048 GNUTLS_X509_FMT_DER) < 0) {
1049 wpa_printf(MSG_INFO, "TLS: Could not parse peer "
1050 "certificate %d/%d", i + 1, num_certs);
1051 gnutls_x509_crt_deinit(cert);
1052 err = GNUTLS_A_BAD_CERTIFICATE;
1053 goto out;
1054 }
1055
1056 gnutls_x509_crt_get_dn(cert, NULL, &len);
1057 len++;
1058 buf = os_malloc(len + 1);
1059 if (buf) {
1060 buf[0] = buf[len] = '\0';
1061 gnutls_x509_crt_get_dn(cert, buf, &len);
1062 }
1063 wpa_printf(MSG_DEBUG, "TLS: Peer cert chain %d/%d: %s",
1064 i + 1, num_certs, buf);
1065
1066 if (i == 0) {
1067 if (conn->suffix_match &&
1068 !gnutls_x509_crt_check_hostname(
1069 cert, conn->suffix_match)) {
1070 wpa_printf(MSG_WARNING,
1071 "TLS: Domain suffix match '%s' not found",
1072 conn->suffix_match);
1073 gnutls_tls_fail_event(
1074 conn, &certs[i], i, buf,
1075 "Domain suffix mismatch",
1076 TLS_FAIL_DOMAIN_SUFFIX_MISMATCH);
1077 err = GNUTLS_A_BAD_CERTIFICATE;
1078 gnutls_x509_crt_deinit(cert);
1079 os_free(buf);
1080 goto out;
1081 }
1082
1083 /* TODO: validate altsubject_match.
1084 * For now, any such configuration is rejected in
1085 * tls_connection_set_params() */
1086
1087 #if GNUTLS_VERSION_NUMBER < 0x030300
1088 /*
1089 * gnutls_certificate_verify_peers() not available, so
1090 * need to check EKU separately.
1091 */
1092 if (!conn->global->server &&
1093 !server_eku_purpose(cert)) {
1094 wpa_printf(MSG_WARNING,
1095 "GnuTLS: No server EKU");
1096 gnutls_tls_fail_event(
1097 conn, &certs[i], i, buf,
1098 "No server EKU",
1099 TLS_FAIL_BAD_CERTIFICATE);
1100 err = GNUTLS_A_BAD_CERTIFICATE;
1101 gnutls_x509_crt_deinit(cert);
1102 os_free(buf);
1103 goto out;
1104 }
1105 #endif /* < 3.3.0 */
1106 }
1107
1108 if (!conn->disable_time_checks &&
1109 (gnutls_x509_crt_get_expiration_time(cert) < now.sec ||
1110 gnutls_x509_crt_get_activation_time(cert) > now.sec)) {
1111 wpa_printf(MSG_INFO, "TLS: Peer certificate %d/%d is "
1112 "not valid at this time",
1113 i + 1, num_certs);
1114 gnutls_tls_fail_event(
1115 conn, &certs[i], i, buf,
1116 "Certificate is not valid at this time",
1117 TLS_FAIL_EXPIRED);
1118 gnutls_x509_crt_deinit(cert);
1119 os_free(buf);
1120 err = GNUTLS_A_CERTIFICATE_EXPIRED;
1121 goto out;
1122 }
1123
1124 os_free(buf);
1125
1126 gnutls_x509_crt_deinit(cert);
1127 }
1128
1129 return 0;
1130
1131 out:
1132 conn->failed++;
1133 gnutls_alert_send(session, GNUTLS_AL_FATAL, err);
1134 return GNUTLS_E_CERTIFICATE_ERROR;
1135 }
1136
1137
1138 static struct wpabuf * gnutls_get_appl_data(struct tls_connection *conn)
1139 {
1140 int res;
1141 struct wpabuf *ad;
1142 wpa_printf(MSG_DEBUG, "GnuTLS: Check for possible Application Data");
1143 ad = wpabuf_alloc((wpabuf_len(conn->pull_buf) + 500) * 3);
1144 if (ad == NULL)
1145 return NULL;
1146
1147 res = gnutls_record_recv(conn->session, wpabuf_mhead(ad),
1148 wpabuf_size(ad));
1149 wpa_printf(MSG_DEBUG, "GnuTLS: gnutls_record_recv: %d", res);
1150 if (res < 0) {
1151 wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d "
1152 "(%s)", __func__, (int) res,
1153 gnutls_strerror(res));
1154 wpabuf_free(ad);
1155 return NULL;
1156 }
1157
1158 wpabuf_put(ad, res);
1159 wpa_printf(MSG_DEBUG, "GnuTLS: Received %d bytes of Application Data",
1160 res);
1161 return ad;
1162 }
1163
1164
1165 struct wpabuf * tls_connection_handshake(void *tls_ctx,
1166 struct tls_connection *conn,
1167 const struct wpabuf *in_data,
1168 struct wpabuf **appl_data)
1169 {
1170 struct tls_global *global = tls_ctx;
1171 struct wpabuf *out_data;
1172 int ret;
1173
1174 if (appl_data)
1175 *appl_data = NULL;
1176
1177 if (in_data && wpabuf_len(in_data) > 0) {
1178 if (conn->pull_buf) {
1179 wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
1180 "pull_buf", __func__,
1181 (unsigned long) wpabuf_len(conn->pull_buf));
1182 wpabuf_free(conn->pull_buf);
1183 }
1184 conn->pull_buf = wpabuf_dup(in_data);
1185 if (conn->pull_buf == NULL)
1186 return NULL;
1187 conn->pull_buf_offset = wpabuf_head(conn->pull_buf);
1188 }
1189
1190 ret = gnutls_handshake(conn->session);
1191 if (ret < 0) {
1192 switch (ret) {
1193 case GNUTLS_E_AGAIN:
1194 if (global->server && conn->established &&
1195 conn->push_buf == NULL) {
1196 /* Need to return something to trigger
1197 * completion of EAP-TLS. */
1198 conn->push_buf = wpabuf_alloc(0);
1199 }
1200 break;
1201 case GNUTLS_E_FATAL_ALERT_RECEIVED:
1202 wpa_printf(MSG_DEBUG, "%s - received fatal '%s' alert",
1203 __func__, gnutls_alert_get_name(
1204 gnutls_alert_get(conn->session)));
1205 conn->read_alerts++;
1206 /* continue */
1207 default:
1208 wpa_printf(MSG_DEBUG, "%s - gnutls_handshake failed "
1209 "-> %s", __func__, gnutls_strerror(ret));
1210 conn->failed++;
1211 }
1212 } else {
1213 size_t size;
1214
1215 wpa_printf(MSG_DEBUG, "TLS: Handshake completed successfully");
1216
1217 #if GNUTLS_VERSION_NUMBER >= 0x03010a
1218 {
1219 char *desc;
1220
1221 desc = gnutls_session_get_desc(conn->session);
1222 if (desc) {
1223 wpa_printf(MSG_DEBUG, "GnuTLS: %s", desc);
1224 gnutls_free(desc);
1225 }
1226 }
1227 #endif /* GnuTLS 3.1.10 or newer */
1228
1229 conn->established = 1;
1230 if (conn->push_buf == NULL) {
1231 /* Need to return something to get final TLS ACK. */
1232 conn->push_buf = wpabuf_alloc(0);
1233 }
1234
1235 gnutls_session_get_data(conn->session, NULL, &size);
1236 if (global->session_data == NULL ||
1237 global->session_data_size < size) {
1238 os_free(global->session_data);
1239 global->session_data = os_malloc(size);
1240 }
1241 if (global->session_data) {
1242 global->session_data_size = size;
1243 gnutls_session_get_data(conn->session,
1244 global->session_data,
1245 &global->session_data_size);
1246 }
1247
1248 if (conn->pull_buf && appl_data)
1249 *appl_data = gnutls_get_appl_data(conn);
1250 }
1251
1252 out_data = conn->push_buf;
1253 conn->push_buf = NULL;
1254 return out_data;
1255 }
1256
1257
1258 struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
1259 struct tls_connection *conn,
1260 const struct wpabuf *in_data,
1261 struct wpabuf **appl_data)
1262 {
1263 return tls_connection_handshake(tls_ctx, conn, in_data, appl_data);
1264 }
1265
1266
1267 struct wpabuf * tls_connection_encrypt(void *tls_ctx,
1268 struct tls_connection *conn,
1269 const struct wpabuf *in_data)
1270 {
1271 ssize_t res;
1272 struct wpabuf *buf;
1273
1274 res = gnutls_record_send(conn->session, wpabuf_head(in_data),
1275 wpabuf_len(in_data));
1276 if (res < 0) {
1277 wpa_printf(MSG_INFO, "%s: Encryption failed: %s",
1278 __func__, gnutls_strerror(res));
1279 return NULL;
1280 }
1281
1282 buf = conn->push_buf;
1283 conn->push_buf = NULL;
1284 return buf;
1285 }
1286
1287
1288 struct wpabuf * tls_connection_decrypt(void *tls_ctx,
1289 struct tls_connection *conn,
1290 const struct wpabuf *in_data)
1291 {
1292 ssize_t res;
1293 struct wpabuf *out;
1294
1295 if (conn->pull_buf) {
1296 wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
1297 "pull_buf", __func__,
1298 (unsigned long) wpabuf_len(conn->pull_buf));
1299 wpabuf_free(conn->pull_buf);
1300 }
1301 conn->pull_buf = wpabuf_dup(in_data);
1302 if (conn->pull_buf == NULL)
1303 return NULL;
1304 conn->pull_buf_offset = wpabuf_head(conn->pull_buf);
1305
1306 /*
1307 * Even though we try to disable TLS compression, it is possible that
1308 * this cannot be done with all TLS libraries. Add extra buffer space
1309 * to handle the possibility of the decrypted data being longer than
1310 * input data.
1311 */
1312 out = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
1313 if (out == NULL)
1314 return NULL;
1315
1316 res = gnutls_record_recv(conn->session, wpabuf_mhead(out),
1317 wpabuf_size(out));
1318 if (res < 0) {
1319 wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d "
1320 "(%s)", __func__, (int) res, gnutls_strerror(res));
1321 wpabuf_free(out);
1322 return NULL;
1323 }
1324 wpabuf_put(out, res);
1325
1326 return out;
1327 }
1328
1329
1330 int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
1331 {
1332 if (conn == NULL)
1333 return 0;
1334 return gnutls_session_is_resumed(conn->session);
1335 }
1336
1337
1338 int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
1339 u8 *ciphers)
1340 {
1341 /* TODO */
1342 return -1;
1343 }
1344
1345
1346 int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
1347 char *buf, size_t buflen)
1348 {
1349 /* TODO */
1350 buf[0] = '\0';
1351 return 0;
1352 }
1353
1354
1355 int tls_connection_enable_workaround(void *ssl_ctx,
1356 struct tls_connection *conn)
1357 {
1358 gnutls_record_disable_padding(conn->session);
1359 return 0;
1360 }
1361
1362
1363 int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
1364 int ext_type, const u8 *data,
1365 size_t data_len)
1366 {
1367 /* TODO */
1368 return -1;
1369 }
1370
1371
1372 int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
1373 {
1374 if (conn == NULL)
1375 return -1;
1376 return conn->failed;
1377 }
1378
1379
1380 int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn)
1381 {
1382 if (conn == NULL)
1383 return -1;
1384 return conn->read_alerts;
1385 }
1386
1387
1388 int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
1389 {
1390 if (conn == NULL)
1391 return -1;
1392 return conn->write_alerts;
1393 }
1394
1395
1396 int tls_connection_get_keyblock_size(void *tls_ctx,
1397 struct tls_connection *conn)
1398 {
1399 /* TODO */
1400 return -1;
1401 }
1402
1403
1404 unsigned int tls_capabilities(void *tls_ctx)
1405 {
1406 return 0;
1407 }
1408
1409
1410 int tls_connection_set_session_ticket_cb(void *tls_ctx,
1411 struct tls_connection *conn,
1412 tls_session_ticket_cb cb, void *ctx)
1413 {
1414 return -1;
1415 }
1416
1417
1418 int tls_get_library_version(char *buf, size_t buf_len)
1419 {
1420 return os_snprintf(buf, buf_len, "GnuTLS build=%s run=%s",
1421 GNUTLS_VERSION, gnutls_check_version(NULL));
1422 }