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