📄 tls_gnutls.c
字号:
/* * WPA Supplicant / SSL/TLS interface functions for openssl * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */#include "includes.h"#include <gnutls/gnutls.h>#include <gnutls/x509.h>#ifdef PKCS12_FUNCS#include <gnutls/pkcs12.h>#endif /* PKCS12_FUNCS */#ifdef CONFIG_GNUTLS_EXTRA#if LIBGNUTLS_VERSION_NUMBER >= 0x010302#define GNUTLS_IA#include <gnutls/extra.h>#if LIBGNUTLS_VERSION_NUMBER == 0x010302/* This function is not included in the current gnutls/extra.h even though it * should be, so define it here as a workaround for the time being. */int gnutls_ia_verify_endphase(gnutls_session_t session, char *checksum);#endif /* LIBGNUTLS_VERSION_NUMBER == 0x010302 */#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */#endif /* CONFIG_GNUTLS_EXTRA */#include "common.h"#include "tls.h"#define TLS_RANDOM_SIZE 32#define TLS_MASTER_SIZE 48#if LIBGNUTLS_VERSION_NUMBER < 0x010302/* GnuTLS 1.3.2 added functions for using master secret. Older versions require * use of internal structures to get the master_secret and * {server,client}_random. */#define GNUTLS_INTERNAL_STRUCTURE_HACK#endif /* LIBGNUTLS_VERSION_NUMBER < 0x010302 */#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK/* * It looks like gnutls does not provide access to client/server_random and * master_key. This is somewhat unfortunate since these are needed for key * derivation in EAP-{TLS,TTLS,PEAP,FAST}. Workaround for now is a horrible * hack that copies the gnutls_session_int definition from gnutls_int.h so that * we can get the needed information. */typedef u8 uint8;typedef unsigned char opaque;typedef struct { uint8 suite[2];} cipher_suite_st;typedef struct { gnutls_connection_end_t entity; gnutls_kx_algorithm_t kx_algorithm; gnutls_cipher_algorithm_t read_bulk_cipher_algorithm; gnutls_mac_algorithm_t read_mac_algorithm; gnutls_compression_method_t read_compression_algorithm; gnutls_cipher_algorithm_t write_bulk_cipher_algorithm; gnutls_mac_algorithm_t write_mac_algorithm; gnutls_compression_method_t write_compression_algorithm; cipher_suite_st current_cipher_suite; opaque master_secret[TLS_MASTER_SIZE]; opaque client_random[TLS_RANDOM_SIZE]; opaque server_random[TLS_RANDOM_SIZE]; /* followed by stuff we are not interested in */} security_parameters_st;struct gnutls_session_int { security_parameters_st security_parameters; /* followed by things we are not interested in */};#endif /* LIBGNUTLS_VERSION_NUMBER < 0x010302 */static int tls_gnutls_ref_count = 0;struct tls_global { /* Data for session resumption */ void *session_data; size_t session_data_size; int server; int params_set; gnutls_certificate_credentials_t xcred;};struct tls_connection { gnutls_session session; char *subject_match, *altsubject_match; int read_alerts, write_alerts, failed; u8 *pre_shared_secret; size_t pre_shared_secret_len; int established; int verify_peer; u8 *push_buf, *pull_buf, *pull_buf_offset; size_t push_buf_len, pull_buf_len; int params_set; gnutls_certificate_credentials_t xcred; int tls_ia; int final_phase_finished;#ifdef GNUTLS_IA gnutls_ia_server_credentials_t iacred_srv; gnutls_ia_client_credentials_t iacred_cli; /* Session keys generated in the current phase for inner secret * permutation before generating/verifying PhaseFinished. */ u8 *session_keys; size_t session_keys_len; u8 inner_secret[TLS_MASTER_SIZE];#endif /* GNUTLS_IA */};static void tls_log_func(int level, const char *msg){ char *s, *pos; if (level == 6 || level == 7) { /* These levels seem to be mostly I/O debug and msg dumps */ return; } s = os_strdup(msg); if (s == NULL) return; pos = s; while (*pos != '\0') { if (*pos == '\n') { *pos = '\0'; break; } pos++; } wpa_printf(level > 3 ? MSG_MSGDUMP : MSG_DEBUG, "gnutls<%d> %s", level, s); os_free(s);}extern int wpa_debug_show_keys;void * tls_init(const struct tls_config *conf){ struct tls_global *global;#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK /* Because of the horrible hack to get master_secret and client/server * random, we need to make sure that the gnutls version is something * that is expected to have same structure definition for the session * data.. */ const char *ver; const char *ok_ver[] = { "1.2.3", "1.2.4", "1.2.5", "1.2.6", "1.2.9", "1.3.2", NULL }; int i;#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */ global = os_zalloc(sizeof(*global)); if (global == NULL) return NULL; if (tls_gnutls_ref_count == 0 && gnutls_global_init() < 0) { os_free(global); return NULL; } tls_gnutls_ref_count++;#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK ver = gnutls_check_version(NULL); if (ver == NULL) { tls_deinit(global); return NULL; } wpa_printf(MSG_DEBUG, "%s - gnutls version %s", __func__, ver); for (i = 0; ok_ver[i]; i++) { if (strcmp(ok_ver[i], ver) == 0) break; } if (ok_ver[i] == NULL) { wpa_printf(MSG_INFO, "Untested gnutls version %s - this needs " "to be tested and enabled in tls_gnutls.c", ver); tls_deinit(global); return NULL; }#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */ gnutls_global_set_log_function(tls_log_func); if (wpa_debug_show_keys) gnutls_global_set_log_level(11); return global;}void tls_deinit(void *ssl_ctx){ struct tls_global *global = ssl_ctx; if (global) { if (global->params_set) gnutls_certificate_free_credentials(global->xcred); os_free(global->session_data); os_free(global); } tls_gnutls_ref_count--; if (tls_gnutls_ref_count == 0) gnutls_global_deinit();}int tls_get_errors(void *ssl_ctx){ return 0;}static ssize_t tls_pull_func(gnutls_transport_ptr ptr, void *buf, size_t len){ struct tls_connection *conn = (struct tls_connection *) ptr; u8 *end; if (conn->pull_buf == NULL) { errno = EWOULDBLOCK; return -1; } end = conn->pull_buf + conn->pull_buf_len; if ((size_t) (end - conn->pull_buf_offset) < len) len = end - conn->pull_buf_offset; os_memcpy(buf, conn->pull_buf_offset, len); conn->pull_buf_offset += len; if (conn->pull_buf_offset == end) { wpa_printf(MSG_DEBUG, "%s - pull_buf consumed", __func__); os_free(conn->pull_buf); conn->pull_buf = conn->pull_buf_offset = NULL; conn->pull_buf_len = 0; } else { wpa_printf(MSG_DEBUG, "%s - %d bytes remaining in pull_buf", __func__, end - conn->pull_buf_offset); } return len;}static ssize_t tls_push_func(gnutls_transport_ptr ptr, const void *buf, size_t len){ struct tls_connection *conn = (struct tls_connection *) ptr; u8 *nbuf; nbuf = os_realloc(conn->push_buf, conn->push_buf_len + len); if (nbuf == NULL) { errno = ENOMEM; return -1; } os_memcpy(nbuf + conn->push_buf_len, buf, len); conn->push_buf = nbuf; conn->push_buf_len += len; return len;}static int tls_gnutls_init_session(struct tls_global *global, struct tls_connection *conn){ const int cert_types[2] = { GNUTLS_CRT_X509, 0 }; const int protos[2] = { GNUTLS_TLS1, 0 }; int ret; ret = gnutls_init(&conn->session, global->server ? GNUTLS_SERVER : GNUTLS_CLIENT); if (ret < 0) { wpa_printf(MSG_INFO, "TLS: Failed to initialize new TLS " "connection: %s", gnutls_strerror(ret)); return -1; } ret = gnutls_set_default_priority(conn->session); if (ret < 0) goto fail; ret = gnutls_certificate_type_set_priority(conn->session, cert_types); if (ret < 0) goto fail; ret = gnutls_protocol_set_priority(conn->session, protos); if (ret < 0) goto fail; gnutls_transport_set_pull_function(conn->session, tls_pull_func); gnutls_transport_set_push_function(conn->session, tls_push_func); gnutls_transport_set_ptr(conn->session, (gnutls_transport_ptr) conn); return 0;fail: wpa_printf(MSG_INFO, "TLS: Failed to setup new TLS connection: %s", gnutls_strerror(ret)); gnutls_deinit(conn->session); return -1;}struct tls_connection * tls_connection_init(void *ssl_ctx){ struct tls_global *global = ssl_ctx; struct tls_connection *conn; int ret; conn = os_zalloc(sizeof(*conn)); if (conn == NULL) return NULL; if (tls_gnutls_init_session(global, conn)) { os_free(conn); return NULL; } if (global->params_set) { ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE, global->xcred); if (ret < 0) { wpa_printf(MSG_INFO, "Failed to configure " "credentials: %s", gnutls_strerror(ret)); os_free(conn); return NULL; } } if (gnutls_certificate_allocate_credentials(&conn->xcred)) { os_free(conn); return NULL; } return conn;}void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn){ if (conn == NULL) return;#ifdef GNUTLS_IA if (conn->iacred_srv) gnutls_ia_free_server_credentials(conn->iacred_srv); if (conn->iacred_cli) gnutls_ia_free_client_credentials(conn->iacred_cli); if (conn->session_keys) { os_memset(conn->session_keys, 0, conn->session_keys_len); os_free(conn->session_keys); }#endif /* GNUTLS_IA */ gnutls_certificate_free_credentials(conn->xcred); gnutls_deinit(conn->session); os_free(conn->pre_shared_secret); os_free(conn->subject_match); os_free(conn->altsubject_match); os_free(conn->push_buf); os_free(conn->pull_buf); os_free(conn);}int tls_connection_established(void *ssl_ctx, struct tls_connection *conn){ return conn ? conn->established : 0;}int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn){ struct tls_global *global = ssl_ctx; int ret; if (conn == NULL) return -1; /* Shutdown previous TLS connection without notifying the peer * because the connection was already terminated in practice * and "close notify" shutdown alert would confuse AS. */ gnutls_bye(conn->session, GNUTLS_SHUT_RDWR); os_free(conn->push_buf); conn->push_buf = NULL; conn->push_buf_len = 0; conn->established = 0; conn->final_phase_finished = 0;#ifdef GNUTLS_IA if (conn->session_keys) { os_memset(conn->session_keys, 0, conn->session_keys_len); os_free(conn->session_keys); } conn->session_keys_len = 0;#endif /* GNUTLS_IA */ gnutls_deinit(conn->session); if (tls_gnutls_init_session(global, conn)) { wpa_printf(MSG_INFO, "GnuTLS: Failed to preparare new session " "for session resumption use"); return -1; } ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE, conn->params_set ? conn->xcred : global->xcred); if (ret < 0) { wpa_printf(MSG_INFO, "GnuTLS: Failed to configure credentials " "for session resumption: %s", gnutls_strerror(ret)); return -1; } if (global->session_data) { ret = gnutls_session_set_data(conn->session, global->session_data, global->session_data_size); if (ret < 0) { wpa_printf(MSG_INFO, "GnuTLS: Failed to set session " "data: %s", gnutls_strerror(ret)); return -1; } } return 0;}#if 0static int tls_match_altsubject(X509 *cert, const char *match){ GENERAL_NAME *gen; char *field, *tmp; void *ext; int i, found = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -