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