00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
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
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
00028
00029 int gnutls_ia_verify_endphase(gnutls_session_t session, char *checksum);
00030 #endif
00031 #endif
00032 #endif
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
00048
00049
00050
00051 #define GNUTLS_INTERNAL_STRUCTURE_HACK
00052 #endif
00053
00054
00055 #ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
00056
00057
00058
00059
00060
00061
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
00084 } security_parameters_st;
00085
00086 struct gnutls_session_int {
00087 security_parameters_st security_parameters;
00088
00089 };
00090 #endif
00091
00092 static int tls_gnutls_ref_count = 0;
00093
00094 struct tls_global {
00095
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
00130
00131 u8 *session_keys;
00132 size_t session_keys_len;
00133
00134 u8 inner_secret[TLS_MASTER_SIZE];
00135 #endif
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
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
00173
00174
00175
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
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
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
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
00404
00405
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
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
00573
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
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
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
00640 #endif
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
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
00692
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
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
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
00772 #endif
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
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
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
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
00837 #endif
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
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
00864 return -1;
00865 #endif
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
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
01037
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
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
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
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
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
01165
01166
01167
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
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
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
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
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
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
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
01364 return -1;
01365 #endif
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
01405 return NULL;
01406 #endif
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
01447 return -1;
01448 #endif
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 }