📄 tls_gnutls.c
字号:
/* * WPA Supplicant / SSL/TLS interface functions for openssl * Copyright (c) 2004-2006, 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 <stdlib.h>#include <stdio.h>#include <string.h>#include <errno.h>#include <gnutls/gnutls.h>#include <gnutls/x509.h>#include "common.h"#include "tls.h"/* * 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;#define TLS_RANDOM_SIZE 32#define TLS_MASTER_SIZE 48typedef 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 */};static int tls_gnutls_ref_count = 0;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; gnutls_certificate_credentials_t xcred;};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 = 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); free(s);}extern int wpa_debug_show_keys;void * tls_init(const struct tls_config *conf){ /* 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", NULL }; int i; if (tls_gnutls_ref_count == 0 && gnutls_global_init() < 0) return NULL; tls_gnutls_ref_count++; ver = gnutls_check_version(NULL); if (ver == NULL) 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); return NULL; } gnutls_global_set_log_function(tls_log_func); if (wpa_debug_show_keys) gnutls_global_set_log_level(11); return (void *) 1;}void tls_deinit(void *ssl_ctx){ 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; 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__); 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 = realloc(conn->push_buf, conn->push_buf_len + len); if (nbuf == NULL) { errno = ENOMEM; return -1; } memcpy(nbuf + conn->push_buf_len, buf, len); conn->push_buf = nbuf; conn->push_buf_len += len; return len;}struct tls_connection * tls_connection_init(void *ssl_ctx){ struct tls_connection *conn; const int cert_types[2] = { GNUTLS_CRT_X509, 0 }; const int protos[2] = { GNUTLS_TLS1, 0 }; conn = malloc(sizeof(*conn)); if (conn == NULL) return NULL; memset(conn, 0, sizeof(*conn)); if (gnutls_init(&conn->session, GNUTLS_CLIENT) < 0) { wpa_printf(MSG_INFO, "TLS: Failed to initialize new TLS " "connection"); free(conn); return NULL; } gnutls_set_default_priority(conn->session); gnutls_certificate_type_set_priority(conn->session, cert_types); gnutls_protocol_set_priority(conn->session, protos); 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); gnutls_certificate_allocate_credentials(&conn->xcred); return conn;}void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn){ if (conn == NULL) return; gnutls_certificate_free_credentials(conn->xcred); gnutls_deinit(conn->session); free(conn->pre_shared_secret); free(conn->subject_match); free(conn->altsubject_match); free(conn->push_buf); free(conn->pull_buf); 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){ 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); free(conn->push_buf); conn->push_buf = NULL; conn->push_buf_len = 0; conn->established = 0; /* TODO: what to do trigger new handshake for re-auth? */ 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; size_t len; ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) { gen = sk_GENERAL_NAME_value(ext, i); switch (gen->type) { case GEN_EMAIL: field = "EMAIL"; break; case GEN_DNS: field = "DNS"; break; case GEN_URI: field = "URI"; break; default: field = NULL; wpa_printf(MSG_DEBUG, "TLS: altSubjectName: " "unsupported type=%d", gen->type); break; } if (!field) continue; wpa_printf(MSG_DEBUG, "TLS: altSubjectName: %s:%s", field, gen->d.ia5->data); len = strlen(field) + 1 + strlen((char *) gen->d.ia5->data) + 1; tmp = malloc(len); if (tmp == NULL) continue; snprintf(tmp, len, "%s:%s", field, gen->d.ia5->data); if (strstr(tmp, match)) found++; free(tmp); } return found;}#endif#if 0static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx){ char buf[256]; X509 *err_cert; int err, depth; SSL *ssl; struct tls_connection *conn; char *match, *altmatch; err_cert = X509_STORE_CTX_get_current_cert(x509_ctx); err = X509_STORE_CTX_get_error(x509_ctx); depth = X509_STORE_CTX_get_error_depth(x509_ctx); ssl = X509_STORE_CTX_get_ex_data(x509_ctx, SSL_get_ex_data_X509_STORE_CTX_idx()); X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf)); conn = SSL_get_app_data(ssl); match = conn ? conn->subject_match : NULL; altmatch = conn ? conn->altsubject_match : NULL; if (!preverify_ok) { wpa_printf(MSG_WARNING, "TLS: Certificate verification failed," " error %d (%s) depth %d for '%s'", err, X509_verify_cert_error_string(err), depth, buf); } else { wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb - " "preverify_ok=%d err=%d (%s) depth=%d buf='%s'", preverify_ok, err, X509_verify_cert_error_string(err), depth, buf); if (depth == 0 && match && strstr(buf, match) == NULL) { wpa_printf(MSG_WARNING, "TLS: Subject '%s' did not " "match with '%s'", buf, match); preverify_ok = 0; } else if (depth == 0 && altmatch && !tls_match_altsubject(err_cert, altmatch)) { wpa_printf(MSG_WARNING, "TLS: altSubjectName match " "'%s' not found", altmatch); preverify_ok = 0; } } return preverify_ok;}#endifint tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, const struct tls_connection_params *params){ int ret; if (conn == NULL || params == NULL) return -1; free(conn->subject_match); conn->subject_match = NULL; if (params->subject_match) { conn->subject_match = strdup(params->subject_match); if (conn->subject_match == NULL) return -1; } free(conn->altsubject_match); conn->altsubject_match = NULL; if (params->altsubject_match) { conn->altsubject_match = strdup(params->altsubject_match); if (conn->altsubject_match == NULL) return -1; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -