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