Updated through tag hostap_2_5 from git://w1.fi/hostap.git
[mech_eap.git] / libeap / 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, unsigned int flags,
712                               const u8 *session_ctx, size_t session_ctx_len)
713 {
714         if (conn == NULL || conn->session == NULL)
715                 return -1;
716
717         conn->verify_peer = verify_peer;
718         gnutls_certificate_server_set_request(conn->session,
719                                               verify_peer ? GNUTLS_CERT_REQUIRE
720                                               : GNUTLS_CERT_REQUEST);
721
722         return 0;
723 }
724
725
726 int tls_connection_get_random(void *ssl_ctx, struct tls_connection *conn,
727                             struct tls_random *keys)
728 {
729 #if GNUTLS_VERSION_NUMBER >= 0x030012
730         gnutls_datum_t client, server;
731
732         if (conn == NULL || conn->session == NULL || keys == NULL)
733                 return -1;
734
735         os_memset(keys, 0, sizeof(*keys));
736         gnutls_session_get_random(conn->session, &client, &server);
737         keys->client_random = client.data;
738         keys->server_random = server.data;
739         keys->client_random_len = client.size;
740         keys->server_random_len = client.size;
741
742         return 0;
743 #else /* 3.0.18 */
744         return -1;
745 #endif /* 3.0.18 */
746 }
747
748
749 int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
750                        const char *label, int server_random_first,
751                        int skip_keyblock, u8 *out, size_t out_len)
752 {
753         if (conn == NULL || conn->session == NULL || skip_keyblock)
754                 return -1;
755
756         return gnutls_prf(conn->session, os_strlen(label), label,
757                           server_random_first, 0, NULL, out_len, (char *) out);
758 }
759
760
761 static void gnutls_tls_fail_event(struct tls_connection *conn,
762                                   const gnutls_datum_t *cert, int depth,
763                                   const char *subject, const char *err_str,
764                                   enum tls_fail_reason reason)
765 {
766         union tls_event_data ev;
767         struct tls_global *global = conn->global;
768         struct wpabuf *cert_buf = NULL;
769
770         if (global->event_cb == NULL)
771                 return;
772
773         os_memset(&ev, 0, sizeof(ev));
774         ev.cert_fail.depth = depth;
775         ev.cert_fail.subject = subject ? subject : "";
776         ev.cert_fail.reason = reason;
777         ev.cert_fail.reason_txt = err_str;
778         if (cert) {
779                 cert_buf = wpabuf_alloc_copy(cert->data, cert->size);
780                 ev.cert_fail.cert = cert_buf;
781         }
782         global->event_cb(global->cb_ctx, TLS_CERT_CHAIN_FAILURE, &ev);
783         wpabuf_free(cert_buf);
784 }
785
786
787 #if GNUTLS_VERSION_NUMBER < 0x030300
788 static int server_eku_purpose(gnutls_x509_crt_t cert)
789 {
790         unsigned int i;
791
792         for (i = 0; ; i++) {
793                 char oid[128];
794                 size_t oid_size = sizeof(oid);
795                 int res;
796
797                 res = gnutls_x509_crt_get_key_purpose_oid(cert, i, oid,
798                                                           &oid_size, NULL);
799                 if (res == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
800                         if (i == 0) {
801                                 /* No EKU - assume any use allowed */
802                                 return 1;
803                         }
804                         break;
805                 }
806
807                 if (res < 0) {
808                         wpa_printf(MSG_INFO, "GnuTLS: Failed to get EKU");
809                         return 0;
810                 }
811
812                 wpa_printf(MSG_DEBUG, "GnuTLS: Certificate purpose: %s", oid);
813                 if (os_strcmp(oid, GNUTLS_KP_TLS_WWW_SERVER) == 0 ||
814                     os_strcmp(oid, GNUTLS_KP_ANY) == 0)
815                         return 1;
816         }
817
818         return 0;
819 }
820 #endif /* < 3.3.0 */
821
822
823 static int check_ocsp(struct tls_connection *conn, gnutls_session_t session,
824                       gnutls_alert_description_t *err)
825 {
826 #if GNUTLS_VERSION_NUMBER >= 0x030103
827         gnutls_datum_t response, buf;
828         gnutls_ocsp_resp_t resp;
829         unsigned int cert_status;
830         int res;
831
832         if (!(conn->flags & (TLS_CONN_REQUEST_OCSP | TLS_CONN_REQUIRE_OCSP)))
833                 return 0;
834
835         if (!gnutls_ocsp_status_request_is_checked(session, 0)) {
836                 if (conn->flags & TLS_CONN_REQUIRE_OCSP) {
837                         wpa_printf(MSG_INFO,
838                                    "GnuTLS: No valid OCSP response received");
839                         goto ocsp_error;
840                 }
841
842                 wpa_printf(MSG_DEBUG,
843                            "GnuTLS: Valid OCSP response was not received - continue since OCSP was not required");
844                 return 0;
845         }
846
847         /*
848          * GnuTLS has already verified the OCSP response in
849          * check_ocsp_response() and rejected handshake if the certificate was
850          * found to be revoked. However, if the response indicates that the
851          * status is unknown, handshake continues and reaches here. We need to
852          * re-import the OCSP response to check for unknown certificate status,
853          * but we do not need to repeat gnutls_ocsp_resp_check_crt() and
854          * gnutls_ocsp_resp_verify_direct() calls.
855          */
856
857         res = gnutls_ocsp_status_request_get(session, &response);
858         if (res != GNUTLS_E_SUCCESS) {
859                 wpa_printf(MSG_INFO,
860                            "GnuTLS: OCSP response was received, but it was not valid");
861                 goto ocsp_error;
862         }
863
864         if (gnutls_ocsp_resp_init(&resp) != GNUTLS_E_SUCCESS)
865                 goto ocsp_error;
866
867         res = gnutls_ocsp_resp_import(resp, &response);
868         if (res != GNUTLS_E_SUCCESS) {
869                 wpa_printf(MSG_INFO,
870                            "GnuTLS: Could not parse received OCSP response: %s",
871                            gnutls_strerror(res));
872                 gnutls_ocsp_resp_deinit(resp);
873                 goto ocsp_error;
874         }
875
876         res = gnutls_ocsp_resp_print(resp, GNUTLS_OCSP_PRINT_FULL, &buf);
877         if (res == GNUTLS_E_SUCCESS) {
878                 wpa_printf(MSG_DEBUG, "GnuTLS: %s", buf.data);
879                 gnutls_free(buf.data);
880         }
881
882         res = gnutls_ocsp_resp_get_single(resp, 0, NULL, NULL, NULL,
883                                           NULL, &cert_status, NULL,
884                                           NULL, NULL, NULL);
885         gnutls_ocsp_resp_deinit(resp);
886         if (res != GNUTLS_E_SUCCESS) {
887                 wpa_printf(MSG_INFO,
888                            "GnuTLS: Failed to extract OCSP information: %s",
889                            gnutls_strerror(res));
890                 goto ocsp_error;
891         }
892
893         if (cert_status == GNUTLS_OCSP_CERT_GOOD) {
894                 wpa_printf(MSG_DEBUG, "GnuTLS: OCSP cert status: good");
895         } else if (cert_status == GNUTLS_OCSP_CERT_REVOKED) {
896                 wpa_printf(MSG_DEBUG,
897                            "GnuTLS: OCSP cert status: revoked");
898                 goto ocsp_error;
899         } else {
900                 wpa_printf(MSG_DEBUG,
901                            "GnuTLS: OCSP cert status: unknown");
902                 if (conn->flags & TLS_CONN_REQUIRE_OCSP)
903                         goto ocsp_error;
904                 wpa_printf(MSG_DEBUG,
905                            "GnuTLS: OCSP was not required, so allow connection to continue");
906         }
907
908         return 0;
909
910 ocsp_error:
911         gnutls_tls_fail_event(conn, NULL, 0, NULL,
912                               "bad certificate status response",
913                               TLS_FAIL_REVOKED);
914         *err = GNUTLS_A_CERTIFICATE_REVOKED;
915         return -1;
916 #else /* GnuTLS 3.1.3 or newer */
917         return 0;
918 #endif /* GnuTLS 3.1.3 or newer */
919 }
920
921
922 static int tls_connection_verify_peer(gnutls_session_t session)
923 {
924         struct tls_connection *conn;
925         unsigned int status, num_certs, i;
926         struct os_time now;
927         const gnutls_datum_t *certs;
928         gnutls_x509_crt_t cert;
929         gnutls_alert_description_t err;
930         int res;
931
932         conn = gnutls_session_get_ptr(session);
933         if (!conn->verify_peer) {
934                 wpa_printf(MSG_DEBUG,
935                            "GnuTLS: No peer certificate verification enabled");
936                 return 0;
937         }
938
939         wpa_printf(MSG_DEBUG, "GnuTSL: Verifying peer certificate");
940
941 #if GNUTLS_VERSION_NUMBER >= 0x030300
942         {
943                 gnutls_typed_vdata_st data[1];
944                 unsigned int elements = 0;
945
946                 os_memset(data, 0, sizeof(data));
947                 if (!conn->global->server) {
948                         data[elements].type = GNUTLS_DT_KEY_PURPOSE_OID;
949                         data[elements].data = (void *) GNUTLS_KP_TLS_WWW_SERVER;
950                         elements++;
951                 }
952                 res = gnutls_certificate_verify_peers(session, data, 1,
953                                                       &status);
954         }
955 #else /* < 3.3.0 */
956         res = gnutls_certificate_verify_peers2(session, &status);
957 #endif
958         if (res < 0) {
959                 wpa_printf(MSG_INFO, "TLS: Failed to verify peer "
960                            "certificate chain");
961                 err = GNUTLS_A_INTERNAL_ERROR;
962                 goto out;
963         }
964
965 #if GNUTLS_VERSION_NUMBER >= 0x030104
966         {
967                 gnutls_datum_t info;
968                 int ret, type;
969
970                 type = gnutls_certificate_type_get(session);
971                 ret = gnutls_certificate_verification_status_print(status, type,
972                                                                    &info, 0);
973                 if (ret < 0) {
974                         wpa_printf(MSG_DEBUG,
975                                    "GnuTLS: Failed to print verification status");
976                         err = GNUTLS_A_INTERNAL_ERROR;
977                         goto out;
978                 }
979                 wpa_printf(MSG_DEBUG, "GnuTLS: %s", info.data);
980                 gnutls_free(info.data);
981         }
982 #endif /* GnuTLS 3.1.4 or newer */
983
984         certs = gnutls_certificate_get_peers(session, &num_certs);
985         if (certs == NULL || num_certs == 0) {
986                 wpa_printf(MSG_INFO, "TLS: No peer certificate chain received");
987                 err = GNUTLS_A_UNKNOWN_CA;
988                 goto out;
989         }
990
991         if (conn->verify_peer && (status & GNUTLS_CERT_INVALID)) {
992                 wpa_printf(MSG_INFO, "TLS: Peer certificate not trusted");
993                 if (status & GNUTLS_CERT_INSECURE_ALGORITHM) {
994                         wpa_printf(MSG_INFO, "TLS: Certificate uses insecure "
995                                    "algorithm");
996                         gnutls_tls_fail_event(conn, NULL, 0, NULL,
997                                               "certificate uses insecure algorithm",
998                                               TLS_FAIL_BAD_CERTIFICATE);
999                         err = GNUTLS_A_INSUFFICIENT_SECURITY;
1000                         goto out;
1001                 }
1002                 if (status & GNUTLS_CERT_NOT_ACTIVATED) {
1003                         wpa_printf(MSG_INFO, "TLS: Certificate not yet "
1004                                    "activated");
1005                         gnutls_tls_fail_event(conn, NULL, 0, NULL,
1006                                               "certificate not yet valid",
1007                                               TLS_FAIL_NOT_YET_VALID);
1008                         err = GNUTLS_A_CERTIFICATE_EXPIRED;
1009                         goto out;
1010                 }
1011                 if (status & GNUTLS_CERT_EXPIRED) {
1012                         wpa_printf(MSG_INFO, "TLS: Certificate expired");
1013                         gnutls_tls_fail_event(conn, NULL, 0, NULL,
1014                                               "certificate has expired",
1015                                               TLS_FAIL_EXPIRED);
1016                         err = GNUTLS_A_CERTIFICATE_EXPIRED;
1017                         goto out;
1018                 }
1019                 gnutls_tls_fail_event(conn, NULL, 0, NULL,
1020                                       "untrusted certificate",
1021                                       TLS_FAIL_UNTRUSTED);
1022                 err = GNUTLS_A_INTERNAL_ERROR;
1023                 goto out;
1024         }
1025
1026         if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
1027                 wpa_printf(MSG_INFO, "TLS: Peer certificate does not have a "
1028                            "known issuer");
1029                 gnutls_tls_fail_event(conn, NULL, 0, NULL, "signed not found",
1030                                       TLS_FAIL_UNTRUSTED);
1031                 err = GNUTLS_A_UNKNOWN_CA;
1032                 goto out;
1033         }
1034
1035         if (status & GNUTLS_CERT_REVOKED) {
1036                 wpa_printf(MSG_INFO, "TLS: Peer certificate has been revoked");
1037                 gnutls_tls_fail_event(conn, NULL, 0, NULL,
1038                                       "certificate revoked",
1039                                       TLS_FAIL_REVOKED);
1040                 err = GNUTLS_A_CERTIFICATE_REVOKED;
1041                 goto out;
1042         }
1043
1044         if (status != 0) {
1045                 wpa_printf(MSG_INFO, "TLS: Unknown verification status: %d",
1046                            status);
1047                 err = GNUTLS_A_INTERNAL_ERROR;
1048                 goto out;
1049         }
1050
1051         if (check_ocsp(conn, session, &err))
1052                 goto out;
1053
1054         os_get_time(&now);
1055
1056         for (i = 0; i < num_certs; i++) {
1057                 char *buf;
1058                 size_t len;
1059                 if (gnutls_x509_crt_init(&cert) < 0) {
1060                         wpa_printf(MSG_INFO, "TLS: Certificate initialization "
1061                                    "failed");
1062                         err = GNUTLS_A_BAD_CERTIFICATE;
1063                         goto out;
1064                 }
1065
1066                 if (gnutls_x509_crt_import(cert, &certs[i],
1067                                            GNUTLS_X509_FMT_DER) < 0) {
1068                         wpa_printf(MSG_INFO, "TLS: Could not parse peer "
1069                                    "certificate %d/%d", i + 1, num_certs);
1070                         gnutls_x509_crt_deinit(cert);
1071                         err = GNUTLS_A_BAD_CERTIFICATE;
1072                         goto out;
1073                 }
1074
1075                 gnutls_x509_crt_get_dn(cert, NULL, &len);
1076                 len++;
1077                 buf = os_malloc(len + 1);
1078                 if (buf) {
1079                         buf[0] = buf[len] = '\0';
1080                         gnutls_x509_crt_get_dn(cert, buf, &len);
1081                 }
1082                 wpa_printf(MSG_DEBUG, "TLS: Peer cert chain %d/%d: %s",
1083                            i + 1, num_certs, buf);
1084
1085                 if (conn->global->event_cb) {
1086                         struct wpabuf *cert_buf = NULL;
1087                         union tls_event_data ev;
1088 #ifdef CONFIG_SHA256
1089                         u8 hash[32];
1090                         const u8 *_addr[1];
1091                         size_t _len[1];
1092 #endif /* CONFIG_SHA256 */
1093
1094                         os_memset(&ev, 0, sizeof(ev));
1095                         if (conn->global->cert_in_cb) {
1096                                 cert_buf = wpabuf_alloc_copy(certs[i].data,
1097                                                              certs[i].size);
1098                                 ev.peer_cert.cert = cert_buf;
1099                         }
1100 #ifdef CONFIG_SHA256
1101                         _addr[0] = certs[i].data;
1102                         _len[0] = certs[i].size;
1103                         if (sha256_vector(1, _addr, _len, hash) == 0) {
1104                                 ev.peer_cert.hash = hash;
1105                                 ev.peer_cert.hash_len = sizeof(hash);
1106                         }
1107 #endif /* CONFIG_SHA256 */
1108                         ev.peer_cert.depth = i;
1109                         ev.peer_cert.subject = buf;
1110                         conn->global->event_cb(conn->global->cb_ctx,
1111                                                TLS_PEER_CERTIFICATE, &ev);
1112                         wpabuf_free(cert_buf);
1113                 }
1114
1115                 if (i == 0) {
1116                         if (conn->suffix_match &&
1117                             !gnutls_x509_crt_check_hostname(
1118                                     cert, conn->suffix_match)) {
1119                                 wpa_printf(MSG_WARNING,
1120                                            "TLS: Domain suffix match '%s' not found",
1121                                            conn->suffix_match);
1122                                 gnutls_tls_fail_event(
1123                                         conn, &certs[i], i, buf,
1124                                         "Domain suffix mismatch",
1125                                         TLS_FAIL_DOMAIN_SUFFIX_MISMATCH);
1126                                 err = GNUTLS_A_BAD_CERTIFICATE;
1127                                 gnutls_x509_crt_deinit(cert);
1128                                 os_free(buf);
1129                                 goto out;
1130                         }
1131
1132 #if GNUTLS_VERSION_NUMBER >= 0x030300
1133                         if (conn->domain_match &&
1134                             !gnutls_x509_crt_check_hostname2(
1135                                     cert, conn->domain_match,
1136                                     GNUTLS_VERIFY_DO_NOT_ALLOW_WILDCARDS)) {
1137                                 wpa_printf(MSG_WARNING,
1138                                            "TLS: Domain match '%s' not found",
1139                                            conn->domain_match);
1140                                 gnutls_tls_fail_event(
1141                                         conn, &certs[i], i, buf,
1142                                         "Domain mismatch",
1143                                         TLS_FAIL_DOMAIN_MISMATCH);
1144                                 err = GNUTLS_A_BAD_CERTIFICATE;
1145                                 gnutls_x509_crt_deinit(cert);
1146                                 os_free(buf);
1147                                 goto out;
1148                         }
1149 #endif /* >= 3.3.0 */
1150
1151                         /* TODO: validate altsubject_match.
1152                          * For now, any such configuration is rejected in
1153                          * tls_connection_set_params() */
1154
1155 #if GNUTLS_VERSION_NUMBER < 0x030300
1156                         /*
1157                          * gnutls_certificate_verify_peers() not available, so
1158                          * need to check EKU separately.
1159                          */
1160                         if (!conn->global->server &&
1161                             !server_eku_purpose(cert)) {
1162                                 wpa_printf(MSG_WARNING,
1163                                            "GnuTLS: No server EKU");
1164                                 gnutls_tls_fail_event(
1165                                         conn, &certs[i], i, buf,
1166                                         "No server EKU",
1167                                         TLS_FAIL_BAD_CERTIFICATE);
1168                                 err = GNUTLS_A_BAD_CERTIFICATE;
1169                                 gnutls_x509_crt_deinit(cert);
1170                                 os_free(buf);
1171                                 goto out;
1172                         }
1173 #endif /* < 3.3.0 */
1174                 }
1175
1176                 if (!conn->disable_time_checks &&
1177                     (gnutls_x509_crt_get_expiration_time(cert) < now.sec ||
1178                      gnutls_x509_crt_get_activation_time(cert) > now.sec)) {
1179                         wpa_printf(MSG_INFO, "TLS: Peer certificate %d/%d is "
1180                                    "not valid at this time",
1181                                    i + 1, num_certs);
1182                         gnutls_tls_fail_event(
1183                                 conn, &certs[i], i, buf,
1184                                 "Certificate is not valid at this time",
1185                                 TLS_FAIL_EXPIRED);
1186                         gnutls_x509_crt_deinit(cert);
1187                         os_free(buf);
1188                         err = GNUTLS_A_CERTIFICATE_EXPIRED;
1189                         goto out;
1190                 }
1191
1192                 os_free(buf);
1193
1194                 gnutls_x509_crt_deinit(cert);
1195         }
1196
1197         if (conn->global->event_cb != NULL)
1198                 conn->global->event_cb(conn->global->cb_ctx,
1199                                        TLS_CERT_CHAIN_SUCCESS, NULL);
1200
1201         return 0;
1202
1203 out:
1204         conn->failed++;
1205         gnutls_alert_send(session, GNUTLS_AL_FATAL, err);
1206         return GNUTLS_E_CERTIFICATE_ERROR;
1207 }
1208
1209
1210 static struct wpabuf * gnutls_get_appl_data(struct tls_connection *conn)
1211 {
1212         int res;
1213         struct wpabuf *ad;
1214         wpa_printf(MSG_DEBUG, "GnuTLS: Check for possible Application Data");
1215         ad = wpabuf_alloc((wpabuf_len(conn->pull_buf) + 500) * 3);
1216         if (ad == NULL)
1217                 return NULL;
1218
1219         res = gnutls_record_recv(conn->session, wpabuf_mhead(ad),
1220                                  wpabuf_size(ad));
1221         wpa_printf(MSG_DEBUG, "GnuTLS: gnutls_record_recv: %d", res);
1222         if (res < 0) {
1223                 wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d "
1224                            "(%s)", __func__, (int) res,
1225                            gnutls_strerror(res));
1226                 wpabuf_free(ad);
1227                 return NULL;
1228         }
1229
1230         wpabuf_put(ad, res);
1231         wpa_printf(MSG_DEBUG, "GnuTLS: Received %d bytes of Application Data",
1232                    res);
1233         return ad;
1234 }
1235
1236
1237 struct wpabuf * tls_connection_handshake(void *tls_ctx,
1238                                          struct tls_connection *conn,
1239                                          const struct wpabuf *in_data,
1240                                          struct wpabuf **appl_data)
1241 {
1242         struct tls_global *global = tls_ctx;
1243         struct wpabuf *out_data;
1244         int ret;
1245
1246         if (appl_data)
1247                 *appl_data = NULL;
1248
1249         if (in_data && wpabuf_len(in_data) > 0) {
1250                 if (conn->pull_buf) {
1251                         wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
1252                                    "pull_buf", __func__,
1253                                    (unsigned long) wpabuf_len(conn->pull_buf));
1254                         wpabuf_free(conn->pull_buf);
1255                 }
1256                 conn->pull_buf = wpabuf_dup(in_data);
1257                 if (conn->pull_buf == NULL)
1258                         return NULL;
1259                 conn->pull_buf_offset = wpabuf_head(conn->pull_buf);
1260         }
1261
1262         ret = gnutls_handshake(conn->session);
1263         if (ret < 0) {
1264                 gnutls_alert_description_t alert;
1265
1266                 switch (ret) {
1267                 case GNUTLS_E_AGAIN:
1268                         if (global->server && conn->established &&
1269                             conn->push_buf == NULL) {
1270                                 /* Need to return something to trigger
1271                                  * completion of EAP-TLS. */
1272                                 conn->push_buf = wpabuf_alloc(0);
1273                         }
1274                         break;
1275                 case GNUTLS_E_FATAL_ALERT_RECEIVED:
1276                         alert = gnutls_alert_get(conn->session);
1277                         wpa_printf(MSG_DEBUG, "%s - received fatal '%s' alert",
1278                                    __func__, gnutls_alert_get_name(alert));
1279                         conn->read_alerts++;
1280                         if (conn->global->event_cb != NULL) {
1281                                 union tls_event_data ev;
1282
1283                                 os_memset(&ev, 0, sizeof(ev));
1284                                 ev.alert.is_local = 0;
1285                                 ev.alert.type = gnutls_alert_get_name(alert);
1286                                 ev.alert.description = ev.alert.type;
1287                                 conn->global->event_cb(conn->global->cb_ctx,
1288                                                        TLS_ALERT, &ev);
1289                         }
1290                         /* continue */
1291                 default:
1292                         wpa_printf(MSG_DEBUG, "%s - gnutls_handshake failed "
1293                                    "-> %s", __func__, gnutls_strerror(ret));
1294                         conn->failed++;
1295                 }
1296         } else {
1297                 size_t size;
1298
1299                 wpa_printf(MSG_DEBUG, "TLS: Handshake completed successfully");
1300
1301 #if GNUTLS_VERSION_NUMBER >= 0x03010a
1302                 {
1303                         char *desc;
1304
1305                         desc = gnutls_session_get_desc(conn->session);
1306                         if (desc) {
1307                                 wpa_printf(MSG_DEBUG, "GnuTLS: %s", desc);
1308                                 gnutls_free(desc);
1309                         }
1310                 }
1311 #endif /* GnuTLS 3.1.10 or newer */
1312
1313                 conn->established = 1;
1314                 if (conn->push_buf == NULL) {
1315                         /* Need to return something to get final TLS ACK. */
1316                         conn->push_buf = wpabuf_alloc(0);
1317                 }
1318
1319                 gnutls_session_get_data(conn->session, NULL, &size);
1320                 if (global->session_data == NULL ||
1321                     global->session_data_size < size) {
1322                         os_free(global->session_data);
1323                         global->session_data = os_malloc(size);
1324                 }
1325                 if (global->session_data) {
1326                         global->session_data_size = size;
1327                         gnutls_session_get_data(conn->session,
1328                                                 global->session_data,
1329                                                 &global->session_data_size);
1330                 }
1331
1332                 if (conn->pull_buf && appl_data)
1333                         *appl_data = gnutls_get_appl_data(conn);
1334         }
1335
1336         out_data = conn->push_buf;
1337         conn->push_buf = NULL;
1338         return out_data;
1339 }
1340
1341
1342 struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
1343                                                 struct tls_connection *conn,
1344                                                 const struct wpabuf *in_data,
1345                                                 struct wpabuf **appl_data)
1346 {
1347         return tls_connection_handshake(tls_ctx, conn, in_data, appl_data);
1348 }
1349
1350
1351 struct wpabuf * tls_connection_encrypt(void *tls_ctx,
1352                                        struct tls_connection *conn,
1353                                        const struct wpabuf *in_data)
1354 {
1355         ssize_t res;
1356         struct wpabuf *buf;
1357
1358         res = gnutls_record_send(conn->session, wpabuf_head(in_data),
1359                                  wpabuf_len(in_data));
1360         if (res < 0) {
1361                 wpa_printf(MSG_INFO, "%s: Encryption failed: %s",
1362                            __func__, gnutls_strerror(res));
1363                 return NULL;
1364         }
1365
1366         buf = conn->push_buf;
1367         conn->push_buf = NULL;
1368         return buf;
1369 }
1370
1371
1372 struct wpabuf * tls_connection_decrypt(void *tls_ctx,
1373                                        struct tls_connection *conn,
1374                                        const struct wpabuf *in_data)
1375 {
1376         ssize_t res;
1377         struct wpabuf *out;
1378
1379         if (conn->pull_buf) {
1380                 wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
1381                            "pull_buf", __func__,
1382                            (unsigned long) wpabuf_len(conn->pull_buf));
1383                 wpabuf_free(conn->pull_buf);
1384         }
1385         conn->pull_buf = wpabuf_dup(in_data);
1386         if (conn->pull_buf == NULL)
1387                 return NULL;
1388         conn->pull_buf_offset = wpabuf_head(conn->pull_buf);
1389
1390         /*
1391          * Even though we try to disable TLS compression, it is possible that
1392          * this cannot be done with all TLS libraries. Add extra buffer space
1393          * to handle the possibility of the decrypted data being longer than
1394          * input data.
1395          */
1396         out = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
1397         if (out == NULL)
1398                 return NULL;
1399
1400         res = gnutls_record_recv(conn->session, wpabuf_mhead(out),
1401                                  wpabuf_size(out));
1402         if (res < 0) {
1403                 wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d "
1404                            "(%s)", __func__, (int) res, gnutls_strerror(res));
1405                 wpabuf_free(out);
1406                 return NULL;
1407         }
1408         wpabuf_put(out, res);
1409
1410         return out;
1411 }
1412
1413
1414 int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
1415 {
1416         if (conn == NULL)
1417                 return 0;
1418         return gnutls_session_is_resumed(conn->session);
1419 }
1420
1421
1422 int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
1423                                    u8 *ciphers)
1424 {
1425         /* TODO */
1426         return -1;
1427 }
1428
1429
1430 int tls_get_version(void *ssl_ctx, struct tls_connection *conn,
1431                     char *buf, size_t buflen)
1432 {
1433         /* TODO */
1434         return -1;
1435 }
1436
1437
1438 int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
1439                    char *buf, size_t buflen)
1440 {
1441         /* TODO */
1442         buf[0] = '\0';
1443         return 0;
1444 }
1445
1446
1447 int tls_connection_enable_workaround(void *ssl_ctx,
1448                                      struct tls_connection *conn)
1449 {
1450         gnutls_record_disable_padding(conn->session);
1451         return 0;
1452 }
1453
1454
1455 int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
1456                                     int ext_type, const u8 *data,
1457                                     size_t data_len)
1458 {
1459         /* TODO */
1460         return -1;
1461 }
1462
1463
1464 int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
1465 {
1466         if (conn == NULL)
1467                 return -1;
1468         return conn->failed;
1469 }
1470
1471
1472 int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn)
1473 {
1474         if (conn == NULL)
1475                 return -1;
1476         return conn->read_alerts;
1477 }
1478
1479
1480 int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
1481 {
1482         if (conn == NULL)
1483                 return -1;
1484         return conn->write_alerts;
1485 }
1486
1487
1488 int tls_connection_set_session_ticket_cb(void *tls_ctx,
1489                                          struct tls_connection *conn,
1490                                          tls_session_ticket_cb cb, void *ctx)
1491 {
1492         return -1;
1493 }
1494
1495
1496 int tls_get_library_version(char *buf, size_t buf_len)
1497 {
1498         return os_snprintf(buf, buf_len, "GnuTLS build=%s run=%s",
1499                            GNUTLS_VERSION, gnutls_check_version(NULL));
1500 }
1501
1502
1503 void tls_connection_set_success_data(struct tls_connection *conn,
1504                                      struct wpabuf *data)
1505 {
1506 }
1507
1508
1509 void tls_connection_set_success_data_resumed(struct tls_connection *conn)
1510 {
1511 }
1512
1513
1514 const struct wpabuf *
1515 tls_connection_get_success_data(struct tls_connection *conn)
1516 {
1517         return NULL;
1518 }
1519
1520
1521 void tls_connection_remove_session(struct tls_connection *conn)
1522 {
1523 }