static int _gnutls_ia_client_handshake (gnutls_session_t session) { char *buf = NULL; size_t buflen = 0; char tmp[1024]; /* XXX */ ssize_t len; int ret; const struct gnutls_ia_client_credentials_st *cred = _gnutls_get_cred (session->key, GNUTLS_CRD_IA, NULL); if (cred == NULL) return GNUTLS_E_INTERNAL_ERROR; while (1) { char *avp; size_t avplen; ret = cred->avp_func (session, cred->avp_ptr, buf, buflen, &avp, &avplen); if (ret) { int tmpret; tmpret = gnutls_alert_send (session, GNUTLS_AL_FATAL, GNUTLS_A_INNER_APPLICATION_FAILURE); if (tmpret < 0) gnutls_assert (); return ret; } len = gnutls_ia_send (session, avp, avplen); gnutls_free (avp); if (len < 0) return len; len = gnutls_ia_recv (session, tmp, sizeof (tmp)); if (len == GNUTLS_E_WARNING_IA_IPHF_RECEIVED || len == GNUTLS_E_WARNING_IA_FPHF_RECEIVED) { ret = gnutls_ia_verify_endphase (session, tmp); if (ret < 0) return ret; ret = gnutls_ia_endphase_send (session, len == GNUTLS_E_WARNING_IA_FPHF_RECEIVED); if (ret < 0) return ret; } if (len == GNUTLS_E_WARNING_IA_IPHF_RECEIVED) { buf = NULL; buflen = 0; continue; } else if (len == GNUTLS_E_WARNING_IA_FPHF_RECEIVED) break; if (len < 0) return len; buflen = len; buf = tmp; } return 0; }
static int _gnutls_ia_server_handshake (gnutls_session_t session) { gnutls_ia_apptype_t msg_type; ssize_t len; char buf[1024]; int ret; const struct gnutls_ia_server_credentials_st *cred = _gnutls_get_cred (session->key, GNUTLS_CRD_IA, NULL); if (cred == NULL) return GNUTLS_E_INTERNAL_ERROR; do { char *avp; size_t avplen; len = gnutls_ia_recv (session, buf, sizeof (buf)); if (len == GNUTLS_E_WARNING_IA_IPHF_RECEIVED || len == GNUTLS_E_WARNING_IA_FPHF_RECEIVED) { ret = gnutls_ia_verify_endphase (session, buf); if (ret < 0) return ret; } if (len == GNUTLS_E_WARNING_IA_IPHF_RECEIVED) continue; else if (len == GNUTLS_E_WARNING_IA_FPHF_RECEIVED) break; if (len < 0) return len; avp = NULL; avplen = 0; ret = cred->avp_func (session, cred->avp_ptr, buf, len, &avp, &avplen); if (ret < 0) { int tmpret; tmpret = gnutls_alert_send (session, GNUTLS_AL_FATAL, GNUTLS_A_INNER_APPLICATION_FAILURE); if (tmpret < 0) gnutls_assert (); return ret; } msg_type = ret; if (msg_type != GNUTLS_IA_APPLICATION_PAYLOAD) { ret = gnutls_ia_endphase_send (session, msg_type == GNUTLS_IA_FINAL_PHASE_FINISHED); if (ret < 0) return ret; } else { len = gnutls_ia_send (session, avp, avplen); gnutls_free (avp); if (len < 0) return len; } } while (1); return 0; }
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) { ssize_t res; 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 -1; os_memcpy(conn->pull_buf, in_data, in_len); conn->pull_buf_offset = conn->pull_buf; conn->pull_buf_len = in_len; #ifdef GNUTLS_IA if (conn->tls_ia) { res = gnutls_ia_recv(conn->session, out_data, out_len); if (out_len >= 12 && (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"); res = gnutls_ia_permute_inner_secret( conn->session, conn->session_keys_len, conn->session_keys); if (conn->session_keys) { os_memset(conn->session_keys, 0, conn->session_keys_len); os_free(conn->session_keys); } conn->session_keys = NULL; conn->session_keys_len = 0; if (res) { wpa_printf(MSG_DEBUG, "%s: Failed to permute " "inner secret: %s", __func__, gnutls_strerror(res)); return -1; } res = gnutls_ia_verify_endphase(conn->session, out_data); if (res == 0) { wpa_printf(MSG_DEBUG, "%s: Correct endphase " "checksum", __func__); } else { wpa_printf(MSG_INFO, "%s: Endphase " "verification failed: %s", __func__, gnutls_strerror(res)); return -1; } if (final) conn->final_phase_finished = 1; return 0; }