1139825Simp/* 299654Sbenno * SSL/TLS interface functions for GnuTLS 399654Sbenno * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi> 499654Sbenno * 599654Sbenno * This software may be distributed under the terms of the BSD license. 699654Sbenno * See README for more details. 799654Sbenno */ 899654Sbenno 999654Sbenno#include "includes.h" 1099654Sbenno#include <gnutls/gnutls.h> 1199654Sbenno#include <gnutls/x509.h> 1299654Sbenno#ifdef PKCS12_FUNCS 1399654Sbenno#include <gnutls/pkcs12.h> 1499654Sbenno#endif /* PKCS12_FUNCS */ 1599654Sbenno 1699654Sbenno#include "common.h" 1799654Sbenno#include "tls.h" 1899654Sbenno 1999654Sbenno 2099654Sbenno#define WPA_TLS_RANDOM_SIZE 32 2199654Sbenno#define WPA_TLS_MASTER_SIZE 48 2299654Sbenno 2399654Sbenno 2499654Sbenno#if LIBGNUTLS_VERSION_NUMBER < 0x010302 2599654Sbenno/* GnuTLS 1.3.2 added functions for using master secret. Older versions require 2699654Sbenno * use of internal structures to get the master_secret and 2799654Sbenno * {server,client}_random. 2899654Sbenno */ 2999654Sbenno#define GNUTLS_INTERNAL_STRUCTURE_HACK 3099654Sbenno#endif /* LIBGNUTLS_VERSION_NUMBER < 0x010302 */ 3199654Sbenno 3299654Sbenno 33209486Snwhitehorn#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK 34171805Smarcel/* 35209486Snwhitehorn * It looks like gnutls does not provide access to client/server_random and 3699654Sbenno * master_key. This is somewhat unfortunate since these are needed for key 3799654Sbenno * derivation in EAP-{TLS,TTLS,PEAP,FAST}. Workaround for now is a horrible 3899654Sbenno * hack that copies the gnutls_session_int definition from gnutls_int.h so that 3999654Sbenno * we can get the needed information. 4099654Sbenno */ 4199654Sbenno 4299654Sbennotypedef u8 uint8; 4399654Sbennotypedef unsigned char opaque; 4499654Sbennotypedef struct { 4599654Sbenno uint8 suite[2]; 4699654Sbenno} cipher_suite_st; 4799654Sbenno 4899654Sbennotypedef struct { 4999654Sbenno gnutls_connection_end_t entity; 5099654Sbenno gnutls_kx_algorithm_t kx_algorithm; 51171805Smarcel gnutls_cipher_algorithm_t read_bulk_cipher_algorithm; 52171805Smarcel gnutls_mac_algorithm_t read_mac_algorithm; 5399654Sbenno gnutls_compression_method_t read_compression_algorithm; 5499654Sbenno gnutls_cipher_algorithm_t write_bulk_cipher_algorithm; 5599654Sbenno gnutls_mac_algorithm_t write_mac_algorithm; 56209298Snwhitehorn gnutls_compression_method_t write_compression_algorithm; 5799654Sbenno cipher_suite_st current_cipher_suite; 58171805Smarcel opaque master_secret[WPA_TLS_MASTER_SIZE]; 59171805Smarcel opaque client_random[WPA_TLS_RANDOM_SIZE]; 60171805Smarcel opaque server_random[WPA_TLS_RANDOM_SIZE]; 61171805Smarcel /* followed by stuff we are not interested in */ 62171805Smarcel} security_parameters_st; 6399654Sbenno 64171805Smarcelstruct gnutls_session_int { 65171805Smarcel security_parameters_st security_parameters; 6699654Sbenno /* followed by things we are not interested in */ 67171805Smarcel}; 68171805Smarcel#endif /* LIBGNUTLS_VERSION_NUMBER < 0x010302 */ 69124469Sgrehan 70171805Smarcelstatic int tls_gnutls_ref_count = 0; 71176208Smarcel 72171805Smarcelstruct tls_global { 73176208Smarcel /* Data for session resumption */ 74171805Smarcel void *session_data; 7599654Sbenno size_t session_data_size; 76209486Snwhitehorn 77209725Snwhitehorn int server; 78176208Smarcel 79176208Smarcel int params_set; 80171805Smarcel gnutls_certificate_credentials_t xcred; 81176208Smarcel}; 82209486Snwhitehorn 83124469Sgrehanstruct tls_connection { 8499654Sbenno gnutls_session session; 85124469Sgrehan char *subject_match, *altsubject_match; 86218075Smarcel int read_alerts, write_alerts, failed; 87124469Sgrehan 88124469Sgrehan u8 *pre_shared_secret; 89178628Smarcel size_t pre_shared_secret_len; 90124469Sgrehan int established; 91103603Sgrehan int verify_peer; 92124469Sgrehan 93171805Smarcel struct wpabuf *push_buf; 94103603Sgrehan struct wpabuf *pull_buf; 95171805Smarcel const u8 *pull_buf_offset; 96171805Smarcel 97171805Smarcel int params_set; 98124469Sgrehan gnutls_certificate_credentials_t xcred; 99171805Smarcel}; 100171805Smarcel 101171805Smarcel 102171805Smarcelstatic void tls_log_func(int level, const char *msg) 103171805Smarcel{ 104171805Smarcel char *s, *pos; 105171805Smarcel if (level == 6 || level == 7) { 106171805Smarcel /* These levels seem to be mostly I/O debug and msg dumps */ 107208149Snwhitehorn return; 108208149Snwhitehorn } 109208149Snwhitehorn 110208149Snwhitehorn s = os_strdup(msg); 111208149Snwhitehorn if (s == NULL) 112208149Snwhitehorn return; 113208149Snwhitehorn 114208149Snwhitehorn pos = s; 115208149Snwhitehorn while (*pos != '\0') { 116208149Snwhitehorn if (*pos == '\n') { 117209298Snwhitehorn *pos = '\0'; 118209298Snwhitehorn break; 119209298Snwhitehorn } 120209485Smarcel pos++; 121209485Smarcel } 122209485Smarcel wpa_printf(level > 3 ? MSG_MSGDUMP : MSG_DEBUG, 123209485Smarcel "gnutls<%d> %s", level, s); 124209485Smarcel os_free(s); 125209485Smarcel} 126209485Smarcel 127209485Smarcel 128209485Smarcelextern int wpa_debug_show_keys; 129209298Snwhitehorn 130209298Snwhitehornvoid * tls_init(const struct tls_config *conf) 131209298Snwhitehorn{ 132209298Snwhitehorn struct tls_global *global; 133209298Snwhitehorn 134209298Snwhitehorn#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK 135209485Smarcel /* Because of the horrible hack to get master_secret and client/server 136209298Snwhitehorn * random, we need to make sure that the gnutls version is something 137209298Snwhitehorn * that is expected to have same structure definition for the session 138209298Snwhitehorn * data.. */ 139209298Snwhitehorn const char *ver; 140209298Snwhitehorn const char *ok_ver[] = { "1.2.3", "1.2.4", "1.2.5", "1.2.6", "1.2.9", 141209298Snwhitehorn "1.3.2", 142209298Snwhitehorn NULL }; 143209298Snwhitehorn int i; 144209298Snwhitehorn#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */ 145209298Snwhitehorn 146209298Snwhitehorn global = os_zalloc(sizeof(*global)); 147124469Sgrehan if (global == NULL) 148124469Sgrehan return NULL; 14999654Sbenno 15099654Sbenno if (tls_gnutls_ref_count == 0 && gnutls_global_init() < 0) { 15199654Sbenno os_free(global); 15299654Sbenno return NULL; 15399654Sbenno } 15499654Sbenno tls_gnutls_ref_count++; 15599654Sbenno 15699654Sbenno#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK 15799654Sbenno ver = gnutls_check_version(NULL); 15899654Sbenno if (ver == NULL) { 15999654Sbenno tls_deinit(global); 16099654Sbenno return NULL; 16199654Sbenno } 16299654Sbenno wpa_printf(MSG_DEBUG, "%s - gnutls version %s", __func__, ver); 163124469Sgrehan for (i = 0; ok_ver[i]; i++) { 164110167Sbenno if (strcmp(ok_ver[i], ver) == 0) 165124469Sgrehan break; 166110167Sbenno } 16799654Sbenno if (ok_ver[i] == NULL) { 168111156Sgrehan wpa_printf(MSG_INFO, "Untested gnutls version %s - this needs " 169193909Sgrehan "to be tested and enabled in tls_gnutls.c", ver); 170111156Sgrehan tls_deinit(global); 171193909Sgrehan return NULL; 172111156Sgrehan } 173193909Sgrehan#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */ 174193909Sgrehan 175111156Sgrehan gnutls_global_set_log_function(tls_log_func); 176124469Sgrehan if (wpa_debug_show_keys) 177124469Sgrehan gnutls_global_set_log_level(11); 178124469Sgrehan return global; 179124469Sgrehan} 18099654Sbenno 181178628Smarcel 182178628Smarcelvoid tls_deinit(void *ssl_ctx) 183178628Smarcel{ 184176208Smarcel struct tls_global *global = ssl_ctx; 185176208Smarcel if (global) { 186176208Smarcel if (global->params_set) 187176208Smarcel gnutls_certificate_free_credentials(global->xcred); 188209299Snwhitehorn os_free(global->session_data); 189176208Smarcel os_free(global); 190176208Smarcel } 191176208Smarcel 192176208Smarcel tls_gnutls_ref_count--; 19399654Sbenno if (tls_gnutls_ref_count == 0) 194176208Smarcel gnutls_global_deinit(); 195176208Smarcel} 196176208Smarcel 197176208Smarcel 198176208Smarcelint tls_get_errors(void *ssl_ctx) 199176208Smarcel{ 200176208Smarcel return 0; 20199654Sbenno} 20299654Sbenno 20399654Sbenno 20499654Sbennostatic ssize_t tls_pull_func(gnutls_transport_ptr ptr, void *buf, 20599654Sbenno size_t len) 20699654Sbenno{ 20799654Sbenno struct tls_connection *conn = (struct tls_connection *) ptr; 20899654Sbenno const u8 *end; 20999654Sbenno if (conn->pull_buf == NULL) { 21099654Sbenno errno = EWOULDBLOCK; 211209725Snwhitehorn return -1; 212103603Sgrehan } 213209725Snwhitehorn 214209725Snwhitehorn end = wpabuf_head_u8(conn->pull_buf) + wpabuf_len(conn->pull_buf); 21599654Sbenno if ((size_t) (end - conn->pull_buf_offset) < len) 21699654Sbenno len = end - conn->pull_buf_offset; 217183028Smarcel os_memcpy(buf, conn->pull_buf_offset, len); 218183028Smarcel conn->pull_buf_offset += len; 219183028Smarcel if (conn->pull_buf_offset == end) { 220218075Smarcel wpa_printf(MSG_DEBUG, "%s - pull_buf consumed", __func__); 22199654Sbenno wpabuf_free(conn->pull_buf); 222209298Snwhitehorn conn->pull_buf = NULL; 223209298Snwhitehorn conn->pull_buf_offset = NULL; 224209298Snwhitehorn } else { 225209298Snwhitehorn wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in pull_buf", 22699654Sbenno __func__, 22799654Sbenno (unsigned long) (end - conn->pull_buf_offset)); 22899654Sbenno } 22999654Sbenno return len; 230171805Smarcel} 23199654Sbenno 23299654Sbenno 233171805Smarcelstatic ssize_t tls_push_func(gnutls_transport_ptr ptr, const void *buf, 234222813Sattilio size_t len) 235209486Snwhitehorn{ 236209486Snwhitehorn struct tls_connection *conn = (struct tls_connection *) ptr; 237209486Snwhitehorn 238209486Snwhitehorn if (wpabuf_resize(&conn->push_buf, len) < 0) { 239209486Snwhitehorn errno = ENOMEM; 240209486Snwhitehorn return -1; 241209486Snwhitehorn } 242209486Snwhitehorn wpabuf_put_data(conn->push_buf, buf, len); 243222813Sattilio 244222813Sattilio return len; 245222813Sattilio} 246222813Sattilio 247222813Sattilio 248222813Sattiliostatic int tls_gnutls_init_session(struct tls_global *global, 249209486Snwhitehorn struct tls_connection *conn) 250209486Snwhitehorn{ 251209486Snwhitehorn#if LIBGNUTLS_VERSION_NUMBER >= 0x020200 252176918Smarcel const char *err; 253176918Smarcel#else /* LIBGNUTLS_VERSION_NUMBER >= 0x020200 */ 254176918Smarcel const int cert_types[2] = { GNUTLS_CRT_X509, 0 }; 255176918Smarcel const int protos[2] = { GNUTLS_TLS1, 0 }; 256176918Smarcel#endif /* LIBGNUTLS_VERSION_NUMBER < 0x020200 */ 257176918Smarcel int ret; 258176918Smarcel 259176918Smarcel ret = gnutls_init(&conn->session, 260176918Smarcel global->server ? GNUTLS_SERVER : GNUTLS_CLIENT); 261176918Smarcel if (ret < 0) { 262176918Smarcel wpa_printf(MSG_INFO, "TLS: Failed to initialize new TLS " 263176918Smarcel "connection: %s", gnutls_strerror(ret)); 264176918Smarcel return -1; 265176918Smarcel } 266176918Smarcel 267176918Smarcel ret = gnutls_set_default_priority(conn->session); 268176918Smarcel if (ret < 0) 269176918Smarcel goto fail; 270176918Smarcel 271209298Snwhitehorn#if LIBGNUTLS_VERSION_NUMBER >= 0x020200 272209298Snwhitehorn ret = gnutls_priority_set_direct(conn->session, "NORMAL:-VERS-SSL3.0", 273209298Snwhitehorn &err); 274209298Snwhitehorn if (ret < 0) { 275209298Snwhitehorn wpa_printf(MSG_ERROR, "GnuTLS: Priority string failure at " 276209298Snwhitehorn "'%s'", err); 277209298Snwhitehorn goto fail; 278209298Snwhitehorn } 279209298Snwhitehorn#else /* LIBGNUTLS_VERSION_NUMBER >= 0x020200 */ 280209298Snwhitehorn ret = gnutls_certificate_type_set_priority(conn->session, cert_types); 281209298Snwhitehorn if (ret < 0) 282176918Smarcel goto fail; 283171805Smarcel 28499654Sbenno ret = gnutls_protocol_set_priority(conn->session, protos); 285171805Smarcel if (ret < 0) 286183028Smarcel goto fail; 28799654Sbenno#endif /* LIBGNUTLS_VERSION_NUMBER < 0x020200 */ 288192532Sraj 289192532Sraj gnutls_transport_set_pull_function(conn->session, tls_pull_func); 290209725Snwhitehorn gnutls_transport_set_push_function(conn->session, tls_push_func); 291209725Snwhitehorn gnutls_transport_set_ptr(conn->session, (gnutls_transport_ptr) conn); 292183028Smarcel 293171805Smarcel return 0; 294183028Smarcel 295171805Smarcelfail: 296171805Smarcel wpa_printf(MSG_INFO, "TLS: Failed to setup new TLS connection: %s", 297171805Smarcel gnutls_strerror(ret)); 298171805Smarcel gnutls_deinit(conn->session); 299124469Sgrehan return -1; 30099654Sbenno} 30199654Sbenno 302171805Smarcel 303171805Smarcelstruct tls_connection * tls_connection_init(void *ssl_ctx) 30499654Sbenno{ 305171805Smarcel struct tls_global *global = ssl_ctx; 306171805Smarcel struct tls_connection *conn; 30799654Sbenno int ret; 30899654Sbenno 309176208Smarcel conn = os_zalloc(sizeof(*conn)); 310176208Smarcel if (conn == NULL) 311176208Smarcel return NULL; 312176208Smarcel 313176208Smarcel if (tls_gnutls_init_session(global, conn)) { 314176208Smarcel os_free(conn); 315176208Smarcel return NULL; 316176208Smarcel } 317176208Smarcel 318176208Smarcel if (global->params_set) { 319176208Smarcel ret = gnutls_credentials_set(conn->session, 32099654Sbenno GNUTLS_CRD_CERTIFICATE, 32199654Sbenno global->xcred); 322171805Smarcel if (ret < 0) { 323171805Smarcel wpa_printf(MSG_INFO, "Failed to configure " 32499654Sbenno "credentials: %s", gnutls_strerror(ret)); 325171805Smarcel os_free(conn); 326209725Snwhitehorn return NULL; 32799654Sbenno } 328209725Snwhitehorn } 329209725Snwhitehorn 330171805Smarcel if (gnutls_certificate_allocate_credentials(&conn->xcred)) { 331209725Snwhitehorn os_free(conn); 33299654Sbenno return NULL; 33399654Sbenno } 334171805Smarcel 335176208Smarcel return conn; 336176208Smarcel} 337176208Smarcel 338176208Smarcel 339209726Snwhitehornvoid tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn) 340209726Snwhitehorn{ 341176208Smarcel if (conn == NULL) 342209486Snwhitehorn return; 343209726Snwhitehorn 344176208Smarcel gnutls_certificate_free_credentials(conn->xcred); 345209486Snwhitehorn gnutls_deinit(conn->session); 346176208Smarcel os_free(conn->pre_shared_secret); 347176208Smarcel os_free(conn->subject_match); 348176208Smarcel os_free(conn->altsubject_match); 349171805Smarcel wpabuf_free(conn->push_buf); 35099654Sbenno wpabuf_free(conn->pull_buf); 351171805Smarcel os_free(conn); 352171805Smarcel} 35399654Sbenno 354171805Smarcel 355176208Smarcelint tls_connection_established(void *ssl_ctx, struct tls_connection *conn) 356176208Smarcel{ 357176208Smarcel return conn ? conn->established : 0; 358176208Smarcel} 359176208Smarcel 360176208Smarcel 361176208Smarcelint tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn) 362176208Smarcel{ 363176208Smarcel struct tls_global *global = ssl_ctx; 36499654Sbenno int ret; 36599654Sbenno 366171805Smarcel if (conn == NULL) 367171805Smarcel return -1; 36899654Sbenno 369171805Smarcel /* Shutdown previous TLS connection without notifying the peer 370171805Smarcel * because the connection was already terminated in practice 37199654Sbenno * and "close notify" shutdown alert would confuse AS. */ 372171805Smarcel gnutls_bye(conn->session, GNUTLS_SHUT_RDWR); 373176208Smarcel wpabuf_free(conn->push_buf); 374176208Smarcel conn->push_buf = NULL; 375176208Smarcel conn->established = 0; 376176208Smarcel 377176208Smarcel gnutls_deinit(conn->session); 378176208Smarcel if (tls_gnutls_init_session(global, conn)) { 379176208Smarcel wpa_printf(MSG_INFO, "GnuTLS: Failed to preparare new session " 380176208Smarcel "for session resumption use"); 381176208Smarcel return -1; 38299654Sbenno } 383 384 ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE, 385 conn->params_set ? conn->xcred : 386 global->xcred); 387 if (ret < 0) { 388 wpa_printf(MSG_INFO, "GnuTLS: Failed to configure credentials " 389 "for session resumption: %s", gnutls_strerror(ret)); 390 return -1; 391 } 392 393 if (global->session_data) { 394 ret = gnutls_session_set_data(conn->session, 395 global->session_data, 396 global->session_data_size); 397 if (ret < 0) { 398 wpa_printf(MSG_INFO, "GnuTLS: Failed to set session " 399 "data: %s", gnutls_strerror(ret)); 400 return -1; 401 } 402 } 403 404 return 0; 405} 406 407 408#if 0 409static int tls_match_altsubject(X509 *cert, const char *match) 410{ 411 GENERAL_NAME *gen; 412 char *field, *tmp; 413 void *ext; 414 int i, found = 0; 415 size_t len; 416 417 ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); 418 419 for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) { 420 gen = sk_GENERAL_NAME_value(ext, i); 421 switch (gen->type) { 422 case GEN_EMAIL: 423 field = "EMAIL"; 424 break; 425 case GEN_DNS: 426 field = "DNS"; 427 break; 428 case GEN_URI: 429 field = "URI"; 430 break; 431 default: 432 field = NULL; 433 wpa_printf(MSG_DEBUG, "TLS: altSubjectName: " 434 "unsupported type=%d", gen->type); 435 break; 436 } 437 438 if (!field) 439 continue; 440 441 wpa_printf(MSG_DEBUG, "TLS: altSubjectName: %s:%s", 442 field, gen->d.ia5->data); 443 len = os_strlen(field) + 1 + 444 strlen((char *) gen->d.ia5->data) + 1; 445 tmp = os_malloc(len); 446 if (tmp == NULL) 447 continue; 448 snprintf(tmp, len, "%s:%s", field, gen->d.ia5->data); 449 if (strstr(tmp, match)) 450 found++; 451 os_free(tmp); 452 } 453 454 return found; 455} 456#endif 457 458 459#if 0 460static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx) 461{ 462 char buf[256]; 463 X509 *err_cert; 464 int err, depth; 465 SSL *ssl; 466 struct tls_connection *conn; 467 char *match, *altmatch; 468 469 err_cert = X509_STORE_CTX_get_current_cert(x509_ctx); 470 err = X509_STORE_CTX_get_error(x509_ctx); 471 depth = X509_STORE_CTX_get_error_depth(x509_ctx); 472 ssl = X509_STORE_CTX_get_ex_data(x509_ctx, 473 SSL_get_ex_data_X509_STORE_CTX_idx()); 474 X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf)); 475 476 conn = SSL_get_app_data(ssl); 477 match = conn ? conn->subject_match : NULL; 478 altmatch = conn ? conn->altsubject_match : NULL; 479 480 if (!preverify_ok) { 481 wpa_printf(MSG_WARNING, "TLS: Certificate verification failed," 482 " error %d (%s) depth %d for '%s'", err, 483 X509_verify_cert_error_string(err), depth, buf); 484 } else { 485 wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb - " 486 "preverify_ok=%d err=%d (%s) depth=%d buf='%s'", 487 preverify_ok, err, 488 X509_verify_cert_error_string(err), depth, buf); 489 if (depth == 0 && match && strstr(buf, match) == NULL) { 490 wpa_printf(MSG_WARNING, "TLS: Subject '%s' did not " 491 "match with '%s'", buf, match); 492 preverify_ok = 0; 493 } else if (depth == 0 && altmatch && 494 !tls_match_altsubject(err_cert, altmatch)) { 495 wpa_printf(MSG_WARNING, "TLS: altSubjectName match " 496 "'%s' not found", altmatch); 497 preverify_ok = 0; 498 } 499 } 500 501 return preverify_ok; 502} 503#endif 504 505 506int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, 507 const struct tls_connection_params *params) 508{ 509 int ret; 510 511 if (conn == NULL || params == NULL) 512 return -1; 513 514 os_free(conn->subject_match); 515 conn->subject_match = NULL; 516 if (params->subject_match) { 517 conn->subject_match = os_strdup(params->subject_match); 518 if (conn->subject_match == NULL) 519 return -1; 520 } 521 522 os_free(conn->altsubject_match); 523 conn->altsubject_match = NULL; 524 if (params->altsubject_match) { 525 conn->altsubject_match = os_strdup(params->altsubject_match); 526 if (conn->altsubject_match == NULL) 527 return -1; 528 } 529 530 /* TODO: gnutls_certificate_set_verify_flags(xcred, flags); 531 * to force peer validation(?) */ 532 533 if (params->ca_cert) { 534 conn->verify_peer = 1; 535 ret = gnutls_certificate_set_x509_trust_file( 536 conn->xcred, params->ca_cert, GNUTLS_X509_FMT_PEM); 537 if (ret < 0) { 538 wpa_printf(MSG_DEBUG, "Failed to read CA cert '%s' " 539 "in PEM format: %s", params->ca_cert, 540 gnutls_strerror(ret)); 541 ret = gnutls_certificate_set_x509_trust_file( 542 conn->xcred, params->ca_cert, 543 GNUTLS_X509_FMT_DER); 544 if (ret < 0) { 545 wpa_printf(MSG_DEBUG, "Failed to read CA cert " 546 "'%s' in DER format: %s", 547 params->ca_cert, 548 gnutls_strerror(ret)); 549 return -1; 550 } 551 } 552 553 if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) { 554 gnutls_certificate_set_verify_flags( 555 conn->xcred, GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5); 556 } 557 558#if LIBGNUTLS_VERSION_NUMBER >= 0x020800 559 if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) { 560 gnutls_certificate_set_verify_flags( 561 conn->xcred, 562 GNUTLS_VERIFY_DISABLE_TIME_CHECKS); 563 } 564#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x020800 */ 565 } 566 567 if (params->client_cert && params->private_key) { 568 /* TODO: private_key_passwd? */ 569 ret = gnutls_certificate_set_x509_key_file( 570 conn->xcred, params->client_cert, params->private_key, 571 GNUTLS_X509_FMT_PEM); 572 if (ret < 0) { 573 wpa_printf(MSG_DEBUG, "Failed to read client cert/key " 574 "in PEM format: %s", gnutls_strerror(ret)); 575 ret = gnutls_certificate_set_x509_key_file( 576 conn->xcred, params->client_cert, 577 params->private_key, GNUTLS_X509_FMT_DER); 578 if (ret < 0) { 579 wpa_printf(MSG_DEBUG, "Failed to read client " 580 "cert/key in DER format: %s", 581 gnutls_strerror(ret)); 582 return ret; 583 } 584 } 585 } else if (params->private_key) { 586 int pkcs12_ok = 0; 587#ifdef PKCS12_FUNCS 588 /* Try to load in PKCS#12 format */ 589#if LIBGNUTLS_VERSION_NUMBER >= 0x010302 590 ret = gnutls_certificate_set_x509_simple_pkcs12_file( 591 conn->xcred, params->private_key, GNUTLS_X509_FMT_DER, 592 params->private_key_passwd); 593 if (ret != 0) { 594 wpa_printf(MSG_DEBUG, "Failed to load private_key in " 595 "PKCS#12 format: %s", gnutls_strerror(ret)); 596 return -1; 597 } else 598 pkcs12_ok = 1; 599#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */ 600#endif /* PKCS12_FUNCS */ 601 602 if (!pkcs12_ok) { 603 wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not " 604 "included"); 605 return -1; 606 } 607 } 608 609 conn->params_set = 1; 610 611 ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE, 612 conn->xcred); 613 if (ret < 0) { 614 wpa_printf(MSG_INFO, "Failed to configure credentials: %s", 615 gnutls_strerror(ret)); 616 } 617 618 return ret; 619} 620 621 622int tls_global_set_params(void *tls_ctx, 623 const struct tls_connection_params *params) 624{ 625 struct tls_global *global = tls_ctx; 626 int ret; 627 628 /* Currently, global parameters are only set when running in server 629 * mode. */ 630 global->server = 1; 631 632 if (global->params_set) { 633 gnutls_certificate_free_credentials(global->xcred); 634 global->params_set = 0; 635 } 636 637 ret = gnutls_certificate_allocate_credentials(&global->xcred); 638 if (ret) { 639 wpa_printf(MSG_DEBUG, "Failed to allocate global credentials " 640 "%s", gnutls_strerror(ret)); 641 return -1; 642 } 643 644 if (params->ca_cert) { 645 ret = gnutls_certificate_set_x509_trust_file( 646 global->xcred, params->ca_cert, GNUTLS_X509_FMT_PEM); 647 if (ret < 0) { 648 wpa_printf(MSG_DEBUG, "Failed to read CA cert '%s' " 649 "in PEM format: %s", params->ca_cert, 650 gnutls_strerror(ret)); 651 ret = gnutls_certificate_set_x509_trust_file( 652 global->xcred, params->ca_cert, 653 GNUTLS_X509_FMT_DER); 654 if (ret < 0) { 655 wpa_printf(MSG_DEBUG, "Failed to read CA cert " 656 "'%s' in DER format: %s", 657 params->ca_cert, 658 gnutls_strerror(ret)); 659 goto fail; 660 } 661 } 662 663 if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) { 664 gnutls_certificate_set_verify_flags( 665 global->xcred, 666 GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5); 667 } 668 669#if LIBGNUTLS_VERSION_NUMBER >= 0x020800 670 if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) { 671 gnutls_certificate_set_verify_flags( 672 global->xcred, 673 GNUTLS_VERIFY_DISABLE_TIME_CHECKS); 674 } 675#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x020800 */ 676 } 677 678 if (params->client_cert && params->private_key) { 679 /* TODO: private_key_passwd? */ 680 ret = gnutls_certificate_set_x509_key_file( 681 global->xcred, params->client_cert, 682 params->private_key, GNUTLS_X509_FMT_PEM); 683 if (ret < 0) { 684 wpa_printf(MSG_DEBUG, "Failed to read client cert/key " 685 "in PEM format: %s", gnutls_strerror(ret)); 686 ret = gnutls_certificate_set_x509_key_file( 687 global->xcred, params->client_cert, 688 params->private_key, GNUTLS_X509_FMT_DER); 689 if (ret < 0) { 690 wpa_printf(MSG_DEBUG, "Failed to read client " 691 "cert/key in DER format: %s", 692 gnutls_strerror(ret)); 693 goto fail; 694 } 695 } 696 } else if (params->private_key) { 697 int pkcs12_ok = 0; 698#ifdef PKCS12_FUNCS 699 /* Try to load in PKCS#12 format */ 700#if LIBGNUTLS_VERSION_NUMBER >= 0x010302 701 ret = gnutls_certificate_set_x509_simple_pkcs12_file( 702 global->xcred, params->private_key, 703 GNUTLS_X509_FMT_DER, params->private_key_passwd); 704 if (ret != 0) { 705 wpa_printf(MSG_DEBUG, "Failed to load private_key in " 706 "PKCS#12 format: %s", gnutls_strerror(ret)); 707 goto fail; 708 } else 709 pkcs12_ok = 1; 710#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */ 711#endif /* PKCS12_FUNCS */ 712 713 if (!pkcs12_ok) { 714 wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not " 715 "included"); 716 goto fail; 717 } 718 } 719 720 global->params_set = 1; 721 722 return 0; 723 724fail: 725 gnutls_certificate_free_credentials(global->xcred); 726 return -1; 727} 728 729 730int tls_global_set_verify(void *ssl_ctx, int check_crl) 731{ 732 /* TODO */ 733 return 0; 734} 735 736 737int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn, 738 int verify_peer) 739{ 740 if (conn == NULL || conn->session == NULL) 741 return -1; 742 743 conn->verify_peer = verify_peer; 744 gnutls_certificate_server_set_request(conn->session, 745 verify_peer ? GNUTLS_CERT_REQUIRE 746 : GNUTLS_CERT_REQUEST); 747 748 return 0; 749} 750 751 752int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn, 753 struct tls_keys *keys) 754{ 755#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK 756 security_parameters_st *sec; 757#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */ 758 759 if (conn == NULL || conn->session == NULL || keys == NULL) 760 return -1; 761 762 os_memset(keys, 0, sizeof(*keys)); 763 764#if LIBGNUTLS_VERSION_NUMBER < 0x020c00 765#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK 766 sec = &conn->session->security_parameters; 767 keys->master_key = sec->master_secret; 768 keys->master_key_len = WPA_TLS_MASTER_SIZE; 769 keys->client_random = sec->client_random; 770 keys->server_random = sec->server_random; 771#else /* GNUTLS_INTERNAL_STRUCTURE_HACK */ 772 keys->client_random = 773 (u8 *) gnutls_session_get_client_random(conn->session); 774 keys->server_random = 775 (u8 *) gnutls_session_get_server_random(conn->session); 776 /* No access to master_secret */ 777#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */ 778#endif /* LIBGNUTLS_VERSION_NUMBER < 0x020c00 */ 779 780#if LIBGNUTLS_VERSION_NUMBER < 0x020c00 781 keys->client_random_len = WPA_TLS_RANDOM_SIZE; 782 keys->server_random_len = WPA_TLS_RANDOM_SIZE; 783#endif /* LIBGNUTLS_VERSION_NUMBER < 0x020c00 */ 784 785 return 0; 786} 787 788 789int tls_connection_prf(void *tls_ctx, struct tls_connection *conn, 790 const char *label, int server_random_first, 791 u8 *out, size_t out_len) 792{ 793#if LIBGNUTLS_VERSION_NUMBER >= 0x010302 794 if (conn == NULL || conn->session == NULL) 795 return -1; 796 797 return gnutls_prf(conn->session, os_strlen(label), label, 798 server_random_first, 0, NULL, out_len, (char *) out); 799#else /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */ 800 return -1; 801#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */ 802} 803 804 805static int tls_connection_verify_peer(struct tls_connection *conn, 806 gnutls_alert_description_t *err) 807{ 808 unsigned int status, num_certs, i; 809 struct os_time now; 810 const gnutls_datum_t *certs; 811 gnutls_x509_crt_t cert; 812 813 if (gnutls_certificate_verify_peers2(conn->session, &status) < 0) { 814 wpa_printf(MSG_INFO, "TLS: Failed to verify peer " 815 "certificate chain"); 816 *err = GNUTLS_A_INTERNAL_ERROR; 817 return -1; 818 } 819 820 if (conn->verify_peer && (status & GNUTLS_CERT_INVALID)) { 821 wpa_printf(MSG_INFO, "TLS: Peer certificate not trusted"); 822 *err = GNUTLS_A_INTERNAL_ERROR; 823 if (status & GNUTLS_CERT_INSECURE_ALGORITHM) { 824 wpa_printf(MSG_INFO, "TLS: Certificate uses insecure " 825 "algorithm"); 826 *err = GNUTLS_A_INSUFFICIENT_SECURITY; 827 } 828#if LIBGNUTLS_VERSION_NUMBER >= 0x020800 829 if (status & GNUTLS_CERT_NOT_ACTIVATED) { 830 wpa_printf(MSG_INFO, "TLS: Certificate not yet " 831 "activated"); 832 *err = GNUTLS_A_CERTIFICATE_EXPIRED; 833 } 834 if (status & GNUTLS_CERT_EXPIRED) { 835 wpa_printf(MSG_INFO, "TLS: Certificate expired"); 836 *err = GNUTLS_A_CERTIFICATE_EXPIRED; 837 } 838#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x020800 */ 839 return -1; 840 } 841 842 if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) { 843 wpa_printf(MSG_INFO, "TLS: Peer certificate does not have a " 844 "known issuer"); 845 *err = GNUTLS_A_UNKNOWN_CA; 846 return -1; 847 } 848 849 if (status & GNUTLS_CERT_REVOKED) { 850 wpa_printf(MSG_INFO, "TLS: Peer certificate has been revoked"); 851 *err = GNUTLS_A_CERTIFICATE_REVOKED; 852 return -1; 853 } 854 855 os_get_time(&now); 856 857 certs = gnutls_certificate_get_peers(conn->session, &num_certs); 858 if (certs == NULL) { 859 wpa_printf(MSG_INFO, "TLS: No peer certificate chain " 860 "received"); 861 *err = GNUTLS_A_UNKNOWN_CA; 862 return -1; 863 } 864 865 for (i = 0; i < num_certs; i++) { 866 char *buf; 867 size_t len; 868 if (gnutls_x509_crt_init(&cert) < 0) { 869 wpa_printf(MSG_INFO, "TLS: Certificate initialization " 870 "failed"); 871 *err = GNUTLS_A_BAD_CERTIFICATE; 872 return -1; 873 } 874 875 if (gnutls_x509_crt_import(cert, &certs[i], 876 GNUTLS_X509_FMT_DER) < 0) { 877 wpa_printf(MSG_INFO, "TLS: Could not parse peer " 878 "certificate %d/%d", i + 1, num_certs); 879 gnutls_x509_crt_deinit(cert); 880 *err = GNUTLS_A_BAD_CERTIFICATE; 881 return -1; 882 } 883 884 gnutls_x509_crt_get_dn(cert, NULL, &len); 885 len++; 886 buf = os_malloc(len + 1); 887 if (buf) { 888 buf[0] = buf[len] = '\0'; 889 gnutls_x509_crt_get_dn(cert, buf, &len); 890 } 891 wpa_printf(MSG_DEBUG, "TLS: Peer cert chain %d/%d: %s", 892 i + 1, num_certs, buf); 893 894 if (i == 0) { 895 /* TODO: validate subject_match and altsubject_match */ 896 } 897 898 os_free(buf); 899 900 if (gnutls_x509_crt_get_expiration_time(cert) < now.sec || 901 gnutls_x509_crt_get_activation_time(cert) > now.sec) { 902 wpa_printf(MSG_INFO, "TLS: Peer certificate %d/%d is " 903 "not valid at this time", 904 i + 1, num_certs); 905 gnutls_x509_crt_deinit(cert); 906 *err = GNUTLS_A_CERTIFICATE_EXPIRED; 907 return -1; 908 } 909 910 gnutls_x509_crt_deinit(cert); 911 } 912 913 return 0; 914} 915 916 917static struct wpabuf * gnutls_get_appl_data(struct tls_connection *conn) 918{ 919 int res; 920 struct wpabuf *ad; 921 wpa_printf(MSG_DEBUG, "GnuTLS: Check for possible Application Data"); 922 ad = wpabuf_alloc((wpabuf_len(conn->pull_buf) + 500) * 3); 923 if (ad == NULL) 924 return NULL; 925 926 res = gnutls_record_recv(conn->session, wpabuf_mhead(ad), 927 wpabuf_size(ad)); 928 wpa_printf(MSG_DEBUG, "GnuTLS: gnutls_record_recv: %d", res); 929 if (res < 0) { 930 wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d " 931 "(%s)", __func__, (int) res, 932 gnutls_strerror(res)); 933 wpabuf_free(ad); 934 return NULL; 935 } 936 937 wpabuf_put(ad, res); 938 wpa_printf(MSG_DEBUG, "GnuTLS: Received %d bytes of Application Data", 939 res); 940 return ad; 941} 942 943 944struct wpabuf * tls_connection_handshake(void *tls_ctx, 945 struct tls_connection *conn, 946 const struct wpabuf *in_data, 947 struct wpabuf **appl_data) 948{ 949 struct tls_global *global = tls_ctx; 950 struct wpabuf *out_data; 951 int ret; 952 953 if (appl_data) 954 *appl_data = NULL; 955 956 if (in_data && wpabuf_len(in_data) > 0) { 957 if (conn->pull_buf) { 958 wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in " 959 "pull_buf", __func__, 960 (unsigned long) wpabuf_len(conn->pull_buf)); 961 wpabuf_free(conn->pull_buf); 962 } 963 conn->pull_buf = wpabuf_dup(in_data); 964 if (conn->pull_buf == NULL) 965 return NULL; 966 conn->pull_buf_offset = wpabuf_head(conn->pull_buf); 967 } 968 969 ret = gnutls_handshake(conn->session); 970 if (ret < 0) { 971 switch (ret) { 972 case GNUTLS_E_AGAIN: 973 if (global->server && conn->established && 974 conn->push_buf == NULL) { 975 /* Need to return something to trigger 976 * completion of EAP-TLS. */ 977 conn->push_buf = wpabuf_alloc(0); 978 } 979 break; 980 case GNUTLS_E_FATAL_ALERT_RECEIVED: 981 wpa_printf(MSG_DEBUG, "%s - received fatal '%s' alert", 982 __func__, gnutls_alert_get_name( 983 gnutls_alert_get(conn->session))); 984 conn->read_alerts++; 985 /* continue */ 986 default: 987 wpa_printf(MSG_DEBUG, "%s - gnutls_handshake failed " 988 "-> %s", __func__, gnutls_strerror(ret)); 989 conn->failed++; 990 } 991 } else { 992 size_t size; 993 gnutls_alert_description_t err; 994 995 if (conn->verify_peer && 996 tls_connection_verify_peer(conn, &err)) { 997 wpa_printf(MSG_INFO, "TLS: Peer certificate chain " 998 "failed validation"); 999 conn->failed++; 1000 gnutls_alert_send(conn->session, GNUTLS_AL_FATAL, err); 1001 goto out; 1002 } 1003 1004 wpa_printf(MSG_DEBUG, "TLS: Handshake completed successfully"); 1005 conn->established = 1; 1006 if (conn->push_buf == NULL) { 1007 /* Need to return something to get final TLS ACK. */ 1008 conn->push_buf = wpabuf_alloc(0); 1009 } 1010 1011 gnutls_session_get_data(conn->session, NULL, &size); 1012 if (global->session_data == NULL || 1013 global->session_data_size < size) { 1014 os_free(global->session_data); 1015 global->session_data = os_malloc(size); 1016 } 1017 if (global->session_data) { 1018 global->session_data_size = size; 1019 gnutls_session_get_data(conn->session, 1020 global->session_data, 1021 &global->session_data_size); 1022 } 1023 1024 if (conn->pull_buf && appl_data) 1025 *appl_data = gnutls_get_appl_data(conn); 1026 } 1027 1028out: 1029 out_data = conn->push_buf; 1030 conn->push_buf = NULL; 1031 return out_data; 1032} 1033 1034 1035struct wpabuf * tls_connection_server_handshake(void *tls_ctx, 1036 struct tls_connection *conn, 1037 const struct wpabuf *in_data, 1038 struct wpabuf **appl_data) 1039{ 1040 return tls_connection_handshake(tls_ctx, conn, in_data, appl_data); 1041} 1042 1043 1044struct wpabuf * tls_connection_encrypt(void *tls_ctx, 1045 struct tls_connection *conn, 1046 const struct wpabuf *in_data) 1047{ 1048 ssize_t res; 1049 struct wpabuf *buf; 1050 1051 res = gnutls_record_send(conn->session, wpabuf_head(in_data), 1052 wpabuf_len(in_data)); 1053 if (res < 0) { 1054 wpa_printf(MSG_INFO, "%s: Encryption failed: %s", 1055 __func__, gnutls_strerror(res)); 1056 return NULL; 1057 } 1058 1059 buf = conn->push_buf; 1060 conn->push_buf = NULL; 1061 return buf; 1062} 1063 1064 1065struct wpabuf * tls_connection_decrypt(void *tls_ctx, 1066 struct tls_connection *conn, 1067 const struct wpabuf *in_data) 1068{ 1069 ssize_t res; 1070 struct wpabuf *out; 1071 1072 if (conn->pull_buf) { 1073 wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in " 1074 "pull_buf", __func__, 1075 (unsigned long) wpabuf_len(conn->pull_buf)); 1076 wpabuf_free(conn->pull_buf); 1077 } 1078 conn->pull_buf = wpabuf_dup(in_data); 1079 if (conn->pull_buf == NULL) 1080 return NULL; 1081 conn->pull_buf_offset = wpabuf_head(conn->pull_buf); 1082 1083 /* 1084 * Even though we try to disable TLS compression, it is possible that 1085 * this cannot be done with all TLS libraries. Add extra buffer space 1086 * to handle the possibility of the decrypted data being longer than 1087 * input data. 1088 */ 1089 out = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3); 1090 if (out == NULL) 1091 return NULL; 1092 1093 res = gnutls_record_recv(conn->session, wpabuf_mhead(out), 1094 wpabuf_size(out)); 1095 if (res < 0) { 1096 wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d " 1097 "(%s)", __func__, (int) res, gnutls_strerror(res)); 1098 wpabuf_free(out); 1099 return NULL; 1100 } 1101 wpabuf_put(out, res); 1102 1103 return out; 1104} 1105 1106 1107int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn) 1108{ 1109 if (conn == NULL) 1110 return 0; 1111 return gnutls_session_is_resumed(conn->session); 1112} 1113 1114 1115int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn, 1116 u8 *ciphers) 1117{ 1118 /* TODO */ 1119 return -1; 1120} 1121 1122 1123int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn, 1124 char *buf, size_t buflen) 1125{ 1126 /* TODO */ 1127 buf[0] = '\0'; 1128 return 0; 1129} 1130 1131 1132int tls_connection_enable_workaround(void *ssl_ctx, 1133 struct tls_connection *conn) 1134{ 1135 gnutls_record_disable_padding(conn->session); 1136 return 0; 1137} 1138 1139 1140int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn, 1141 int ext_type, const u8 *data, 1142 size_t data_len) 1143{ 1144 /* TODO */ 1145 return -1; 1146} 1147 1148 1149int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn) 1150{ 1151 if (conn == NULL) 1152 return -1; 1153 return conn->failed; 1154} 1155 1156 1157int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn) 1158{ 1159 if (conn == NULL) 1160 return -1; 1161 return conn->read_alerts; 1162} 1163 1164 1165int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn) 1166{ 1167 if (conn == NULL) 1168 return -1; 1169 return conn->write_alerts; 1170} 1171 1172 1173int tls_connection_get_keyblock_size(void *tls_ctx, 1174 struct tls_connection *conn) 1175{ 1176 /* TODO */ 1177 return -1; 1178} 1179 1180 1181unsigned int tls_capabilities(void *tls_ctx) 1182{ 1183 return 0; 1184} 1185 1186 1187int tls_connection_set_session_ticket_cb(void *tls_ctx, 1188 struct tls_connection *conn, 1189 tls_session_ticket_cb cb, void *ctx) 1190{ 1191 return -1; 1192} 1193