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