hostapd: Update vendor branch to 0.6.10
[dragonfly.git] / contrib / hostapd / src / crypto / tls_gnutls.c
blob2c5c5a2b640650f15dfdf237d226992c1574f53c
1 /*
2 * WPA Supplicant / SSL/TLS interface functions for openssl
3 * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
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.
9 * Alternatively, this software may be distributed under the terms of BSD
10 * license.
12 * See README and COPYING for more details.
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 */
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 */
34 #include "common.h"
35 #include "tls.h"
38 #ifndef TLS_RANDOM_SIZE
39 #define TLS_RANDOM_SIZE 32
40 #endif
41 #ifndef TLS_MASTER_SIZE
42 #define TLS_MASTER_SIZE 48
43 #endif
46 #if LIBGNUTLS_VERSION_NUMBER < 0x010302
47 /* GnuTLS 1.3.2 added functions for using master secret. Older versions require
48 * use of internal structures to get the master_secret and
49 * {server,client}_random.
51 #define GNUTLS_INTERNAL_STRUCTURE_HACK
52 #endif /* LIBGNUTLS_VERSION_NUMBER < 0x010302 */
55 #ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
57 * It looks like gnutls does not provide access to client/server_random and
58 * master_key. This is somewhat unfortunate since these are needed for key
59 * derivation in EAP-{TLS,TTLS,PEAP,FAST}. Workaround for now is a horrible
60 * hack that copies the gnutls_session_int definition from gnutls_int.h so that
61 * we can get the needed information.
64 typedef u8 uint8;
65 typedef unsigned char opaque;
66 typedef struct {
67 uint8 suite[2];
68 } cipher_suite_st;
70 typedef struct {
71 gnutls_connection_end_t entity;
72 gnutls_kx_algorithm_t kx_algorithm;
73 gnutls_cipher_algorithm_t read_bulk_cipher_algorithm;
74 gnutls_mac_algorithm_t read_mac_algorithm;
75 gnutls_compression_method_t read_compression_algorithm;
76 gnutls_cipher_algorithm_t write_bulk_cipher_algorithm;
77 gnutls_mac_algorithm_t write_mac_algorithm;
78 gnutls_compression_method_t write_compression_algorithm;
79 cipher_suite_st current_cipher_suite;
80 opaque master_secret[TLS_MASTER_SIZE];
81 opaque client_random[TLS_RANDOM_SIZE];
82 opaque server_random[TLS_RANDOM_SIZE];
83 /* followed by stuff we are not interested in */
84 } security_parameters_st;
86 struct gnutls_session_int {
87 security_parameters_st security_parameters;
88 /* followed by things we are not interested in */
90 #endif /* LIBGNUTLS_VERSION_NUMBER < 0x010302 */
92 static int tls_gnutls_ref_count = 0;
94 struct tls_global {
95 /* Data for session resumption */
96 void *session_data;
97 size_t session_data_size;
99 int server;
101 int params_set;
102 gnutls_certificate_credentials_t xcred;
105 struct tls_connection {
106 gnutls_session session;
107 char *subject_match, *altsubject_match;
108 int read_alerts, write_alerts, failed;
110 u8 *pre_shared_secret;
111 size_t pre_shared_secret_len;
112 int established;
113 int verify_peer;
115 u8 *push_buf, *pull_buf, *pull_buf_offset;
116 size_t push_buf_len, pull_buf_len;
118 int params_set;
119 gnutls_certificate_credentials_t xcred;
121 int tls_ia;
122 int final_phase_finished;
124 #ifdef GNUTLS_IA
125 gnutls_ia_server_credentials_t iacred_srv;
126 gnutls_ia_client_credentials_t iacred_cli;
128 /* Session keys generated in the current phase for inner secret
129 * permutation before generating/verifying PhaseFinished. */
130 u8 *session_keys;
131 size_t session_keys_len;
133 u8 inner_secret[TLS_MASTER_SIZE];
134 #endif /* GNUTLS_IA */
138 static void tls_log_func(int level, const char *msg)
140 char *s, *pos;
141 if (level == 6 || level == 7) {
142 /* These levels seem to be mostly I/O debug and msg dumps */
143 return;
146 s = os_strdup(msg);
147 if (s == NULL)
148 return;
150 pos = s;
151 while (*pos != '\0') {
152 if (*pos == '\n') {
153 *pos = '\0';
154 break;
156 pos++;
158 wpa_printf(level > 3 ? MSG_MSGDUMP : MSG_DEBUG,
159 "gnutls<%d> %s", level, s);
160 os_free(s);
164 extern int wpa_debug_show_keys;
166 void * tls_init(const struct tls_config *conf)
168 struct tls_global *global;
170 #ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
171 /* Because of the horrible hack to get master_secret and client/server
172 * random, we need to make sure that the gnutls version is something
173 * that is expected to have same structure definition for the session
174 * data.. */
175 const char *ver;
176 const char *ok_ver[] = { "1.2.3", "1.2.4", "1.2.5", "1.2.6", "1.2.9",
177 "1.3.2",
178 NULL };
179 int i;
180 #endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
182 global = os_zalloc(sizeof(*global));
183 if (global == NULL)
184 return NULL;
186 if (tls_gnutls_ref_count == 0 && gnutls_global_init() < 0) {
187 os_free(global);
188 return NULL;
190 tls_gnutls_ref_count++;
192 #ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
193 ver = gnutls_check_version(NULL);
194 if (ver == NULL) {
195 tls_deinit(global);
196 return NULL;
198 wpa_printf(MSG_DEBUG, "%s - gnutls version %s", __func__, ver);
199 for (i = 0; ok_ver[i]; i++) {
200 if (strcmp(ok_ver[i], ver) == 0)
201 break;
203 if (ok_ver[i] == NULL) {
204 wpa_printf(MSG_INFO, "Untested gnutls version %s - this needs "
205 "to be tested and enabled in tls_gnutls.c", ver);
206 tls_deinit(global);
207 return NULL;
209 #endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
211 gnutls_global_set_log_function(tls_log_func);
212 if (wpa_debug_show_keys)
213 gnutls_global_set_log_level(11);
214 return global;
218 void tls_deinit(void *ssl_ctx)
220 struct tls_global *global = ssl_ctx;
221 if (global) {
222 if (global->params_set)
223 gnutls_certificate_free_credentials(global->xcred);
224 os_free(global->session_data);
225 os_free(global);
228 tls_gnutls_ref_count--;
229 if (tls_gnutls_ref_count == 0)
230 gnutls_global_deinit();
234 int tls_get_errors(void *ssl_ctx)
236 return 0;
240 static ssize_t tls_pull_func(gnutls_transport_ptr ptr, void *buf,
241 size_t len)
243 struct tls_connection *conn = (struct tls_connection *) ptr;
244 u8 *end;
245 if (conn->pull_buf == NULL) {
246 errno = EWOULDBLOCK;
247 return -1;
250 end = conn->pull_buf + conn->pull_buf_len;
251 if ((size_t) (end - conn->pull_buf_offset) < len)
252 len = end - conn->pull_buf_offset;
253 os_memcpy(buf, conn->pull_buf_offset, len);
254 conn->pull_buf_offset += len;
255 if (conn->pull_buf_offset == end) {
256 wpa_printf(MSG_DEBUG, "%s - pull_buf consumed", __func__);
257 os_free(conn->pull_buf);
258 conn->pull_buf = conn->pull_buf_offset = NULL;
259 conn->pull_buf_len = 0;
260 } else {
261 wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in pull_buf",
262 __func__,
263 (unsigned long) (end - conn->pull_buf_offset));
265 return len;
269 static ssize_t tls_push_func(gnutls_transport_ptr ptr, const void *buf,
270 size_t len)
272 struct tls_connection *conn = (struct tls_connection *) ptr;
273 u8 *nbuf;
275 nbuf = os_realloc(conn->push_buf, conn->push_buf_len + len);
276 if (nbuf == NULL) {
277 errno = ENOMEM;
278 return -1;
280 os_memcpy(nbuf + conn->push_buf_len, buf, len);
281 conn->push_buf = nbuf;
282 conn->push_buf_len += len;
284 return len;
288 static int tls_gnutls_init_session(struct tls_global *global,
289 struct tls_connection *conn)
291 const int cert_types[2] = { GNUTLS_CRT_X509, 0 };
292 const int protos[2] = { GNUTLS_TLS1, 0 };
293 int ret;
295 ret = gnutls_init(&conn->session,
296 global->server ? GNUTLS_SERVER : GNUTLS_CLIENT);
297 if (ret < 0) {
298 wpa_printf(MSG_INFO, "TLS: Failed to initialize new TLS "
299 "connection: %s", gnutls_strerror(ret));
300 return -1;
303 ret = gnutls_set_default_priority(conn->session);
304 if (ret < 0)
305 goto fail;
307 ret = gnutls_certificate_type_set_priority(conn->session, cert_types);
308 if (ret < 0)
309 goto fail;
311 ret = gnutls_protocol_set_priority(conn->session, protos);
312 if (ret < 0)
313 goto fail;
315 gnutls_transport_set_pull_function(conn->session, tls_pull_func);
316 gnutls_transport_set_push_function(conn->session, tls_push_func);
317 gnutls_transport_set_ptr(conn->session, (gnutls_transport_ptr) conn);
319 return 0;
321 fail:
322 wpa_printf(MSG_INFO, "TLS: Failed to setup new TLS connection: %s",
323 gnutls_strerror(ret));
324 gnutls_deinit(conn->session);
325 return -1;
329 struct tls_connection * tls_connection_init(void *ssl_ctx)
331 struct tls_global *global = ssl_ctx;
332 struct tls_connection *conn;
333 int ret;
335 conn = os_zalloc(sizeof(*conn));
336 if (conn == NULL)
337 return NULL;
339 if (tls_gnutls_init_session(global, conn)) {
340 os_free(conn);
341 return NULL;
344 if (global->params_set) {
345 ret = gnutls_credentials_set(conn->session,
346 GNUTLS_CRD_CERTIFICATE,
347 global->xcred);
348 if (ret < 0) {
349 wpa_printf(MSG_INFO, "Failed to configure "
350 "credentials: %s", gnutls_strerror(ret));
351 os_free(conn);
352 return NULL;
356 if (gnutls_certificate_allocate_credentials(&conn->xcred)) {
357 os_free(conn);
358 return NULL;
361 return conn;
365 void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
367 if (conn == NULL)
368 return;
370 #ifdef GNUTLS_IA
371 if (conn->iacred_srv)
372 gnutls_ia_free_server_credentials(conn->iacred_srv);
373 if (conn->iacred_cli)
374 gnutls_ia_free_client_credentials(conn->iacred_cli);
375 if (conn->session_keys) {
376 os_memset(conn->session_keys, 0, conn->session_keys_len);
377 os_free(conn->session_keys);
379 #endif /* GNUTLS_IA */
381 gnutls_certificate_free_credentials(conn->xcred);
382 gnutls_deinit(conn->session);
383 os_free(conn->pre_shared_secret);
384 os_free(conn->subject_match);
385 os_free(conn->altsubject_match);
386 os_free(conn->push_buf);
387 os_free(conn->pull_buf);
388 os_free(conn);
392 int tls_connection_established(void *ssl_ctx, struct tls_connection *conn)
394 return conn ? conn->established : 0;
398 int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
400 struct tls_global *global = ssl_ctx;
401 int ret;
403 if (conn == NULL)
404 return -1;
406 /* Shutdown previous TLS connection without notifying the peer
407 * because the connection was already terminated in practice
408 * and "close notify" shutdown alert would confuse AS. */
409 gnutls_bye(conn->session, GNUTLS_SHUT_RDWR);
410 os_free(conn->push_buf);
411 conn->push_buf = NULL;
412 conn->push_buf_len = 0;
413 conn->established = 0;
414 conn->final_phase_finished = 0;
415 #ifdef GNUTLS_IA
416 if (conn->session_keys) {
417 os_memset(conn->session_keys, 0, conn->session_keys_len);
418 os_free(conn->session_keys);
420 conn->session_keys_len = 0;
421 #endif /* GNUTLS_IA */
423 gnutls_deinit(conn->session);
424 if (tls_gnutls_init_session(global, conn)) {
425 wpa_printf(MSG_INFO, "GnuTLS: Failed to preparare new session "
426 "for session resumption use");
427 return -1;
430 ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
431 conn->params_set ? conn->xcred :
432 global->xcred);
433 if (ret < 0) {
434 wpa_printf(MSG_INFO, "GnuTLS: Failed to configure credentials "
435 "for session resumption: %s", gnutls_strerror(ret));
436 return -1;
439 if (global->session_data) {
440 ret = gnutls_session_set_data(conn->session,
441 global->session_data,
442 global->session_data_size);
443 if (ret < 0) {
444 wpa_printf(MSG_INFO, "GnuTLS: Failed to set session "
445 "data: %s", gnutls_strerror(ret));
446 return -1;
450 return 0;
454 #if 0
455 static int tls_match_altsubject(X509 *cert, const char *match)
457 GENERAL_NAME *gen;
458 char *field, *tmp;
459 void *ext;
460 int i, found = 0;
461 size_t len;
463 ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
465 for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) {
466 gen = sk_GENERAL_NAME_value(ext, i);
467 switch (gen->type) {
468 case GEN_EMAIL:
469 field = "EMAIL";
470 break;
471 case GEN_DNS:
472 field = "DNS";
473 break;
474 case GEN_URI:
475 field = "URI";
476 break;
477 default:
478 field = NULL;
479 wpa_printf(MSG_DEBUG, "TLS: altSubjectName: "
480 "unsupported type=%d", gen->type);
481 break;
484 if (!field)
485 continue;
487 wpa_printf(MSG_DEBUG, "TLS: altSubjectName: %s:%s",
488 field, gen->d.ia5->data);
489 len = os_strlen(field) + 1 +
490 strlen((char *) gen->d.ia5->data) + 1;
491 tmp = os_malloc(len);
492 if (tmp == NULL)
493 continue;
494 snprintf(tmp, len, "%s:%s", field, gen->d.ia5->data);
495 if (strstr(tmp, match))
496 found++;
497 os_free(tmp);
500 return found;
502 #endif
505 #if 0
506 static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
508 char buf[256];
509 X509 *err_cert;
510 int err, depth;
511 SSL *ssl;
512 struct tls_connection *conn;
513 char *match, *altmatch;
515 err_cert = X509_STORE_CTX_get_current_cert(x509_ctx);
516 err = X509_STORE_CTX_get_error(x509_ctx);
517 depth = X509_STORE_CTX_get_error_depth(x509_ctx);
518 ssl = X509_STORE_CTX_get_ex_data(x509_ctx,
519 SSL_get_ex_data_X509_STORE_CTX_idx());
520 X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf));
522 conn = SSL_get_app_data(ssl);
523 match = conn ? conn->subject_match : NULL;
524 altmatch = conn ? conn->altsubject_match : NULL;
526 if (!preverify_ok) {
527 wpa_printf(MSG_WARNING, "TLS: Certificate verification failed,"
528 " error %d (%s) depth %d for '%s'", err,
529 X509_verify_cert_error_string(err), depth, buf);
530 } else {
531 wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb - "
532 "preverify_ok=%d err=%d (%s) depth=%d buf='%s'",
533 preverify_ok, err,
534 X509_verify_cert_error_string(err), depth, buf);
535 if (depth == 0 && match && strstr(buf, match) == NULL) {
536 wpa_printf(MSG_WARNING, "TLS: Subject '%s' did not "
537 "match with '%s'", buf, match);
538 preverify_ok = 0;
539 } else if (depth == 0 && altmatch &&
540 !tls_match_altsubject(err_cert, altmatch)) {
541 wpa_printf(MSG_WARNING, "TLS: altSubjectName match "
542 "'%s' not found", altmatch);
543 preverify_ok = 0;
547 return preverify_ok;
549 #endif
552 int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
553 const struct tls_connection_params *params)
555 int ret;
557 if (conn == NULL || params == NULL)
558 return -1;
560 os_free(conn->subject_match);
561 conn->subject_match = NULL;
562 if (params->subject_match) {
563 conn->subject_match = os_strdup(params->subject_match);
564 if (conn->subject_match == NULL)
565 return -1;
568 os_free(conn->altsubject_match);
569 conn->altsubject_match = NULL;
570 if (params->altsubject_match) {
571 conn->altsubject_match = os_strdup(params->altsubject_match);
572 if (conn->altsubject_match == NULL)
573 return -1;
576 /* TODO: gnutls_certificate_set_verify_flags(xcred, flags);
577 * to force peer validation(?) */
579 if (params->ca_cert) {
580 conn->verify_peer = 1;
581 ret = gnutls_certificate_set_x509_trust_file(
582 conn->xcred, params->ca_cert, GNUTLS_X509_FMT_PEM);
583 if (ret < 0) {
584 wpa_printf(MSG_DEBUG, "Failed to read CA cert '%s' "
585 "in PEM format: %s", params->ca_cert,
586 gnutls_strerror(ret));
587 ret = gnutls_certificate_set_x509_trust_file(
588 conn->xcred, params->ca_cert,
589 GNUTLS_X509_FMT_DER);
590 if (ret < 0) {
591 wpa_printf(MSG_DEBUG, "Failed to read CA cert "
592 "'%s' in DER format: %s",
593 params->ca_cert,
594 gnutls_strerror(ret));
595 return -1;
599 if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) {
600 gnutls_certificate_set_verify_flags(
601 conn->xcred, GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
604 if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
605 gnutls_certificate_set_verify_flags(
606 conn->xcred,
607 GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
611 if (params->client_cert && params->private_key) {
612 /* TODO: private_key_passwd? */
613 ret = gnutls_certificate_set_x509_key_file(
614 conn->xcred, params->client_cert, params->private_key,
615 GNUTLS_X509_FMT_PEM);
616 if (ret < 0) {
617 wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
618 "in PEM format: %s", gnutls_strerror(ret));
619 ret = gnutls_certificate_set_x509_key_file(
620 conn->xcred, params->client_cert,
621 params->private_key, GNUTLS_X509_FMT_DER);
622 if (ret < 0) {
623 wpa_printf(MSG_DEBUG, "Failed to read client "
624 "cert/key in DER format: %s",
625 gnutls_strerror(ret));
626 return ret;
629 } else if (params->private_key) {
630 int pkcs12_ok = 0;
631 #ifdef PKCS12_FUNCS
632 /* Try to load in PKCS#12 format */
633 #if LIBGNUTLS_VERSION_NUMBER >= 0x010302
634 ret = gnutls_certificate_set_x509_simple_pkcs12_file(
635 conn->xcred, params->private_key, GNUTLS_X509_FMT_DER,
636 params->private_key_passwd);
637 if (ret != 0) {
638 wpa_printf(MSG_DEBUG, "Failed to load private_key in "
639 "PKCS#12 format: %s", gnutls_strerror(ret));
640 return -1;
641 } else
642 pkcs12_ok = 1;
643 #endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
644 #endif /* PKCS12_FUNCS */
646 if (!pkcs12_ok) {
647 wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not "
648 "included");
649 return -1;
653 conn->tls_ia = params->tls_ia;
654 conn->params_set = 1;
656 ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
657 conn->xcred);
658 if (ret < 0) {
659 wpa_printf(MSG_INFO, "Failed to configure credentials: %s",
660 gnutls_strerror(ret));
663 #ifdef GNUTLS_IA
664 if (conn->iacred_cli)
665 gnutls_ia_free_client_credentials(conn->iacred_cli);
667 ret = gnutls_ia_allocate_client_credentials(&conn->iacred_cli);
668 if (ret) {
669 wpa_printf(MSG_DEBUG, "Failed to allocate IA credentials: %s",
670 gnutls_strerror(ret));
671 return -1;
674 ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_IA,
675 conn->iacred_cli);
676 if (ret) {
677 wpa_printf(MSG_DEBUG, "Failed to configure IA credentials: %s",
678 gnutls_strerror(ret));
679 gnutls_ia_free_client_credentials(conn->iacred_cli);
680 conn->iacred_cli = NULL;
681 return -1;
683 #endif /* GNUTLS_IE */
685 return ret;
689 int tls_global_set_params(void *tls_ctx,
690 const struct tls_connection_params *params)
692 struct tls_global *global = tls_ctx;
693 int ret;
695 /* Currently, global parameters are only set when running in server
696 * mode. */
697 global->server = 1;
699 if (global->params_set) {
700 gnutls_certificate_free_credentials(global->xcred);
701 global->params_set = 0;
704 ret = gnutls_certificate_allocate_credentials(&global->xcred);
705 if (ret) {
706 wpa_printf(MSG_DEBUG, "Failed to allocate global credentials "
707 "%s", gnutls_strerror(ret));
708 return -1;
711 if (params->ca_cert) {
712 ret = gnutls_certificate_set_x509_trust_file(
713 global->xcred, params->ca_cert, GNUTLS_X509_FMT_PEM);
714 if (ret < 0) {
715 wpa_printf(MSG_DEBUG, "Failed to read CA cert '%s' "
716 "in PEM format: %s", params->ca_cert,
717 gnutls_strerror(ret));
718 ret = gnutls_certificate_set_x509_trust_file(
719 global->xcred, params->ca_cert,
720 GNUTLS_X509_FMT_DER);
721 if (ret < 0) {
722 wpa_printf(MSG_DEBUG, "Failed to read CA cert "
723 "'%s' in DER format: %s",
724 params->ca_cert,
725 gnutls_strerror(ret));
726 goto fail;
730 if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) {
731 gnutls_certificate_set_verify_flags(
732 global->xcred,
733 GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
736 if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
737 gnutls_certificate_set_verify_flags(
738 global->xcred,
739 GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
743 if (params->client_cert && params->private_key) {
744 /* TODO: private_key_passwd? */
745 ret = gnutls_certificate_set_x509_key_file(
746 global->xcred, params->client_cert,
747 params->private_key, GNUTLS_X509_FMT_PEM);
748 if (ret < 0) {
749 wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
750 "in PEM format: %s", gnutls_strerror(ret));
751 ret = gnutls_certificate_set_x509_key_file(
752 global->xcred, params->client_cert,
753 params->private_key, GNUTLS_X509_FMT_DER);
754 if (ret < 0) {
755 wpa_printf(MSG_DEBUG, "Failed to read client "
756 "cert/key in DER format: %s",
757 gnutls_strerror(ret));
758 goto fail;
761 } else if (params->private_key) {
762 int pkcs12_ok = 0;
763 #ifdef PKCS12_FUNCS
764 /* Try to load in PKCS#12 format */
765 #if LIBGNUTLS_VERSION_NUMBER >= 0x010302
766 ret = gnutls_certificate_set_x509_simple_pkcs12_file(
767 global->xcred, params->private_key,
768 GNUTLS_X509_FMT_DER, params->private_key_passwd);
769 if (ret != 0) {
770 wpa_printf(MSG_DEBUG, "Failed to load private_key in "
771 "PKCS#12 format: %s", gnutls_strerror(ret));
772 goto fail;
773 } else
774 pkcs12_ok = 1;
775 #endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
776 #endif /* PKCS12_FUNCS */
778 if (!pkcs12_ok) {
779 wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not "
780 "included");
781 goto fail;
785 global->params_set = 1;
787 return 0;
789 fail:
790 gnutls_certificate_free_credentials(global->xcred);
791 return -1;
795 int tls_global_set_verify(void *ssl_ctx, int check_crl)
797 /* TODO */
798 return 0;
802 int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
803 int verify_peer)
805 if (conn == NULL || conn->session == NULL)
806 return -1;
808 conn->verify_peer = verify_peer;
809 gnutls_certificate_server_set_request(conn->session,
810 verify_peer ? GNUTLS_CERT_REQUIRE
811 : GNUTLS_CERT_REQUEST);
813 return 0;
817 int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
818 struct tls_keys *keys)
820 #ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
821 security_parameters_st *sec;
822 #endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
824 if (conn == NULL || conn->session == NULL || keys == NULL)
825 return -1;
827 os_memset(keys, 0, sizeof(*keys));
829 #ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
830 sec = &conn->session->security_parameters;
831 keys->master_key = sec->master_secret;
832 keys->master_key_len = TLS_MASTER_SIZE;
833 keys->client_random = sec->client_random;
834 keys->server_random = sec->server_random;
835 #else /* GNUTLS_INTERNAL_STRUCTURE_HACK */
836 keys->client_random =
837 (u8 *) gnutls_session_get_client_random(conn->session);
838 keys->server_random =
839 (u8 *) gnutls_session_get_server_random(conn->session);
840 /* No access to master_secret */
841 #endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
843 #ifdef GNUTLS_IA
844 gnutls_ia_extract_inner_secret(conn->session,
845 (char *) conn->inner_secret);
846 keys->inner_secret = conn->inner_secret;
847 keys->inner_secret_len = TLS_MASTER_SIZE;
848 #endif /* GNUTLS_IA */
850 keys->client_random_len = TLS_RANDOM_SIZE;
851 keys->server_random_len = TLS_RANDOM_SIZE;
853 return 0;
857 int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
858 const char *label, int server_random_first,
859 u8 *out, size_t out_len)
861 #if LIBGNUTLS_VERSION_NUMBER >= 0x010302
862 if (conn == NULL || conn->session == NULL)
863 return -1;
865 return gnutls_prf(conn->session, os_strlen(label), label,
866 server_random_first, 0, NULL, out_len, (char *) out);
867 #else /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
868 return -1;
869 #endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
873 static int tls_connection_verify_peer(struct tls_connection *conn,
874 gnutls_alert_description_t *err)
876 unsigned int status, num_certs, i;
877 struct os_time now;
878 const gnutls_datum_t *certs;
879 gnutls_x509_crt_t cert;
881 if (gnutls_certificate_verify_peers2(conn->session, &status) < 0) {
882 wpa_printf(MSG_INFO, "TLS: Failed to verify peer "
883 "certificate chain");
884 *err = GNUTLS_A_INTERNAL_ERROR;
885 return -1;
888 if (conn->verify_peer && (status & GNUTLS_CERT_INVALID)) {
889 wpa_printf(MSG_INFO, "TLS: Peer certificate not trusted");
890 if (status & GNUTLS_CERT_INSECURE_ALGORITHM) {
891 wpa_printf(MSG_INFO, "TLS: Certificate uses insecure "
892 "algorithm");
893 *err = GNUTLS_A_INSUFFICIENT_SECURITY;
895 if (status & GNUTLS_CERT_NOT_ACTIVATED) {
896 wpa_printf(MSG_INFO, "TLS: Certificate not yet "
897 "activated");
898 *err = GNUTLS_A_CERTIFICATE_EXPIRED;
900 if (status & GNUTLS_CERT_EXPIRED) {
901 wpa_printf(MSG_INFO, "TLS: Certificate expired");
902 *err = GNUTLS_A_CERTIFICATE_EXPIRED;
904 return -1;
907 if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
908 wpa_printf(MSG_INFO, "TLS: Peer certificate does not have a "
909 "known issuer");
910 *err = GNUTLS_A_UNKNOWN_CA;
911 return -1;
914 if (status & GNUTLS_CERT_REVOKED) {
915 wpa_printf(MSG_INFO, "TLS: Peer certificate has been revoked");
916 *err = GNUTLS_A_CERTIFICATE_REVOKED;
917 return -1;
920 os_get_time(&now);
922 certs = gnutls_certificate_get_peers(conn->session, &num_certs);
923 if (certs == NULL) {
924 wpa_printf(MSG_INFO, "TLS: No peer certificate chain "
925 "received");
926 *err = GNUTLS_A_UNKNOWN_CA;
927 return -1;
930 for (i = 0; i < num_certs; i++) {
931 char *buf;
932 size_t len;
933 if (gnutls_x509_crt_init(&cert) < 0) {
934 wpa_printf(MSG_INFO, "TLS: Certificate initialization "
935 "failed");
936 *err = GNUTLS_A_BAD_CERTIFICATE;
937 return -1;
940 if (gnutls_x509_crt_import(cert, &certs[i],
941 GNUTLS_X509_FMT_DER) < 0) {
942 wpa_printf(MSG_INFO, "TLS: Could not parse peer "
943 "certificate %d/%d", i + 1, num_certs);
944 gnutls_x509_crt_deinit(cert);
945 *err = GNUTLS_A_BAD_CERTIFICATE;
946 return -1;
949 gnutls_x509_crt_get_dn(cert, NULL, &len);
950 len++;
951 buf = os_malloc(len + 1);
952 if (buf) {
953 buf[0] = buf[len] = '\0';
954 gnutls_x509_crt_get_dn(cert, buf, &len);
956 wpa_printf(MSG_DEBUG, "TLS: Peer cert chain %d/%d: %s",
957 i + 1, num_certs, buf);
959 if (i == 0) {
960 /* TODO: validate subject_match and altsubject_match */
963 os_free(buf);
965 if (gnutls_x509_crt_get_expiration_time(cert) < now.sec ||
966 gnutls_x509_crt_get_activation_time(cert) > now.sec) {
967 wpa_printf(MSG_INFO, "TLS: Peer certificate %d/%d is "
968 "not valid at this time",
969 i + 1, num_certs);
970 gnutls_x509_crt_deinit(cert);
971 *err = GNUTLS_A_CERTIFICATE_EXPIRED;
972 return -1;
975 gnutls_x509_crt_deinit(cert);
978 return 0;
982 u8 * tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn,
983 const u8 *in_data, size_t in_len,
984 size_t *out_len, u8 **appl_data,
985 size_t *appl_data_len)
987 struct tls_global *global = ssl_ctx;
988 u8 *out_data;
989 int ret;
991 if (appl_data)
992 *appl_data = NULL;
994 if (in_data && in_len) {
995 if (conn->pull_buf) {
996 wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
997 "pull_buf", __func__,
998 (unsigned long) conn->pull_buf_len);
999 os_free(conn->pull_buf);
1001 conn->pull_buf = os_malloc(in_len);
1002 if (conn->pull_buf == NULL)
1003 return NULL;
1004 os_memcpy(conn->pull_buf, in_data, in_len);
1005 conn->pull_buf_offset = conn->pull_buf;
1006 conn->pull_buf_len = in_len;
1009 ret = gnutls_handshake(conn->session);
1010 if (ret < 0) {
1011 switch (ret) {
1012 case GNUTLS_E_AGAIN:
1013 if (global->server && conn->established &&
1014 conn->push_buf == NULL) {
1015 /* Need to return something to trigger
1016 * completion of EAP-TLS. */
1017 conn->push_buf = os_malloc(1);
1019 break;
1020 case GNUTLS_E_FATAL_ALERT_RECEIVED:
1021 wpa_printf(MSG_DEBUG, "%s - received fatal '%s' alert",
1022 __func__, gnutls_alert_get_name(
1023 gnutls_alert_get(conn->session)));
1024 conn->read_alerts++;
1025 /* continue */
1026 default:
1027 wpa_printf(MSG_DEBUG, "%s - gnutls_handshake failed "
1028 "-> %s", __func__, gnutls_strerror(ret));
1029 conn->failed++;
1031 } else {
1032 size_t size;
1033 gnutls_alert_description_t err;
1035 if (conn->verify_peer &&
1036 tls_connection_verify_peer(conn, &err)) {
1037 wpa_printf(MSG_INFO, "TLS: Peer certificate chain "
1038 "failed validation");
1039 conn->failed++;
1040 gnutls_alert_send(conn->session, GNUTLS_AL_FATAL, err);
1041 goto out;
1044 #ifdef CONFIG_GNUTLS_EXTRA
1045 if (conn->tls_ia && !gnutls_ia_handshake_p(conn->session)) {
1046 wpa_printf(MSG_INFO, "TLS: No TLS/IA negotiation");
1047 conn->failed++;
1048 return NULL;
1050 #endif /* CONFIG_GNUTLS_EXTRA */
1052 if (conn->tls_ia)
1053 wpa_printf(MSG_DEBUG, "TLS: Start TLS/IA handshake");
1054 else {
1055 wpa_printf(MSG_DEBUG, "TLS: Handshake completed "
1056 "successfully");
1058 conn->established = 1;
1059 if (conn->push_buf == NULL) {
1060 /* Need to return something to get final TLS ACK. */
1061 conn->push_buf = os_malloc(1);
1064 gnutls_session_get_data(conn->session, NULL, &size);
1065 if (global->session_data == NULL ||
1066 global->session_data_size < size) {
1067 os_free(global->session_data);
1068 global->session_data = os_malloc(size);
1070 if (global->session_data) {
1071 global->session_data_size = size;
1072 gnutls_session_get_data(conn->session,
1073 global->session_data,
1074 &global->session_data_size);
1078 out:
1079 out_data = conn->push_buf;
1080 *out_len = conn->push_buf_len;
1081 conn->push_buf = NULL;
1082 conn->push_buf_len = 0;
1083 return out_data;
1087 u8 * tls_connection_server_handshake(void *ssl_ctx,
1088 struct tls_connection *conn,
1089 const u8 *in_data, size_t in_len,
1090 size_t *out_len)
1092 return tls_connection_handshake(ssl_ctx, conn, in_data, in_len,
1093 out_len, NULL, NULL);
1097 int tls_connection_encrypt(void *ssl_ctx, struct tls_connection *conn,
1098 const u8 *in_data, size_t in_len,
1099 u8 *out_data, size_t out_len)
1101 ssize_t res;
1103 #ifdef GNUTLS_IA
1104 if (conn->tls_ia)
1105 res = gnutls_ia_send(conn->session, (char *) in_data, in_len);
1106 else
1107 #endif /* GNUTLS_IA */
1108 res = gnutls_record_send(conn->session, in_data, in_len);
1109 if (res < 0) {
1110 wpa_printf(MSG_INFO, "%s: Encryption failed: %s",
1111 __func__, gnutls_strerror(res));
1112 return -1;
1114 if (conn->push_buf == NULL)
1115 return -1;
1116 if (conn->push_buf_len < out_len)
1117 out_len = conn->push_buf_len;
1118 else if (conn->push_buf_len > out_len) {
1119 wpa_printf(MSG_INFO, "GnuTLS: Not enough buffer space for "
1120 "encrypted message (in_len=%lu push_buf_len=%lu "
1121 "out_len=%lu",
1122 (unsigned long) in_len,
1123 (unsigned long) conn->push_buf_len,
1124 (unsigned long) out_len);
1126 os_memcpy(out_data, conn->push_buf, out_len);
1127 os_free(conn->push_buf);
1128 conn->push_buf = NULL;
1129 conn->push_buf_len = 0;
1130 return out_len;
1134 int tls_connection_decrypt(void *ssl_ctx, struct tls_connection *conn,
1135 const u8 *in_data, size_t in_len,
1136 u8 *out_data, size_t out_len)
1138 ssize_t res;
1140 if (conn->pull_buf) {
1141 wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
1142 "pull_buf", __func__,
1143 (unsigned long) conn->pull_buf_len);
1144 os_free(conn->pull_buf);
1146 conn->pull_buf = os_malloc(in_len);
1147 if (conn->pull_buf == NULL)
1148 return -1;
1149 os_memcpy(conn->pull_buf, in_data, in_len);
1150 conn->pull_buf_offset = conn->pull_buf;
1151 conn->pull_buf_len = in_len;
1153 #ifdef GNUTLS_IA
1154 if (conn->tls_ia) {
1155 res = gnutls_ia_recv(conn->session, (char *) out_data,
1156 out_len);
1157 if (out_len >= 12 &&
1158 (res == GNUTLS_E_WARNING_IA_IPHF_RECEIVED ||
1159 res == GNUTLS_E_WARNING_IA_FPHF_RECEIVED)) {
1160 int final = res == GNUTLS_E_WARNING_IA_FPHF_RECEIVED;
1161 wpa_printf(MSG_DEBUG, "%s: Received %sPhaseFinished",
1162 __func__, final ? "Final" : "Intermediate");
1164 res = gnutls_ia_permute_inner_secret(
1165 conn->session, conn->session_keys_len,
1166 (char *) conn->session_keys);
1167 if (conn->session_keys) {
1168 os_memset(conn->session_keys, 0,
1169 conn->session_keys_len);
1170 os_free(conn->session_keys);
1172 conn->session_keys = NULL;
1173 conn->session_keys_len = 0;
1174 if (res) {
1175 wpa_printf(MSG_DEBUG, "%s: Failed to permute "
1176 "inner secret: %s",
1177 __func__, gnutls_strerror(res));
1178 return -1;
1181 res = gnutls_ia_verify_endphase(conn->session,
1182 (char *) out_data);
1183 if (res == 0) {
1184 wpa_printf(MSG_DEBUG, "%s: Correct endphase "
1185 "checksum", __func__);
1186 } else {
1187 wpa_printf(MSG_INFO, "%s: Endphase "
1188 "verification failed: %s",
1189 __func__, gnutls_strerror(res));
1190 return -1;
1193 if (final)
1194 conn->final_phase_finished = 1;
1196 return 0;
1199 if (res < 0) {
1200 wpa_printf(MSG_DEBUG, "%s - gnutls_ia_recv failed: %d "
1201 "(%s)", __func__, (int) res,
1202 gnutls_strerror(res));
1204 return res;
1206 #endif /* GNUTLS_IA */
1208 res = gnutls_record_recv(conn->session, out_data, out_len);
1209 if (res < 0) {
1210 wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d "
1211 "(%s)", __func__, (int) res, gnutls_strerror(res));
1214 return res;
1218 int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
1220 if (conn == NULL)
1221 return 0;
1222 return gnutls_session_is_resumed(conn->session);
1226 int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
1227 u8 *ciphers)
1229 /* TODO */
1230 return -1;
1234 int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
1235 char *buf, size_t buflen)
1237 /* TODO */
1238 buf[0] = '\0';
1239 return 0;
1243 int tls_connection_enable_workaround(void *ssl_ctx,
1244 struct tls_connection *conn)
1246 /* TODO: set SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS */
1247 return 0;
1251 int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
1252 int ext_type, const u8 *data,
1253 size_t data_len)
1255 /* TODO */
1256 return -1;
1260 int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
1262 if (conn == NULL)
1263 return -1;
1264 return conn->failed;
1268 int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn)
1270 if (conn == NULL)
1271 return -1;
1272 return conn->read_alerts;
1276 int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
1278 if (conn == NULL)
1279 return -1;
1280 return conn->write_alerts;
1284 int tls_connection_get_keyblock_size(void *tls_ctx,
1285 struct tls_connection *conn)
1287 /* TODO */
1288 return -1;
1292 unsigned int tls_capabilities(void *tls_ctx)
1294 unsigned int capa = 0;
1296 #ifdef GNUTLS_IA
1297 capa |= TLS_CAPABILITY_IA;
1298 #endif /* GNUTLS_IA */
1300 return capa;
1304 int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn,
1305 int tls_ia)
1307 #ifdef GNUTLS_IA
1308 int ret;
1310 if (conn == NULL)
1311 return -1;
1313 conn->tls_ia = tls_ia;
1314 if (!tls_ia)
1315 return 0;
1317 ret = gnutls_ia_allocate_server_credentials(&conn->iacred_srv);
1318 if (ret) {
1319 wpa_printf(MSG_DEBUG, "Failed to allocate IA credentials: %s",
1320 gnutls_strerror(ret));
1321 return -1;
1324 ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_IA,
1325 conn->iacred_srv);
1326 if (ret) {
1327 wpa_printf(MSG_DEBUG, "Failed to configure IA credentials: %s",
1328 gnutls_strerror(ret));
1329 gnutls_ia_free_server_credentials(conn->iacred_srv);
1330 conn->iacred_srv = NULL;
1331 return -1;
1334 return 0;
1335 #else /* GNUTLS_IA */
1336 return -1;
1337 #endif /* GNUTLS_IA */
1341 int tls_connection_ia_send_phase_finished(void *tls_ctx,
1342 struct tls_connection *conn,
1343 int final,
1344 u8 *out_data, size_t out_len)
1346 #ifdef GNUTLS_IA
1347 int ret;
1349 if (conn == NULL || conn->session == NULL || !conn->tls_ia)
1350 return -1;
1352 ret = gnutls_ia_permute_inner_secret(conn->session,
1353 conn->session_keys_len,
1354 (char *) conn->session_keys);
1355 if (conn->session_keys) {
1356 os_memset(conn->session_keys, 0, conn->session_keys_len);
1357 os_free(conn->session_keys);
1359 conn->session_keys = NULL;
1360 conn->session_keys_len = 0;
1361 if (ret) {
1362 wpa_printf(MSG_DEBUG, "%s: Failed to permute inner secret: %s",
1363 __func__, gnutls_strerror(ret));
1364 return -1;
1367 ret = gnutls_ia_endphase_send(conn->session, final);
1368 if (ret) {
1369 wpa_printf(MSG_DEBUG, "%s: Failed to send endphase: %s",
1370 __func__, gnutls_strerror(ret));
1371 return -1;
1374 if (conn->push_buf == NULL)
1375 return -1;
1376 if (conn->push_buf_len < out_len)
1377 out_len = conn->push_buf_len;
1378 os_memcpy(out_data, conn->push_buf, out_len);
1379 os_free(conn->push_buf);
1380 conn->push_buf = NULL;
1381 conn->push_buf_len = 0;
1382 return out_len;
1383 #else /* GNUTLS_IA */
1384 return -1;
1385 #endif /* GNUTLS_IA */
1389 int tls_connection_ia_final_phase_finished(void *tls_ctx,
1390 struct tls_connection *conn)
1392 if (conn == NULL)
1393 return -1;
1395 return conn->final_phase_finished;
1399 int tls_connection_ia_permute_inner_secret(void *tls_ctx,
1400 struct tls_connection *conn,
1401 const u8 *key, size_t key_len)
1403 #ifdef GNUTLS_IA
1404 if (conn == NULL || !conn->tls_ia)
1405 return -1;
1407 if (conn->session_keys) {
1408 os_memset(conn->session_keys, 0, conn->session_keys_len);
1409 os_free(conn->session_keys);
1411 conn->session_keys_len = 0;
1413 if (key) {
1414 conn->session_keys = os_malloc(key_len);
1415 if (conn->session_keys == NULL)
1416 return -1;
1417 os_memcpy(conn->session_keys, key, key_len);
1418 conn->session_keys_len = key_len;
1419 } else {
1420 conn->session_keys = NULL;
1421 conn->session_keys_len = 0;
1424 return 0;
1425 #else /* GNUTLS_IA */
1426 return -1;
1427 #endif /* GNUTLS_IA */