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