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