18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* 28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * IKEv2 responder (RFC 4306) for EAP-IKEV2 38d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright (c) 2007, Jouni Malinen <j@w1.fi> 48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 5c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * This software may be distributed under the terms of the BSD license. 6c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * See README for more details. 78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "includes.h" 108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common.h" 128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/dh_groups.h" 138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/random.h" 148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "ikev2.h" 158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid ikev2_responder_deinit(struct ikev2_responder_data *data) 188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ikev2_free_keys(&data->keys); 208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_free(data->i_dh_public); 218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_free(data->r_dh_private); 228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(data->IDi); 238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(data->IDr); 248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(data->shared_secret); 258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_free(data->i_sign_msg); 268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_free(data->r_sign_msg); 278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(data->key_pad); 288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ikev2_derive_keys(struct ikev2_responder_data *data) 328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *buf, *pos, *pad, skeyseed[IKEV2_MAX_HASH_LEN]; 348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t buf_len, pad_len; 358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpabuf *shared; 368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const struct ikev2_integ_alg *integ; 378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const struct ikev2_prf_alg *prf; 388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const struct ikev2_encr_alg *encr; 398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int ret; 408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *addr[2]; 418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t len[2]; 428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* RFC 4306, Sect. 2.14 */ 448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt integ = ikev2_get_integ(data->proposal.integ); 468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt prf = ikev2_get_prf(data->proposal.prf); 478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt encr = ikev2_get_encr(data->proposal.encr); 488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (integ == NULL || prf == NULL || encr == NULL) { 498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: Unsupported proposal"); 508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt shared = dh_derive_shared(data->i_dh_public, data->r_dh_private, 548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->dh); 558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (shared == NULL) 568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Construct Ni | Nr | SPIi | SPIr */ 598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt buf_len = data->i_nonce_len + data->r_nonce_len + 2 * IKEV2_SPI_LEN; 618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt buf = os_malloc(buf_len); 628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (buf == NULL) { 638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_free(shared); 648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = buf; 688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(pos, data->i_nonce, data->i_nonce_len); 698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += data->i_nonce_len; 708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(pos, data->r_nonce, data->r_nonce_len); 718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += data->r_nonce_len; 728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(pos, data->i_spi, IKEV2_SPI_LEN); 738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += IKEV2_SPI_LEN; 748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(pos, data->r_spi, IKEV2_SPI_LEN); 758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* SKEYSEED = prf(Ni | Nr, g^ir) */ 778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Use zero-padding per RFC 4306, Sect. 2.14 */ 788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pad_len = data->dh->prime_len - wpabuf_len(shared); 798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pad = os_zalloc(pad_len ? pad_len : 1); 808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pad == NULL) { 818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_free(shared); 828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(buf); 838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[0] = pad; 878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len[0] = pad_len; 888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[1] = wpabuf_head(shared); 898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len[1] = wpabuf_len(shared); 908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ikev2_prf_hash(prf->id, buf, data->i_nonce_len + data->r_nonce_len, 918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2, addr, len, skeyseed) < 0) { 928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_free(shared); 938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(buf); 948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(pad); 958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(pad); 988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_free(shared); 998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* DH parameters are not needed anymore, so free them */ 1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_free(data->i_dh_public); 1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->i_dh_public = NULL; 1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_free(data->r_dh_private); 1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->r_dh_private = NULL; 1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump_key(MSG_DEBUG, "IKEV2: SKEYSEED", 1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt skeyseed, prf->hash_len); 1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret = ikev2_derive_sk_keys(prf, integ, encr, skeyseed, buf, buf_len, 1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &data->keys); 1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(buf); 1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return ret; 1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ikev2_parse_transform(struct ikev2_proposal_data *prop, 1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *pos, const u8 *end) 1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int transform_len; 1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const struct ikev2_transform *t; 1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u16 transform_id; 1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *tend; 1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (end - pos < (int) sizeof(*t)) { 1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: Too short transform"); 1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt t = (const struct ikev2_transform *) pos; 1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt transform_len = WPA_GET_BE16(t->transform_length); 131d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt if (transform_len < (int) sizeof(*t) || transform_len > end - pos) { 1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: Invalid transform length %d", 1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt transform_len); 1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tend = pos + transform_len; 1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt transform_id = WPA_GET_BE16(t->transform_id); 1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "IKEV2: Transform:"); 1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "IKEV2: Type: %d Transform Length: %d " 1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "Transform Type: %d Transform ID: %d", 1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt t->type, transform_len, t->transform_type, transform_id); 1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (t->type != 0 && t->type != 3) { 1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: Unexpected Transform type"); 1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = (const u8 *) (t + 1); 1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pos < tend) { 1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "IKEV2: Transform Attributes", 1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos, tend - pos); 1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt switch (t->transform_type) { 1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case IKEV2_TRANSFORM_ENCR: 1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ikev2_get_encr(transform_id)) { 1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (transform_id == ENCR_AES_CBC) { 1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (tend - pos != 4) { 1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "IKEV2: No " 1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "Transform Attr for AES"); 1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (WPA_GET_BE16(pos) != 0x800e) { 1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "IKEV2: Not a " 1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "Key Size attribute for " 1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "AES"); 1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (WPA_GET_BE16(pos + 2) != 128) { 1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "IKEV2: " 1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "Unsupported AES key size " 1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "%d bits", 1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt WPA_GET_BE16(pos + 2)); 1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt prop->encr = transform_id; 1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case IKEV2_TRANSFORM_PRF: 1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ikev2_get_prf(transform_id)) 1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt prop->prf = transform_id; 1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case IKEV2_TRANSFORM_INTEG: 1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ikev2_get_integ(transform_id)) 1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt prop->integ = transform_id; 1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case IKEV2_TRANSFORM_DH: 1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (dh_groups_get(transform_id)) 1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt prop->dh = transform_id; 1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return transform_len; 1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ikev2_parse_proposal(struct ikev2_proposal_data *prop, 2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *pos, const u8 *end) 2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *pend, *ppos; 2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int proposal_len, i; 2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const struct ikev2_proposal *p; 2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (end - pos < (int) sizeof(*p)) { 2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: Too short proposal"); 2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* FIX: AND processing if multiple proposals use the same # */ 2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt p = (const struct ikev2_proposal *) pos; 2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt proposal_len = WPA_GET_BE16(p->proposal_length); 216fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt if (proposal_len < (int) sizeof(*p) || proposal_len > end - pos) { 2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: Invalid proposal length %d", 2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt proposal_len); 2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "IKEV2: SAi1 Proposal # %d", 2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt p->proposal_num); 2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "IKEV2: Type: %d Proposal Length: %d " 2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt " Protocol ID: %d", 2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt p->type, proposal_len, p->protocol_id); 2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "IKEV2: SPI Size: %d Transforms: %d", 2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt p->spi_size, p->num_transforms); 2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (p->type != 0 && p->type != 2) { 2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: Unexpected Proposal type"); 2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (p->protocol_id != IKEV2_PROTOCOL_IKE) { 2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "IKEV2: Unexpected Protocol ID " 2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "(only IKE allowed for EAP-IKEv2)"); 2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (p->proposal_num != prop->proposal_num) { 2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (p->proposal_num == prop->proposal_num + 1) 2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt prop->proposal_num = p->proposal_num; 2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else { 2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: Unexpected Proposal #"); 2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ppos = (const u8 *) (p + 1); 2508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pend = pos + proposal_len; 251d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt if (p->spi_size > pend - ppos) { 2528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: Not enough room for SPI " 2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "in proposal"); 2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (p->spi_size) { 2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "IKEV2: SPI", 2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ppos, p->spi_size); 2598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ppos += p->spi_size; 2608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * For initial IKE_SA negotiation, SPI Size MUST be zero; for 2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * subsequent negotiations, it must be 8 for IKE. We only support 2658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * initial case for now. 2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (p->spi_size != 0) { 2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: Unexpected SPI Size"); 2698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (p->num_transforms == 0) { 2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: At least one transform required"); 2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < (int) p->num_transforms; i++) { 2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int tlen = ikev2_parse_transform(prop, ppos, pend); 2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (tlen < 0) 2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ppos += tlen; 2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ppos != pend) { 2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: Unexpected data after " 2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "transforms"); 2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return proposal_len; 2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ikev2_process_sai1(struct ikev2_responder_data *data, 2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *sai1, size_t sai1_len) 2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct ikev2_proposal_data prop; 2988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *pos, *end; 2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int found = 0; 3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Security Association Payloads: <Proposals> */ 3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (sai1 == NULL) { 3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: SAi1 not received"); 3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memset(&prop, 0, sizeof(prop)); 3098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt prop.proposal_num = 1; 3108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = sai1; 3128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt end = sai1 + sai1_len; 3138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (pos < end) { 3158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int plen; 3168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt prop.integ = -1; 3188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt prop.prf = -1; 3198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt prop.encr = -1; 3208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt prop.dh = -1; 3218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt plen = ikev2_parse_proposal(&prop, pos, end); 3228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (plen < 0) 3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!found && prop.integ != -1 && prop.prf != -1 && 3268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt prop.encr != -1 && prop.dh != -1) { 3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(&data->proposal, &prop, sizeof(prop)); 3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->dh = dh_groups_get(prop.dh); 3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt found = 1; 3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += plen; 3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pos != end) { 3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: Unexpected data after proposals"); 3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!found) { 3418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: No acceptable proposal found"); 3428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 3438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "IKEV2: Accepted proposal #%d: ENCR:%d PRF:%d " 3468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "INTEG:%d D-H:%d", data->proposal.proposal_num, 3478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->proposal.encr, data->proposal.prf, 3488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->proposal.integ, data->proposal.dh); 3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 3518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 3528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ikev2_process_kei(struct ikev2_responder_data *data, 3558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *kei, size_t kei_len) 3568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 3578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u16 group; 3588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 3608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Key Exchange Payload: 3618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * DH Group # (16 bits) 3628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * RESERVED (16 bits) 3638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Key Exchange Data (Diffie-Hellman public value) 3648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 3658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (kei == NULL) { 3678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: KEi not received"); 3688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 3698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (kei_len < 4 + 96) { 372fb45fd5cfed8bdccd0859c7fc05449fc187e2d06Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: Too short Key Exchange Payload"); 3738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 3748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt group = WPA_GET_BE16(kei); 3778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "IKEV2: KEi DH Group #%u", group); 3788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (group != data->proposal.dh) { 3808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "IKEV2: KEi DH Group #%u does not match " 3818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "with the selected proposal (%u)", 3828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt group, data->proposal.dh); 3838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Reject message with Notify payload of type 3848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * INVALID_KE_PAYLOAD (RFC 4306, Sect. 3.4) */ 3858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->error_type = INVALID_KE_PAYLOAD; 3868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->state = NOTIFY; 3878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 3888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->dh == NULL) { 3918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: Unsupported DH group"); 3928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 3938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* RFC 4306, Section 3.4: 3961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * The length of DH public value MUST be equal to the length of the 3978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * prime modulus. 3988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 3998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (kei_len - 4 != data->dh->prime_len) { 4008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: Invalid DH public value length " 4018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "%ld (expected %ld)", 4028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (long) (kei_len - 4), (long) data->dh->prime_len); 4038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 4048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_free(data->i_dh_public); 4078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->i_dh_public = wpabuf_alloc(kei_len - 4); 4088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->i_dh_public == NULL) 4098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 4108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_data(data->i_dh_public, kei + 4, kei_len - 4); 4118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump_buf(MSG_DEBUG, "IKEV2: KEi Diffie-Hellman Public Value", 4138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->i_dh_public); 4148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 4168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 4178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ikev2_process_ni(struct ikev2_responder_data *data, 4208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *ni, size_t ni_len) 4218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 4228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ni == NULL) { 4238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: Ni not received"); 4248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 4258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ni_len < IKEV2_NONCE_MIN_LEN || ni_len > IKEV2_NONCE_MAX_LEN) { 4288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: Invalid Ni length %ld", 4298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (long) ni_len); 4308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 4318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->i_nonce_len = ni_len; 4348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(data->i_nonce, ni, ni_len); 4358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump(MSG_MSGDUMP, "IKEV2: Ni", 4368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->i_nonce, data->i_nonce_len); 4378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 4398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 4408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ikev2_process_sa_init(struct ikev2_responder_data *data, 4438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const struct ikev2_hdr *hdr, 4448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct ikev2_payloads *pl) 4458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 4468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ikev2_process_sai1(data, pl->sa, pl->sa_len) < 0 || 4478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ikev2_process_kei(data, pl->ke, pl->ke_len) < 0 || 4488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ikev2_process_ni(data, pl->nonce, pl->nonce_len) < 0) 4498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 4508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(data->i_spi, hdr->i_spi, IKEV2_SPI_LEN); 4528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 4548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 4558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ikev2_process_idi(struct ikev2_responder_data *data, 4588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *idi, size_t idi_len) 4598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 4608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 id_type; 4618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (idi == NULL) { 4638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: No IDi received"); 4648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 4658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (idi_len < 4) { 4688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: Too short IDi payload"); 4698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 4708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt id_type = idi[0]; 4738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt idi += 4; 4748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt idi_len -= 4; 4758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "IKEV2: IDi ID Type %d", id_type); 4778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump_ascii(MSG_DEBUG, "IKEV2: IDi", idi, idi_len); 4788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(data->IDi); 4798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->IDi = os_malloc(idi_len); 4808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->IDi == NULL) 4818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 4828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(data->IDi, idi, idi_len); 4838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->IDi_len = idi_len; 4848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->IDi_type = id_type; 4858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 4878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 4888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ikev2_process_cert(struct ikev2_responder_data *data, 4918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *cert, size_t cert_len) 4928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 4938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 cert_encoding; 4948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (cert == NULL) { 4968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->peer_auth == PEER_AUTH_CERT) { 4978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: No Certificate received"); 4988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 4998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 5018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (cert_len < 1) { 5048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: No Cert Encoding field"); 5058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 5068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt cert_encoding = cert[0]; 5098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt cert++; 5108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt cert_len--; 5118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "IKEV2: Cert Encoding %d", cert_encoding); 5138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump(MSG_MSGDUMP, "IKEV2: Certificate Data", cert, cert_len); 5148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* TODO: validate certificate */ 5168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 5188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 5198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ikev2_process_auth_cert(struct ikev2_responder_data *data, 5228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 method, const u8 *auth, size_t auth_len) 5238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 5248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (method != AUTH_RSA_SIGN) { 5258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: Unsupported authentication " 5268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "method %d", method); 5278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 5288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* TODO: validate AUTH */ 5318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 5328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 5338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ikev2_process_auth_secret(struct ikev2_responder_data *data, 5368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 method, const u8 *auth, 5378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t auth_len) 5388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 5398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 auth_data[IKEV2_MAX_HASH_LEN]; 5408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const struct ikev2_prf_alg *prf; 5418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (method != AUTH_SHARED_KEY_MIC) { 5438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: Unsupported authentication " 5448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "method %d", method); 5458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 5468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* msg | Nr | prf(SK_pi,IDi') */ 5498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ikev2_derive_auth_data(data->proposal.prf, data->i_sign_msg, 5508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->IDi, data->IDi_len, data->IDi_type, 5518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &data->keys, 1, data->shared_secret, 5528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->shared_secret_len, 5538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->r_nonce, data->r_nonce_len, 5548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->key_pad, data->key_pad_len, 5558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt auth_data) < 0) { 5568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: Could not derive AUTH data"); 5578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 5588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_free(data->i_sign_msg); 5618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->i_sign_msg = NULL; 5628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt prf = ikev2_get_prf(data->proposal.prf); 5648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (prf == NULL) 5658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 5668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (auth_len != prf->hash_len || 568c28170251eb54dbf64a9074a07fee377587425b2Dmitry Shmidt os_memcmp_const(auth, auth_data, auth_len) != 0) { 5698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: Invalid Authentication Data"); 5708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "IKEV2: Received Authentication Data", 5718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt auth, auth_len); 5728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "IKEV2: Expected Authentication Data", 5738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt auth_data, prf->hash_len); 5748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->error_type = AUTHENTICATION_FAILED; 5758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->state = NOTIFY; 5768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 5778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "IKEV2: Server authenticated successfully " 5808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "using shared keys"); 5818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 5838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 5848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ikev2_process_auth(struct ikev2_responder_data *data, 5878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *auth, size_t auth_len) 5888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 5898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 auth_method; 5908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (auth == NULL) { 5928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: No Authentication Payload"); 5938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 5948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (auth_len < 4) { 5978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: Too short Authentication " 5988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "Payload"); 5998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 6008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt auth_method = auth[0]; 6038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt auth += 4; 6048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt auth_len -= 4; 6058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "IKEV2: Auth Method %d", auth_method); 6078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump(MSG_MSGDUMP, "IKEV2: Authentication Data", auth, auth_len); 6088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt switch (data->peer_auth) { 6108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case PEER_AUTH_CERT: 6118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return ikev2_process_auth_cert(data, auth_method, auth, 6128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt auth_len); 6138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case PEER_AUTH_SECRET: 6148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return ikev2_process_auth_secret(data, auth_method, auth, 6158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt auth_len); 6168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 6198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 6208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ikev2_process_sa_auth_decrypted(struct ikev2_responder_data *data, 6238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 next_payload, 6248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *payload, size_t payload_len) 6258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 6268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct ikev2_payloads pl; 6278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "IKEV2: Processing decrypted payloads"); 6298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ikev2_parse_payloads(&pl, next_payload, payload, payload + 6318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt payload_len) < 0) { 6328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: Failed to parse decrypted " 6338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "payloads"); 6348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 6358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ikev2_process_idi(data, pl.idi, pl.idi_len) < 0 || 6388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ikev2_process_cert(data, pl.cert, pl.cert_len) < 0 || 6398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ikev2_process_auth(data, pl.auth, pl.auth_len) < 0) 6408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 6418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 6438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 6448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ikev2_process_sa_auth(struct ikev2_responder_data *data, 6478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const struct ikev2_hdr *hdr, 6488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct ikev2_payloads *pl) 6498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 6508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *decrypted; 6518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t decrypted_len; 6528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int ret; 6538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt decrypted = ikev2_decrypt_payload(data->proposal.encr, 6558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->proposal.integ, 6568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &data->keys, 1, hdr, pl->encrypted, 6578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pl->encrypted_len, &decrypted_len); 6588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (decrypted == NULL) 6598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 6608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret = ikev2_process_sa_auth_decrypted(data, pl->encr_next_payload, 6628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt decrypted, decrypted_len); 6638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(decrypted); 6648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return ret; 6668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 6678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ikev2_validate_rx_state(struct ikev2_responder_data *data, 6708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 exchange_type, u32 message_id) 6718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 6728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt switch (data->state) { 6738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case SA_INIT: 6748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Expect to receive IKE_SA_INIT: HDR, SAi1, KEi, Ni */ 6758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (exchange_type != IKE_SA_INIT) { 6768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: Unexpected Exchange Type " 6778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "%u in SA_INIT state", exchange_type); 6788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 6798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (message_id != 0) { 6818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: Unexpected Message ID %u " 6828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "in SA_INIT state", message_id); 6838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 6848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 6868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case SA_AUTH: 6878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Expect to receive IKE_SA_AUTH: 6888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * HDR, SK {IDi, [CERT,] [CERTREQ,] [IDr,] 6898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * AUTH, SAi2, TSi, TSr} 6908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 6918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (exchange_type != IKE_SA_AUTH) { 6928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: Unexpected Exchange Type " 6938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "%u in SA_AUTH state", exchange_type); 6948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 6958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (message_id != 1) { 6978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: Unexpected Message ID %u " 6988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "in SA_AUTH state", message_id); 6998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 7008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 7028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case CHILD_SA: 7038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (exchange_type != CREATE_CHILD_SA) { 7048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: Unexpected Exchange Type " 7058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "%u in CHILD_SA state", exchange_type); 7068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 7078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (message_id != 2) { 7098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: Unexpected Message ID %u " 7108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "in CHILD_SA state", message_id); 7118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 7128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 7148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case NOTIFY: 7158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case IKEV2_DONE: 7168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case IKEV2_FAILED: 7178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 7188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 7218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 7228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint ikev2_responder_process(struct ikev2_responder_data *data, 7258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const struct wpabuf *buf) 7268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 7278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const struct ikev2_hdr *hdr; 7288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u32 length, message_id; 7298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *pos, *end; 7308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct ikev2_payloads pl; 7318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_MSGDUMP, "IKEV2: Received message (len %lu)", 7338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (unsigned long) wpabuf_len(buf)); 7348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (wpabuf_len(buf) < sizeof(*hdr)) { 7368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: Too short frame to include HDR"); 7378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 7388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->error_type = 0; 7418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr = (const struct ikev2_hdr *) wpabuf_head(buf); 7428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt end = wpabuf_head_u8(buf) + wpabuf_len(buf); 7438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt message_id = WPA_GET_BE32(hdr->message_id); 7448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt length = WPA_GET_BE32(hdr->length); 7458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "IKEV2: IKE_SA Initiator's SPI", 7478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr->i_spi, IKEV2_SPI_LEN); 7488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "IKEV2: IKE_SA Responder's SPI", 7498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr->r_spi, IKEV2_SPI_LEN); 7508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "IKEV2: Next Payload: %u Version: 0x%x " 7518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "Exchange Type: %u", 7528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr->next_payload, hdr->version, hdr->exchange_type); 7538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "IKEV2: Message ID: %u Length: %u", 7548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt message_id, length); 7558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (hdr->version != IKEV2_VERSION) { 7578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: Unsupported HDR version 0x%x " 7588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "(expected 0x%x)", hdr->version, IKEV2_VERSION); 7598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 7608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (length != wpabuf_len(buf)) { 7638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: Invalid length (HDR: %lu != " 7648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "RX: %lu)", (unsigned long) length, 7658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (unsigned long) wpabuf_len(buf)); 7668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 7678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ikev2_validate_rx_state(data, hdr->exchange_type, message_id) < 0) 7708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 7718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((hdr->flags & (IKEV2_HDR_INITIATOR | IKEV2_HDR_RESPONSE)) != 7738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt IKEV2_HDR_INITIATOR) { 7748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: Unexpected Flags value 0x%x", 7758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr->flags); 7768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 7778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->state != SA_INIT) { 7808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (os_memcmp(data->i_spi, hdr->i_spi, IKEV2_SPI_LEN) != 0) { 7818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: Unexpected IKE_SA " 7828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "Initiator's SPI"); 7838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 7848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (os_memcmp(data->r_spi, hdr->r_spi, IKEV2_SPI_LEN) != 0) { 7868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: Unexpected IKE_SA " 7878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "Responder's SPI"); 7888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 7898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = (const u8 *) (hdr + 1); 7938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ikev2_parse_payloads(&pl, hdr->next_payload, pos, end) < 0) 7948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 7958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->state == SA_INIT) { 7978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->last_msg = LAST_MSG_SA_INIT; 7988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ikev2_process_sa_init(data, hdr, &pl) < 0) { 7998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->state == NOTIFY) 8008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 8018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 8028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_free(data->i_sign_msg); 8048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->i_sign_msg = wpabuf_dup(buf); 8058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->state == SA_AUTH) { 8088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->last_msg = LAST_MSG_SA_AUTH; 8098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ikev2_process_sa_auth(data, hdr, &pl) < 0) { 8108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->state == NOTIFY) 8118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 8128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 8138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 8178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 8188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void ikev2_build_hdr(struct ikev2_responder_data *data, 8218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpabuf *msg, u8 exchange_type, 8228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 next_payload, u32 message_id) 8238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 8248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct ikev2_hdr *hdr; 8258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "IKEV2: Adding HDR"); 8278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* HDR - RFC 4306, Sect. 3.1 */ 8298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr = wpabuf_put(msg, sizeof(*hdr)); 8308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(hdr->i_spi, data->i_spi, IKEV2_SPI_LEN); 8318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(hdr->r_spi, data->r_spi, IKEV2_SPI_LEN); 8328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr->next_payload = next_payload; 8338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr->version = IKEV2_VERSION; 8348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr->exchange_type = exchange_type; 8358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr->flags = IKEV2_HDR_RESPONSE; 8368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt WPA_PUT_BE32(hdr->message_id, message_id); 8378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 8388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ikev2_build_sar1(struct ikev2_responder_data *data, 8418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpabuf *msg, u8 next_payload) 8428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 8438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct ikev2_payload_hdr *phdr; 8448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t plen; 8458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct ikev2_proposal *p; 8468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct ikev2_transform *t; 8478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "IKEV2: Adding SAr1 payload"); 8498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* SAr1 - RFC 4306, Sect. 2.7 and 3.3 */ 8518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt phdr = wpabuf_put(msg, sizeof(*phdr)); 8528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt phdr->next_payload = next_payload; 8538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt phdr->flags = 0; 8548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt p = wpabuf_put(msg, sizeof(*p)); 8568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt p->proposal_num = data->proposal.proposal_num; 8578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt p->protocol_id = IKEV2_PROTOCOL_IKE; 8588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt p->num_transforms = 4; 8598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt t = wpabuf_put(msg, sizeof(*t)); 8618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt t->type = 3; 8628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt t->transform_type = IKEV2_TRANSFORM_ENCR; 8638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt WPA_PUT_BE16(t->transform_id, data->proposal.encr); 8648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->proposal.encr == ENCR_AES_CBC) { 8658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Transform Attribute: Key Len = 128 bits */ 8668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_be16(msg, 0x800e); /* AF=1, AttrType=14 */ 8678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_be16(msg, 128); /* 128-bit key */ 8688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) t; 8708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt WPA_PUT_BE16(t->transform_length, plen); 8718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt t = wpabuf_put(msg, sizeof(*t)); 8738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt t->type = 3; 8748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt WPA_PUT_BE16(t->transform_length, sizeof(*t)); 8758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt t->transform_type = IKEV2_TRANSFORM_PRF; 8768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt WPA_PUT_BE16(t->transform_id, data->proposal.prf); 8778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt t = wpabuf_put(msg, sizeof(*t)); 8798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt t->type = 3; 8808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt WPA_PUT_BE16(t->transform_length, sizeof(*t)); 8818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt t->transform_type = IKEV2_TRANSFORM_INTEG; 8828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt WPA_PUT_BE16(t->transform_id, data->proposal.integ); 8838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt t = wpabuf_put(msg, sizeof(*t)); 8858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt WPA_PUT_BE16(t->transform_length, sizeof(*t)); 8868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt t->transform_type = IKEV2_TRANSFORM_DH; 8878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt WPA_PUT_BE16(t->transform_id, data->proposal.dh); 8888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) p; 8908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt WPA_PUT_BE16(p->proposal_length, plen); 8918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr; 8938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt WPA_PUT_BE16(phdr->payload_length, plen); 8948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 8968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 8978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ikev2_build_ker(struct ikev2_responder_data *data, 9008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpabuf *msg, u8 next_payload) 9018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 9028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct ikev2_payload_hdr *phdr; 9038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t plen; 9048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpabuf *pv; 9058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "IKEV2: Adding KEr payload"); 9078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pv = dh_init(data->dh, &data->r_dh_private); 9098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pv == NULL) { 9108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "IKEV2: Failed to initialize DH"); 9118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 9128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 9138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* KEr - RFC 4306, Sect. 3.4 */ 9158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt phdr = wpabuf_put(msg, sizeof(*phdr)); 9168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt phdr->next_payload = next_payload; 9178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt phdr->flags = 0; 9188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_be16(msg, data->proposal.dh); /* DH Group # */ 9208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put(msg, 2); /* RESERVED */ 9218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 9228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * RFC 4306, Sect. 3.4: possible zero padding for public value to 9238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * match the length of the prime. 9248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 9258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put(msg, data->dh->prime_len - wpabuf_len(pv)); 9268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_buf(msg, pv); 9278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_free(pv); 9288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr; 9308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt WPA_PUT_BE16(phdr->payload_length, plen); 9318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 9328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 9338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ikev2_build_nr(struct ikev2_responder_data *data, 9368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpabuf *msg, u8 next_payload) 9378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 9388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct ikev2_payload_hdr *phdr; 9398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t plen; 9408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "IKEV2: Adding Nr payload"); 9428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Nr - RFC 4306, Sect. 3.9 */ 9448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt phdr = wpabuf_put(msg, sizeof(*phdr)); 9458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt phdr->next_payload = next_payload; 9468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt phdr->flags = 0; 9478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_data(msg, data->r_nonce, data->r_nonce_len); 9488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr; 9498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt WPA_PUT_BE16(phdr->payload_length, plen); 9508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 9518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 9528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ikev2_build_idr(struct ikev2_responder_data *data, 9558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpabuf *msg, u8 next_payload) 9568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 9578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct ikev2_payload_hdr *phdr; 9588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t plen; 9598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "IKEV2: Adding IDr payload"); 9618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->IDr == NULL) { 9638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: No IDr available"); 9648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 9658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 9668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* IDr - RFC 4306, Sect. 3.5 */ 9688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt phdr = wpabuf_put(msg, sizeof(*phdr)); 9698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt phdr->next_payload = next_payload; 9708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt phdr->flags = 0; 9718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_u8(msg, ID_KEY_ID); 9728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put(msg, 3); /* RESERVED */ 9738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_data(msg, data->IDr, data->IDr_len); 9748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr; 9758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt WPA_PUT_BE16(phdr->payload_length, plen); 9768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 9778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 9788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ikev2_build_auth(struct ikev2_responder_data *data, 9818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpabuf *msg, u8 next_payload) 9828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 9838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct ikev2_payload_hdr *phdr; 9848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t plen; 9858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const struct ikev2_prf_alg *prf; 9868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "IKEV2: Adding AUTH payload"); 9888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt prf = ikev2_get_prf(data->proposal.prf); 9908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (prf == NULL) 9918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 9928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Authentication - RFC 4306, Sect. 3.8 */ 9948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt phdr = wpabuf_put(msg, sizeof(*phdr)); 9958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt phdr->next_payload = next_payload; 9968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt phdr->flags = 0; 9978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_u8(msg, AUTH_SHARED_KEY_MIC); 9988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put(msg, 3); /* RESERVED */ 9998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* msg | Ni | prf(SK_pr,IDr') */ 10018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ikev2_derive_auth_data(data->proposal.prf, data->r_sign_msg, 10028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->IDr, data->IDr_len, ID_KEY_ID, 10038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &data->keys, 0, data->shared_secret, 10048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->shared_secret_len, 10058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->i_nonce, data->i_nonce_len, 10068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->key_pad, data->key_pad_len, 10078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put(msg, prf->hash_len)) < 0) { 10088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: Could not derive AUTH data"); 10098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 10108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 10118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_free(data->r_sign_msg); 10128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->r_sign_msg = NULL; 10138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr; 10158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt WPA_PUT_BE16(phdr->payload_length, plen); 10168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 10178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 10188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ikev2_build_notification(struct ikev2_responder_data *data, 10218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpabuf *msg, u8 next_payload) 10228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 10238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct ikev2_payload_hdr *phdr; 10248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t plen; 10258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "IKEV2: Adding Notification payload"); 10278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->error_type == 0) { 10298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: No Notify Message Type " 10308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "available"); 10318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 10328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 10338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Notify - RFC 4306, Sect. 3.10 */ 10358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt phdr = wpabuf_put(msg, sizeof(*phdr)); 10368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt phdr->next_payload = next_payload; 10378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt phdr->flags = 0; 10388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_u8(msg, 0); /* Protocol ID: no existing SA */ 10398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_u8(msg, 0); /* SPI Size */ 10408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_be16(msg, data->error_type); 10418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt switch (data->error_type) { 10438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case INVALID_KE_PAYLOAD: 10448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->proposal.dh == -1) { 10458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: No DH Group selected for " 10468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "INVALID_KE_PAYLOAD notifications"); 10478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 10488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 10498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_be16(msg, data->proposal.dh); 10508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "IKEV2: INVALID_KE_PAYLOAD - request " 10518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "DH Group #%d", data->proposal.dh); 10528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 10538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case AUTHENTICATION_FAILED: 10548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* no associated data */ 10558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 10568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt default: 10578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: Unsupported Notify Message Type " 10588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "%d", data->error_type); 10598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 10608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 10618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr; 10638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt WPA_PUT_BE16(phdr->payload_length, plen); 10648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 10658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 10668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct wpabuf * ikev2_build_sa_init(struct ikev2_responder_data *data) 10698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 10708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpabuf *msg; 10718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* build IKE_SA_INIT: HDR, SAr1, KEr, Nr, [CERTREQ], [SK{IDr}] */ 10738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (os_get_random(data->r_spi, IKEV2_SPI_LEN)) 10758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 10768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "IKEV2: IKE_SA Responder's SPI", 10778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->r_spi, IKEV2_SPI_LEN); 10788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->r_nonce_len = IKEV2_NONCE_MIN_LEN; 10808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (random_get_bytes(data->r_nonce, data->r_nonce_len)) 10818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 10828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "IKEV2: Nr", data->r_nonce, data->r_nonce_len); 10838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg = wpabuf_alloc(sizeof(struct ikev2_hdr) + data->IDr_len + 1500); 10858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (msg == NULL) 10868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 10878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ikev2_build_hdr(data, msg, IKE_SA_INIT, IKEV2_PAYLOAD_SA, 0); 10898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ikev2_build_sar1(data, msg, IKEV2_PAYLOAD_KEY_EXCHANGE) || 10908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ikev2_build_ker(data, msg, IKEV2_PAYLOAD_NONCE) || 10918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ikev2_build_nr(data, msg, data->peer_auth == PEER_AUTH_SECRET ? 10928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt IKEV2_PAYLOAD_ENCRYPTED : 10938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt IKEV2_PAYLOAD_NO_NEXT_PAYLOAD)) { 10948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_free(msg); 10958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 10968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 10978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ikev2_derive_keys(data)) { 10998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_free(msg); 11008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 11018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 11028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->peer_auth == PEER_AUTH_CERT) { 11048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* TODO: CERTREQ with SHA-1 hashes of Subject Public Key Info 11058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * for trust agents */ 11068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 11078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->peer_auth == PEER_AUTH_SECRET) { 11098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpabuf *plain = wpabuf_alloc(data->IDr_len + 1000); 11108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (plain == NULL) { 11118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_free(msg); 11128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 11138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 11148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ikev2_build_idr(data, plain, 11158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt IKEV2_PAYLOAD_NO_NEXT_PAYLOAD) || 11168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ikev2_build_encrypted(data->proposal.encr, 11178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->proposal.integ, 11188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &data->keys, 0, msg, plain, 11198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt IKEV2_PAYLOAD_IDr)) { 11208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_free(plain); 11218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_free(msg); 11228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 11238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 11248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_free(plain); 11258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 11268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ikev2_update_hdr(msg); 11288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump_buf(MSG_MSGDUMP, "IKEV2: Sending message (SA_INIT)", msg); 11308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->state = SA_AUTH; 11328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_free(data->r_sign_msg); 11348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->r_sign_msg = wpabuf_dup(msg); 11358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return msg; 11378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 11388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct wpabuf * ikev2_build_sa_auth(struct ikev2_responder_data *data) 11418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 11428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpabuf *msg, *plain; 11438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* build IKE_SA_AUTH: HDR, SK {IDr, [CERT,] AUTH} */ 11458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg = wpabuf_alloc(sizeof(struct ikev2_hdr) + data->IDr_len + 1000); 11478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (msg == NULL) 11488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 11498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ikev2_build_hdr(data, msg, IKE_SA_AUTH, IKEV2_PAYLOAD_ENCRYPTED, 1); 11508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt plain = wpabuf_alloc(data->IDr_len + 1000); 11528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (plain == NULL) { 11538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_free(msg); 11548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 11558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 11568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ikev2_build_idr(data, plain, IKEV2_PAYLOAD_AUTHENTICATION) || 11588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ikev2_build_auth(data, plain, IKEV2_PAYLOAD_NO_NEXT_PAYLOAD) || 11598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ikev2_build_encrypted(data->proposal.encr, data->proposal.integ, 11608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &data->keys, 0, msg, plain, 11618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt IKEV2_PAYLOAD_IDr)) { 11628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_free(plain); 11638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_free(msg); 11648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 11658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 11668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_free(plain); 11678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump_buf(MSG_MSGDUMP, "IKEV2: Sending message (SA_AUTH)", msg); 11698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->state = IKEV2_DONE; 11718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return msg; 11738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 11748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct wpabuf * ikev2_build_notify(struct ikev2_responder_data *data) 11778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 11788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpabuf *msg; 11798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg = wpabuf_alloc(sizeof(struct ikev2_hdr) + 1000); 11818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (msg == NULL) 11828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 11838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->last_msg == LAST_MSG_SA_AUTH) { 11848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* HDR, SK{N} */ 11858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpabuf *plain = wpabuf_alloc(100); 11868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (plain == NULL) { 11878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_free(msg); 11888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 11898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 11908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ikev2_build_hdr(data, msg, IKE_SA_AUTH, 11918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt IKEV2_PAYLOAD_ENCRYPTED, 1); 11928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ikev2_build_notification(data, plain, 11938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt IKEV2_PAYLOAD_NO_NEXT_PAYLOAD) || 11948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ikev2_build_encrypted(data->proposal.encr, 11958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->proposal.integ, 11968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &data->keys, 0, msg, plain, 11978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt IKEV2_PAYLOAD_NOTIFICATION)) { 11988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_free(plain); 11998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_free(msg); 12008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 12018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1202fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt wpabuf_free(plain); 12038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->state = IKEV2_FAILED; 12048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else { 12058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* HDR, N */ 12068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ikev2_build_hdr(data, msg, IKE_SA_INIT, 12078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt IKEV2_PAYLOAD_NOTIFICATION, 0); 12088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ikev2_build_notification(data, msg, 12098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt IKEV2_PAYLOAD_NO_NEXT_PAYLOAD)) { 12108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_free(msg); 12118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 12128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 12138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->state = SA_INIT; 12148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 12158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ikev2_update_hdr(msg); 12178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump_buf(MSG_MSGDUMP, "IKEV2: Sending message (Notification)", 12198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg); 12208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return msg; 12228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 12238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct wpabuf * ikev2_responder_build(struct ikev2_responder_data *data) 12268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 12278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt switch (data->state) { 12288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case SA_INIT: 12298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return ikev2_build_sa_init(data); 12308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case SA_AUTH: 12318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return ikev2_build_sa_auth(data); 12328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case CHILD_SA: 12338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 12348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case NOTIFY: 12358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return ikev2_build_notify(data); 12368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case IKEV2_DONE: 12378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case IKEV2_FAILED: 12388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 12398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 12408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 12418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1242