From 81c85c069ac0f2980db4745e1f85f521affb8619 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sun, 20 Dec 2009 18:17:55 +0200 Subject: [PATCH] Convert TLS wrapper to use struct wpabuf This converts tls_connection_handshake(), tls_connection_server_handshake(), tls_connection_encrypt(), and tls_connection_decrypt() to use struct wpa_buf to allow higher layer code to be cleaned up with consistent struct wpabuf use. --- src/crypto/tls.h | 74 +++++------ src/crypto/tls_gnutls.c | 134 ++++++++++--------- src/crypto/tls_internal.c | 162 +++++++++++++++++------ src/crypto/tls_none.c | 41 +++--- src/crypto/tls_nss.c | 107 ++++++++------- src/crypto/tls_openssl.c | 227 ++++++++++++++++---------------- src/crypto/tls_schannel.c | 154 ++++++++++------------ src/eap_peer/eap_tls_common.c | 156 ++++++++-------------- src/eap_peer/eap_tls_common.h | 19 +-- src/eap_server/eap_fast.c | 63 +++------ src/eap_server/eap_peap.c | 71 +++------- src/eap_server/eap_tls_common.c | 45 ++----- src/eap_server/eap_tls_common.h | 6 +- src/eap_server/eap_ttls.c | 74 ++++------- 14 files changed, 621 insertions(+), 712 deletions(-) diff --git a/src/crypto/tls.h b/src/crypto/tls.h index 4ee03332f..89dea3aa3 100644 --- a/src/crypto/tls.h +++ b/src/crypto/tls.h @@ -1,6 +1,6 @@ /* - * WPA Supplicant / SSL/TLS interface definition - * Copyright (c) 2004-2007, Jouni Malinen + * SSL/TLS interface definition + * Copyright (c) 2004-2009, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -287,17 +287,14 @@ int __must_check tls_connection_prf(void *tls_ctx, * tls_connection_handshake - Process TLS handshake (client side) * @tls_ctx: TLS context data from tls_init() * @conn: Connection context data from tls_connection_init() - * @in_data: Input data from TLS peer - * @in_len: Input data length - * @out_len: Length of the output buffer. + * @in_data: Input data from TLS server * @appl_data: Pointer to application data pointer, or %NULL if dropped - * @appl_data_len: Pointer to variable that is set to appl_data length - * Returns: Pointer to output data, %NULL on failure + * Returns: Output data, %NULL on failure * - * Caller is responsible for freeing returned output data. If the final + * The caller is responsible for freeing the returned output data. If the final * handshake message includes application data, this is decrypted and - * appl_data (if not %NULL) is set to point this data. Caller is responsible - * for freeing appl_data. + * appl_data (if not %NULL) is set to point this data. The caller is + * responsible for freeing appl_data. * * This function is used during TLS handshake. The first call is done with * in_data == %NULL and the library is expected to return ClientHello packet. @@ -313,62 +310,55 @@ int __must_check tls_connection_prf(void *tls_ctx, * tls_connection_established() should return 1 once the TLS handshake has been * completed successfully. */ -u8 * tls_connection_handshake(void *tls_ctx, struct tls_connection *conn, - const u8 *in_data, size_t in_len, - size_t *out_len, u8 **appl_data, - size_t *appl_data_len); +struct wpabuf * tls_connection_handshake(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data, + struct wpabuf **appl_data); /** * tls_connection_server_handshake - Process TLS handshake (server side) * @tls_ctx: TLS context data from tls_init() * @conn: Connection context data from tls_connection_init() * @in_data: Input data from TLS peer - * @in_len: Input data length - * @out_len: Length of the output buffer. - * Returns: pointer to output data, %NULL on failure + * @appl_data: Pointer to application data pointer, or %NULL if dropped + * Returns: Output data, %NULL on failure * - * Caller is responsible for freeing returned output data. + * The caller is responsible for freeing the returned output data. */ -u8 * tls_connection_server_handshake(void *tls_ctx, - struct tls_connection *conn, - const u8 *in_data, size_t in_len, - size_t *out_len); +struct wpabuf * tls_connection_server_handshake(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data, + struct wpabuf **appl_data); /** * tls_connection_encrypt - Encrypt data into TLS tunnel * @tls_ctx: TLS context data from tls_init() * @conn: Connection context data from tls_connection_init() - * @in_data: Pointer to plaintext data to be encrypted - * @in_len: Input buffer length - * @out_data: Pointer to output buffer (encrypted TLS data) - * @out_len: Maximum out_data length - * Returns: Number of bytes written to out_data, -1 on failure + * @in_data: Plaintext data to be encrypted + * Returns: Encrypted TLS data or %NULL on failure * * This function is used after TLS handshake has been completed successfully to - * send data in the encrypted tunnel. + * send data in the encrypted tunnel. The caller is responsible for freeing the + * returned output data. */ -int __must_check tls_connection_encrypt(void *tls_ctx, - struct tls_connection *conn, - const u8 *in_data, size_t in_len, - u8 *out_data, size_t out_len); +struct wpabuf * tls_connection_encrypt(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data); /** * tls_connection_decrypt - Decrypt data from TLS tunnel * @tls_ctx: TLS context data from tls_init() * @conn: Connection context data from tls_connection_init() - * @in_data: Pointer to input buffer (encrypted TLS data) - * @in_len: Input buffer length - * @out_data: Pointer to output buffer (decrypted data from TLS tunnel) - * @out_len: Maximum out_data length - * Returns: Number of bytes written to out_data, -1 on failure + * @in_data: Encrypted TLS data + * Returns: Decrypted TLS data or %NULL on failure * * This function is used after TLS handshake has been completed successfully to - * receive data from the encrypted tunnel. + * receive data from the encrypted tunnel. The caller is responsible for + * freeing the returned output data. */ -int __must_check tls_connection_decrypt(void *tls_ctx, - struct tls_connection *conn, - const u8 *in_data, size_t in_len, - u8 *out_data, size_t out_len); +struct wpabuf * tls_connection_decrypt(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data); /** * tls_connection_resumed - Was session resumption used diff --git a/src/crypto/tls_gnutls.c b/src/crypto/tls_gnutls.c index 05d6dd32f..876c82d90 100644 --- a/src/crypto/tls_gnutls.c +++ b/src/crypto/tls_gnutls.c @@ -1,6 +1,6 @@ /* - * WPA Supplicant / SSL/TLS interface functions for openssl - * Copyright (c) 2004-2007, Jouni Malinen + * SSL/TLS interface functions for GnuTLS + * Copyright (c) 2004-2009, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -934,31 +934,32 @@ static int tls_connection_verify_peer(struct tls_connection *conn) } -u8 * tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn, - const u8 *in_data, size_t in_len, - size_t *out_len, u8 **appl_data, - size_t *appl_data_len) +struct wpabuf * tls_connection_handshake(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data, + struct wpabuf **appl_data) { - struct tls_global *global = ssl_ctx; - u8 *out_data; + struct tls_global *global = tls_ctx; + struct wpabuf *out_data; int ret; if (appl_data) *appl_data = NULL; - if (in_data && in_len) { + if (in_data && wpabuf_len(in_data) > 0) { if (conn->pull_buf) { wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in " "pull_buf", __func__, (unsigned long) conn->pull_buf_len); os_free(conn->pull_buf); } - conn->pull_buf = os_malloc(in_len); + conn->pull_buf = os_malloc(wpabuf_len(in_data)); if (conn->pull_buf == NULL) return NULL; - os_memcpy(conn->pull_buf, in_data, in_len); + os_memcpy(conn->pull_buf, wpabuf_head(in_data), + wpabuf_len(in_data)); conn->pull_buf_offset = conn->pull_buf; - conn->pull_buf_len = in_len; + conn->pull_buf_len = wpabuf_len(in_data); } ret = gnutls_handshake(conn->session); @@ -1027,66 +1028,63 @@ u8 * tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn, } } - out_data = conn->push_buf; - *out_len = conn->push_buf_len; + if (conn->push_buf == NULL) + return NULL; + out_data = wpabuf_alloc_ext_data(conn->push_buf, conn->push_buf_len); + if (out_data == NULL) + os_free(conn->push_buf); conn->push_buf = NULL; conn->push_buf_len = 0; return out_data; } -u8 * tls_connection_server_handshake(void *ssl_ctx, - struct tls_connection *conn, - const u8 *in_data, size_t in_len, - size_t *out_len) +struct wpabuf * tls_connection_server_handshake(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data, + struct wpabuf **appl_data) { - return tls_connection_handshake(ssl_ctx, conn, in_data, in_len, - out_len, NULL, NULL); + return tls_connection_handshake(tls_ctx, conn, in_data, appl_data); } -int tls_connection_encrypt(void *ssl_ctx, struct tls_connection *conn, - const u8 *in_data, size_t in_len, - u8 *out_data, size_t out_len) +struct wpabuf * tls_connection_encrypt(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data) { ssize_t res; + struct wpabuf *buf; #ifdef GNUTLS_IA if (conn->tls_ia) - res = gnutls_ia_send(conn->session, (char *) in_data, in_len); + res = gnutls_ia_send(conn->session, wpabuf_head(in_data), + wpabuf_len(in_data)); else #endif /* GNUTLS_IA */ - res = gnutls_record_send(conn->session, in_data, in_len); + res = gnutls_record_send(conn->session, wpabuf_head(in_data), + wpabuf_len(in_data)); if (res < 0) { wpa_printf(MSG_INFO, "%s: Encryption failed: %s", __func__, gnutls_strerror(res)); - return -1; + return NULL; } if (conn->push_buf == NULL) - return -1; - if (conn->push_buf_len < out_len) - out_len = conn->push_buf_len; - else if (conn->push_buf_len > out_len) { - wpa_printf(MSG_INFO, "GnuTLS: Not enough buffer space for " - "encrypted message (in_len=%lu push_buf_len=%lu " - "out_len=%lu", - (unsigned long) in_len, - (unsigned long) conn->push_buf_len, - (unsigned long) out_len); - } - os_memcpy(out_data, conn->push_buf, out_len); - os_free(conn->push_buf); + return NULL; + buf = wpabuf_alloc_ext_data(conn->push_buf, conn->push_buf_len); + if (buf == NULL) + os_free(conn->push_buf); conn->push_buf = NULL; conn->push_buf_len = 0; - return out_len; + return buf; } -int tls_connection_decrypt(void *ssl_ctx, struct tls_connection *conn, - const u8 *in_data, size_t in_len, - u8 *out_data, size_t out_len) +struct wpabuf * tls_connection_decrypt(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data) { ssize_t res; + struct wpabuf *out; if (conn->pull_buf) { wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in " @@ -1094,20 +1092,29 @@ int tls_connection_decrypt(void *ssl_ctx, struct tls_connection *conn, (unsigned long) conn->pull_buf_len); os_free(conn->pull_buf); } - conn->pull_buf = os_malloc(in_len); + conn->pull_buf = os_malloc(wpabuf_len(in_data)); if (conn->pull_buf == NULL) - return -1; - os_memcpy(conn->pull_buf, in_data, in_len); + return NULL; + os_memcpy(conn->pull_buf, wpabuf_head(in_data), wpabuf_len(in_data)); conn->pull_buf_offset = conn->pull_buf; - conn->pull_buf_len = in_len; + conn->pull_buf_len = wpabuf_len(in_data); + + /* + * Even though we try to disable TLS compression, it is possible that + * this cannot be done with all TLS libraries. Add extra buffer space + * to handle the possibility of the decrypted data being longer than + * input data. + */ + out = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3); + if (out == NULL) + return NULL; #ifdef GNUTLS_IA if (conn->tls_ia) { - res = gnutls_ia_recv(conn->session, (char *) out_data, - out_len); - if (out_len >= 12 && - (res == GNUTLS_E_WARNING_IA_IPHF_RECEIVED || - res == GNUTLS_E_WARNING_IA_FPHF_RECEIVED)) { + res = gnutls_ia_recv(conn->session, wpabuf_mhead(out), + wpabuf_size(out)); + if (res == GNUTLS_E_WARNING_IA_IPHF_RECEIVED || + res == GNUTLS_E_WARNING_IA_FPHF_RECEIVED) { int final = res == GNUTLS_E_WARNING_IA_FPHF_RECEIVED; wpa_printf(MSG_DEBUG, "%s: Received %sPhaseFinished", __func__, final ? "Final" : "Intermediate"); @@ -1126,11 +1133,12 @@ int tls_connection_decrypt(void *ssl_ctx, struct tls_connection *conn, wpa_printf(MSG_DEBUG, "%s: Failed to permute " "inner secret: %s", __func__, gnutls_strerror(res)); - return -1; + wpabuf_free(out); + return NULL; } res = gnutls_ia_verify_endphase(conn->session, - (char *) out_data); + wpabuf_head(out)); if (res == 0) { wpa_printf(MSG_DEBUG, "%s: Correct endphase " "checksum", __func__); @@ -1138,31 +1146,39 @@ int tls_connection_decrypt(void *ssl_ctx, struct tls_connection *conn, wpa_printf(MSG_INFO, "%s: Endphase " "verification failed: %s", __func__, gnutls_strerror(res)); - return -1; + wpabuf_free(out); + return NULL; } if (final) conn->final_phase_finished = 1; - return 0; + return out; } if (res < 0) { wpa_printf(MSG_DEBUG, "%s - gnutls_ia_recv failed: %d " "(%s)", __func__, (int) res, gnutls_strerror(res)); + wpabuf_free(out); + return NULL; } - return res; + wpabuf_put(out, res); + return out; } #endif /* GNUTLS_IA */ - res = gnutls_record_recv(conn->session, out_data, out_len); + res = gnutls_record_recv(conn->session, wpabuf_mhead(out), + wpabuf_size(out)); if (res < 0) { wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d " "(%s)", __func__, (int) res, gnutls_strerror(res)); + wpabuf_free(out); + return NULL; } + wpabuf_put(out, res); - return res; + return out; } diff --git a/src/crypto/tls_internal.c b/src/crypto/tls_internal.c index 42120c8a8..27a31662d 100644 --- a/src/crypto/tls_internal.c +++ b/src/crypto/tls_internal.c @@ -1,6 +1,6 @@ /* - * WPA Supplicant / TLS interface functions and an internal TLS implementation - * Copyright (c) 2004-2007, Jouni Malinen + * TLS interface functions and an internal TLS implementation + * Copyright (c) 2004-2009, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -331,45 +331,77 @@ int tls_connection_prf(void *tls_ctx, struct tls_connection *conn, } -u8 * tls_connection_handshake(void *tls_ctx, struct tls_connection *conn, - const u8 *in_data, size_t in_len, - size_t *out_len, u8 **appl_data, - size_t *appl_data_len) +struct wpabuf * tls_connection_handshake(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data, + struct wpabuf **appl_data) { #ifdef CONFIG_TLS_INTERNAL_CLIENT + u8 *res, *ad; + size_t res_len, ad_len; + struct wpabuf *out; + if (conn->client == NULL) return NULL; - if (appl_data) - *appl_data = NULL; + ad = NULL; + res = tlsv1_client_handshake(conn->client, + in_data ? wpabuf_head(in_data) : NULL, + in_data ? wpabuf_len(in_data) : 0, + &res_len, &ad, &ad_len); + if (res == NULL) + return NULL; + out = wpabuf_alloc_ext_data(res, res_len); + if (out == NULL) { + os_free(res); + os_free(ad); + return NULL; + } + if (appl_data) { + if (ad) { + *appl_data = wpabuf_alloc_ext_data(ad, ad_len); + if (*appl_data == NULL) + os_free(ad); + } else + *appl_data = NULL; + } else + os_free(ad); - wpa_printf(MSG_DEBUG, "TLS: %s(in_data=%p in_len=%lu)", - __func__, in_data, (unsigned long) in_len); - return tlsv1_client_handshake(conn->client, in_data, in_len, out_len, - appl_data, appl_data_len); + return out; #else /* CONFIG_TLS_INTERNAL_CLIENT */ return NULL; #endif /* CONFIG_TLS_INTERNAL_CLIENT */ } -u8 * tls_connection_server_handshake(void *tls_ctx, - struct tls_connection *conn, - const u8 *in_data, size_t in_len, - size_t *out_len) +struct wpabuf * tls_connection_server_handshake(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data, + struct wpabuf **appl_data) { #ifdef CONFIG_TLS_INTERNAL_SERVER - u8 *out; + u8 *res; + size_t res_len; + struct wpabuf *out; + if (conn->server == NULL) return NULL; - wpa_printf(MSG_DEBUG, "TLS: %s(in_data=%p in_len=%lu)", - __func__, in_data, (unsigned long) in_len); - out = tlsv1_server_handshake(conn->server, in_data, in_len, out_len); - if (out == NULL && tlsv1_server_established(conn->server)) { - out = os_malloc(1); - *out_len = 0; + if (appl_data) + *appl_data = NULL; + + res = tlsv1_server_handshake(conn->server, wpabuf_head(in_data), + wpabuf_len(in_data), &res_len); + if (res == NULL && tlsv1_server_established(conn->server)) + return wpabuf_alloc(0); + if (res == NULL) + return NULL; + out = wpabuf_alloc_ext_data(res, res_len); + if (out == NULL) { + os_free(res); + return NULL; } + return out; #else /* CONFIG_TLS_INTERNAL_SERVER */ return NULL; @@ -377,43 +409,95 @@ u8 * tls_connection_server_handshake(void *tls_ctx, } -int tls_connection_encrypt(void *tls_ctx, struct tls_connection *conn, - const u8 *in_data, size_t in_len, - u8 *out_data, size_t out_len) +struct wpabuf * tls_connection_encrypt(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data) { #ifdef CONFIG_TLS_INTERNAL_CLIENT if (conn->client) { - return tlsv1_client_encrypt(conn->client, in_data, in_len, - out_data, out_len); + struct wpabuf *buf; + int res; + buf = wpabuf_alloc(wpabuf_len(in_data) + 300); + if (buf == NULL) + return NULL; + res = tlsv1_client_encrypt(conn->client, wpabuf_head(in_data), + wpabuf_len(in_data), + wpabuf_mhead(buf), + wpabuf_size(buf)); + if (res < 0) { + wpabuf_free(buf); + return NULL; + } + wpabuf_put(buf, res); + return buf; } #endif /* CONFIG_TLS_INTERNAL_CLIENT */ #ifdef CONFIG_TLS_INTERNAL_SERVER if (conn->server) { - return tlsv1_server_encrypt(conn->server, in_data, in_len, - out_data, out_len); + struct wpabuf *buf; + int res; + buf = wpabuf_alloc(wpabuf_len(in_data) + 300); + if (buf == NULL) + return NULL; + res = tlsv1_server_encrypt(conn->server, wpabuf_head(in_data), + wpabuf_len(in_data), + wpabuf_mhead(buf), + wpabuf_size(buf)); + if (res < 0) { + wpabuf_free(buf); + return NULL; + } + wpabuf_put(buf, res); + return buf; } #endif /* CONFIG_TLS_INTERNAL_SERVER */ - return -1; + return NULL; } -int tls_connection_decrypt(void *tls_ctx, struct tls_connection *conn, - const u8 *in_data, size_t in_len, - u8 *out_data, size_t out_len) +struct wpabuf * tls_connection_decrypt(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data) { #ifdef CONFIG_TLS_INTERNAL_CLIENT if (conn->client) { - return tlsv1_client_decrypt(conn->client, in_data, in_len, - out_data, out_len); + struct wpabuf *buf; + int res; + buf = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3); + if (buf == NULL) + return NULL; + res = tlsv1_client_decrypt(conn->client, wpabuf_head(in_data), + wpabuf_len(in_data), + wpabuf_mhead(buf), + wpabuf_size(buf)); + if (res < 0) { + wpabuf_free(buf); + return NULL; + } + wpabuf_put(buf, res); + return buf; } #endif /* CONFIG_TLS_INTERNAL_CLIENT */ #ifdef CONFIG_TLS_INTERNAL_SERVER if (conn->server) { - return tlsv1_server_decrypt(conn->server, in_data, in_len, - out_data, out_len); + struct wpabuf *buf; + int res; + buf = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3); + if (buf == NULL) + return NULL; + res = tlsv1_server_decrypt(conn->server, wpabuf_head(in_data), + wpabuf_len(in_data), + wpabuf_mhead(buf), + wpabuf_size(buf)); + if (res < 0) { + wpabuf_free(buf); + return NULL; + } + wpabuf_put(buf, res); + return buf; } #endif /* CONFIG_TLS_INTERNAL_SERVER */ - return -1; + return NULL; } diff --git a/src/crypto/tls_none.c b/src/crypto/tls_none.c index f731628b0..d532def84 100644 --- a/src/crypto/tls_none.c +++ b/src/crypto/tls_none.c @@ -1,6 +1,6 @@ /* - * WPA Supplicant / SSL/TLS interface functions for no TLS case - * Copyright (c) 2004, Jouni Malinen + * SSL/TLS interface functions for no TLS case + * Copyright (c) 2004-2009, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -22,13 +22,12 @@ void * tls_init(const struct tls_config *conf) return (void *) 1; } + void tls_deinit(void *ssl_ctx) { } -#ifdef EAP_TLS_NONE - int tls_get_errors(void *tls_ctx) { return 0; @@ -107,37 +106,37 @@ int tls_connection_prf(void *tls_ctx, struct tls_connection *conn, } -u8 * tls_connection_handshake(void *tls_ctx, struct tls_connection *conn, - const u8 *in_data, size_t in_len, - size_t *out_len, u8 **appl_data, - size_t *appl_data_len) +struct wpabuf * tls_connection_handshake(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data, + struct wpabuf **appl_data) { return NULL; } -u8 * tls_connection_server_handshake(void *tls_ctx, - struct tls_connection *conn, - const u8 *in_data, size_t in_len, - size_t *out_len) +struct wpabuf * tls_connection_server_handshake(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data, + struct wpabuf **appl_data) { return NULL; } -int tls_connection_encrypt(void *tls_ctx, struct tls_connection *conn, - const u8 *in_data, size_t in_len, - u8 *out_data, size_t out_len) +struct wpabuf * tls_connection_encrypt(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data) { - return -1; + return NULL; } -int tls_connection_decrypt(void *tls_ctx, struct tls_connection *conn, - const u8 *in_data, size_t in_len, - u8 *out_data, size_t out_len) +struct wpabuf * tls_connection_decrypt(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data) { - return -1; + return NULL; } @@ -230,5 +229,3 @@ int tls_connection_ia_permute_inner_secret(void *tls_ctx, { return -1; } - -#endif /* EAP_TLS_NONE */ diff --git a/src/crypto/tls_nss.c b/src/crypto/tls_nss.c index b4f86655c..b35ed07ad 100644 --- a/src/crypto/tls_nss.c +++ b/src/crypto/tls_nss.c @@ -456,32 +456,33 @@ int tls_connection_prf(void *tls_ctx, struct tls_connection *conn, } -u8 * tls_connection_handshake(void *tls_ctx, struct tls_connection *conn, - const u8 *in_data, size_t in_len, - size_t *out_len, u8 **appl_data, - size_t *appl_data_len) +struct wpabuf * tls_connection_handshake(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data, + struct wpabuf **appl_data) { - u8 *out_data; + struct wpabuf *out_data; wpa_printf(MSG_DEBUG, "NSS: handshake: in_len=%u", - (unsigned int) in_len); + in_data ? (unsigned int) wpabuf_len(in_data) : 0); if (appl_data) *appl_data = NULL; - if (in_data && in_len) { + if (in_data && wpabuf_len(in_data) > 0) { if (conn->pull_buf) { wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in " "pull_buf", __func__, (unsigned long) conn->pull_buf_len); os_free(conn->pull_buf); } - conn->pull_buf = os_malloc(in_len); + conn->pull_buf = os_malloc(wpabuf_len(in_data)); if (conn->pull_buf == NULL) return NULL; - os_memcpy(conn->pull_buf, in_data, in_len); + os_memcpy(conn->pull_buf, wpabuf_head(in_data), + wpabuf_len(in_data)); conn->pull_buf_offset = conn->pull_buf; - conn->pull_buf_len = in_len; + conn->pull_buf_len = wpabuf_len(in_data); } SSL_ForceHandshake(conn->fd); @@ -491,79 +492,93 @@ u8 * tls_connection_handshake(void *tls_ctx, struct tls_connection *conn, conn->push_buf = os_malloc(1); } - out_data = conn->push_buf; - *out_len = conn->push_buf_len; + if (conn->push_buf == NULL) + return NULL; + out_data = wpabuf_alloc_ext_data(conn->push_buf, conn->push_buf_len); + if (out_data == NULL) + os_free(conn->push_buf); conn->push_buf = NULL; conn->push_buf_len = 0; return out_data; } -u8 * tls_connection_server_handshake(void *tls_ctx, - struct tls_connection *conn, - const u8 *in_data, size_t in_len, - size_t *out_len) +struct wpabuf * tls_connection_server_handshake(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data, + struct wpabuf **appl_data) { return NULL; } -int tls_connection_encrypt(void *tls_ctx, struct tls_connection *conn, - const u8 *in_data, size_t in_len, - u8 *out_data, size_t out_len) +struct wpabuf * tls_connection_encrypt(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data) { PRInt32 res; + struct wpabuf *buf; - wpa_printf(MSG_DEBUG, "NSS: encrypt %d bytes", (int) in_len); - res = PR_Send(conn->fd, in_data, in_len, 0, 0); + wpa_printf(MSG_DEBUG, "NSS: encrypt %d bytes", + (int) wpabuf_len(in_data)); + res = PR_Send(conn->fd, wpabuf_head(in_data), wpabuf_len(in_data), 0, + 0); if (res < 0) { wpa_printf(MSG_ERROR, "NSS: Encryption failed"); - return -1; + return NULL; } if (conn->push_buf == NULL) - return -1; - if (conn->push_buf_len < out_len) - out_len = conn->push_buf_len; - else if (conn->push_buf_len > out_len) { - wpa_printf(MSG_INFO, "NSS: Not enough buffer space for " - "encrypted message (in_len=%lu push_buf_len=%lu " - "out_len=%lu", - (unsigned long) in_len, - (unsigned long) conn->push_buf_len, - (unsigned long) out_len); - } - os_memcpy(out_data, conn->push_buf, out_len); - os_free(conn->push_buf); + return NULL; + buf = wpabuf_alloc_ext_data(conn->push_buf, conn->push_buf_len); + if (buf == NULL) + os_free(conn->push_buf); conn->push_buf = NULL; conn->push_buf_len = 0; - return out_len; + return buf; } -int tls_connection_decrypt(void *tls_ctx, struct tls_connection *conn, - const u8 *in_data, size_t in_len, - u8 *out_data, size_t out_len) +struct wpabuf * tls_connection_decrypt(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data) { PRInt32 res; + struct wpabuf *out; - wpa_printf(MSG_DEBUG, "NSS: decrypt %d bytes", (int) in_len); + wpa_printf(MSG_DEBUG, "NSS: decrypt %d bytes", + (int) wpabuf_len(in_data)); if (conn->pull_buf) { wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in " "pull_buf", __func__, (unsigned long) conn->pull_buf_len); os_free(conn->pull_buf); } - conn->pull_buf = os_malloc(in_len); + conn->pull_buf = os_malloc(wpabuf_len(in_data)); if (conn->pull_buf == NULL) - return -1; - os_memcpy(conn->pull_buf, in_data, in_len); + return NULL; + os_memcpy(conn->pull_buf, wpabuf_head(in_data), wpabuf_len(in_data)); conn->pull_buf_offset = conn->pull_buf; - conn->pull_buf_len = in_len; + conn->pull_buf_len = wpabuf_len(in_data); - res = PR_Recv(conn->fd, out_data, out_len, 0, 0); + /* + * Even though we try to disable TLS compression, it is possible that + * this cannot be done with all TLS libraries. Add extra buffer space + * to handle the possibility of the decrypted data being longer than + * input data. + */ + out = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3); + if (out == NULL) + return NULL; + + res = PR_Recv(conn->fd, wpabuf_mhead(out), wpabuf_size(out), 0, 0); wpa_printf(MSG_DEBUG, "NSS: PR_Recv: %d", res); + if (res < 0) { + wpabuf_free(out); + return NULL; + } + wpabuf_put(out, res); - return res; + return out; } diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c index 777405a10..689e6aac0 100644 --- a/src/crypto/tls_openssl.c +++ b/src/crypto/tls_openssl.c @@ -1,5 +1,5 @@ /* - * WPA Supplicant / SSL/TLS interface functions for openssl + * SSL/TLS interface functions for OpenSSL * Copyright (c) 2004-2009, Jouni Malinen * * This program is free software; you can redistribute it and/or modify @@ -1990,30 +1990,30 @@ int tls_connection_prf(void *tls_ctx, struct tls_connection *conn, } -u8 * tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn, - const u8 *in_data, size_t in_len, - size_t *out_len, u8 **appl_data, - size_t *appl_data_len) +static struct wpabuf * +openssl_handshake(struct tls_connection *conn, const struct wpabuf *in_data, + int server) { int res; - u8 *out_data; - - if (appl_data) - *appl_data = NULL; + struct wpabuf *out_data; /* * Give TLS handshake data from the server (if available) to OpenSSL * for processing. */ if (in_data && - BIO_write(conn->ssl_in, in_data, in_len) < 0) { + BIO_write(conn->ssl_in, wpabuf_head(in_data), wpabuf_len(in_data)) + < 0) { tls_show_errors(MSG_INFO, __func__, "Handshake failed - BIO_write"); return NULL; } /* Initiate TLS handshake or continue the existing handshake */ - res = SSL_connect(conn->ssl); + if (server) + res = SSL_accept(conn->ssl); + else + res = SSL_connect(conn->ssl); if (res != 1) { int err = SSL_get_error(conn->ssl, res); if (err == SSL_ERROR_WANT_READ) @@ -2031,7 +2031,7 @@ u8 * tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn, /* Get the TLS handshake data to be sent to the server */ res = BIO_ctrl_pending(conn->ssl_out); wpa_printf(MSG_DEBUG, "SSL: %d bytes pending from ssl_out", res); - out_data = os_malloc(res == 0 ? 1 : res); + out_data = wpabuf_alloc(res); if (out_data == NULL) { wpa_printf(MSG_DEBUG, "SSL: Failed to allocate memory for " "handshake output (%d bytes)", res); @@ -2039,10 +2039,10 @@ u8 * tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn, tls_show_errors(MSG_INFO, __func__, "BIO_reset failed"); } - *out_len = 0; return NULL; } - res = res == 0 ? 0 : BIO_read(conn->ssl_out, out_data, res); + res = res == 0 ? 0 : BIO_read(conn->ssl_out, wpabuf_mhead(out_data), + res); if (res < 0) { tls_show_errors(MSG_INFO, __func__, "Handshake failed - BIO_read"); @@ -2050,169 +2050,168 @@ u8 * tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn, tls_show_errors(MSG_INFO, __func__, "BIO_reset failed"); } - *out_len = 0; + wpabuf_free(out_data); return NULL; } - *out_len = res; - - if (SSL_is_init_finished(conn->ssl) && appl_data) { - *appl_data = os_malloc(in_len); - if (*appl_data) { - res = SSL_read(conn->ssl, *appl_data, in_len); - if (res < 0) { - int err = SSL_get_error(conn->ssl, res); - if (err == SSL_ERROR_WANT_READ || - err == SSL_ERROR_WANT_WRITE) { - wpa_printf(MSG_DEBUG, - "SSL: No Application Data " - "included"); - } else { - tls_show_errors(MSG_INFO, __func__, - "Failed to read " - "possible " - "Application Data"); - } - os_free(*appl_data); - *appl_data = NULL; - } else { - *appl_data_len = res; - wpa_hexdump_key(MSG_MSGDUMP, "SSL: Application" - " Data in Finish message", - *appl_data, *appl_data_len); - } - } - } + wpabuf_put(out_data, res); return out_data; } -u8 * tls_connection_server_handshake(void *ssl_ctx, - struct tls_connection *conn, - const u8 *in_data, size_t in_len, - size_t *out_len) +static struct wpabuf * +openssl_get_appl_data(struct tls_connection *conn, size_t max_len) { + struct wpabuf *appl_data; int res; - u8 *out_data; - /* - * Give TLS handshake data from the client (if available) to OpenSSL - * for processing. - */ - if (in_data && - BIO_write(conn->ssl_in, in_data, in_len) < 0) { - tls_show_errors(MSG_INFO, __func__, - "Handshake failed - BIO_write"); + appl_data = wpabuf_alloc(max_len + 100); + if (appl_data == NULL) return NULL; - } - /* Initiate TLS handshake or continue the existing handshake */ - res = SSL_accept(conn->ssl); - if (res != 1) { + res = SSL_read(conn->ssl, wpabuf_mhead(appl_data), + wpabuf_size(appl_data)); + if (res < 0) { int err = SSL_get_error(conn->ssl, res); - if (err == SSL_ERROR_WANT_READ) - wpa_printf(MSG_DEBUG, "SSL: SSL_accept - want " - "more data"); - else if (err == SSL_ERROR_WANT_WRITE) - wpa_printf(MSG_DEBUG, "SSL: SSL_accept - want to " - "write"); - else { - tls_show_errors(MSG_INFO, __func__, "SSL_accept"); - return NULL; + if (err == SSL_ERROR_WANT_READ || + err == SSL_ERROR_WANT_WRITE) { + wpa_printf(MSG_DEBUG, "SSL: No Application Data " + "included"); + } else { + tls_show_errors(MSG_INFO, __func__, + "Failed to read possible " + "Application Data"); } + wpabuf_free(appl_data); + return NULL; } - /* Get the TLS handshake data to be sent to the client */ - res = BIO_ctrl_pending(conn->ssl_out); - wpa_printf(MSG_DEBUG, "SSL: %d bytes pending from ssl_out", res); - out_data = os_malloc(res == 0 ? 1 : res); - if (out_data == NULL) { - wpa_printf(MSG_DEBUG, "SSL: Failed to allocate memory for " - "handshake output (%d bytes)", res); - if (BIO_reset(conn->ssl_out) < 0) { - tls_show_errors(MSG_INFO, __func__, - "BIO_reset failed"); - } - *out_len = 0; + wpabuf_put(appl_data, res); + wpa_hexdump_buf_key(MSG_MSGDUMP, "SSL: Application Data in Finished " + "message", appl_data); + + return appl_data; +} + + +static struct wpabuf * +openssl_connection_handshake(struct tls_connection *conn, + const struct wpabuf *in_data, + struct wpabuf **appl_data, int server) +{ + struct wpabuf *out_data; + + if (appl_data) + *appl_data = NULL; + + out_data = openssl_handshake(conn, in_data, server); + if (out_data == NULL) return NULL; - } - res = res == 0 ? 0 : BIO_read(conn->ssl_out, out_data, res); - if (res < 0) { - tls_show_errors(MSG_INFO, __func__, - "Handshake failed - BIO_read"); - if (BIO_reset(conn->ssl_out) < 0) { - tls_show_errors(MSG_INFO, __func__, - "BIO_reset failed"); - } - *out_len = 0; - return NULL; - } - *out_len = res; + + if (SSL_is_init_finished(conn->ssl) && appl_data && in_data) + *appl_data = openssl_get_appl_data(conn, wpabuf_len(in_data)); + return out_data; } -int tls_connection_encrypt(void *ssl_ctx, struct tls_connection *conn, - const u8 *in_data, size_t in_len, - u8 *out_data, size_t out_len) +struct wpabuf * +tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn, + const struct wpabuf *in_data, + struct wpabuf **appl_data) +{ + return openssl_connection_handshake(conn, in_data, appl_data, 0); +} + + +struct wpabuf * tls_connection_server_handshake(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data, + struct wpabuf **appl_data) +{ + return openssl_connection_handshake(conn, in_data, appl_data, 1); +} + + +struct wpabuf * tls_connection_encrypt(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data) { int res; + struct wpabuf *buf; if (conn == NULL) - return -1; + return NULL; /* Give plaintext data for OpenSSL to encrypt into the TLS tunnel. */ if ((res = BIO_reset(conn->ssl_in)) < 0 || (res = BIO_reset(conn->ssl_out)) < 0) { tls_show_errors(MSG_INFO, __func__, "BIO_reset failed"); - return res; + return NULL; } - res = SSL_write(conn->ssl, in_data, in_len); + res = SSL_write(conn->ssl, wpabuf_head(in_data), wpabuf_len(in_data)); if (res < 0) { tls_show_errors(MSG_INFO, __func__, "Encryption failed - SSL_write"); - return res; + return NULL; } /* Read encrypted data to be sent to the server */ - res = BIO_read(conn->ssl_out, out_data, out_len); + buf = wpabuf_alloc(wpabuf_len(in_data) + 300); + if (buf == NULL) + return NULL; + res = BIO_read(conn->ssl_out, wpabuf_mhead(buf), wpabuf_size(buf)); if (res < 0) { tls_show_errors(MSG_INFO, __func__, "Encryption failed - BIO_read"); - return res; + wpabuf_free(buf); + return NULL; } + wpabuf_put(buf, res); - return res; + return buf; } -int tls_connection_decrypt(void *ssl_ctx, struct tls_connection *conn, - const u8 *in_data, size_t in_len, - u8 *out_data, size_t out_len) +struct wpabuf * tls_connection_decrypt(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data) { int res; + struct wpabuf *buf; /* Give encrypted data from TLS tunnel for OpenSSL to decrypt. */ - res = BIO_write(conn->ssl_in, in_data, in_len); + res = BIO_write(conn->ssl_in, wpabuf_head(in_data), + wpabuf_len(in_data)); if (res < 0) { tls_show_errors(MSG_INFO, __func__, "Decryption failed - BIO_write"); - return res; + return NULL; } if (BIO_reset(conn->ssl_out) < 0) { tls_show_errors(MSG_INFO, __func__, "BIO_reset failed"); - return res; + return NULL; } /* Read decrypted data for further processing */ - res = SSL_read(conn->ssl, out_data, out_len); + /* + * Even though we try to disable TLS compression, it is possible that + * this cannot be done with all TLS libraries. Add extra buffer space + * to handle the possibility of the decrypted data being longer than + * input data. + */ + buf = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3); + if (buf == NULL) + return NULL; + res = SSL_read(conn->ssl, wpabuf_mhead(buf), wpabuf_size(buf)); if (res < 0) { tls_show_errors(MSG_INFO, __func__, "Decryption failed - SSL_read"); - return res; + return NULL; } + wpabuf_put(buf, res); - return res; + return buf; } diff --git a/src/crypto/tls_schannel.c b/src/crypto/tls_schannel.c index 87e74353d..6600d42e7 100644 --- a/src/crypto/tls_schannel.c +++ b/src/crypto/tls_schannel.c @@ -1,6 +1,6 @@ /* - * WPA Supplicant / SSL/TLS interface functions for Microsoft Schannel - * Copyright (c) 2005, Jouni Malinen + * SSL/TLS interface functions for Microsoft Schannel + * Copyright (c) 2005-2009, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -215,9 +215,8 @@ int tls_connection_prf(void *tls_ctx, struct tls_connection *conn, } -static u8 * tls_conn_hs_clienthello(struct tls_global *global, - struct tls_connection *conn, - size_t *out_len) +static struct wpabuf * tls_conn_hs_clienthello(struct tls_global *global, + struct tls_connection *conn) { DWORD sspi_flags, sspi_flags_out; SecBufferDesc outbuf; @@ -260,15 +259,14 @@ static u8 * tls_conn_hs_clienthello(struct tls_global *global, } if (outbufs[0].cbBuffer != 0 && outbufs[0].pvBuffer) { - u8 *buf; + struct wpabuf *buf; wpa_hexdump(MSG_MSGDUMP, "SChannel - ClientHello", outbufs[0].pvBuffer, outbufs[0].cbBuffer); conn->start = 0; - *out_len = outbufs[0].cbBuffer; - buf = os_malloc(*out_len); + buf = wpabuf_alloc_copy(outbufs[0].pvBuffer, + outbufs[0].cbBuffer); if (buf == NULL) return NULL; - os_memcpy(buf, outbufs[0].pvBuffer, *out_len); global->sspi->FreeContextBuffer(outbufs[0].pvBuffer); return buf; } @@ -316,28 +314,27 @@ static int tls_get_eap(struct tls_global *global, struct tls_connection *conn) } -u8 * tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn, - const u8 *in_data, size_t in_len, - size_t *out_len, u8 **appl_data, - size_t *appl_data_len) +struct wpabuf * tls_connection_handshake(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data, + struct wpabuf **appl_data) { - struct tls_global *global = ssl_ctx; + struct tls_global *global = tls_ctx; DWORD sspi_flags, sspi_flags_out; SecBufferDesc inbuf, outbuf; SecBuffer inbufs[2], outbufs[1]; SECURITY_STATUS status; TimeStamp ts_expiry; - u8 *out_buf = NULL; + struct wpabuf *out_buf = NULL; if (appl_data) *appl_data = NULL; - if (conn->start) { - return tls_conn_hs_clienthello(global, conn, out_len); - } + if (conn->start) + return tls_conn_hs_clienthello(global, conn); wpa_printf(MSG_DEBUG, "SChannel: %d bytes handshake data to process", - in_len); + (int) wpabuf_len(in_data)); sspi_flags = ISC_REQ_REPLAY_DETECT | ISC_REQ_CONFIDENTIALITY | @@ -346,8 +343,8 @@ u8 * tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn, ISC_REQ_MANUAL_CRED_VALIDATION; /* Input buffer for Schannel */ - inbufs[0].pvBuffer = (u8 *) in_data; - inbufs[0].cbBuffer = in_len; + inbufs[0].pvBuffer = (u8 *) wpabuf_head(in_data); + inbufs[0].cbBuffer = wpabuf_len(in_data); inbufs[0].BufferType = SECBUFFER_TOKEN; /* Place for leftover data from Schannel */ @@ -392,11 +389,8 @@ u8 * tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn, if (outbufs[0].cbBuffer != 0 && outbufs[0].pvBuffer) { wpa_hexdump(MSG_MSGDUMP, "SChannel - output", outbufs[0].pvBuffer, outbufs[0].cbBuffer); - *out_len = outbufs[0].cbBuffer; - out_buf = os_malloc(*out_len); - if (out_buf) - os_memcpy(out_buf, outbufs[0].pvBuffer, - *out_len); + out_buf = wpabuf_alloc_copy(outbufs[0].pvBuffer, + outbufs[0].cbBuffer); global->sspi->FreeContextBuffer(outbufs[0].pvBuffer); outbufs[0].pvBuffer = NULL; if (out_buf == NULL) @@ -420,19 +414,16 @@ u8 * tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn, /* Need to return something to get final TLS ACK. */ if (out_buf == NULL) - out_buf = os_malloc(1); + out_buf = wpabuf_alloc(0); if (inbufs[1].BufferType == SECBUFFER_EXTRA) { wpa_hexdump(MSG_MSGDUMP, "SChannel - Encrypted " "application data", inbufs[1].pvBuffer, inbufs[1].cbBuffer); if (appl_data) { - *appl_data_len = outbufs[1].cbBuffer; - appl_data = os_malloc(*appl_data_len); - if (appl_data) - os_memcpy(appl_data, - outbufs[1].pvBuffer, - *appl_data_len); + *appl_data = wpabuf_alloc_copy( + outbufs[1].pvBuffer, + outbufs[1].cbBuffer); } global->sspi->FreeContextBuffer(inbufs[1].pvBuffer); inbufs[1].pvBuffer = NULL; @@ -470,26 +461,26 @@ u8 * tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn, } -u8 * tls_connection_server_handshake(void *ssl_ctx, - struct tls_connection *conn, - const u8 *in_data, size_t in_len, - size_t *out_len) +struct wpabuf * tls_connection_server_handshake(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data, + struct wpabuf **appl_data) { return NULL; } -int tls_connection_encrypt(void *ssl_ctx, struct tls_connection *conn, - const u8 *in_data, size_t in_len, - u8 *out_data, size_t out_len) +struct wpabuf * tls_connection_encrypt(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data) { - struct tls_global *global = ssl_ctx; + struct tls_global *global = tls_ctx; SECURITY_STATUS status; SecBufferDesc buf; SecBuffer bufs[4]; SecPkgContext_StreamSizes sizes; int i; - size_t total_len; + struct wpabuf *out; status = global->sspi->QueryContextAttributes(&conn->context, SECPKG_ATTR_STREAM_SIZES, @@ -497,34 +488,27 @@ int tls_connection_encrypt(void *ssl_ctx, struct tls_connection *conn, if (status != SEC_E_OK) { wpa_printf(MSG_DEBUG, "%s: QueryContextAttributes failed", __func__); - return -1; + return NULL; } wpa_printf(MSG_DEBUG, "%s: Stream sizes: header=%u trailer=%u", __func__, (unsigned int) sizes.cbHeader, (unsigned int) sizes.cbTrailer); - total_len = sizes.cbHeader + in_len + sizes.cbTrailer; - - if (out_len < total_len) { - wpa_printf(MSG_DEBUG, "%s: too short out_data (out_len=%lu " - "in_len=%lu total_len=%lu)", __func__, - (unsigned long) out_len, (unsigned long) in_len, - (unsigned long) total_len); - return -1; - } + out = wpabuf_alloc(sizes.cbHeader + wpabuf_len(in_data) + + sizes.cbTrailer); os_memset(&bufs, 0, sizeof(bufs)); - bufs[0].pvBuffer = out_data; + bufs[0].pvBuffer = wpabuf_put(out, sizes.cbHeader); bufs[0].cbBuffer = sizes.cbHeader; bufs[0].BufferType = SECBUFFER_STREAM_HEADER; - os_memcpy(out_data + sizes.cbHeader, in_data, in_len); - bufs[1].pvBuffer = out_data + sizes.cbHeader; - bufs[1].cbBuffer = in_len; + bufs[1].pvBuffer = wpabuf_put(out, 0); + wpabuf_put_buf(out, in_data); + bufs[1].cbBuffer = wpabuf_len(in_data); bufs[1].BufferType = SECBUFFER_DATA; - bufs[2].pvBuffer = out_data + sizes.cbHeader + in_len; + bufs[2].pvBuffer = wpabuf_put(out, sizes.cbTrailer); bufs[2].cbBuffer = sizes.cbTrailer; bufs[2].BufferType = SECBUFFER_STREAM_TRAILER; @@ -543,7 +527,7 @@ int tls_connection_encrypt(void *ssl_ctx, struct tls_connection *conn, (int) bufs[2].cbBuffer, (int) bufs[2].BufferType); wpa_printf(MSG_MSGDUMP, "Schannel: EncryptMessage pointers: " "out_data=%p bufs %p %p %p", - out_data, bufs[0].pvBuffer, bufs[1].pvBuffer, + wpabuf_head(out), bufs[0].pvBuffer, bufs[1].pvBuffer, bufs[2].pvBuffer); for (i = 0; i < 3; i++) { @@ -556,39 +540,37 @@ int tls_connection_encrypt(void *ssl_ctx, struct tls_connection *conn, if (status == SEC_E_OK) { wpa_printf(MSG_DEBUG, "%s: SEC_E_OK", __func__); - wpa_hexdump_key(MSG_MSGDUMP, "Schannel: Encrypted data from " - "EncryptMessage", out_data, total_len); - return total_len; + wpa_hexdump_buf_key(MSG_MSGDUMP, "Schannel: Encrypted data " + "from EncryptMessage", out); + return out; } wpa_printf(MSG_DEBUG, "%s: Failed - status=%d", __func__, (int) status); - return -1; + wpabuf_free(out); + return NULL; } -int tls_connection_decrypt(void *ssl_ctx, struct tls_connection *conn, - const u8 *in_data, size_t in_len, - u8 *out_data, size_t out_len) +struct wpabuf * tls_connection_decrypt(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data) { - struct tls_global *global = ssl_ctx; + struct tls_global *global = tls_ctx; SECURITY_STATUS status; SecBufferDesc buf; SecBuffer bufs[4]; int i; + struct wpabuf *out, *tmp; - if (out_len < in_len) { - wpa_printf(MSG_DEBUG, "%s: out_len=%lu < in_len=%lu", __func__, - (unsigned long) out_len, (unsigned long) in_len); - return -1; - } - - wpa_hexdump(MSG_MSGDUMP, "Schannel: Encrypted data to DecryptMessage", - in_data, in_len); + wpa_hexdump_buf(MSG_MSGDUMP, + "Schannel: Encrypted data to DecryptMessage", in_data); os_memset(&bufs, 0, sizeof(bufs)); - os_memcpy(out_data, in_data, in_len); - bufs[0].pvBuffer = out_data; - bufs[0].cbBuffer = in_len; + tmp = wpabuf_dup(in_data); + if (tmp == NULL) + return NULL; + bufs[0].pvBuffer = wpabuf_mhead(tmp); + bufs[0].cbBuffer = wpabuf_len(in_data); bufs[0].BufferType = SECBUFFER_DATA; bufs[1].BufferType = SECBUFFER_EMPTY; @@ -611,7 +593,7 @@ int tls_connection_decrypt(void *ssl_ctx, struct tls_connection *conn, (int) bufs[3].cbBuffer, (int) bufs[3].BufferType); wpa_printf(MSG_MSGDUMP, "Schannel: DecryptMessage pointers: " "out_data=%p bufs %p %p %p %p", - out_data, bufs[0].pvBuffer, bufs[1].pvBuffer, + wpabuf_head(tmp), bufs[0].pvBuffer, bufs[1].pvBuffer, bufs[2].pvBuffer, bufs[3].pvBuffer); switch (status) { @@ -628,23 +610,21 @@ int tls_connection_decrypt(void *ssl_ctx, struct tls_connection *conn, if (i == 4) { wpa_printf(MSG_DEBUG, "%s: No output data from " "DecryptMessage", __func__); - return -1; + wpabuf_free(tmp); + return NULL; } wpa_hexdump_key(MSG_MSGDUMP, "Schannel: Decrypted data from " "DecryptMessage", bufs[i].pvBuffer, bufs[i].cbBuffer); - if (bufs[i].cbBuffer > out_len) { - wpa_printf(MSG_DEBUG, "%s: Too long output data", - __func__); - return -1; - } - os_memmove(out_data, bufs[i].pvBuffer, bufs[i].cbBuffer); - return bufs[i].cbBuffer; + out = wpabuf_alloc_copy(bufs[i].pvBuffer, bufs[i].cbBuffer); + wpabuf_free(tmp); + return out; } wpa_printf(MSG_DEBUG, "%s: Failed - status=%d", __func__, (int) status); - return -1; + wpabuf_free(tmp); + return NULL; } diff --git a/src/eap_peer/eap_tls_common.c b/src/eap_peer/eap_tls_common.c index 43ee58405..956dda2b0 100644 --- a/src/eap_peer/eap_tls_common.c +++ b/src/eap_peer/eap_tls_common.c @@ -1,6 +1,6 @@ /* * EAP peer: EAP-TLS/PEAP/TTLS/FAST common functions - * Copyright (c) 2004-2008, Jouni Malinen + * Copyright (c) 2004-2009, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -296,27 +296,29 @@ fail: * eap_peer_tls_reassemble_fragment - Reassemble a received fragment * @data: Data for TLS processing * @in_data: Next incoming TLS segment - * @in_len: Length of in_data * Returns: 0 on success, 1 if more data is needed for the full message, or * -1 on error */ static int eap_peer_tls_reassemble_fragment(struct eap_ssl_data *data, - const u8 *in_data, size_t in_len) + const struct wpabuf *in_data) { - u8 *buf; + size_t tls_in_len, in_len; - if (data->tls_in_len + in_len == 0) { + tls_in_len = data->tls_in ? wpabuf_len(data->tls_in) : 0; + in_len = in_data ? wpabuf_len(in_data) : 0; + + if (tls_in_len + in_len == 0) { /* No message data received?! */ wpa_printf(MSG_WARNING, "SSL: Invalid reassembly state: " "tls_in_left=%lu tls_in_len=%lu in_len=%lu", (unsigned long) data->tls_in_left, - (unsigned long) data->tls_in_len, + (unsigned long) tls_in_len, (unsigned long) in_len); eap_peer_tls_reset_input(data); return -1; } - if (data->tls_in_len + in_len > 65536) { + if (tls_in_len + in_len > 65536) { /* * Limit length to avoid rogue servers from causing large * memory allocations. @@ -335,16 +337,13 @@ static int eap_peer_tls_reassemble_fragment(struct eap_ssl_data *data, return -1; } - buf = os_realloc(data->tls_in, data->tls_in_len + in_len); - if (buf == NULL) { + if (wpabuf_resize(&data->tls_in, in_len) < 0) { wpa_printf(MSG_INFO, "SSL: Could not allocate memory for TLS " "data"); eap_peer_tls_reset_input(data); return -1; } - os_memcpy(buf + data->tls_in_len, in_data, in_len); - data->tls_in = buf; - data->tls_in_len += in_len; + wpabuf_put_buf(data->tls_in, in_data); data->tls_in_left -= in_len; if (data->tls_in_left > 0) { @@ -361,8 +360,6 @@ static int eap_peer_tls_reassemble_fragment(struct eap_ssl_data *data, * eap_peer_tls_data_reassemble - Reassemble TLS data * @data: Data for TLS processing * @in_data: Next incoming TLS segment - * @in_len: Length of in_data - * @out_len: Variable for returning length of the reassembled message * @need_more_input: Variable for returning whether more input data is needed * to reassemble this TLS packet * Returns: Pointer to output data, %NULL on error or when more data is needed @@ -371,16 +368,15 @@ static int eap_peer_tls_reassemble_fragment(struct eap_ssl_data *data, * This function reassembles TLS fragments. Caller must not free the returned * data buffer since an internal pointer to it is maintained. */ -const u8 * eap_peer_tls_data_reassemble( - struct eap_ssl_data *data, const u8 *in_data, size_t in_len, - size_t *out_len, int *need_more_input) +static const struct wpabuf * eap_peer_tls_data_reassemble( + struct eap_ssl_data *data, const struct wpabuf *in_data, + int *need_more_input) { *need_more_input = 0; - if (data->tls_in_left > in_len || data->tls_in) { + if (data->tls_in_left > wpabuf_len(in_data) || data->tls_in) { /* Message has fragments */ - int res = eap_peer_tls_reassemble_fragment(data, in_data, - in_len); + int res = eap_peer_tls_reassemble_fragment(data, in_data); if (res) { if (res == 1) *need_more_input = 1; @@ -391,14 +387,11 @@ const u8 * eap_peer_tls_data_reassemble( } else { /* No fragments in this message, so just make a copy of it. */ data->tls_in_left = 0; - data->tls_in = os_malloc(in_len ? in_len : 1); + data->tls_in = wpabuf_dup(in_data); if (data->tls_in == NULL) return NULL; - os_memcpy(data->tls_in, in_data, in_len); - data->tls_in_len = in_len; } - *out_len = data->tls_in_len; return data->tls_in; } @@ -417,14 +410,13 @@ static int eap_tls_process_input(struct eap_sm *sm, struct eap_ssl_data *data, const u8 *in_data, size_t in_len, struct wpabuf **out_data) { - const u8 *msg; - size_t msg_len; + const struct wpabuf *msg; int need_more_input; - u8 *appl_data; - size_t appl_data_len; + struct wpabuf *appl_data; + struct wpabuf buf; - msg = eap_peer_tls_data_reassemble(data, in_data, in_len, - &msg_len, &need_more_input); + wpabuf_set(&buf, in_data, in_len); + msg = eap_peer_tls_data_reassemble(data, &buf, &need_more_input); if (msg == NULL) return need_more_input ? 1 : -1; @@ -433,31 +425,25 @@ static int eap_tls_process_input(struct eap_sm *sm, struct eap_ssl_data *data, /* This should not happen.. */ wpa_printf(MSG_INFO, "SSL: eap_tls_process_input - pending " "tls_out data even though tls_out_len = 0"); - os_free(data->tls_out); + wpabuf_free(data->tls_out); WPA_ASSERT(data->tls_out == NULL); } appl_data = NULL; data->tls_out = tls_connection_handshake(sm->ssl_ctx, data->conn, - msg, msg_len, - &data->tls_out_len, - &appl_data, &appl_data_len); + msg, &appl_data); eap_peer_tls_reset_input(data); if (appl_data && tls_connection_established(sm->ssl_ctx, data->conn) && !tls_connection_get_failed(sm->ssl_ctx, data->conn)) { - wpa_hexdump_key(MSG_MSGDUMP, "SSL: Application data", - appl_data, appl_data_len); - *out_data = wpabuf_alloc_ext_data(appl_data, appl_data_len); - if (*out_data == NULL) { - os_free(appl_data); - return -1; - } + wpa_hexdump_buf_key(MSG_MSGDUMP, "SSL: Application data", + appl_data); + *out_data = appl_data; return 2; } - os_free(appl_data); + wpabuf_free(appl_data); return 0; } @@ -480,11 +466,14 @@ static int eap_tls_process_output(struct eap_ssl_data *data, EapType eap_type, size_t len; u8 *flags; int more_fragments, length_included; - - len = data->tls_out_len - data->tls_out_pos; + + if (data->tls_out == NULL) + return -1; + len = wpabuf_len(data->tls_out) - data->tls_out_pos; wpa_printf(MSG_DEBUG, "SSL: %lu bytes left to be sent out (of total " "%lu bytes)", - (unsigned long) len, (unsigned long) data->tls_out_len); + (unsigned long) len, + (unsigned long) wpabuf_len(data->tls_out)); /* * Limit outgoing message to the configured maximum size. Fragment @@ -499,7 +488,7 @@ static int eap_tls_process_output(struct eap_ssl_data *data, EapType eap_type, more_fragments = 0; length_included = data->tls_out_pos == 0 && - (data->tls_out_len > data->tls_out_limit || + (wpabuf_len(data->tls_out) > data->tls_out_limit || data->include_tls_length); if (!length_included && eap_type == EAP_TYPE_PEAP && peap_version == 0 && @@ -525,10 +514,12 @@ static int eap_tls_process_output(struct eap_ssl_data *data, EapType eap_type, *flags |= EAP_TLS_FLAGS_MORE_FRAGMENTS; if (length_included) { *flags |= EAP_TLS_FLAGS_LENGTH_INCLUDED; - wpabuf_put_be32(*out_data, data->tls_out_len); + wpabuf_put_be32(*out_data, wpabuf_len(data->tls_out)); } - wpabuf_put_data(*out_data, &data->tls_out[data->tls_out_pos], len); + wpabuf_put_data(*out_data, + wpabuf_head_u8(data->tls_out) + data->tls_out_pos, + len); data->tls_out_pos += len; if (!more_fragments) @@ -576,13 +567,13 @@ int eap_peer_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data, *out_data = NULL; - if (data->tls_out_len > 0 && in_len > 0) { + if (data->tls_out && wpabuf_len(data->tls_out) > 0 && in_len > 0) { wpa_printf(MSG_DEBUG, "SSL: Received non-ACK when output " "fragments are waiting to be sent out"); return -1; } - if (data->tls_out_len == 0) { + if (data->tls_out == NULL || wpabuf_len(data->tls_out) == 0) { /* * No more data to send out - expect to receive more data from * the AS. @@ -621,14 +612,14 @@ int eap_peer_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data, /* TODO: clean pin if engine used? */ } - if (data->tls_out_len == 0) { + if (data->tls_out == NULL || wpabuf_len(data->tls_out) == 0) { /* * TLS negotiation should now be complete since all other cases * needing more data should have been caught above based on * the TLS Message Length field. */ wpa_printf(MSG_DEBUG, "SSL: No data to be sent out"); - os_free(data->tls_out); + wpabuf_free(data->tls_out); data->tls_out = NULL; return 1; } @@ -780,9 +771,8 @@ const u8 * eap_peer_tls_process_init(struct eap_sm *sm, if (data->tls_in_left == 0) { data->tls_in_total = tls_msg_len; data->tls_in_left = tls_msg_len; - os_free(data->tls_in); + wpabuf_free(data->tls_in); data->tls_in = NULL; - data->tls_in_len = 0; } pos += 4; left -= 4; @@ -807,8 +797,8 @@ const u8 * eap_peer_tls_process_init(struct eap_sm *sm, */ void eap_peer_tls_reset_input(struct eap_ssl_data *data) { - data->tls_in_left = data->tls_in_total = data->tls_in_len = 0; - os_free(data->tls_in); + data->tls_in_left = data->tls_in_total = 0; + wpabuf_free(data->tls_in); data->tls_in = NULL; } @@ -822,9 +812,8 @@ void eap_peer_tls_reset_input(struct eap_ssl_data *data) */ void eap_peer_tls_reset_output(struct eap_ssl_data *data) { - data->tls_out_len = 0; data->tls_out_pos = 0; - os_free(data->tls_out); + wpabuf_free(data->tls_out); data->tls_out = NULL; } @@ -841,44 +830,19 @@ int eap_peer_tls_decrypt(struct eap_sm *sm, struct eap_ssl_data *data, const struct wpabuf *in_data, struct wpabuf **in_decrypted) { - int res; - const u8 *msg; - size_t msg_len, buf_len; + const struct wpabuf *msg; int need_more_input; - msg = eap_peer_tls_data_reassemble(data, wpabuf_head(in_data), - wpabuf_len(in_data), &msg_len, - &need_more_input); + msg = eap_peer_tls_data_reassemble(data, in_data, &need_more_input); if (msg == NULL) return need_more_input ? 1 : -1; - buf_len = wpabuf_len(in_data); - if (data->tls_in_total > buf_len) - buf_len = data->tls_in_total; - /* - * Even though we try to disable TLS compression, it is possible that - * this cannot be done with all TLS libraries. Add extra buffer space - * to handle the possibility of the decrypted data being longer than - * input data. - */ - buf_len += 500; - buf_len *= 3; - *in_decrypted = wpabuf_alloc(buf_len ? buf_len : 1); - if (*in_decrypted == NULL) { - eap_peer_tls_reset_input(data); - wpa_printf(MSG_WARNING, "SSL: Failed to allocate memory for " - "decryption"); - return -1; - } - - res = tls_connection_decrypt(sm->ssl_ctx, data->conn, msg, msg_len, - wpabuf_mhead(*in_decrypted), buf_len); + *in_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->conn, msg); eap_peer_tls_reset_input(data); - if (res < 0) { + if (*in_decrypted == NULL) { wpa_printf(MSG_INFO, "SSL: Failed to decrypt Phase 2 data"); return -1; } - wpabuf_put(*in_decrypted, res); return 0; } @@ -899,29 +863,17 @@ int eap_peer_tls_encrypt(struct eap_sm *sm, struct eap_ssl_data *data, const struct wpabuf *in_data, struct wpabuf **out_data) { - int res; - size_t len; - if (in_data) { eap_peer_tls_reset_output(data); - len = wpabuf_len(in_data) + 300; - data->tls_out = os_malloc(len); - if (data->tls_out == NULL) - return -1; - - res = tls_connection_encrypt(sm->ssl_ctx, data->conn, - wpabuf_head(in_data), - wpabuf_len(in_data), - data->tls_out, len); - if (res < 0) { + data->tls_out = tls_connection_encrypt(sm->ssl_ctx, data->conn, + in_data); + if (data->tls_out == NULL) { wpa_printf(MSG_INFO, "SSL: Failed to encrypt Phase 2 " "data (in_len=%lu)", (unsigned long) wpabuf_len(in_data)); eap_peer_tls_reset_output(data); return -1; } - - data->tls_out_len = res; } return eap_tls_process_output(data, eap_type, peap_version, id, 0, diff --git a/src/eap_peer/eap_tls_common.h b/src/eap_peer/eap_tls_common.h index 2c87427c2..ff86c055b 100644 --- a/src/eap_peer/eap_tls_common.h +++ b/src/eap_peer/eap_tls_common.h @@ -1,6 +1,6 @@ /* * EAP peer: EAP-TLS/PEAP/TTLS/FAST common functions - * Copyright (c) 2004-2006, Jouni Malinen + * Copyright (c) 2004-2009, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -27,12 +27,7 @@ struct eap_ssl_data { /** * tls_out - TLS message to be sent out in fragments */ - u8 *tls_out; - - /** - * tls_out_len - Total length of the outgoing TLS message - */ - size_t tls_out_len; + struct wpabuf *tls_out; /** * tls_out_pos - The current position in the outgoing TLS message @@ -47,12 +42,7 @@ struct eap_ssl_data { /** * tls_in - Received TLS message buffer for re-assembly */ - u8 *tls_in; - - /** - * tls_in_len - Number of bytes of the received TLS message in tls_in - */ - size_t tls_in_len; + struct wpabuf *tls_in; /** * tls_in_left - Number of remaining bytes in the incoming TLS message @@ -102,9 +92,6 @@ int eap_peer_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data, void eap_peer_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data); u8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data, const char *label, size_t len); -const u8 * eap_peer_tls_data_reassemble( - struct eap_ssl_data *data, const u8 *in_data, size_t in_len, - size_t *out_len, int *need_more_input); int eap_peer_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data, EapType eap_type, int peap_version, u8 id, const u8 *in_data, size_t in_len, diff --git a/src/eap_server/eap_fast.c b/src/eap_server/eap_fast.c index 9f7f22972..b4e2f1afa 100644 --- a/src/eap_server/eap_fast.c +++ b/src/eap_server/eap_fast.c @@ -816,8 +816,7 @@ static int eap_fast_encrypt_phase2(struct eap_sm *sm, wpa_hexdump_buf_key(MSG_DEBUG, "EAP-FAST: Encrypting Phase 2 TLVs", plain); - encr = eap_server_tls_encrypt(sm, &data->ssl, wpabuf_mhead(plain), - wpabuf_len(plain)); + encr = eap_server_tls_encrypt(sm, &data->ssl, plain); wpabuf_free(plain); if (data->ssl.out_buf && piggyback) { @@ -1121,7 +1120,7 @@ static void eap_fast_process_phase2_eap(struct eap_sm *sm, } -static int eap_fast_parse_tlvs(u8 *data, size_t data_len, +static int eap_fast_parse_tlvs(struct wpabuf *data, struct eap_fast_tlv_parse *tlv) { int mandatory, tlv_type, len, res; @@ -1129,8 +1128,8 @@ static int eap_fast_parse_tlvs(u8 *data, size_t data_len, os_memset(tlv, 0, sizeof(*tlv)); - pos = data; - end = data + data_len; + pos = wpabuf_mhead(data); + end = pos + wpabuf_len(data); while (pos + 4 < end) { mandatory = pos[0] & 0x80; tlv_type = WPA_GET_BE16(pos) & 0x3fff; @@ -1241,12 +1240,12 @@ static int eap_fast_pac_type(u8 *pac, size_t len, u16 type) static void eap_fast_process_phase2_tlvs(struct eap_sm *sm, struct eap_fast_data *data, - u8 *in_data, size_t in_len) + struct wpabuf *in_data) { struct eap_fast_tlv_parse tlv; int check_crypto_binding = data->state == CRYPTO_BINDING; - if (eap_fast_parse_tlvs(in_data, in_len, &tlv) < 0) { + if (eap_fast_parse_tlvs(in_data, &tlv) < 0) { wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to parse received " "Phase 2 TLVs"); return; @@ -1373,70 +1372,44 @@ static void eap_fast_process_phase2(struct eap_sm *sm, struct eap_fast_data *data, struct wpabuf *in_buf) { - u8 *in_decrypted; - int len_decrypted; - size_t buf_len; - u8 *in_data; - size_t in_len; - - in_data = wpabuf_mhead(in_buf); - in_len = wpabuf_len(in_buf); + struct wpabuf *in_decrypted; wpa_printf(MSG_DEBUG, "EAP-FAST: Received %lu bytes encrypted data for" - " Phase 2", (unsigned long) in_len); + " Phase 2", (unsigned long) wpabuf_len(in_buf)); if (data->pending_phase2_resp) { wpa_printf(MSG_DEBUG, "EAP-PEAP: Pending Phase 2 response - " "skip decryption and use old data"); - eap_fast_process_phase2_tlvs( - sm, data, wpabuf_mhead(data->pending_phase2_resp), - wpabuf_len(data->pending_phase2_resp)); + eap_fast_process_phase2_tlvs(sm, data, + data->pending_phase2_resp); wpabuf_free(data->pending_phase2_resp); data->pending_phase2_resp = NULL; return; } - buf_len = in_len; - /* - * Even though we try to disable TLS compression, it is possible that - * this cannot be done with all TLS libraries. Add extra buffer space - * to handle the possibility of the decrypted data being longer than - * input data. - */ - buf_len += 500; - buf_len *= 3; - in_decrypted = os_malloc(buf_len); + in_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn, + in_buf); if (in_decrypted == NULL) { - wpa_printf(MSG_WARNING, "EAP-FAST: Failed to allocate memory " - "for decryption"); - return; - } - - len_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn, - in_data, in_len, - in_decrypted, buf_len); - if (len_decrypted < 0) { wpa_printf(MSG_INFO, "EAP-FAST: Failed to decrypt Phase 2 " "data"); - os_free(in_decrypted); eap_fast_state(data, FAILURE); return; } - wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Decrypted Phase 2 TLVs", - in_decrypted, len_decrypted); + wpa_hexdump_buf_key(MSG_DEBUG, "EAP-FAST: Decrypted Phase 2 TLVs", + in_decrypted); - eap_fast_process_phase2_tlvs(sm, data, in_decrypted, len_decrypted); + eap_fast_process_phase2_tlvs(sm, data, in_decrypted); if (sm->method_pending == METHOD_PENDING_WAIT) { wpa_printf(MSG_DEBUG, "EAP-FAST: Phase2 method is in " "pending wait state - save decrypted response"); wpabuf_free(data->pending_phase2_resp); - data->pending_phase2_resp = wpabuf_alloc_copy(in_decrypted, - len_decrypted); + data->pending_phase2_resp = in_decrypted; + return; } - os_free(in_decrypted); + wpabuf_free(in_decrypted); } diff --git a/src/eap_server/eap_peap.c b/src/eap_server/eap_peap.c index 9ffb15d9d..23b6a4b93 100644 --- a/src/eap_server/eap_peap.c +++ b/src/eap_server/eap_peap.c @@ -235,7 +235,7 @@ static struct wpabuf * eap_peap_build_phase2_req(struct eap_sm *sm, struct eap_peap_data *data, u8 id) { - struct wpabuf *buf, *encr_req; + struct wpabuf *buf, *encr_req, msgbuf; const u8 *req; size_t req_len; @@ -260,7 +260,8 @@ static struct wpabuf * eap_peap_build_phase2_req(struct eap_sm *sm, req_len -= sizeof(struct eap_hdr); } - encr_req = eap_server_tls_encrypt(sm, &data->ssl, req, req_len); + wpabuf_set(&msgbuf, req, req_len); + encr_req = eap_server_tls_encrypt(sm, &data->ssl, &msgbuf); wpabuf_free(buf); return encr_req; @@ -272,7 +273,7 @@ static struct wpabuf * eap_peap_build_phase2_soh(struct eap_sm *sm, struct eap_peap_data *data, u8 id) { - struct wpabuf *buf1, *buf, *encr_req; + struct wpabuf *buf1, *buf, *encr_req, msgbuf; const u8 *req; size_t req_len; @@ -297,8 +298,9 @@ static struct wpabuf * eap_peap_build_phase2_soh(struct eap_sm *sm, req += sizeof(struct eap_hdr); req_len -= sizeof(struct eap_hdr); + wpabuf_set(&msgbuf, req, req_len); - encr_req = eap_server_tls_encrypt(sm, &data->ssl, req, req_len); + encr_req = eap_server_tls_encrypt(sm, &data->ssl, &msgbuf); wpabuf_free(buf); return encr_req; @@ -450,8 +452,7 @@ static struct wpabuf * eap_peap_build_phase2_tlv(struct eap_sm *sm, wpa_hexdump_buf_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 TLV data", buf); - encr_req = eap_server_tls_encrypt(sm, &data->ssl, wpabuf_head(buf), - wpabuf_len(buf)); + encr_req = eap_server_tls_encrypt(sm, &data->ssl, buf); wpabuf_free(buf); return encr_req; @@ -462,7 +463,7 @@ static struct wpabuf * eap_peap_build_phase2_term(struct eap_sm *sm, struct eap_peap_data *data, u8 id, int success) { - struct wpabuf *encr_req; + struct wpabuf *encr_req, msgbuf; size_t req_len; struct eap_hdr *hdr; @@ -478,7 +479,8 @@ static struct wpabuf * eap_peap_build_phase2_term(struct eap_sm *sm, wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 data", (u8 *) hdr, req_len); - encr_req = eap_server_tls_encrypt(sm, &data->ssl, (u8 *) hdr, req_len); + wpabuf_set(&msgbuf, hdr, req_len); + encr_req = eap_server_tls_encrypt(sm, &data->ssl, &msgbuf); os_free(hdr); return encr_req; @@ -1029,17 +1031,11 @@ static void eap_peap_process_phase2(struct eap_sm *sm, struct wpabuf *in_buf) { struct wpabuf *in_decrypted; - int len_decrypted; const struct eap_hdr *hdr; - size_t buf_len, len; - u8 *in_data; - size_t in_len; - - in_data = wpabuf_mhead(in_buf); - in_len = wpabuf_len(in_buf); + size_t len; wpa_printf(MSG_DEBUG, "EAP-PEAP: received %lu bytes encrypted data for" - " Phase 2", (unsigned long) in_len); + " Phase 2", (unsigned long) wpabuf_len(in_buf)); if (data->pending_phase2_resp) { wpa_printf(MSG_DEBUG, "EAP-PEAP: Pending Phase 2 response - " @@ -1051,34 +1047,14 @@ static void eap_peap_process_phase2(struct eap_sm *sm, return; } - buf_len = in_len; - /* - * Even though we try to disable TLS compression, it is possible that - * this cannot be done with all TLS libraries. Add extra buffer space - * to handle the possibility of the decrypted data being longer than - * input data. - */ - buf_len += 500; - buf_len *= 3; - in_decrypted = wpabuf_alloc(buf_len); + in_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn, + in_buf); if (in_decrypted == NULL) { - wpa_printf(MSG_WARNING, "EAP-PEAP: failed to allocate memory " - "for decryption"); - return; - } - - len_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn, - in_data, in_len, - wpabuf_mhead(in_decrypted), - buf_len); - if (len_decrypted < 0) { wpa_printf(MSG_INFO, "EAP-PEAP: Failed to decrypt Phase 2 " "data"); - wpabuf_free(in_decrypted); eap_peap_state(data, FAILURE); return; } - wpabuf_put(in_decrypted, len_decrypted); wpa_hexdump_buf_key(MSG_DEBUG, "EAP-PEAP: Decrypted Phase 2 EAP", in_decrypted); @@ -1191,7 +1167,7 @@ static void eap_peap_process_phase2(struct eap_sm *sm, break; } - os_free(in_decrypted); + wpabuf_free(in_decrypted); } @@ -1199,7 +1175,6 @@ static int eap_peapv2_start_phase2(struct eap_sm *sm, struct eap_peap_data *data) { struct wpabuf *buf, *buf2; - int res; wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Phase1 done, include first Phase2 " "payload in the same message"); @@ -1218,26 +1193,16 @@ static int eap_peapv2_start_phase2(struct eap_sm *sm, wpa_hexdump_buf(MSG_DEBUG, "EAP-PEAPv2: Identity Request", buf2); - buf = wpabuf_alloc(data->ssl.tls_out_limit); - if (buf == NULL) { - wpabuf_free(buf2); - return -1; - } - - res = tls_connection_encrypt(sm->ssl_ctx, data->ssl.conn, - wpabuf_head(buf2), wpabuf_len(buf2), - wpabuf_put(buf, 0), - data->ssl.tls_out_limit); + buf = tls_connection_encrypt(sm->ssl_ctx, data->ssl.conn, + buf2); wpabuf_free(buf2); - if (res < 0) { + if (buf == NULL) { wpa_printf(MSG_INFO, "EAP-PEAPv2: Failed to encrypt Phase 2 " "data"); - wpabuf_free(buf); return -1; } - wpabuf_put(buf, res); wpa_hexdump_buf(MSG_DEBUG, "EAP-PEAPv2: Encrypted Identity Request", buf); diff --git a/src/eap_server/eap_tls_common.c b/src/eap_server/eap_tls_common.c index d70aff6df..c4c7806ed 100644 --- a/src/eap_server/eap_tls_common.c +++ b/src/eap_server/eap_tls_common.c @@ -1,6 +1,6 @@ /* - * hostapd / EAP-TLS/PEAP/TTLS/FAST common functions - * Copyright (c) 2004-2008, Jouni Malinen + * EAP-TLS/PEAP/TTLS/FAST server common functions + * Copyright (c) 2004-2009, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -239,30 +239,22 @@ static int eap_server_tls_process_fragment(struct eap_ssl_data *data, int eap_server_tls_phase1(struct eap_sm *sm, struct eap_ssl_data *data) { - u8 *next; - size_t next_len; - - next = tls_connection_server_handshake( - sm->ssl_ctx, data->conn, - wpabuf_mhead(data->in_buf), - wpabuf_len(data->in_buf), - &next_len); - if (next == NULL) { - wpa_printf(MSG_INFO, "SSL: TLS processing failed"); - return -1; - } if (data->out_buf) { /* This should not happen.. */ wpa_printf(MSG_INFO, "SSL: pending tls_out data when " "processing new message"); - os_free(data->out_buf); + wpabuf_free(data->out_buf); WPA_ASSERT(data->out_buf == NULL); } - data->out_buf = wpabuf_alloc_ext_data(next, next_len); + + data->out_buf = tls_connection_server_handshake(sm->ssl_ctx, + data->conn, + data->in_buf, NULL); if (data->out_buf == NULL) { - os_free(next); + wpa_printf(MSG_INFO, "SSL: TLS processing failed"); return -1; } + return 0; } @@ -337,28 +329,17 @@ static void eap_server_tls_free_in_buf(struct eap_ssl_data *data) struct wpabuf * eap_server_tls_encrypt(struct eap_sm *sm, struct eap_ssl_data *data, - const u8 *plain, size_t plain_len) + const struct wpabuf *plain) { - int res; struct wpabuf *buf; - size_t buf_len; - /* reserve some extra room for encryption overhead */ - buf_len = plain_len + 300; - buf = wpabuf_alloc(buf_len); - if (buf == NULL) - return NULL; - res = tls_connection_encrypt(sm->ssl_ctx, data->conn, - plain, plain_len, wpabuf_put(buf, 0), - buf_len); - if (res < 0) { + buf = tls_connection_encrypt(sm->ssl_ctx, data->conn, + plain); + if (buf == NULL) { wpa_printf(MSG_INFO, "SSL: Failed to encrypt Phase 2 data"); - wpabuf_free(buf); return NULL; } - wpabuf_put(buf, res); - return buf; } diff --git a/src/eap_server/eap_tls_common.h b/src/eap_server/eap_tls_common.h index ce8dd252b..e24287fe9 100644 --- a/src/eap_server/eap_tls_common.h +++ b/src/eap_server/eap_tls_common.h @@ -1,6 +1,6 @@ /* - * hostapd / EAP-TLS/PEAP/TTLS/FAST common functions - * Copyright (c) 2004-2008, Jouni Malinen + * EAP-TLS/PEAP/TTLS/FAST server common functions + * Copyright (c) 2004-2009, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -53,7 +53,7 @@ struct wpabuf * eap_server_tls_build_ack(u8 id, int eap_type, int version); int eap_server_tls_phase1(struct eap_sm *sm, struct eap_ssl_data *data); struct wpabuf * eap_server_tls_encrypt(struct eap_sm *sm, struct eap_ssl_data *data, - const u8 *plain, size_t plain_len); + const struct wpabuf *plain); int eap_server_tls_process(struct eap_sm *sm, struct eap_ssl_data *data, struct wpabuf *respData, void *priv, int eap_type, int (*proc_version)(struct eap_sm *sm, void *priv, diff --git a/src/eap_server/eap_ttls.c b/src/eap_server/eap_ttls.c index c59b9d105..14c323356 100644 --- a/src/eap_server/eap_ttls.c +++ b/src/eap_server/eap_ttls.c @@ -163,14 +163,14 @@ struct eap_ttls_avp { }; -static int eap_ttls_avp_parse(u8 *buf, size_t len, struct eap_ttls_avp *parse) +static int eap_ttls_avp_parse(struct wpabuf *buf, struct eap_ttls_avp *parse) { struct ttls_avp *avp; u8 *pos; int left; - pos = buf; - left = len; + pos = wpabuf_mhead(buf); + left = wpabuf_len(buf); os_memset(parse, 0, sizeof(*parse)); while (left > 0) { @@ -449,8 +449,6 @@ static struct wpabuf * eap_ttls_build_phase2_eap_req( struct eap_sm *sm, struct eap_ttls_data *data, u8 id) { struct wpabuf *buf, *encr_req; - u8 *req; - size_t req_len; buf = data->phase2_method->buildReq(sm, data->phase2_priv, id); @@ -467,12 +465,10 @@ static struct wpabuf * eap_ttls_build_phase2_eap_req( return NULL; } - req = wpabuf_mhead(buf); - req_len = wpabuf_len(buf); - wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS/EAP: Encrypt encapsulated Phase " - "2 data", req, req_len); + wpa_hexdump_buf_key(MSG_DEBUG, "EAP-TTLS/EAP: Encrypt encapsulated " + "Phase 2 data", buf); - encr_req = eap_server_tls_encrypt(sm, &data->ssl, req, req_len); + encr_req = eap_server_tls_encrypt(sm, &data->ssl, buf); wpabuf_free(buf); return encr_req; @@ -482,10 +478,9 @@ static struct wpabuf * eap_ttls_build_phase2_eap_req( static struct wpabuf * eap_ttls_build_phase2_mschapv2( struct eap_sm *sm, struct eap_ttls_data *data) { - struct wpabuf *encr_req; + struct wpabuf *encr_req, msgbuf; u8 *req, *pos, *end; int ret; - size_t req_len; pos = req = os_malloc(100); if (req == NULL) @@ -510,11 +505,11 @@ static struct wpabuf * eap_ttls_build_phase2_mschapv2( AVP_PAD(req, pos); } - req_len = pos - req; - wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Encrypting Phase 2 " - "data", req, req_len); + wpabuf_set(&msgbuf, req, pos - req); + wpa_hexdump_buf_key(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Encrypting Phase 2 " + "data", &msgbuf); - encr_req = eap_server_tls_encrypt(sm, &data->ssl, req, req_len); + encr_req = eap_server_tls_encrypt(sm, &data->ssl, &msgbuf); os_free(req); return encr_req; @@ -1126,18 +1121,11 @@ static void eap_ttls_process_phase2(struct eap_sm *sm, struct eap_ttls_data *data, struct wpabuf *in_buf) { - u8 *in_decrypted; - int len_decrypted; + struct wpabuf *in_decrypted; struct eap_ttls_avp parse; - size_t buf_len; - u8 *in_data; - size_t in_len; - - in_data = wpabuf_mhead(in_buf); - in_len = wpabuf_len(in_buf); wpa_printf(MSG_DEBUG, "EAP-TTLS: received %lu bytes encrypted data for" - " Phase 2", (unsigned long) in_len); + " Phase 2", (unsigned long) wpabuf_len(in_buf)); if (data->pending_phase2_eap_resp) { wpa_printf(MSG_DEBUG, "EAP-TTLS: Pending Phase 2 EAP response " @@ -1150,35 +1138,17 @@ static void eap_ttls_process_phase2(struct eap_sm *sm, return; } - buf_len = in_len; - /* - * Even though we try to disable TLS compression, it is possible that - * this cannot be done with all TLS libraries. Add extra buffer space - * to handle the possibility of the decrypted data being longer than - * input data. - */ - buf_len += 500; - buf_len *= 3; - in_decrypted = os_malloc(buf_len); + in_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn, + in_buf); if (in_decrypted == NULL) { - wpa_printf(MSG_WARNING, "EAP-TTLS: failed to allocate memory " - "for decryption"); - return; - } - - len_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn, - in_data, in_len, - in_decrypted, buf_len); - if (len_decrypted < 0) { wpa_printf(MSG_INFO, "EAP-TTLS: Failed to decrypt Phase 2 " "data"); - os_free(in_decrypted); eap_ttls_state(data, FAILURE); return; } if (data->state == PHASE_FINISHED) { - if (len_decrypted == 0 && + if (wpabuf_len(in_decrypted) == 0 && tls_connection_ia_final_phase_finished(sm->ssl_ctx, data->ssl.conn)) { wpa_printf(MSG_DEBUG, "EAP-TTLS: FinalPhaseFinished " @@ -1190,16 +1160,16 @@ static void eap_ttls_process_phase2(struct eap_sm *sm, eap_ttls_state(data, FAILURE); } - os_free(in_decrypted); + wpabuf_free(in_decrypted); return; } - wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Decrypted Phase 2 EAP", - in_decrypted, len_decrypted); + wpa_hexdump_buf_key(MSG_DEBUG, "EAP-TTLS: Decrypted Phase 2 EAP", + in_decrypted); - if (eap_ttls_avp_parse(in_decrypted, len_decrypted, &parse) < 0) { + if (eap_ttls_avp_parse(in_decrypted, &parse) < 0) { wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to parse AVPs"); - os_free(in_decrypted); + wpabuf_free(in_decrypted); eap_ttls_state(data, FAILURE); return; } @@ -1257,7 +1227,7 @@ static void eap_ttls_process_phase2(struct eap_sm *sm, } done: - os_free(in_decrypted); + wpabuf_free(in_decrypted); os_free(parse.eap); }