u8 * tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn, const u8 *in_data, size_t in_len, size_t *out_len) { u8 *out_data; int ret; if (in_data && in_len) { if (conn->pull_buf) { wpa_printf(MSG_DEBUG, "%s - %d bytes remaining in " "pull_buf", __func__, conn->pull_buf_len); free(conn->pull_buf); } conn->pull_buf = malloc(in_len); if (conn->pull_buf == NULL) return NULL; memcpy(conn->pull_buf, in_data, in_len); conn->pull_buf_offset = conn->pull_buf; conn->pull_buf_len = in_len; } ret = gnutls_handshake(conn->session); if (ret < 0) { switch (ret) { case GNUTLS_E_AGAIN: break; case GNUTLS_E_FATAL_ALERT_RECEIVED: wpa_printf(MSG_DEBUG, "%s - received fatal '%s' alert", __func__, gnutls_alert_get_name( gnutls_alert_get(conn->session))); conn->read_alerts++; /* continue */ default: wpa_printf(MSG_DEBUG, "%s - gnutls_handshake failed " "-> %s", __func__, gnutls_strerror(ret)); conn->failed++; } } else { wpa_printf(MSG_DEBUG, "TLS: Handshake completed successfully"); if (conn->verify_peer && tls_connection_verify_peer(conn)) { wpa_printf(MSG_INFO, "TLS: Peer certificate chain " "failed validation"); conn->failed++; return NULL; } conn->established = 1; if (conn->push_buf == NULL) { /* Need to return something to get final TLS ACK. */ conn->push_buf = malloc(1); } } out_data = conn->push_buf; *out_len = conn->push_buf_len; conn->push_buf = NULL; conn->push_buf_len = 0; return out_data; }
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 tls_global *global = ssl_ctx; u8 *out_data; int ret; if (appl_data) *appl_data = NULL; if (in_data && in_len) { if (conn->pull_buf) { wpa_printf(MSG_DEBUG, "%s - %d bytes remaining in " "pull_buf", __func__, conn->pull_buf_len); os_free(conn->pull_buf); } conn->pull_buf = os_malloc(in_len); if (conn->pull_buf == NULL) return NULL; os_memcpy(conn->pull_buf, in_data, in_len); conn->pull_buf_offset = conn->pull_buf; conn->pull_buf_len = in_len; } ret = gnutls_handshake(conn->session); if (ret < 0) { switch (ret) { case GNUTLS_E_AGAIN: if (global->server && conn->established && conn->push_buf == NULL) { /* Need to return something to trigger * completion of EAP-TLS. */ conn->push_buf = os_malloc(1); } break; case GNUTLS_E_FATAL_ALERT_RECEIVED: wpa_printf(MSG_DEBUG, "%s - received fatal '%s' alert", __func__, gnutls_alert_get_name( gnutls_alert_get(conn->session))); conn->read_alerts++; /* continue */ default: wpa_printf(MSG_DEBUG, "%s - gnutls_handshake failed " "-> %s", __func__, gnutls_strerror(ret)); conn->failed++; } } else { size_t size; if (conn->verify_peer && tls_connection_verify_peer(conn)) { wpa_printf(MSG_INFO, "TLS: Peer certificate chain " "failed validation"); conn->failed++; return NULL; } if (conn->tls_ia && !gnutls_ia_handshake_p(conn->session)) { wpa_printf(MSG_INFO, "TLS: No TLS/IA negotiation"); conn->failed++; return NULL; } if (conn->tls_ia) wpa_printf(MSG_DEBUG, "TLS: Start TLS/IA handshake"); else { wpa_printf(MSG_DEBUG, "TLS: Handshake completed " "successfully"); } conn->established = 1; if (conn->push_buf == NULL) { /* Need to return something to get final TLS ACK. */ conn->push_buf = os_malloc(1); } gnutls_session_get_data(conn->session, NULL, &size); if (global->session_data == NULL || global->session_data_size < size) { os_free(global->session_data); global->session_data = os_malloc(size); } if (global->session_data) { global->session_data_size = size; gnutls_session_get_data(conn->session, global->session_data, &global->session_data_size); } } out_data = conn->push_buf; *out_len = conn->push_buf_len; conn->push_buf = NULL; conn->push_buf_len = 0; return out_data; }
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 = tls_ctx; struct wpabuf *out_data; int ret; if (appl_data) *appl_data = NULL; 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) wpabuf_len(conn->pull_buf)); wpabuf_free(conn->pull_buf); } conn->pull_buf = wpabuf_dup(in_data); if (conn->pull_buf == NULL) return NULL; conn->pull_buf_offset = wpabuf_head(conn->pull_buf); } ret = gnutls_handshake(conn->session); if (ret < 0) { switch (ret) { case GNUTLS_E_AGAIN: if (global->server && conn->established && conn->push_buf == NULL) { /* Need to return something to trigger * completion of EAP-TLS. */ conn->push_buf = wpabuf_alloc(0); } break; case GNUTLS_E_FATAL_ALERT_RECEIVED: wpa_printf(MSG_DEBUG, "%s - received fatal '%s' alert", __func__, gnutls_alert_get_name( gnutls_alert_get(conn->session))); conn->read_alerts++; /* continue */ default: wpa_printf(MSG_DEBUG, "%s - gnutls_handshake failed " "-> %s", __func__, gnutls_strerror(ret)); conn->failed++; } } else { size_t size; gnutls_alert_description_t err; if (conn->verify_peer && tls_connection_verify_peer(conn, &err)) { wpa_printf(MSG_INFO, "TLS: Peer certificate chain " "failed validation"); conn->failed++; gnutls_alert_send(conn->session, GNUTLS_AL_FATAL, err); goto out; } wpa_printf(MSG_DEBUG, "TLS: Handshake completed successfully"); conn->established = 1; if (conn->push_buf == NULL) { /* Need to return something to get final TLS ACK. */ conn->push_buf = wpabuf_alloc(0); } gnutls_session_get_data(conn->session, NULL, &size); if (global->session_data == NULL || global->session_data_size < size) { os_free(global->session_data); global->session_data = os_malloc(size); } if (global->session_data) { global->session_data_size = size; gnutls_session_get_data(conn->session, global->session_data, &global->session_data_size); } if (conn->pull_buf && appl_data) *appl_data = gnutls_get_appl_data(conn); } out: out_data = conn->push_buf; conn->push_buf = NULL; return out_data; }