$search
00001 /* 00002 * SSL/TLS interface functions for GnuTLS 00003 * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi> 00004 * 00005 * This program is free software; you can redistribute it and/or modify 00006 * it under the terms of the GNU General Public License version 2 as 00007 * published by the Free Software Foundation. 00008 * 00009 * Alternatively, this software may be distributed under the terms of BSD 00010 * license. 00011 * 00012 * See README and COPYING for more details. 00013 */ 00014 00015 #include "includes.h" 00016 #include <gnutls/gnutls.h> 00017 #include <gnutls/x509.h> 00018 #ifdef PKCS12_FUNCS 00019 #include <gnutls/pkcs12.h> 00020 #endif /* PKCS12_FUNCS */ 00021 00022 #ifdef CONFIG_GNUTLS_EXTRA 00023 #if LIBGNUTLS_VERSION_NUMBER >= 0x010302 00024 #define GNUTLS_IA 00025 #include <gnutls/extra.h> 00026 #if LIBGNUTLS_VERSION_NUMBER == 0x010302 00027 /* This function is not included in the current gnutls/extra.h even though it 00028 * should be, so define it here as a workaround for the time being. */ 00029 int gnutls_ia_verify_endphase(gnutls_session_t session, char *checksum); 00030 #endif /* LIBGNUTLS_VERSION_NUMBER == 0x010302 */ 00031 #endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */ 00032 #endif /* CONFIG_GNUTLS_EXTRA */ 00033 00034 #include "common.h" 00035 #include "tls.h" 00036 00037 00038 #ifndef TLS_RANDOM_SIZE 00039 #define TLS_RANDOM_SIZE 32 00040 #endif 00041 #ifndef TLS_MASTER_SIZE 00042 #define TLS_MASTER_SIZE 48 00043 #endif 00044 00045 00046 #if LIBGNUTLS_VERSION_NUMBER < 0x010302 00047 /* GnuTLS 1.3.2 added functions for using master secret. Older versions require 00048 * use of internal structures to get the master_secret and 00049 * {server,client}_random. 00050 */ 00051 #define GNUTLS_INTERNAL_STRUCTURE_HACK 00052 #endif /* LIBGNUTLS_VERSION_NUMBER < 0x010302 */ 00053 00054 00055 #ifdef GNUTLS_INTERNAL_STRUCTURE_HACK 00056 /* 00057 * It looks like gnutls does not provide access to client/server_random and 00058 * master_key. This is somewhat unfortunate since these are needed for key 00059 * derivation in EAP-{TLS,TTLS,PEAP,FAST}. Workaround for now is a horrible 00060 * hack that copies the gnutls_session_int definition from gnutls_int.h so that 00061 * we can get the needed information. 00062 */ 00063 00064 typedef u8 uint8; 00065 typedef unsigned char opaque; 00066 typedef struct { 00067 uint8 suite[2]; 00068 } cipher_suite_st; 00069 00070 typedef struct { 00071 gnutls_connection_end_t entity; 00072 gnutls_kx_algorithm_t kx_algorithm; 00073 gnutls_cipher_algorithm_t read_bulk_cipher_algorithm; 00074 gnutls_mac_algorithm_t read_mac_algorithm; 00075 gnutls_compression_method_t read_compression_algorithm; 00076 gnutls_cipher_algorithm_t write_bulk_cipher_algorithm; 00077 gnutls_mac_algorithm_t write_mac_algorithm; 00078 gnutls_compression_method_t write_compression_algorithm; 00079 cipher_suite_st current_cipher_suite; 00080 opaque master_secret[TLS_MASTER_SIZE]; 00081 opaque client_random[TLS_RANDOM_SIZE]; 00082 opaque server_random[TLS_RANDOM_SIZE]; 00083 /* followed by stuff we are not interested in */ 00084 } security_parameters_st; 00085 00086 struct gnutls_session_int { 00087 security_parameters_st security_parameters; 00088 /* followed by things we are not interested in */ 00089 }; 00090 #endif /* LIBGNUTLS_VERSION_NUMBER < 0x010302 */ 00091 00092 static int tls_gnutls_ref_count = 0; 00093 00094 struct tls_global { 00095 /* Data for session resumption */ 00096 void *session_data; 00097 size_t session_data_size; 00098 00099 int server; 00100 00101 int params_set; 00102 gnutls_certificate_credentials_t xcred; 00103 }; 00104 00105 struct tls_connection { 00106 gnutls_session session; 00107 char *subject_match, *altsubject_match; 00108 int read_alerts, write_alerts, failed; 00109 00110 u8 *pre_shared_secret; 00111 size_t pre_shared_secret_len; 00112 int established; 00113 int verify_peer; 00114 00115 struct wpabuf *push_buf; 00116 struct wpabuf *pull_buf; 00117 const u8 *pull_buf_offset; 00118 00119 int params_set; 00120 gnutls_certificate_credentials_t xcred; 00121 00122 int tls_ia; 00123 int final_phase_finished; 00124 00125 #ifdef GNUTLS_IA 00126 gnutls_ia_server_credentials_t iacred_srv; 00127 gnutls_ia_client_credentials_t iacred_cli; 00128 00129 /* Session keys generated in the current phase for inner secret 00130 * permutation before generating/verifying PhaseFinished. */ 00131 u8 *session_keys; 00132 size_t session_keys_len; 00133 00134 u8 inner_secret[TLS_MASTER_SIZE]; 00135 #endif /* GNUTLS_IA */ 00136 }; 00137 00138 00139 static void tls_log_func(int level, const char *msg) 00140 { 00141 char *s, *pos; 00142 if (level == 6 || level == 7) { 00143 /* These levels seem to be mostly I/O debug and msg dumps */ 00144 return; 00145 } 00146 00147 s = os_strdup(msg); 00148 if (s == NULL) 00149 return; 00150 00151 pos = s; 00152 while (*pos != '\0') { 00153 if (*pos == '\n') { 00154 *pos = '\0'; 00155 break; 00156 } 00157 pos++; 00158 } 00159 wpa_printf(level > 3 ? MSG_MSGDUMP : MSG_DEBUG, 00160 "gnutls<%d> %s", level, s); 00161 os_free(s); 00162 } 00163 00164 00165 extern int wpa_debug_show_keys; 00166 00167 void * tls_init(const struct tls_config *conf) 00168 { 00169 struct tls_global *global; 00170 00171 #ifdef GNUTLS_INTERNAL_STRUCTURE_HACK 00172 /* Because of the horrible hack to get master_secret and client/server 00173 * random, we need to make sure that the gnutls version is something 00174 * that is expected to have same structure definition for the session 00175 * data.. */ 00176 const char *ver; 00177 const char *ok_ver[] = { "1.2.3", "1.2.4", "1.2.5", "1.2.6", "1.2.9", 00178 "1.3.2", 00179 NULL }; 00180 int i; 00181 #endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */ 00182 00183 global = os_zalloc(sizeof(*global)); 00184 if (global == NULL) 00185 return NULL; 00186 00187 if (tls_gnutls_ref_count == 0 && gnutls_global_init() < 0) { 00188 os_free(global); 00189 return NULL; 00190 } 00191 tls_gnutls_ref_count++; 00192 00193 #ifdef GNUTLS_INTERNAL_STRUCTURE_HACK 00194 ver = gnutls_check_version(NULL); 00195 if (ver == NULL) { 00196 tls_deinit(global); 00197 return NULL; 00198 } 00199 wpa_printf(MSG_DEBUG, "%s - gnutls version %s", __func__, ver); 00200 for (i = 0; ok_ver[i]; i++) { 00201 if (strcmp(ok_ver[i], ver) == 0) 00202 break; 00203 } 00204 if (ok_ver[i] == NULL) { 00205 wpa_printf(MSG_INFO, "Untested gnutls version %s - this needs " 00206 "to be tested and enabled in tls_gnutls.c", ver); 00207 tls_deinit(global); 00208 return NULL; 00209 } 00210 #endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */ 00211 00212 gnutls_global_set_log_function(tls_log_func); 00213 if (wpa_debug_show_keys) 00214 gnutls_global_set_log_level(11); 00215 return global; 00216 } 00217 00218 00219 void tls_deinit(void *ssl_ctx) 00220 { 00221 struct tls_global *global = ssl_ctx; 00222 if (global) { 00223 if (global->params_set) 00224 gnutls_certificate_free_credentials(global->xcred); 00225 os_free(global->session_data); 00226 os_free(global); 00227 } 00228 00229 tls_gnutls_ref_count--; 00230 if (tls_gnutls_ref_count == 0) 00231 gnutls_global_deinit(); 00232 } 00233 00234 00235 int tls_get_errors(void *ssl_ctx) 00236 { 00237 return 0; 00238 } 00239 00240 00241 static ssize_t tls_pull_func(gnutls_transport_ptr ptr, void *buf, 00242 size_t len) 00243 { 00244 struct tls_connection *conn = (struct tls_connection *) ptr; 00245 const u8 *end; 00246 if (conn->pull_buf == NULL) { 00247 errno = EWOULDBLOCK; 00248 return -1; 00249 } 00250 00251 end = wpabuf_head_u8(conn->pull_buf) + wpabuf_len(conn->pull_buf); 00252 if ((size_t) (end - conn->pull_buf_offset) < len) 00253 len = end - conn->pull_buf_offset; 00254 os_memcpy(buf, conn->pull_buf_offset, len); 00255 conn->pull_buf_offset += len; 00256 if (conn->pull_buf_offset == end) { 00257 wpa_printf(MSG_DEBUG, "%s - pull_buf consumed", __func__); 00258 wpabuf_free(conn->pull_buf); 00259 conn->pull_buf = NULL; 00260 conn->pull_buf_offset = NULL; 00261 } else { 00262 wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in pull_buf", 00263 __func__, 00264 (unsigned long) (end - conn->pull_buf_offset)); 00265 } 00266 return len; 00267 } 00268 00269 00270 static ssize_t tls_push_func(gnutls_transport_ptr ptr, const void *buf, 00271 size_t len) 00272 { 00273 struct tls_connection *conn = (struct tls_connection *) ptr; 00274 00275 if (wpabuf_resize(&conn->push_buf, len) < 0) { 00276 errno = ENOMEM; 00277 return -1; 00278 } 00279 wpabuf_put_data(conn->push_buf, buf, len); 00280 00281 return len; 00282 } 00283 00284 00285 static int tls_gnutls_init_session(struct tls_global *global, 00286 struct tls_connection *conn) 00287 { 00288 const int cert_types[2] = { GNUTLS_CRT_X509, 0 }; 00289 const int protos[2] = { GNUTLS_TLS1, 0 }; 00290 int ret; 00291 00292 ret = gnutls_init(&conn->session, 00293 global->server ? GNUTLS_SERVER : GNUTLS_CLIENT); 00294 if (ret < 0) { 00295 wpa_printf(MSG_INFO, "TLS: Failed to initialize new TLS " 00296 "connection: %s", gnutls_strerror(ret)); 00297 return -1; 00298 } 00299 00300 ret = gnutls_set_default_priority(conn->session); 00301 if (ret < 0) 00302 goto fail; 00303 00304 ret = gnutls_certificate_type_set_priority(conn->session, cert_types); 00305 if (ret < 0) 00306 goto fail; 00307 00308 ret = gnutls_protocol_set_priority(conn->session, protos); 00309 if (ret < 0) 00310 goto fail; 00311 00312 gnutls_transport_set_pull_function(conn->session, tls_pull_func); 00313 gnutls_transport_set_push_function(conn->session, tls_push_func); 00314 gnutls_transport_set_ptr(conn->session, (gnutls_transport_ptr) conn); 00315 00316 return 0; 00317 00318 fail: 00319 wpa_printf(MSG_INFO, "TLS: Failed to setup new TLS connection: %s", 00320 gnutls_strerror(ret)); 00321 gnutls_deinit(conn->session); 00322 return -1; 00323 } 00324 00325 00326 struct tls_connection * tls_connection_init(void *ssl_ctx) 00327 { 00328 struct tls_global *global = ssl_ctx; 00329 struct tls_connection *conn; 00330 int ret; 00331 00332 conn = os_zalloc(sizeof(*conn)); 00333 if (conn == NULL) 00334 return NULL; 00335 00336 if (tls_gnutls_init_session(global, conn)) { 00337 os_free(conn); 00338 return NULL; 00339 } 00340 00341 if (global->params_set) { 00342 ret = gnutls_credentials_set(conn->session, 00343 GNUTLS_CRD_CERTIFICATE, 00344 global->xcred); 00345 if (ret < 0) { 00346 wpa_printf(MSG_INFO, "Failed to configure " 00347 "credentials: %s", gnutls_strerror(ret)); 00348 os_free(conn); 00349 return NULL; 00350 } 00351 } 00352 00353 if (gnutls_certificate_allocate_credentials(&conn->xcred)) { 00354 os_free(conn); 00355 return NULL; 00356 } 00357 00358 return conn; 00359 } 00360 00361 00362 void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn) 00363 { 00364 if (conn == NULL) 00365 return; 00366 00367 #ifdef GNUTLS_IA 00368 if (conn->iacred_srv) 00369 gnutls_ia_free_server_credentials(conn->iacred_srv); 00370 if (conn->iacred_cli) 00371 gnutls_ia_free_client_credentials(conn->iacred_cli); 00372 if (conn->session_keys) { 00373 os_memset(conn->session_keys, 0, conn->session_keys_len); 00374 os_free(conn->session_keys); 00375 } 00376 #endif /* GNUTLS_IA */ 00377 00378 gnutls_certificate_free_credentials(conn->xcred); 00379 gnutls_deinit(conn->session); 00380 os_free(conn->pre_shared_secret); 00381 os_free(conn->subject_match); 00382 os_free(conn->altsubject_match); 00383 wpabuf_free(conn->push_buf); 00384 wpabuf_free(conn->pull_buf); 00385 os_free(conn); 00386 } 00387 00388 00389 int tls_connection_established(void *ssl_ctx, struct tls_connection *conn) 00390 { 00391 return conn ? conn->established : 0; 00392 } 00393 00394 00395 int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn) 00396 { 00397 struct tls_global *global = ssl_ctx; 00398 int ret; 00399 00400 if (conn == NULL) 00401 return -1; 00402 00403 /* Shutdown previous TLS connection without notifying the peer 00404 * because the connection was already terminated in practice 00405 * and "close notify" shutdown alert would confuse AS. */ 00406 gnutls_bye(conn->session, GNUTLS_SHUT_RDWR); 00407 wpabuf_free(conn->push_buf); 00408 conn->push_buf = NULL; 00409 conn->established = 0; 00410 conn->final_phase_finished = 0; 00411 #ifdef GNUTLS_IA 00412 if (conn->session_keys) { 00413 os_memset(conn->session_keys, 0, conn->session_keys_len); 00414 os_free(conn->session_keys); 00415 } 00416 conn->session_keys_len = 0; 00417 #endif /* GNUTLS_IA */ 00418 00419 gnutls_deinit(conn->session); 00420 if (tls_gnutls_init_session(global, conn)) { 00421 wpa_printf(MSG_INFO, "GnuTLS: Failed to preparare new session " 00422 "for session resumption use"); 00423 return -1; 00424 } 00425 00426 ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE, 00427 conn->params_set ? conn->xcred : 00428 global->xcred); 00429 if (ret < 0) { 00430 wpa_printf(MSG_INFO, "GnuTLS: Failed to configure credentials " 00431 "for session resumption: %s", gnutls_strerror(ret)); 00432 return -1; 00433 } 00434 00435 if (global->session_data) { 00436 ret = gnutls_session_set_data(conn->session, 00437 global->session_data, 00438 global->session_data_size); 00439 if (ret < 0) { 00440 wpa_printf(MSG_INFO, "GnuTLS: Failed to set session " 00441 "data: %s", gnutls_strerror(ret)); 00442 return -1; 00443 } 00444 } 00445 00446 return 0; 00447 } 00448 00449 00450 #if 0 00451 static int tls_match_altsubject(X509 *cert, const char *match) 00452 { 00453 GENERAL_NAME *gen; 00454 char *field, *tmp; 00455 void *ext; 00456 int i, found = 0; 00457 size_t len; 00458 00459 ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); 00460 00461 for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) { 00462 gen = sk_GENERAL_NAME_value(ext, i); 00463 switch (gen->type) { 00464 case GEN_EMAIL: 00465 field = "EMAIL"; 00466 break; 00467 case GEN_DNS: 00468 field = "DNS"; 00469 break; 00470 case GEN_URI: 00471 field = "URI"; 00472 break; 00473 default: 00474 field = NULL; 00475 wpa_printf(MSG_DEBUG, "TLS: altSubjectName: " 00476 "unsupported type=%d", gen->type); 00477 break; 00478 } 00479 00480 if (!field) 00481 continue; 00482 00483 wpa_printf(MSG_DEBUG, "TLS: altSubjectName: %s:%s", 00484 field, gen->d.ia5->data); 00485 len = os_strlen(field) + 1 + 00486 strlen((char *) gen->d.ia5->data) + 1; 00487 tmp = os_malloc(len); 00488 if (tmp == NULL) 00489 continue; 00490 snprintf(tmp, len, "%s:%s", field, gen->d.ia5->data); 00491 if (strstr(tmp, match)) 00492 found++; 00493 os_free(tmp); 00494 } 00495 00496 return found; 00497 } 00498 #endif 00499 00500 00501 #if 0 00502 static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx) 00503 { 00504 char buf[256]; 00505 X509 *err_cert; 00506 int err, depth; 00507 SSL *ssl; 00508 struct tls_connection *conn; 00509 char *match, *altmatch; 00510 00511 err_cert = X509_STORE_CTX_get_current_cert(x509_ctx); 00512 err = X509_STORE_CTX_get_error(x509_ctx); 00513 depth = X509_STORE_CTX_get_error_depth(x509_ctx); 00514 ssl = X509_STORE_CTX_get_ex_data(x509_ctx, 00515 SSL_get_ex_data_X509_STORE_CTX_idx()); 00516 X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf)); 00517 00518 conn = SSL_get_app_data(ssl); 00519 match = conn ? conn->subject_match : NULL; 00520 altmatch = conn ? conn->altsubject_match : NULL; 00521 00522 if (!preverify_ok) { 00523 wpa_printf(MSG_WARNING, "TLS: Certificate verification failed," 00524 " error %d (%s) depth %d for '%s'", err, 00525 X509_verify_cert_error_string(err), depth, buf); 00526 } else { 00527 wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb - " 00528 "preverify_ok=%d err=%d (%s) depth=%d buf='%s'", 00529 preverify_ok, err, 00530 X509_verify_cert_error_string(err), depth, buf); 00531 if (depth == 0 && match && strstr(buf, match) == NULL) { 00532 wpa_printf(MSG_WARNING, "TLS: Subject '%s' did not " 00533 "match with '%s'", buf, match); 00534 preverify_ok = 0; 00535 } else if (depth == 0 && altmatch && 00536 !tls_match_altsubject(err_cert, altmatch)) { 00537 wpa_printf(MSG_WARNING, "TLS: altSubjectName match " 00538 "'%s' not found", altmatch); 00539 preverify_ok = 0; 00540 } 00541 } 00542 00543 return preverify_ok; 00544 } 00545 #endif 00546 00547 00548 int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, 00549 const struct tls_connection_params *params) 00550 { 00551 int ret; 00552 00553 if (conn == NULL || params == NULL) 00554 return -1; 00555 00556 os_free(conn->subject_match); 00557 conn->subject_match = NULL; 00558 if (params->subject_match) { 00559 conn->subject_match = os_strdup(params->subject_match); 00560 if (conn->subject_match == NULL) 00561 return -1; 00562 } 00563 00564 os_free(conn->altsubject_match); 00565 conn->altsubject_match = NULL; 00566 if (params->altsubject_match) { 00567 conn->altsubject_match = os_strdup(params->altsubject_match); 00568 if (conn->altsubject_match == NULL) 00569 return -1; 00570 } 00571 00572 /* TODO: gnutls_certificate_set_verify_flags(xcred, flags); 00573 * to force peer validation(?) */ 00574 00575 if (params->ca_cert) { 00576 conn->verify_peer = 1; 00577 ret = gnutls_certificate_set_x509_trust_file( 00578 conn->xcred, params->ca_cert, GNUTLS_X509_FMT_PEM); 00579 if (ret < 0) { 00580 wpa_printf(MSG_DEBUG, "Failed to read CA cert '%s' " 00581 "in PEM format: %s", params->ca_cert, 00582 gnutls_strerror(ret)); 00583 ret = gnutls_certificate_set_x509_trust_file( 00584 conn->xcred, params->ca_cert, 00585 GNUTLS_X509_FMT_DER); 00586 if (ret < 0) { 00587 wpa_printf(MSG_DEBUG, "Failed to read CA cert " 00588 "'%s' in DER format: %s", 00589 params->ca_cert, 00590 gnutls_strerror(ret)); 00591 return -1; 00592 } 00593 } 00594 00595 if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) { 00596 gnutls_certificate_set_verify_flags( 00597 conn->xcred, GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5); 00598 } 00599 00600 if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) { 00601 gnutls_certificate_set_verify_flags( 00602 conn->xcred, 00603 GNUTLS_VERIFY_DISABLE_TIME_CHECKS); 00604 } 00605 } 00606 00607 if (params->client_cert && params->private_key) { 00608 /* TODO: private_key_passwd? */ 00609 ret = gnutls_certificate_set_x509_key_file( 00610 conn->xcred, params->client_cert, params->private_key, 00611 GNUTLS_X509_FMT_PEM); 00612 if (ret < 0) { 00613 wpa_printf(MSG_DEBUG, "Failed to read client cert/key " 00614 "in PEM format: %s", gnutls_strerror(ret)); 00615 ret = gnutls_certificate_set_x509_key_file( 00616 conn->xcred, params->client_cert, 00617 params->private_key, GNUTLS_X509_FMT_DER); 00618 if (ret < 0) { 00619 wpa_printf(MSG_DEBUG, "Failed to read client " 00620 "cert/key in DER format: %s", 00621 gnutls_strerror(ret)); 00622 return ret; 00623 } 00624 } 00625 } else if (params->private_key) { 00626 int pkcs12_ok = 0; 00627 #ifdef PKCS12_FUNCS 00628 /* Try to load in PKCS#12 format */ 00629 #if LIBGNUTLS_VERSION_NUMBER >= 0x010302 00630 ret = gnutls_certificate_set_x509_simple_pkcs12_file( 00631 conn->xcred, params->private_key, GNUTLS_X509_FMT_DER, 00632 params->private_key_passwd); 00633 if (ret != 0) { 00634 wpa_printf(MSG_DEBUG, "Failed to load private_key in " 00635 "PKCS#12 format: %s", gnutls_strerror(ret)); 00636 return -1; 00637 } else 00638 pkcs12_ok = 1; 00639 #endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */ 00640 #endif /* PKCS12_FUNCS */ 00641 00642 if (!pkcs12_ok) { 00643 wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not " 00644 "included"); 00645 return -1; 00646 } 00647 } 00648 00649 conn->tls_ia = params->tls_ia; 00650 conn->params_set = 1; 00651 00652 ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE, 00653 conn->xcred); 00654 if (ret < 0) { 00655 wpa_printf(MSG_INFO, "Failed to configure credentials: %s", 00656 gnutls_strerror(ret)); 00657 } 00658 00659 #ifdef GNUTLS_IA 00660 if (conn->iacred_cli) 00661 gnutls_ia_free_client_credentials(conn->iacred_cli); 00662 00663 ret = gnutls_ia_allocate_client_credentials(&conn->iacred_cli); 00664 if (ret) { 00665 wpa_printf(MSG_DEBUG, "Failed to allocate IA credentials: %s", 00666 gnutls_strerror(ret)); 00667 return -1; 00668 } 00669 00670 ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_IA, 00671 conn->iacred_cli); 00672 if (ret) { 00673 wpa_printf(MSG_DEBUG, "Failed to configure IA credentials: %s", 00674 gnutls_strerror(ret)); 00675 gnutls_ia_free_client_credentials(conn->iacred_cli); 00676 conn->iacred_cli = NULL; 00677 return -1; 00678 } 00679 #endif /* GNUTLS_IE */ 00680 00681 return ret; 00682 } 00683 00684 00685 int tls_global_set_params(void *tls_ctx, 00686 const struct tls_connection_params *params) 00687 { 00688 struct tls_global *global = tls_ctx; 00689 int ret; 00690 00691 /* Currently, global parameters are only set when running in server 00692 * mode. */ 00693 global->server = 1; 00694 00695 if (global->params_set) { 00696 gnutls_certificate_free_credentials(global->xcred); 00697 global->params_set = 0; 00698 } 00699 00700 ret = gnutls_certificate_allocate_credentials(&global->xcred); 00701 if (ret) { 00702 wpa_printf(MSG_DEBUG, "Failed to allocate global credentials " 00703 "%s", gnutls_strerror(ret)); 00704 return -1; 00705 } 00706 00707 if (params->ca_cert) { 00708 ret = gnutls_certificate_set_x509_trust_file( 00709 global->xcred, params->ca_cert, GNUTLS_X509_FMT_PEM); 00710 if (ret < 0) { 00711 wpa_printf(MSG_DEBUG, "Failed to read CA cert '%s' " 00712 "in PEM format: %s", params->ca_cert, 00713 gnutls_strerror(ret)); 00714 ret = gnutls_certificate_set_x509_trust_file( 00715 global->xcred, params->ca_cert, 00716 GNUTLS_X509_FMT_DER); 00717 if (ret < 0) { 00718 wpa_printf(MSG_DEBUG, "Failed to read CA cert " 00719 "'%s' in DER format: %s", 00720 params->ca_cert, 00721 gnutls_strerror(ret)); 00722 goto fail; 00723 } 00724 } 00725 00726 if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) { 00727 gnutls_certificate_set_verify_flags( 00728 global->xcred, 00729 GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5); 00730 } 00731 00732 if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) { 00733 gnutls_certificate_set_verify_flags( 00734 global->xcred, 00735 GNUTLS_VERIFY_DISABLE_TIME_CHECKS); 00736 } 00737 } 00738 00739 if (params->client_cert && params->private_key) { 00740 /* TODO: private_key_passwd? */ 00741 ret = gnutls_certificate_set_x509_key_file( 00742 global->xcred, params->client_cert, 00743 params->private_key, GNUTLS_X509_FMT_PEM); 00744 if (ret < 0) { 00745 wpa_printf(MSG_DEBUG, "Failed to read client cert/key " 00746 "in PEM format: %s", gnutls_strerror(ret)); 00747 ret = gnutls_certificate_set_x509_key_file( 00748 global->xcred, params->client_cert, 00749 params->private_key, GNUTLS_X509_FMT_DER); 00750 if (ret < 0) { 00751 wpa_printf(MSG_DEBUG, "Failed to read client " 00752 "cert/key in DER format: %s", 00753 gnutls_strerror(ret)); 00754 goto fail; 00755 } 00756 } 00757 } else if (params->private_key) { 00758 int pkcs12_ok = 0; 00759 #ifdef PKCS12_FUNCS 00760 /* Try to load in PKCS#12 format */ 00761 #if LIBGNUTLS_VERSION_NUMBER >= 0x010302 00762 ret = gnutls_certificate_set_x509_simple_pkcs12_file( 00763 global->xcred, params->private_key, 00764 GNUTLS_X509_FMT_DER, params->private_key_passwd); 00765 if (ret != 0) { 00766 wpa_printf(MSG_DEBUG, "Failed to load private_key in " 00767 "PKCS#12 format: %s", gnutls_strerror(ret)); 00768 goto fail; 00769 } else 00770 pkcs12_ok = 1; 00771 #endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */ 00772 #endif /* PKCS12_FUNCS */ 00773 00774 if (!pkcs12_ok) { 00775 wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not " 00776 "included"); 00777 goto fail; 00778 } 00779 } 00780 00781 global->params_set = 1; 00782 00783 return 0; 00784 00785 fail: 00786 gnutls_certificate_free_credentials(global->xcred); 00787 return -1; 00788 } 00789 00790 00791 int tls_global_set_verify(void *ssl_ctx, int check_crl) 00792 { 00793 /* TODO */ 00794 return 0; 00795 } 00796 00797 00798 int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn, 00799 int verify_peer) 00800 { 00801 if (conn == NULL || conn->session == NULL) 00802 return -1; 00803 00804 conn->verify_peer = verify_peer; 00805 gnutls_certificate_server_set_request(conn->session, 00806 verify_peer ? GNUTLS_CERT_REQUIRE 00807 : GNUTLS_CERT_REQUEST); 00808 00809 return 0; 00810 } 00811 00812 00813 int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn, 00814 struct tls_keys *keys) 00815 { 00816 #ifdef GNUTLS_INTERNAL_STRUCTURE_HACK 00817 security_parameters_st *sec; 00818 #endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */ 00819 00820 if (conn == NULL || conn->session == NULL || keys == NULL) 00821 return -1; 00822 00823 os_memset(keys, 0, sizeof(*keys)); 00824 00825 #ifdef GNUTLS_INTERNAL_STRUCTURE_HACK 00826 sec = &conn->session->security_parameters; 00827 keys->master_key = sec->master_secret; 00828 keys->master_key_len = TLS_MASTER_SIZE; 00829 keys->client_random = sec->client_random; 00830 keys->server_random = sec->server_random; 00831 #else /* GNUTLS_INTERNAL_STRUCTURE_HACK */ 00832 keys->client_random = 00833 (u8 *) gnutls_session_get_client_random(conn->session); 00834 keys->server_random = 00835 (u8 *) gnutls_session_get_server_random(conn->session); 00836 /* No access to master_secret */ 00837 #endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */ 00838 00839 #ifdef GNUTLS_IA 00840 gnutls_ia_extract_inner_secret(conn->session, 00841 (char *) conn->inner_secret); 00842 keys->inner_secret = conn->inner_secret; 00843 keys->inner_secret_len = TLS_MASTER_SIZE; 00844 #endif /* GNUTLS_IA */ 00845 00846 keys->client_random_len = TLS_RANDOM_SIZE; 00847 keys->server_random_len = TLS_RANDOM_SIZE; 00848 00849 return 0; 00850 } 00851 00852 00853 int tls_connection_prf(void *tls_ctx, struct tls_connection *conn, 00854 const char *label, int server_random_first, 00855 u8 *out, size_t out_len) 00856 { 00857 #if LIBGNUTLS_VERSION_NUMBER >= 0x010302 00858 if (conn == NULL || conn->session == NULL) 00859 return -1; 00860 00861 return gnutls_prf(conn->session, os_strlen(label), label, 00862 server_random_first, 0, NULL, out_len, (char *) out); 00863 #else /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */ 00864 return -1; 00865 #endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */ 00866 } 00867 00868 00869 static int tls_connection_verify_peer(struct tls_connection *conn, 00870 gnutls_alert_description_t *err) 00871 { 00872 unsigned int status, num_certs, i; 00873 struct os_time now; 00874 const gnutls_datum_t *certs; 00875 gnutls_x509_crt_t cert; 00876 00877 if (gnutls_certificate_verify_peers2(conn->session, &status) < 0) { 00878 wpa_printf(MSG_INFO, "TLS: Failed to verify peer " 00879 "certificate chain"); 00880 *err = GNUTLS_A_INTERNAL_ERROR; 00881 return -1; 00882 } 00883 00884 if (conn->verify_peer && (status & GNUTLS_CERT_INVALID)) { 00885 wpa_printf(MSG_INFO, "TLS: Peer certificate not trusted"); 00886 if (status & GNUTLS_CERT_INSECURE_ALGORITHM) { 00887 wpa_printf(MSG_INFO, "TLS: Certificate uses insecure " 00888 "algorithm"); 00889 *err = GNUTLS_A_INSUFFICIENT_SECURITY; 00890 } 00891 if (status & GNUTLS_CERT_NOT_ACTIVATED) { 00892 wpa_printf(MSG_INFO, "TLS: Certificate not yet " 00893 "activated"); 00894 *err = GNUTLS_A_CERTIFICATE_EXPIRED; 00895 } 00896 if (status & GNUTLS_CERT_EXPIRED) { 00897 wpa_printf(MSG_INFO, "TLS: Certificate expired"); 00898 *err = GNUTLS_A_CERTIFICATE_EXPIRED; 00899 } 00900 return -1; 00901 } 00902 00903 if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) { 00904 wpa_printf(MSG_INFO, "TLS: Peer certificate does not have a " 00905 "known issuer"); 00906 *err = GNUTLS_A_UNKNOWN_CA; 00907 return -1; 00908 } 00909 00910 if (status & GNUTLS_CERT_REVOKED) { 00911 wpa_printf(MSG_INFO, "TLS: Peer certificate has been revoked"); 00912 *err = GNUTLS_A_CERTIFICATE_REVOKED; 00913 return -1; 00914 } 00915 00916 os_get_time(&now); 00917 00918 certs = gnutls_certificate_get_peers(conn->session, &num_certs); 00919 if (certs == NULL) { 00920 wpa_printf(MSG_INFO, "TLS: No peer certificate chain " 00921 "received"); 00922 *err = GNUTLS_A_UNKNOWN_CA; 00923 return -1; 00924 } 00925 00926 for (i = 0; i < num_certs; i++) { 00927 char *buf; 00928 size_t len; 00929 if (gnutls_x509_crt_init(&cert) < 0) { 00930 wpa_printf(MSG_INFO, "TLS: Certificate initialization " 00931 "failed"); 00932 *err = GNUTLS_A_BAD_CERTIFICATE; 00933 return -1; 00934 } 00935 00936 if (gnutls_x509_crt_import(cert, &certs[i], 00937 GNUTLS_X509_FMT_DER) < 0) { 00938 wpa_printf(MSG_INFO, "TLS: Could not parse peer " 00939 "certificate %d/%d", i + 1, num_certs); 00940 gnutls_x509_crt_deinit(cert); 00941 *err = GNUTLS_A_BAD_CERTIFICATE; 00942 return -1; 00943 } 00944 00945 gnutls_x509_crt_get_dn(cert, NULL, &len); 00946 len++; 00947 buf = os_malloc(len + 1); 00948 if (buf) { 00949 buf[0] = buf[len] = '\0'; 00950 gnutls_x509_crt_get_dn(cert, buf, &len); 00951 } 00952 wpa_printf(MSG_DEBUG, "TLS: Peer cert chain %d/%d: %s", 00953 i + 1, num_certs, buf); 00954 00955 if (i == 0) { 00956 /* TODO: validate subject_match and altsubject_match */ 00957 } 00958 00959 os_free(buf); 00960 00961 if (gnutls_x509_crt_get_expiration_time(cert) < now.sec || 00962 gnutls_x509_crt_get_activation_time(cert) > now.sec) { 00963 wpa_printf(MSG_INFO, "TLS: Peer certificate %d/%d is " 00964 "not valid at this time", 00965 i + 1, num_certs); 00966 gnutls_x509_crt_deinit(cert); 00967 *err = GNUTLS_A_CERTIFICATE_EXPIRED; 00968 return -1; 00969 } 00970 00971 gnutls_x509_crt_deinit(cert); 00972 } 00973 00974 return 0; 00975 } 00976 00977 00978 static struct wpabuf * gnutls_get_appl_data(struct tls_connection *conn) 00979 { 00980 int res; 00981 struct wpabuf *ad; 00982 wpa_printf(MSG_DEBUG, "GnuTLS: Check for possible Application Data"); 00983 ad = wpabuf_alloc((wpabuf_len(conn->pull_buf) + 500) * 3); 00984 if (ad == NULL) 00985 return NULL; 00986 00987 res = gnutls_record_recv(conn->session, wpabuf_mhead(ad), 00988 wpabuf_size(ad)); 00989 wpa_printf(MSG_DEBUG, "GnuTLS: gnutls_record_recv: %d", res); 00990 if (res < 0) { 00991 wpa_printf(MSG_DEBUG, "%s - gnutls_ia_recv failed: %d " 00992 "(%s)", __func__, (int) res, 00993 gnutls_strerror(res)); 00994 wpabuf_free(ad); 00995 return NULL; 00996 } 00997 00998 wpabuf_put(ad, res); 00999 wpa_printf(MSG_DEBUG, "GnuTLS: Received %d bytes of Application Data", 01000 res); 01001 return ad; 01002 } 01003 01004 01005 struct wpabuf * tls_connection_handshake(void *tls_ctx, 01006 struct tls_connection *conn, 01007 const struct wpabuf *in_data, 01008 struct wpabuf **appl_data) 01009 { 01010 struct tls_global *global = tls_ctx; 01011 struct wpabuf *out_data; 01012 int ret; 01013 01014 if (appl_data) 01015 *appl_data = NULL; 01016 01017 if (in_data && wpabuf_len(in_data) > 0) { 01018 if (conn->pull_buf) { 01019 wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in " 01020 "pull_buf", __func__, 01021 (unsigned long) wpabuf_len(conn->pull_buf)); 01022 wpabuf_free(conn->pull_buf); 01023 } 01024 conn->pull_buf = wpabuf_dup(in_data); 01025 if (conn->pull_buf == NULL) 01026 return NULL; 01027 conn->pull_buf_offset = wpabuf_head(conn->pull_buf); 01028 } 01029 01030 ret = gnutls_handshake(conn->session); 01031 if (ret < 0) { 01032 switch (ret) { 01033 case GNUTLS_E_AGAIN: 01034 if (global->server && conn->established && 01035 conn->push_buf == NULL) { 01036 /* Need to return something to trigger 01037 * completion of EAP-TLS. */ 01038 conn->push_buf = wpabuf_alloc(0); 01039 } 01040 break; 01041 case GNUTLS_E_FATAL_ALERT_RECEIVED: 01042 wpa_printf(MSG_DEBUG, "%s - received fatal '%s' alert", 01043 __func__, gnutls_alert_get_name( 01044 gnutls_alert_get(conn->session))); 01045 conn->read_alerts++; 01046 /* continue */ 01047 default: 01048 wpa_printf(MSG_DEBUG, "%s - gnutls_handshake failed " 01049 "-> %s", __func__, gnutls_strerror(ret)); 01050 conn->failed++; 01051 } 01052 } else { 01053 size_t size; 01054 gnutls_alert_description_t err; 01055 01056 if (conn->verify_peer && 01057 tls_connection_verify_peer(conn, &err)) { 01058 wpa_printf(MSG_INFO, "TLS: Peer certificate chain " 01059 "failed validation"); 01060 conn->failed++; 01061 gnutls_alert_send(conn->session, GNUTLS_AL_FATAL, err); 01062 goto out; 01063 } 01064 01065 #ifdef CONFIG_GNUTLS_EXTRA 01066 if (conn->tls_ia && !gnutls_ia_handshake_p(conn->session)) { 01067 wpa_printf(MSG_INFO, "TLS: No TLS/IA negotiation"); 01068 conn->failed++; 01069 return NULL; 01070 } 01071 #endif /* CONFIG_GNUTLS_EXTRA */ 01072 01073 if (conn->tls_ia) 01074 wpa_printf(MSG_DEBUG, "TLS: Start TLS/IA handshake"); 01075 else { 01076 wpa_printf(MSG_DEBUG, "TLS: Handshake completed " 01077 "successfully"); 01078 } 01079 conn->established = 1; 01080 if (conn->push_buf == NULL) { 01081 /* Need to return something to get final TLS ACK. */ 01082 conn->push_buf = wpabuf_alloc(0); 01083 } 01084 01085 gnutls_session_get_data(conn->session, NULL, &size); 01086 if (global->session_data == NULL || 01087 global->session_data_size < size) { 01088 os_free(global->session_data); 01089 global->session_data = os_malloc(size); 01090 } 01091 if (global->session_data) { 01092 global->session_data_size = size; 01093 gnutls_session_get_data(conn->session, 01094 global->session_data, 01095 &global->session_data_size); 01096 } 01097 01098 if (conn->pull_buf && appl_data) 01099 *appl_data = gnutls_get_appl_data(conn); 01100 } 01101 01102 out: 01103 out_data = conn->push_buf; 01104 conn->push_buf = NULL; 01105 return out_data; 01106 } 01107 01108 01109 struct wpabuf * tls_connection_server_handshake(void *tls_ctx, 01110 struct tls_connection *conn, 01111 const struct wpabuf *in_data, 01112 struct wpabuf **appl_data) 01113 { 01114 return tls_connection_handshake(tls_ctx, conn, in_data, appl_data); 01115 } 01116 01117 01118 struct wpabuf * tls_connection_encrypt(void *tls_ctx, 01119 struct tls_connection *conn, 01120 const struct wpabuf *in_data) 01121 { 01122 ssize_t res; 01123 struct wpabuf *buf; 01124 01125 #ifdef GNUTLS_IA 01126 if (conn->tls_ia) 01127 res = gnutls_ia_send(conn->session, wpabuf_head(in_data), 01128 wpabuf_len(in_data)); 01129 else 01130 #endif /* GNUTLS_IA */ 01131 res = gnutls_record_send(conn->session, wpabuf_head(in_data), 01132 wpabuf_len(in_data)); 01133 if (res < 0) { 01134 wpa_printf(MSG_INFO, "%s: Encryption failed: %s", 01135 __func__, gnutls_strerror(res)); 01136 return NULL; 01137 } 01138 01139 buf = conn->push_buf; 01140 conn->push_buf = NULL; 01141 return buf; 01142 } 01143 01144 01145 struct wpabuf * tls_connection_decrypt(void *tls_ctx, 01146 struct tls_connection *conn, 01147 const struct wpabuf *in_data) 01148 { 01149 ssize_t res; 01150 struct wpabuf *out; 01151 01152 if (conn->pull_buf) { 01153 wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in " 01154 "pull_buf", __func__, 01155 (unsigned long) wpabuf_len(conn->pull_buf)); 01156 wpabuf_free(conn->pull_buf); 01157 } 01158 conn->pull_buf = wpabuf_dup(in_data); 01159 if (conn->pull_buf == NULL) 01160 return NULL; 01161 conn->pull_buf_offset = wpabuf_head(conn->pull_buf); 01162 01163 /* 01164 * Even though we try to disable TLS compression, it is possible that 01165 * this cannot be done with all TLS libraries. Add extra buffer space 01166 * to handle the possibility of the decrypted data being longer than 01167 * input data. 01168 */ 01169 out = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3); 01170 if (out == NULL) 01171 return NULL; 01172 01173 #ifdef GNUTLS_IA 01174 if (conn->tls_ia) { 01175 res = gnutls_ia_recv(conn->session, wpabuf_mhead(out), 01176 wpabuf_size(out)); 01177 if (res == GNUTLS_E_WARNING_IA_IPHF_RECEIVED || 01178 res == GNUTLS_E_WARNING_IA_FPHF_RECEIVED) { 01179 int final = res == GNUTLS_E_WARNING_IA_FPHF_RECEIVED; 01180 wpa_printf(MSG_DEBUG, "%s: Received %sPhaseFinished", 01181 __func__, final ? "Final" : "Intermediate"); 01182 01183 res = gnutls_ia_permute_inner_secret( 01184 conn->session, conn->session_keys_len, 01185 (char *) conn->session_keys); 01186 if (conn->session_keys) { 01187 os_memset(conn->session_keys, 0, 01188 conn->session_keys_len); 01189 os_free(conn->session_keys); 01190 } 01191 conn->session_keys = NULL; 01192 conn->session_keys_len = 0; 01193 if (res) { 01194 wpa_printf(MSG_DEBUG, "%s: Failed to permute " 01195 "inner secret: %s", 01196 __func__, gnutls_strerror(res)); 01197 wpabuf_free(out); 01198 return NULL; 01199 } 01200 01201 res = gnutls_ia_verify_endphase(conn->session, 01202 wpabuf_head(out)); 01203 if (res == 0) { 01204 wpa_printf(MSG_DEBUG, "%s: Correct endphase " 01205 "checksum", __func__); 01206 } else { 01207 wpa_printf(MSG_INFO, "%s: Endphase " 01208 "verification failed: %s", 01209 __func__, gnutls_strerror(res)); 01210 wpabuf_free(out); 01211 return NULL; 01212 } 01213 01214 if (final) 01215 conn->final_phase_finished = 1; 01216 01217 return out; 01218 } 01219 01220 if (res < 0) { 01221 wpa_printf(MSG_DEBUG, "%s - gnutls_ia_recv failed: %d " 01222 "(%s)", __func__, (int) res, 01223 gnutls_strerror(res)); 01224 wpabuf_free(out); 01225 return NULL; 01226 } 01227 wpabuf_put(out, res); 01228 return out; 01229 } 01230 #endif /* GNUTLS_IA */ 01231 01232 res = gnutls_record_recv(conn->session, wpabuf_mhead(out), 01233 wpabuf_size(out)); 01234 if (res < 0) { 01235 wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d " 01236 "(%s)", __func__, (int) res, gnutls_strerror(res)); 01237 wpabuf_free(out); 01238 return NULL; 01239 } 01240 wpabuf_put(out, res); 01241 01242 return out; 01243 } 01244 01245 01246 int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn) 01247 { 01248 if (conn == NULL) 01249 return 0; 01250 return gnutls_session_is_resumed(conn->session); 01251 } 01252 01253 01254 int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn, 01255 u8 *ciphers) 01256 { 01257 /* TODO */ 01258 return -1; 01259 } 01260 01261 01262 int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn, 01263 char *buf, size_t buflen) 01264 { 01265 /* TODO */ 01266 buf[0] = '\0'; 01267 return 0; 01268 } 01269 01270 01271 int tls_connection_enable_workaround(void *ssl_ctx, 01272 struct tls_connection *conn) 01273 { 01274 gnutls_record_disable_padding(conn->session); 01275 return 0; 01276 } 01277 01278 01279 int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn, 01280 int ext_type, const u8 *data, 01281 size_t data_len) 01282 { 01283 /* TODO */ 01284 return -1; 01285 } 01286 01287 01288 int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn) 01289 { 01290 if (conn == NULL) 01291 return -1; 01292 return conn->failed; 01293 } 01294 01295 01296 int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn) 01297 { 01298 if (conn == NULL) 01299 return -1; 01300 return conn->read_alerts; 01301 } 01302 01303 01304 int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn) 01305 { 01306 if (conn == NULL) 01307 return -1; 01308 return conn->write_alerts; 01309 } 01310 01311 01312 int tls_connection_get_keyblock_size(void *tls_ctx, 01313 struct tls_connection *conn) 01314 { 01315 /* TODO */ 01316 return -1; 01317 } 01318 01319 01320 unsigned int tls_capabilities(void *tls_ctx) 01321 { 01322 unsigned int capa = 0; 01323 01324 #ifdef GNUTLS_IA 01325 capa |= TLS_CAPABILITY_IA; 01326 #endif /* GNUTLS_IA */ 01327 01328 return capa; 01329 } 01330 01331 01332 int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn, 01333 int tls_ia) 01334 { 01335 #ifdef GNUTLS_IA 01336 int ret; 01337 01338 if (conn == NULL) 01339 return -1; 01340 01341 conn->tls_ia = tls_ia; 01342 if (!tls_ia) 01343 return 0; 01344 01345 ret = gnutls_ia_allocate_server_credentials(&conn->iacred_srv); 01346 if (ret) { 01347 wpa_printf(MSG_DEBUG, "Failed to allocate IA credentials: %s", 01348 gnutls_strerror(ret)); 01349 return -1; 01350 } 01351 01352 ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_IA, 01353 conn->iacred_srv); 01354 if (ret) { 01355 wpa_printf(MSG_DEBUG, "Failed to configure IA credentials: %s", 01356 gnutls_strerror(ret)); 01357 gnutls_ia_free_server_credentials(conn->iacred_srv); 01358 conn->iacred_srv = NULL; 01359 return -1; 01360 } 01361 01362 return 0; 01363 #else /* GNUTLS_IA */ 01364 return -1; 01365 #endif /* GNUTLS_IA */ 01366 } 01367 01368 01369 struct wpabuf * tls_connection_ia_send_phase_finished( 01370 void *tls_ctx, struct tls_connection *conn, int final) 01371 { 01372 #ifdef GNUTLS_IA 01373 int ret; 01374 struct wpabuf *buf; 01375 01376 if (conn == NULL || conn->session == NULL || !conn->tls_ia) 01377 return NULL; 01378 01379 ret = gnutls_ia_permute_inner_secret(conn->session, 01380 conn->session_keys_len, 01381 (char *) conn->session_keys); 01382 if (conn->session_keys) { 01383 os_memset(conn->session_keys, 0, conn->session_keys_len); 01384 os_free(conn->session_keys); 01385 } 01386 conn->session_keys = NULL; 01387 conn->session_keys_len = 0; 01388 if (ret) { 01389 wpa_printf(MSG_DEBUG, "%s: Failed to permute inner secret: %s", 01390 __func__, gnutls_strerror(ret)); 01391 return NULL; 01392 } 01393 01394 ret = gnutls_ia_endphase_send(conn->session, final); 01395 if (ret) { 01396 wpa_printf(MSG_DEBUG, "%s: Failed to send endphase: %s", 01397 __func__, gnutls_strerror(ret)); 01398 return NULL; 01399 } 01400 01401 buf = conn->push_buf; 01402 conn->push_buf = NULL; 01403 return buf; 01404 #else /* GNUTLS_IA */ 01405 return NULL; 01406 #endif /* GNUTLS_IA */ 01407 } 01408 01409 01410 int tls_connection_ia_final_phase_finished(void *tls_ctx, 01411 struct tls_connection *conn) 01412 { 01413 if (conn == NULL) 01414 return -1; 01415 01416 return conn->final_phase_finished; 01417 } 01418 01419 01420 int tls_connection_ia_permute_inner_secret(void *tls_ctx, 01421 struct tls_connection *conn, 01422 const u8 *key, size_t key_len) 01423 { 01424 #ifdef GNUTLS_IA 01425 if (conn == NULL || !conn->tls_ia) 01426 return -1; 01427 01428 if (conn->session_keys) { 01429 os_memset(conn->session_keys, 0, conn->session_keys_len); 01430 os_free(conn->session_keys); 01431 } 01432 conn->session_keys_len = 0; 01433 01434 if (key) { 01435 conn->session_keys = os_malloc(key_len); 01436 if (conn->session_keys == NULL) 01437 return -1; 01438 os_memcpy(conn->session_keys, key, key_len); 01439 conn->session_keys_len = key_len; 01440 } else { 01441 conn->session_keys = NULL; 01442 conn->session_keys_len = 0; 01443 } 01444 01445 return 0; 01446 #else /* GNUTLS_IA */ 01447 return -1; 01448 #endif /* GNUTLS_IA */ 01449 } 01450 01451 01452 int tls_connection_set_session_ticket_cb(void *tls_ctx, 01453 struct tls_connection *conn, 01454 tls_session_ticket_cb cb, void *ctx) 01455 { 01456 return -1; 01457 }