2 * SSL/TLS interface functions for GnuTLS
3 * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
10 #include <gnutls/gnutls.h>
11 #include <gnutls/x509.h>
13 #include <gnutls/pkcs12.h>
14 #endif /* PKCS12_FUNCS */
20 #define WPA_TLS_RANDOM_SIZE 32
21 #define WPA_TLS_MASTER_SIZE 48
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.
29 #define GNUTLS_INTERNAL_STRUCTURE_HACK
30 #endif /* LIBGNUTLS_VERSION_NUMBER < 0x010302 */
33 #ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
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.
43 typedef unsigned char opaque;
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;
64 struct gnutls_session_int {
65 security_parameters_st security_parameters;
66 /* followed by things we are not interested in */
68 #endif /* LIBGNUTLS_VERSION_NUMBER < 0x010302 */
70 static int tls_gnutls_ref_count = 0;
73 /* Data for session resumption */
75 size_t session_data_size;
80 gnutls_certificate_credentials_t xcred;
83 struct tls_connection {
84 gnutls_session session;
85 char *subject_match, *altsubject_match;
86 int read_alerts, write_alerts, failed;
88 u8 *pre_shared_secret;
89 size_t pre_shared_secret_len;
93 struct wpabuf *push_buf;
94 struct wpabuf *pull_buf;
95 const u8 *pull_buf_offset;
98 gnutls_certificate_credentials_t xcred;
102 static void tls_log_func(int level, const char *msg)
105 if (level == 6 || level == 7) {
106 /* These levels seem to be mostly I/O debug and msg dumps */
115 while (*pos != '\0') {
122 wpa_printf(level > 3 ? MSG_MSGDUMP : MSG_DEBUG,
123 "gnutls<%d> %s", level, s);
128 void * tls_init(const struct tls_config *conf)
130 struct tls_global *global;
132 #ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
133 /* Because of the horrible hack to get master_secret and client/server
134 * random, we need to make sure that the gnutls version is something
135 * that is expected to have same structure definition for the session
138 const char *ok_ver[] = { "1.2.3", "1.2.4", "1.2.5", "1.2.6", "1.2.9",
142 #endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
144 global = os_zalloc(sizeof(*global));
148 if (tls_gnutls_ref_count == 0 && gnutls_global_init() < 0) {
152 tls_gnutls_ref_count++;
154 #ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
155 ver = gnutls_check_version(NULL);
160 wpa_printf(MSG_DEBUG, "%s - gnutls version %s", __func__, ver);
161 for (i = 0; ok_ver[i]; i++) {
162 if (strcmp(ok_ver[i], ver) == 0)
165 if (ok_ver[i] == NULL) {
166 wpa_printf(MSG_INFO, "Untested gnutls version %s - this needs "
167 "to be tested and enabled in tls_gnutls.c", ver);
171 #endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
173 gnutls_global_set_log_function(tls_log_func);
174 if (wpa_debug_show_keys)
175 gnutls_global_set_log_level(11);
180 void tls_deinit(void *ssl_ctx)
182 struct tls_global *global = ssl_ctx;
184 if (global->params_set)
185 gnutls_certificate_free_credentials(global->xcred);
186 os_free(global->session_data);
190 tls_gnutls_ref_count--;
191 if (tls_gnutls_ref_count == 0)
192 gnutls_global_deinit();
196 int tls_get_errors(void *ssl_ctx)
202 static ssize_t tls_pull_func(gnutls_transport_ptr ptr, void *buf,
205 struct tls_connection *conn = (struct tls_connection *) ptr;
207 if (conn->pull_buf == NULL) {
212 end = wpabuf_head_u8(conn->pull_buf) + wpabuf_len(conn->pull_buf);
213 if ((size_t) (end - conn->pull_buf_offset) < len)
214 len = end - conn->pull_buf_offset;
215 os_memcpy(buf, conn->pull_buf_offset, len);
216 conn->pull_buf_offset += len;
217 if (conn->pull_buf_offset == end) {
218 wpa_printf(MSG_DEBUG, "%s - pull_buf consumed", __func__);
219 wpabuf_free(conn->pull_buf);
220 conn->pull_buf = NULL;
221 conn->pull_buf_offset = NULL;
223 wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in pull_buf",
225 (unsigned long) (end - conn->pull_buf_offset));
231 static ssize_t tls_push_func(gnutls_transport_ptr ptr, const void *buf,
234 struct tls_connection *conn = (struct tls_connection *) ptr;
236 if (wpabuf_resize(&conn->push_buf, len) < 0) {
240 wpabuf_put_data(conn->push_buf, buf, len);
246 static int tls_gnutls_init_session(struct tls_global *global,
247 struct tls_connection *conn)
249 #if LIBGNUTLS_VERSION_NUMBER >= 0x020200
251 #else /* LIBGNUTLS_VERSION_NUMBER >= 0x020200 */
252 const int cert_types[2] = { GNUTLS_CRT_X509, 0 };
253 const int protos[2] = { GNUTLS_TLS1, 0 };
254 #endif /* LIBGNUTLS_VERSION_NUMBER < 0x020200 */
257 ret = gnutls_init(&conn->session,
258 global->server ? GNUTLS_SERVER : GNUTLS_CLIENT);
260 wpa_printf(MSG_INFO, "TLS: Failed to initialize new TLS "
261 "connection: %s", gnutls_strerror(ret));
265 ret = gnutls_set_default_priority(conn->session);
269 #if LIBGNUTLS_VERSION_NUMBER >= 0x020200
270 ret = gnutls_priority_set_direct(conn->session, "NORMAL:-VERS-SSL3.0",
273 wpa_printf(MSG_ERROR, "GnuTLS: Priority string failure at "
277 #else /* LIBGNUTLS_VERSION_NUMBER >= 0x020200 */
278 ret = gnutls_certificate_type_set_priority(conn->session, cert_types);
282 ret = gnutls_protocol_set_priority(conn->session, protos);
285 #endif /* LIBGNUTLS_VERSION_NUMBER < 0x020200 */
287 gnutls_transport_set_pull_function(conn->session, tls_pull_func);
288 gnutls_transport_set_push_function(conn->session, tls_push_func);
289 gnutls_transport_set_ptr(conn->session, (gnutls_transport_ptr) conn);
294 wpa_printf(MSG_INFO, "TLS: Failed to setup new TLS connection: %s",
295 gnutls_strerror(ret));
296 gnutls_deinit(conn->session);
301 struct tls_connection * tls_connection_init(void *ssl_ctx)
303 struct tls_global *global = ssl_ctx;
304 struct tls_connection *conn;
307 conn = os_zalloc(sizeof(*conn));
311 if (tls_gnutls_init_session(global, conn)) {
316 if (global->params_set) {
317 ret = gnutls_credentials_set(conn->session,
318 GNUTLS_CRD_CERTIFICATE,
321 wpa_printf(MSG_INFO, "Failed to configure "
322 "credentials: %s", gnutls_strerror(ret));
328 if (gnutls_certificate_allocate_credentials(&conn->xcred)) {
337 void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
342 gnutls_certificate_free_credentials(conn->xcred);
343 gnutls_deinit(conn->session);
344 os_free(conn->pre_shared_secret);
345 os_free(conn->subject_match);
346 os_free(conn->altsubject_match);
347 wpabuf_free(conn->push_buf);
348 wpabuf_free(conn->pull_buf);
353 int tls_connection_established(void *ssl_ctx, struct tls_connection *conn)
355 return conn ? conn->established : 0;
359 int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
361 struct tls_global *global = ssl_ctx;
367 /* Shutdown previous TLS connection without notifying the peer
368 * because the connection was already terminated in practice
369 * and "close notify" shutdown alert would confuse AS. */
370 gnutls_bye(conn->session, GNUTLS_SHUT_RDWR);
371 wpabuf_free(conn->push_buf);
372 conn->push_buf = NULL;
373 conn->established = 0;
375 gnutls_deinit(conn->session);
376 if (tls_gnutls_init_session(global, conn)) {
377 wpa_printf(MSG_INFO, "GnuTLS: Failed to preparare new session "
378 "for session resumption use");
382 ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
383 conn->params_set ? conn->xcred :
386 wpa_printf(MSG_INFO, "GnuTLS: Failed to configure credentials "
387 "for session resumption: %s", gnutls_strerror(ret));
391 if (global->session_data) {
392 ret = gnutls_session_set_data(conn->session,
393 global->session_data,
394 global->session_data_size);
396 wpa_printf(MSG_INFO, "GnuTLS: Failed to set session "
397 "data: %s", gnutls_strerror(ret));
407 static int tls_match_altsubject(X509 *cert, const char *match)
415 ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
417 for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) {
418 gen = sk_GENERAL_NAME_value(ext, i);
431 wpa_printf(MSG_DEBUG, "TLS: altSubjectName: "
432 "unsupported type=%d", gen->type);
439 wpa_printf(MSG_DEBUG, "TLS: altSubjectName: %s:%s",
440 field, gen->d.ia5->data);
441 len = os_strlen(field) + 1 +
442 strlen((char *) gen->d.ia5->data) + 1;
443 tmp = os_malloc(len);
446 snprintf(tmp, len, "%s:%s", field, gen->d.ia5->data);
447 if (strstr(tmp, match))
458 static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
464 struct tls_connection *conn;
465 char *match, *altmatch;
467 err_cert = X509_STORE_CTX_get_current_cert(x509_ctx);
468 err = X509_STORE_CTX_get_error(x509_ctx);
469 depth = X509_STORE_CTX_get_error_depth(x509_ctx);
470 ssl = X509_STORE_CTX_get_ex_data(x509_ctx,
471 SSL_get_ex_data_X509_STORE_CTX_idx());
472 X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf));
474 conn = SSL_get_app_data(ssl);
475 match = conn ? conn->subject_match : NULL;
476 altmatch = conn ? conn->altsubject_match : NULL;
479 wpa_printf(MSG_WARNING, "TLS: Certificate verification failed,"
480 " error %d (%s) depth %d for '%s'", err,
481 X509_verify_cert_error_string(err), depth, buf);
483 wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb - "
484 "preverify_ok=%d err=%d (%s) depth=%d buf='%s'",
486 X509_verify_cert_error_string(err), depth, buf);
487 if (depth == 0 && match && strstr(buf, match) == NULL) {
488 wpa_printf(MSG_WARNING, "TLS: Subject '%s' did not "
489 "match with '%s'", buf, match);
491 } else if (depth == 0 && altmatch &&
492 !tls_match_altsubject(err_cert, altmatch)) {
493 wpa_printf(MSG_WARNING, "TLS: altSubjectName match "
494 "'%s' not found", altmatch);
504 int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
505 const struct tls_connection_params *params)
509 if (conn == NULL || params == NULL)
512 os_free(conn->subject_match);
513 conn->subject_match = NULL;
514 if (params->subject_match) {
515 conn->subject_match = os_strdup(params->subject_match);
516 if (conn->subject_match == NULL)
520 os_free(conn->altsubject_match);
521 conn->altsubject_match = NULL;
522 if (params->altsubject_match) {
523 conn->altsubject_match = os_strdup(params->altsubject_match);
524 if (conn->altsubject_match == NULL)
528 /* TODO: gnutls_certificate_set_verify_flags(xcred, flags);
529 * to force peer validation(?) */
531 if (params->ca_cert) {
532 conn->verify_peer = 1;
533 ret = gnutls_certificate_set_x509_trust_file(
534 conn->xcred, params->ca_cert, GNUTLS_X509_FMT_PEM);
536 wpa_printf(MSG_DEBUG, "Failed to read CA cert '%s' "
537 "in PEM format: %s", params->ca_cert,
538 gnutls_strerror(ret));
539 ret = gnutls_certificate_set_x509_trust_file(
540 conn->xcred, params->ca_cert,
541 GNUTLS_X509_FMT_DER);
543 wpa_printf(MSG_DEBUG, "Failed to read CA cert "
544 "'%s' in DER format: %s",
546 gnutls_strerror(ret));
551 if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) {
552 gnutls_certificate_set_verify_flags(
553 conn->xcred, GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
556 #if LIBGNUTLS_VERSION_NUMBER >= 0x020800
557 if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
558 gnutls_certificate_set_verify_flags(
560 GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
562 #endif /* LIBGNUTLS_VERSION_NUMBER >= 0x020800 */
565 if (params->client_cert && params->private_key) {
566 /* TODO: private_key_passwd? */
567 ret = gnutls_certificate_set_x509_key_file(
568 conn->xcred, params->client_cert, params->private_key,
569 GNUTLS_X509_FMT_PEM);
571 wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
572 "in PEM format: %s", gnutls_strerror(ret));
573 ret = gnutls_certificate_set_x509_key_file(
574 conn->xcred, params->client_cert,
575 params->private_key, GNUTLS_X509_FMT_DER);
577 wpa_printf(MSG_DEBUG, "Failed to read client "
578 "cert/key in DER format: %s",
579 gnutls_strerror(ret));
583 } else if (params->private_key) {
586 /* Try to load in PKCS#12 format */
587 #if LIBGNUTLS_VERSION_NUMBER >= 0x010302
588 ret = gnutls_certificate_set_x509_simple_pkcs12_file(
589 conn->xcred, params->private_key, GNUTLS_X509_FMT_DER,
590 params->private_key_passwd);
592 wpa_printf(MSG_DEBUG, "Failed to load private_key in "
593 "PKCS#12 format: %s", gnutls_strerror(ret));
597 #endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
598 #endif /* PKCS12_FUNCS */
601 wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not "
607 conn->params_set = 1;
609 ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
612 wpa_printf(MSG_INFO, "Failed to configure credentials: %s",
613 gnutls_strerror(ret));
620 int tls_global_set_params(void *tls_ctx,
621 const struct tls_connection_params *params)
623 struct tls_global *global = tls_ctx;
626 /* Currently, global parameters are only set when running in server
630 if (global->params_set) {
631 gnutls_certificate_free_credentials(global->xcred);
632 global->params_set = 0;
635 ret = gnutls_certificate_allocate_credentials(&global->xcred);
637 wpa_printf(MSG_DEBUG, "Failed to allocate global credentials "
638 "%s", gnutls_strerror(ret));
642 if (params->ca_cert) {
643 ret = gnutls_certificate_set_x509_trust_file(
644 global->xcred, params->ca_cert, GNUTLS_X509_FMT_PEM);
646 wpa_printf(MSG_DEBUG, "Failed to read CA cert '%s' "
647 "in PEM format: %s", params->ca_cert,
648 gnutls_strerror(ret));
649 ret = gnutls_certificate_set_x509_trust_file(
650 global->xcred, params->ca_cert,
651 GNUTLS_X509_FMT_DER);
653 wpa_printf(MSG_DEBUG, "Failed to read CA cert "
654 "'%s' in DER format: %s",
656 gnutls_strerror(ret));
661 if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) {
662 gnutls_certificate_set_verify_flags(
664 GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
667 #if LIBGNUTLS_VERSION_NUMBER >= 0x020800
668 if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
669 gnutls_certificate_set_verify_flags(
671 GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
673 #endif /* LIBGNUTLS_VERSION_NUMBER >= 0x020800 */
676 if (params->client_cert && params->private_key) {
677 /* TODO: private_key_passwd? */
678 ret = gnutls_certificate_set_x509_key_file(
679 global->xcred, params->client_cert,
680 params->private_key, GNUTLS_X509_FMT_PEM);
682 wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
683 "in PEM format: %s", gnutls_strerror(ret));
684 ret = gnutls_certificate_set_x509_key_file(
685 global->xcred, params->client_cert,
686 params->private_key, GNUTLS_X509_FMT_DER);
688 wpa_printf(MSG_DEBUG, "Failed to read client "
689 "cert/key in DER format: %s",
690 gnutls_strerror(ret));
694 } else if (params->private_key) {
697 /* Try to load in PKCS#12 format */
698 #if LIBGNUTLS_VERSION_NUMBER >= 0x010302
699 ret = gnutls_certificate_set_x509_simple_pkcs12_file(
700 global->xcred, params->private_key,
701 GNUTLS_X509_FMT_DER, params->private_key_passwd);
703 wpa_printf(MSG_DEBUG, "Failed to load private_key in "
704 "PKCS#12 format: %s", gnutls_strerror(ret));
708 #endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
709 #endif /* PKCS12_FUNCS */
712 wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not "
718 global->params_set = 1;
723 gnutls_certificate_free_credentials(global->xcred);
728 int tls_global_set_verify(void *ssl_ctx, int check_crl)
735 int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
738 if (conn == NULL || conn->session == NULL)
741 conn->verify_peer = verify_peer;
742 gnutls_certificate_server_set_request(conn->session,
743 verify_peer ? GNUTLS_CERT_REQUIRE
744 : GNUTLS_CERT_REQUEST);
750 int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
751 struct tls_keys *keys)
753 #ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
754 security_parameters_st *sec;
755 #endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
757 if (conn == NULL || conn->session == NULL || keys == NULL)
760 os_memset(keys, 0, sizeof(*keys));
762 #if LIBGNUTLS_VERSION_NUMBER < 0x020c00
763 #ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
764 sec = &conn->session->security_parameters;
765 keys->master_key = sec->master_secret;
766 keys->master_key_len = WPA_TLS_MASTER_SIZE;
767 keys->client_random = sec->client_random;
768 keys->server_random = sec->server_random;
769 #else /* GNUTLS_INTERNAL_STRUCTURE_HACK */
770 keys->client_random =
771 (u8 *) gnutls_session_get_client_random(conn->session);
772 keys->server_random =
773 (u8 *) gnutls_session_get_server_random(conn->session);
774 /* No access to master_secret */
775 #endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
776 #endif /* LIBGNUTLS_VERSION_NUMBER < 0x020c00 */
778 #if LIBGNUTLS_VERSION_NUMBER < 0x020c00
779 keys->client_random_len = WPA_TLS_RANDOM_SIZE;
780 keys->server_random_len = WPA_TLS_RANDOM_SIZE;
781 #endif /* LIBGNUTLS_VERSION_NUMBER < 0x020c00 */
787 int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
788 const char *label, int server_random_first,
789 u8 *out, size_t out_len)
791 #if LIBGNUTLS_VERSION_NUMBER >= 0x010302
792 if (conn == NULL || conn->session == NULL)
795 return gnutls_prf(conn->session, os_strlen(label), label,
796 server_random_first, 0, NULL, out_len, (char *) out);
797 #else /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
799 #endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
803 static int tls_connection_verify_peer(struct tls_connection *conn,
804 gnutls_alert_description_t *err)
806 unsigned int status, num_certs, i;
808 const gnutls_datum_t *certs;
809 gnutls_x509_crt_t cert;
811 if (gnutls_certificate_verify_peers2(conn->session, &status) < 0) {
812 wpa_printf(MSG_INFO, "TLS: Failed to verify peer "
813 "certificate chain");
814 *err = GNUTLS_A_INTERNAL_ERROR;
818 if (conn->verify_peer && (status & GNUTLS_CERT_INVALID)) {
819 wpa_printf(MSG_INFO, "TLS: Peer certificate not trusted");
820 *err = GNUTLS_A_INTERNAL_ERROR;
821 if (status & GNUTLS_CERT_INSECURE_ALGORITHM) {
822 wpa_printf(MSG_INFO, "TLS: Certificate uses insecure "
824 *err = GNUTLS_A_INSUFFICIENT_SECURITY;
826 #if LIBGNUTLS_VERSION_NUMBER >= 0x020800
827 if (status & GNUTLS_CERT_NOT_ACTIVATED) {
828 wpa_printf(MSG_INFO, "TLS: Certificate not yet "
830 *err = GNUTLS_A_CERTIFICATE_EXPIRED;
832 if (status & GNUTLS_CERT_EXPIRED) {
833 wpa_printf(MSG_INFO, "TLS: Certificate expired");
834 *err = GNUTLS_A_CERTIFICATE_EXPIRED;
836 #endif /* LIBGNUTLS_VERSION_NUMBER >= 0x020800 */
840 if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
841 wpa_printf(MSG_INFO, "TLS: Peer certificate does not have a "
843 *err = GNUTLS_A_UNKNOWN_CA;
847 if (status & GNUTLS_CERT_REVOKED) {
848 wpa_printf(MSG_INFO, "TLS: Peer certificate has been revoked");
849 *err = GNUTLS_A_CERTIFICATE_REVOKED;
855 certs = gnutls_certificate_get_peers(conn->session, &num_certs);
857 wpa_printf(MSG_INFO, "TLS: No peer certificate chain "
859 *err = GNUTLS_A_UNKNOWN_CA;
863 for (i = 0; i < num_certs; i++) {
866 if (gnutls_x509_crt_init(&cert) < 0) {
867 wpa_printf(MSG_INFO, "TLS: Certificate initialization "
869 *err = GNUTLS_A_BAD_CERTIFICATE;
873 if (gnutls_x509_crt_import(cert, &certs[i],
874 GNUTLS_X509_FMT_DER) < 0) {
875 wpa_printf(MSG_INFO, "TLS: Could not parse peer "
876 "certificate %d/%d", i + 1, num_certs);
877 gnutls_x509_crt_deinit(cert);
878 *err = GNUTLS_A_BAD_CERTIFICATE;
882 gnutls_x509_crt_get_dn(cert, NULL, &len);
884 buf = os_malloc(len + 1);
886 buf[0] = buf[len] = '\0';
887 gnutls_x509_crt_get_dn(cert, buf, &len);
889 wpa_printf(MSG_DEBUG, "TLS: Peer cert chain %d/%d: %s",
890 i + 1, num_certs, buf);
893 /* TODO: validate subject_match and altsubject_match */
898 if (gnutls_x509_crt_get_expiration_time(cert) < now.sec ||
899 gnutls_x509_crt_get_activation_time(cert) > now.sec) {
900 wpa_printf(MSG_INFO, "TLS: Peer certificate %d/%d is "
901 "not valid at this time",
903 gnutls_x509_crt_deinit(cert);
904 *err = GNUTLS_A_CERTIFICATE_EXPIRED;
908 gnutls_x509_crt_deinit(cert);
915 static struct wpabuf * gnutls_get_appl_data(struct tls_connection *conn)
919 wpa_printf(MSG_DEBUG, "GnuTLS: Check for possible Application Data");
920 ad = wpabuf_alloc((wpabuf_len(conn->pull_buf) + 500) * 3);
924 res = gnutls_record_recv(conn->session, wpabuf_mhead(ad),
926 wpa_printf(MSG_DEBUG, "GnuTLS: gnutls_record_recv: %d", res);
928 wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d "
929 "(%s)", __func__, (int) res,
930 gnutls_strerror(res));
936 wpa_printf(MSG_DEBUG, "GnuTLS: Received %d bytes of Application Data",
942 struct wpabuf * tls_connection_handshake(void *tls_ctx,
943 struct tls_connection *conn,
944 const struct wpabuf *in_data,
945 struct wpabuf **appl_data)
947 struct tls_global *global = tls_ctx;
948 struct wpabuf *out_data;
954 if (in_data && wpabuf_len(in_data) > 0) {
955 if (conn->pull_buf) {
956 wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
957 "pull_buf", __func__,
958 (unsigned long) wpabuf_len(conn->pull_buf));
959 wpabuf_free(conn->pull_buf);
961 conn->pull_buf = wpabuf_dup(in_data);
962 if (conn->pull_buf == NULL)
964 conn->pull_buf_offset = wpabuf_head(conn->pull_buf);
967 ret = gnutls_handshake(conn->session);
971 if (global->server && conn->established &&
972 conn->push_buf == NULL) {
973 /* Need to return something to trigger
974 * completion of EAP-TLS. */
975 conn->push_buf = wpabuf_alloc(0);
978 case GNUTLS_E_FATAL_ALERT_RECEIVED:
979 wpa_printf(MSG_DEBUG, "%s - received fatal '%s' alert",
980 __func__, gnutls_alert_get_name(
981 gnutls_alert_get(conn->session)));
985 wpa_printf(MSG_DEBUG, "%s - gnutls_handshake failed "
986 "-> %s", __func__, gnutls_strerror(ret));
991 gnutls_alert_description_t err;
993 if (conn->verify_peer &&
994 tls_connection_verify_peer(conn, &err)) {
995 wpa_printf(MSG_INFO, "TLS: Peer certificate chain "
996 "failed validation");
998 gnutls_alert_send(conn->session, GNUTLS_AL_FATAL, err);
1002 wpa_printf(MSG_DEBUG, "TLS: Handshake completed successfully");
1003 conn->established = 1;
1004 if (conn->push_buf == NULL) {
1005 /* Need to return something to get final TLS ACK. */
1006 conn->push_buf = wpabuf_alloc(0);
1009 gnutls_session_get_data(conn->session, NULL, &size);
1010 if (global->session_data == NULL ||
1011 global->session_data_size < size) {
1012 os_free(global->session_data);
1013 global->session_data = os_malloc(size);
1015 if (global->session_data) {
1016 global->session_data_size = size;
1017 gnutls_session_get_data(conn->session,
1018 global->session_data,
1019 &global->session_data_size);
1022 if (conn->pull_buf && appl_data)
1023 *appl_data = gnutls_get_appl_data(conn);
1027 out_data = conn->push_buf;
1028 conn->push_buf = NULL;
1033 struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
1034 struct tls_connection *conn,
1035 const struct wpabuf *in_data,
1036 struct wpabuf **appl_data)
1038 return tls_connection_handshake(tls_ctx, conn, in_data, appl_data);
1042 struct wpabuf * tls_connection_encrypt(void *tls_ctx,
1043 struct tls_connection *conn,
1044 const struct wpabuf *in_data)
1049 res = gnutls_record_send(conn->session, wpabuf_head(in_data),
1050 wpabuf_len(in_data));
1052 wpa_printf(MSG_INFO, "%s: Encryption failed: %s",
1053 __func__, gnutls_strerror(res));
1057 buf = conn->push_buf;
1058 conn->push_buf = NULL;
1063 struct wpabuf * tls_connection_decrypt(void *tls_ctx,
1064 struct tls_connection *conn,
1065 const struct wpabuf *in_data)
1070 if (conn->pull_buf) {
1071 wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
1072 "pull_buf", __func__,
1073 (unsigned long) wpabuf_len(conn->pull_buf));
1074 wpabuf_free(conn->pull_buf);
1076 conn->pull_buf = wpabuf_dup(in_data);
1077 if (conn->pull_buf == NULL)
1079 conn->pull_buf_offset = wpabuf_head(conn->pull_buf);
1082 * Even though we try to disable TLS compression, it is possible that
1083 * this cannot be done with all TLS libraries. Add extra buffer space
1084 * to handle the possibility of the decrypted data being longer than
1087 out = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
1091 res = gnutls_record_recv(conn->session, wpabuf_mhead(out),
1094 wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d "
1095 "(%s)", __func__, (int) res, gnutls_strerror(res));
1099 wpabuf_put(out, res);
1105 int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
1109 return gnutls_session_is_resumed(conn->session);
1113 int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
1121 int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
1122 char *buf, size_t buflen)
1130 int tls_connection_enable_workaround(void *ssl_ctx,
1131 struct tls_connection *conn)
1133 gnutls_record_disable_padding(conn->session);
1138 int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
1139 int ext_type, const u8 *data,
1147 int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
1151 return conn->failed;
1155 int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn)
1159 return conn->read_alerts;
1163 int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
1167 return conn->write_alerts;
1171 int tls_connection_get_keyblock_size(void *tls_ctx,
1172 struct tls_connection *conn)
1179 unsigned int tls_capabilities(void *tls_ctx)
1185 int tls_connection_set_session_ticket_cb(void *tls_ctx,
1186 struct tls_connection *conn,
1187 tls_session_ticket_cb cb, void *ctx)