1e5b75505Sopenharmony_ci/* 2e5b75505Sopenharmony_ci * IKEv2 responder (RFC 4306) for EAP-IKEV2 3e5b75505Sopenharmony_ci * Copyright (c) 2007, Jouni Malinen <j@w1.fi> 4e5b75505Sopenharmony_ci * 5e5b75505Sopenharmony_ci * This software may be distributed under the terms of the BSD license. 6e5b75505Sopenharmony_ci * See README for more details. 7e5b75505Sopenharmony_ci */ 8e5b75505Sopenharmony_ci 9e5b75505Sopenharmony_ci#include "includes.h" 10e5b75505Sopenharmony_ci 11e5b75505Sopenharmony_ci#include "common.h" 12e5b75505Sopenharmony_ci#include "crypto/dh_groups.h" 13e5b75505Sopenharmony_ci#include "crypto/random.h" 14e5b75505Sopenharmony_ci#include "ikev2.h" 15e5b75505Sopenharmony_ci 16e5b75505Sopenharmony_ci 17e5b75505Sopenharmony_civoid ikev2_responder_deinit(struct ikev2_responder_data *data) 18e5b75505Sopenharmony_ci{ 19e5b75505Sopenharmony_ci ikev2_free_keys(&data->keys); 20e5b75505Sopenharmony_ci wpabuf_free(data->i_dh_public); 21e5b75505Sopenharmony_ci wpabuf_free(data->r_dh_private); 22e5b75505Sopenharmony_ci os_free(data->IDi); 23e5b75505Sopenharmony_ci os_free(data->IDr); 24e5b75505Sopenharmony_ci os_free(data->shared_secret); 25e5b75505Sopenharmony_ci wpabuf_free(data->i_sign_msg); 26e5b75505Sopenharmony_ci wpabuf_free(data->r_sign_msg); 27e5b75505Sopenharmony_ci os_free(data->key_pad); 28e5b75505Sopenharmony_ci} 29e5b75505Sopenharmony_ci 30e5b75505Sopenharmony_ci 31e5b75505Sopenharmony_cistatic int ikev2_derive_keys(struct ikev2_responder_data *data) 32e5b75505Sopenharmony_ci{ 33e5b75505Sopenharmony_ci u8 *buf, *pos, *pad, skeyseed[IKEV2_MAX_HASH_LEN]; 34e5b75505Sopenharmony_ci size_t buf_len, pad_len; 35e5b75505Sopenharmony_ci struct wpabuf *shared; 36e5b75505Sopenharmony_ci const struct ikev2_integ_alg *integ; 37e5b75505Sopenharmony_ci const struct ikev2_prf_alg *prf; 38e5b75505Sopenharmony_ci const struct ikev2_encr_alg *encr; 39e5b75505Sopenharmony_ci int ret; 40e5b75505Sopenharmony_ci const u8 *addr[2]; 41e5b75505Sopenharmony_ci size_t len[2]; 42e5b75505Sopenharmony_ci 43e5b75505Sopenharmony_ci /* RFC 4306, Sect. 2.14 */ 44e5b75505Sopenharmony_ci 45e5b75505Sopenharmony_ci integ = ikev2_get_integ(data->proposal.integ); 46e5b75505Sopenharmony_ci prf = ikev2_get_prf(data->proposal.prf); 47e5b75505Sopenharmony_ci encr = ikev2_get_encr(data->proposal.encr); 48e5b75505Sopenharmony_ci if (integ == NULL || prf == NULL || encr == NULL) { 49e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "IKEV2: Unsupported proposal"); 50e5b75505Sopenharmony_ci return -1; 51e5b75505Sopenharmony_ci } 52e5b75505Sopenharmony_ci 53e5b75505Sopenharmony_ci shared = dh_derive_shared(data->i_dh_public, data->r_dh_private, 54e5b75505Sopenharmony_ci data->dh); 55e5b75505Sopenharmony_ci if (shared == NULL) 56e5b75505Sopenharmony_ci return -1; 57e5b75505Sopenharmony_ci 58e5b75505Sopenharmony_ci /* Construct Ni | Nr | SPIi | SPIr */ 59e5b75505Sopenharmony_ci 60e5b75505Sopenharmony_ci buf_len = data->i_nonce_len + data->r_nonce_len + 2 * IKEV2_SPI_LEN; 61e5b75505Sopenharmony_ci buf = os_malloc(buf_len); 62e5b75505Sopenharmony_ci if (buf == NULL) { 63e5b75505Sopenharmony_ci wpabuf_free(shared); 64e5b75505Sopenharmony_ci return -1; 65e5b75505Sopenharmony_ci } 66e5b75505Sopenharmony_ci 67e5b75505Sopenharmony_ci pos = buf; 68e5b75505Sopenharmony_ci os_memcpy(pos, data->i_nonce, data->i_nonce_len); 69e5b75505Sopenharmony_ci pos += data->i_nonce_len; 70e5b75505Sopenharmony_ci os_memcpy(pos, data->r_nonce, data->r_nonce_len); 71e5b75505Sopenharmony_ci pos += data->r_nonce_len; 72e5b75505Sopenharmony_ci os_memcpy(pos, data->i_spi, IKEV2_SPI_LEN); 73e5b75505Sopenharmony_ci pos += IKEV2_SPI_LEN; 74e5b75505Sopenharmony_ci os_memcpy(pos, data->r_spi, IKEV2_SPI_LEN); 75e5b75505Sopenharmony_ci 76e5b75505Sopenharmony_ci /* SKEYSEED = prf(Ni | Nr, g^ir) */ 77e5b75505Sopenharmony_ci /* Use zero-padding per RFC 4306, Sect. 2.14 */ 78e5b75505Sopenharmony_ci pad_len = data->dh->prime_len - wpabuf_len(shared); 79e5b75505Sopenharmony_ci pad = os_zalloc(pad_len ? pad_len : 1); 80e5b75505Sopenharmony_ci if (pad == NULL) { 81e5b75505Sopenharmony_ci wpabuf_free(shared); 82e5b75505Sopenharmony_ci os_free(buf); 83e5b75505Sopenharmony_ci return -1; 84e5b75505Sopenharmony_ci } 85e5b75505Sopenharmony_ci 86e5b75505Sopenharmony_ci addr[0] = pad; 87e5b75505Sopenharmony_ci len[0] = pad_len; 88e5b75505Sopenharmony_ci addr[1] = wpabuf_head(shared); 89e5b75505Sopenharmony_ci len[1] = wpabuf_len(shared); 90e5b75505Sopenharmony_ci if (ikev2_prf_hash(prf->id, buf, data->i_nonce_len + data->r_nonce_len, 91e5b75505Sopenharmony_ci 2, addr, len, skeyseed) < 0) { 92e5b75505Sopenharmony_ci wpabuf_free(shared); 93e5b75505Sopenharmony_ci os_free(buf); 94e5b75505Sopenharmony_ci os_free(pad); 95e5b75505Sopenharmony_ci return -1; 96e5b75505Sopenharmony_ci } 97e5b75505Sopenharmony_ci os_free(pad); 98e5b75505Sopenharmony_ci wpabuf_free(shared); 99e5b75505Sopenharmony_ci 100e5b75505Sopenharmony_ci /* DH parameters are not needed anymore, so free them */ 101e5b75505Sopenharmony_ci wpabuf_free(data->i_dh_public); 102e5b75505Sopenharmony_ci data->i_dh_public = NULL; 103e5b75505Sopenharmony_ci wpabuf_free(data->r_dh_private); 104e5b75505Sopenharmony_ci data->r_dh_private = NULL; 105e5b75505Sopenharmony_ci 106e5b75505Sopenharmony_ci wpa_hexdump_key(MSG_DEBUG, "IKEV2: SKEYSEED", 107e5b75505Sopenharmony_ci skeyseed, prf->hash_len); 108e5b75505Sopenharmony_ci 109e5b75505Sopenharmony_ci ret = ikev2_derive_sk_keys(prf, integ, encr, skeyseed, buf, buf_len, 110e5b75505Sopenharmony_ci &data->keys); 111e5b75505Sopenharmony_ci os_free(buf); 112e5b75505Sopenharmony_ci return ret; 113e5b75505Sopenharmony_ci} 114e5b75505Sopenharmony_ci 115e5b75505Sopenharmony_ci 116e5b75505Sopenharmony_cistatic int ikev2_parse_transform(struct ikev2_proposal_data *prop, 117e5b75505Sopenharmony_ci const u8 *pos, const u8 *end) 118e5b75505Sopenharmony_ci{ 119e5b75505Sopenharmony_ci int transform_len; 120e5b75505Sopenharmony_ci const struct ikev2_transform *t; 121e5b75505Sopenharmony_ci u16 transform_id; 122e5b75505Sopenharmony_ci const u8 *tend; 123e5b75505Sopenharmony_ci 124e5b75505Sopenharmony_ci if (end - pos < (int) sizeof(*t)) { 125e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "IKEV2: Too short transform"); 126e5b75505Sopenharmony_ci return -1; 127e5b75505Sopenharmony_ci } 128e5b75505Sopenharmony_ci 129e5b75505Sopenharmony_ci t = (const struct ikev2_transform *) pos; 130e5b75505Sopenharmony_ci transform_len = WPA_GET_BE16(t->transform_length); 131e5b75505Sopenharmony_ci if (transform_len < (int) sizeof(*t) || transform_len > end - pos) { 132e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "IKEV2: Invalid transform length %d", 133e5b75505Sopenharmony_ci transform_len); 134e5b75505Sopenharmony_ci return -1; 135e5b75505Sopenharmony_ci } 136e5b75505Sopenharmony_ci tend = pos + transform_len; 137e5b75505Sopenharmony_ci 138e5b75505Sopenharmony_ci transform_id = WPA_GET_BE16(t->transform_id); 139e5b75505Sopenharmony_ci 140e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "IKEV2: Transform:"); 141e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "IKEV2: Type: %d Transform Length: %d " 142e5b75505Sopenharmony_ci "Transform Type: %d Transform ID: %d", 143e5b75505Sopenharmony_ci t->type, transform_len, t->transform_type, transform_id); 144e5b75505Sopenharmony_ci 145e5b75505Sopenharmony_ci if (t->type != 0 && t->type != 3) { 146e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "IKEV2: Unexpected Transform type"); 147e5b75505Sopenharmony_ci return -1; 148e5b75505Sopenharmony_ci } 149e5b75505Sopenharmony_ci 150e5b75505Sopenharmony_ci pos = (const u8 *) (t + 1); 151e5b75505Sopenharmony_ci if (pos < tend) { 152e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "IKEV2: Transform Attributes", 153e5b75505Sopenharmony_ci pos, tend - pos); 154e5b75505Sopenharmony_ci } 155e5b75505Sopenharmony_ci 156e5b75505Sopenharmony_ci switch (t->transform_type) { 157e5b75505Sopenharmony_ci case IKEV2_TRANSFORM_ENCR: 158e5b75505Sopenharmony_ci if (ikev2_get_encr(transform_id)) { 159e5b75505Sopenharmony_ci if (transform_id == ENCR_AES_CBC) { 160e5b75505Sopenharmony_ci if (tend - pos != 4) { 161e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "IKEV2: No " 162e5b75505Sopenharmony_ci "Transform Attr for AES"); 163e5b75505Sopenharmony_ci break; 164e5b75505Sopenharmony_ci } 165e5b75505Sopenharmony_ci if (WPA_GET_BE16(pos) != 0x800e) { 166e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "IKEV2: Not a " 167e5b75505Sopenharmony_ci "Key Size attribute for " 168e5b75505Sopenharmony_ci "AES"); 169e5b75505Sopenharmony_ci break; 170e5b75505Sopenharmony_ci } 171e5b75505Sopenharmony_ci if (WPA_GET_BE16(pos + 2) != 128) { 172e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "IKEV2: " 173e5b75505Sopenharmony_ci "Unsupported AES key size " 174e5b75505Sopenharmony_ci "%d bits", 175e5b75505Sopenharmony_ci WPA_GET_BE16(pos + 2)); 176e5b75505Sopenharmony_ci break; 177e5b75505Sopenharmony_ci } 178e5b75505Sopenharmony_ci } 179e5b75505Sopenharmony_ci prop->encr = transform_id; 180e5b75505Sopenharmony_ci } 181e5b75505Sopenharmony_ci break; 182e5b75505Sopenharmony_ci case IKEV2_TRANSFORM_PRF: 183e5b75505Sopenharmony_ci if (ikev2_get_prf(transform_id)) 184e5b75505Sopenharmony_ci prop->prf = transform_id; 185e5b75505Sopenharmony_ci break; 186e5b75505Sopenharmony_ci case IKEV2_TRANSFORM_INTEG: 187e5b75505Sopenharmony_ci if (ikev2_get_integ(transform_id)) 188e5b75505Sopenharmony_ci prop->integ = transform_id; 189e5b75505Sopenharmony_ci break; 190e5b75505Sopenharmony_ci case IKEV2_TRANSFORM_DH: 191e5b75505Sopenharmony_ci if (dh_groups_get(transform_id)) 192e5b75505Sopenharmony_ci prop->dh = transform_id; 193e5b75505Sopenharmony_ci break; 194e5b75505Sopenharmony_ci } 195e5b75505Sopenharmony_ci 196e5b75505Sopenharmony_ci return transform_len; 197e5b75505Sopenharmony_ci} 198e5b75505Sopenharmony_ci 199e5b75505Sopenharmony_ci 200e5b75505Sopenharmony_cistatic int ikev2_parse_proposal(struct ikev2_proposal_data *prop, 201e5b75505Sopenharmony_ci const u8 *pos, const u8 *end) 202e5b75505Sopenharmony_ci{ 203e5b75505Sopenharmony_ci const u8 *pend, *ppos; 204e5b75505Sopenharmony_ci int proposal_len, i; 205e5b75505Sopenharmony_ci const struct ikev2_proposal *p; 206e5b75505Sopenharmony_ci 207e5b75505Sopenharmony_ci if (end - pos < (int) sizeof(*p)) { 208e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "IKEV2: Too short proposal"); 209e5b75505Sopenharmony_ci return -1; 210e5b75505Sopenharmony_ci } 211e5b75505Sopenharmony_ci 212e5b75505Sopenharmony_ci /* FIX: AND processing if multiple proposals use the same # */ 213e5b75505Sopenharmony_ci 214e5b75505Sopenharmony_ci p = (const struct ikev2_proposal *) pos; 215e5b75505Sopenharmony_ci proposal_len = WPA_GET_BE16(p->proposal_length); 216e5b75505Sopenharmony_ci if (proposal_len < (int) sizeof(*p) || proposal_len > end - pos) { 217e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "IKEV2: Invalid proposal length %d", 218e5b75505Sopenharmony_ci proposal_len); 219e5b75505Sopenharmony_ci return -1; 220e5b75505Sopenharmony_ci } 221e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "IKEV2: SAi1 Proposal # %d", 222e5b75505Sopenharmony_ci p->proposal_num); 223e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "IKEV2: Type: %d Proposal Length: %d " 224e5b75505Sopenharmony_ci " Protocol ID: %d", 225e5b75505Sopenharmony_ci p->type, proposal_len, p->protocol_id); 226e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "IKEV2: SPI Size: %d Transforms: %d", 227e5b75505Sopenharmony_ci p->spi_size, p->num_transforms); 228e5b75505Sopenharmony_ci 229e5b75505Sopenharmony_ci if (p->type != 0 && p->type != 2) { 230e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "IKEV2: Unexpected Proposal type"); 231e5b75505Sopenharmony_ci return -1; 232e5b75505Sopenharmony_ci } 233e5b75505Sopenharmony_ci 234e5b75505Sopenharmony_ci if (p->protocol_id != IKEV2_PROTOCOL_IKE) { 235e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "IKEV2: Unexpected Protocol ID " 236e5b75505Sopenharmony_ci "(only IKE allowed for EAP-IKEv2)"); 237e5b75505Sopenharmony_ci return -1; 238e5b75505Sopenharmony_ci } 239e5b75505Sopenharmony_ci 240e5b75505Sopenharmony_ci if (p->proposal_num != prop->proposal_num) { 241e5b75505Sopenharmony_ci if (p->proposal_num == prop->proposal_num + 1) 242e5b75505Sopenharmony_ci prop->proposal_num = p->proposal_num; 243e5b75505Sopenharmony_ci else { 244e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "IKEV2: Unexpected Proposal #"); 245e5b75505Sopenharmony_ci return -1; 246e5b75505Sopenharmony_ci } 247e5b75505Sopenharmony_ci } 248e5b75505Sopenharmony_ci 249e5b75505Sopenharmony_ci ppos = (const u8 *) (p + 1); 250e5b75505Sopenharmony_ci pend = pos + proposal_len; 251e5b75505Sopenharmony_ci if (p->spi_size > pend - ppos) { 252e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "IKEV2: Not enough room for SPI " 253e5b75505Sopenharmony_ci "in proposal"); 254e5b75505Sopenharmony_ci return -1; 255e5b75505Sopenharmony_ci } 256e5b75505Sopenharmony_ci if (p->spi_size) { 257e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "IKEV2: SPI", 258e5b75505Sopenharmony_ci ppos, p->spi_size); 259e5b75505Sopenharmony_ci ppos += p->spi_size; 260e5b75505Sopenharmony_ci } 261e5b75505Sopenharmony_ci 262e5b75505Sopenharmony_ci /* 263e5b75505Sopenharmony_ci * For initial IKE_SA negotiation, SPI Size MUST be zero; for 264e5b75505Sopenharmony_ci * subsequent negotiations, it must be 8 for IKE. We only support 265e5b75505Sopenharmony_ci * initial case for now. 266e5b75505Sopenharmony_ci */ 267e5b75505Sopenharmony_ci if (p->spi_size != 0) { 268e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "IKEV2: Unexpected SPI Size"); 269e5b75505Sopenharmony_ci return -1; 270e5b75505Sopenharmony_ci } 271e5b75505Sopenharmony_ci 272e5b75505Sopenharmony_ci if (p->num_transforms == 0) { 273e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "IKEV2: At least one transform required"); 274e5b75505Sopenharmony_ci return -1; 275e5b75505Sopenharmony_ci } 276e5b75505Sopenharmony_ci 277e5b75505Sopenharmony_ci for (i = 0; i < (int) p->num_transforms; i++) { 278e5b75505Sopenharmony_ci int tlen = ikev2_parse_transform(prop, ppos, pend); 279e5b75505Sopenharmony_ci if (tlen < 0) 280e5b75505Sopenharmony_ci return -1; 281e5b75505Sopenharmony_ci ppos += tlen; 282e5b75505Sopenharmony_ci } 283e5b75505Sopenharmony_ci 284e5b75505Sopenharmony_ci if (ppos != pend) { 285e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "IKEV2: Unexpected data after " 286e5b75505Sopenharmony_ci "transforms"); 287e5b75505Sopenharmony_ci return -1; 288e5b75505Sopenharmony_ci } 289e5b75505Sopenharmony_ci 290e5b75505Sopenharmony_ci return proposal_len; 291e5b75505Sopenharmony_ci} 292e5b75505Sopenharmony_ci 293e5b75505Sopenharmony_ci 294e5b75505Sopenharmony_cistatic int ikev2_process_sai1(struct ikev2_responder_data *data, 295e5b75505Sopenharmony_ci const u8 *sai1, size_t sai1_len) 296e5b75505Sopenharmony_ci{ 297e5b75505Sopenharmony_ci struct ikev2_proposal_data prop; 298e5b75505Sopenharmony_ci const u8 *pos, *end; 299e5b75505Sopenharmony_ci int found = 0; 300e5b75505Sopenharmony_ci 301e5b75505Sopenharmony_ci /* Security Association Payloads: <Proposals> */ 302e5b75505Sopenharmony_ci 303e5b75505Sopenharmony_ci if (sai1 == NULL) { 304e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "IKEV2: SAi1 not received"); 305e5b75505Sopenharmony_ci return -1; 306e5b75505Sopenharmony_ci } 307e5b75505Sopenharmony_ci 308e5b75505Sopenharmony_ci os_memset(&prop, 0, sizeof(prop)); 309e5b75505Sopenharmony_ci prop.proposal_num = 1; 310e5b75505Sopenharmony_ci 311e5b75505Sopenharmony_ci pos = sai1; 312e5b75505Sopenharmony_ci end = sai1 + sai1_len; 313e5b75505Sopenharmony_ci 314e5b75505Sopenharmony_ci while (pos < end) { 315e5b75505Sopenharmony_ci int plen; 316e5b75505Sopenharmony_ci 317e5b75505Sopenharmony_ci prop.integ = -1; 318e5b75505Sopenharmony_ci prop.prf = -1; 319e5b75505Sopenharmony_ci prop.encr = -1; 320e5b75505Sopenharmony_ci prop.dh = -1; 321e5b75505Sopenharmony_ci plen = ikev2_parse_proposal(&prop, pos, end); 322e5b75505Sopenharmony_ci if (plen < 0) 323e5b75505Sopenharmony_ci return -1; 324e5b75505Sopenharmony_ci 325e5b75505Sopenharmony_ci if (!found && prop.integ != -1 && prop.prf != -1 && 326e5b75505Sopenharmony_ci prop.encr != -1 && prop.dh != -1) { 327e5b75505Sopenharmony_ci os_memcpy(&data->proposal, &prop, sizeof(prop)); 328e5b75505Sopenharmony_ci data->dh = dh_groups_get(prop.dh); 329e5b75505Sopenharmony_ci found = 1; 330e5b75505Sopenharmony_ci } 331e5b75505Sopenharmony_ci 332e5b75505Sopenharmony_ci pos += plen; 333e5b75505Sopenharmony_ci } 334e5b75505Sopenharmony_ci 335e5b75505Sopenharmony_ci if (pos != end) { 336e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "IKEV2: Unexpected data after proposals"); 337e5b75505Sopenharmony_ci return -1; 338e5b75505Sopenharmony_ci } 339e5b75505Sopenharmony_ci 340e5b75505Sopenharmony_ci if (!found) { 341e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "IKEV2: No acceptable proposal found"); 342e5b75505Sopenharmony_ci return -1; 343e5b75505Sopenharmony_ci } 344e5b75505Sopenharmony_ci 345e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "IKEV2: Accepted proposal #%d: ENCR:%d PRF:%d " 346e5b75505Sopenharmony_ci "INTEG:%d D-H:%d", data->proposal.proposal_num, 347e5b75505Sopenharmony_ci data->proposal.encr, data->proposal.prf, 348e5b75505Sopenharmony_ci data->proposal.integ, data->proposal.dh); 349e5b75505Sopenharmony_ci 350e5b75505Sopenharmony_ci return 0; 351e5b75505Sopenharmony_ci} 352e5b75505Sopenharmony_ci 353e5b75505Sopenharmony_ci 354e5b75505Sopenharmony_cistatic int ikev2_process_kei(struct ikev2_responder_data *data, 355e5b75505Sopenharmony_ci const u8 *kei, size_t kei_len) 356e5b75505Sopenharmony_ci{ 357e5b75505Sopenharmony_ci u16 group; 358e5b75505Sopenharmony_ci 359e5b75505Sopenharmony_ci /* 360e5b75505Sopenharmony_ci * Key Exchange Payload: 361e5b75505Sopenharmony_ci * DH Group # (16 bits) 362e5b75505Sopenharmony_ci * RESERVED (16 bits) 363e5b75505Sopenharmony_ci * Key Exchange Data (Diffie-Hellman public value) 364e5b75505Sopenharmony_ci */ 365e5b75505Sopenharmony_ci 366e5b75505Sopenharmony_ci if (kei == NULL) { 367e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "IKEV2: KEi not received"); 368e5b75505Sopenharmony_ci return -1; 369e5b75505Sopenharmony_ci } 370e5b75505Sopenharmony_ci 371e5b75505Sopenharmony_ci if (kei_len < 4 + 96) { 372e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "IKEV2: Too short Key Exchange Payload"); 373e5b75505Sopenharmony_ci return -1; 374e5b75505Sopenharmony_ci } 375e5b75505Sopenharmony_ci 376e5b75505Sopenharmony_ci group = WPA_GET_BE16(kei); 377e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "IKEV2: KEi DH Group #%u", group); 378e5b75505Sopenharmony_ci 379e5b75505Sopenharmony_ci if (group != data->proposal.dh) { 380e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "IKEV2: KEi DH Group #%u does not match " 381e5b75505Sopenharmony_ci "with the selected proposal (%u)", 382e5b75505Sopenharmony_ci group, data->proposal.dh); 383e5b75505Sopenharmony_ci /* Reject message with Notify payload of type 384e5b75505Sopenharmony_ci * INVALID_KE_PAYLOAD (RFC 4306, Sect. 3.4) */ 385e5b75505Sopenharmony_ci data->error_type = INVALID_KE_PAYLOAD; 386e5b75505Sopenharmony_ci data->state = NOTIFY; 387e5b75505Sopenharmony_ci return -1; 388e5b75505Sopenharmony_ci } 389e5b75505Sopenharmony_ci 390e5b75505Sopenharmony_ci if (data->dh == NULL) { 391e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "IKEV2: Unsupported DH group"); 392e5b75505Sopenharmony_ci return -1; 393e5b75505Sopenharmony_ci } 394e5b75505Sopenharmony_ci 395e5b75505Sopenharmony_ci /* RFC 4306, Section 3.4: 396e5b75505Sopenharmony_ci * The length of DH public value MUST be equal to the length of the 397e5b75505Sopenharmony_ci * prime modulus. 398e5b75505Sopenharmony_ci */ 399e5b75505Sopenharmony_ci if (kei_len - 4 != data->dh->prime_len) { 400e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "IKEV2: Invalid DH public value length " 401e5b75505Sopenharmony_ci "%ld (expected %ld)", 402e5b75505Sopenharmony_ci (long) (kei_len - 4), (long) data->dh->prime_len); 403e5b75505Sopenharmony_ci return -1; 404e5b75505Sopenharmony_ci } 405e5b75505Sopenharmony_ci 406e5b75505Sopenharmony_ci wpabuf_free(data->i_dh_public); 407e5b75505Sopenharmony_ci data->i_dh_public = wpabuf_alloc(kei_len - 4); 408e5b75505Sopenharmony_ci if (data->i_dh_public == NULL) 409e5b75505Sopenharmony_ci return -1; 410e5b75505Sopenharmony_ci wpabuf_put_data(data->i_dh_public, kei + 4, kei_len - 4); 411e5b75505Sopenharmony_ci 412e5b75505Sopenharmony_ci wpa_hexdump_buf(MSG_DEBUG, "IKEV2: KEi Diffie-Hellman Public Value", 413e5b75505Sopenharmony_ci data->i_dh_public); 414e5b75505Sopenharmony_ci 415e5b75505Sopenharmony_ci return 0; 416e5b75505Sopenharmony_ci} 417e5b75505Sopenharmony_ci 418e5b75505Sopenharmony_ci 419e5b75505Sopenharmony_cistatic int ikev2_process_ni(struct ikev2_responder_data *data, 420e5b75505Sopenharmony_ci const u8 *ni, size_t ni_len) 421e5b75505Sopenharmony_ci{ 422e5b75505Sopenharmony_ci if (ni == NULL) { 423e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "IKEV2: Ni not received"); 424e5b75505Sopenharmony_ci return -1; 425e5b75505Sopenharmony_ci } 426e5b75505Sopenharmony_ci 427e5b75505Sopenharmony_ci if (ni_len < IKEV2_NONCE_MIN_LEN || ni_len > IKEV2_NONCE_MAX_LEN) { 428e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "IKEV2: Invalid Ni length %ld", 429e5b75505Sopenharmony_ci (long) ni_len); 430e5b75505Sopenharmony_ci return -1; 431e5b75505Sopenharmony_ci } 432e5b75505Sopenharmony_ci 433e5b75505Sopenharmony_ci data->i_nonce_len = ni_len; 434e5b75505Sopenharmony_ci os_memcpy(data->i_nonce, ni, ni_len); 435e5b75505Sopenharmony_ci wpa_hexdump(MSG_MSGDUMP, "IKEV2: Ni", 436e5b75505Sopenharmony_ci data->i_nonce, data->i_nonce_len); 437e5b75505Sopenharmony_ci 438e5b75505Sopenharmony_ci return 0; 439e5b75505Sopenharmony_ci} 440e5b75505Sopenharmony_ci 441e5b75505Sopenharmony_ci 442e5b75505Sopenharmony_cistatic int ikev2_process_sa_init(struct ikev2_responder_data *data, 443e5b75505Sopenharmony_ci const struct ikev2_hdr *hdr, 444e5b75505Sopenharmony_ci struct ikev2_payloads *pl) 445e5b75505Sopenharmony_ci{ 446e5b75505Sopenharmony_ci if (ikev2_process_sai1(data, pl->sa, pl->sa_len) < 0 || 447e5b75505Sopenharmony_ci ikev2_process_kei(data, pl->ke, pl->ke_len) < 0 || 448e5b75505Sopenharmony_ci ikev2_process_ni(data, pl->nonce, pl->nonce_len) < 0) 449e5b75505Sopenharmony_ci return -1; 450e5b75505Sopenharmony_ci 451e5b75505Sopenharmony_ci os_memcpy(data->i_spi, hdr->i_spi, IKEV2_SPI_LEN); 452e5b75505Sopenharmony_ci 453e5b75505Sopenharmony_ci return 0; 454e5b75505Sopenharmony_ci} 455e5b75505Sopenharmony_ci 456e5b75505Sopenharmony_ci 457e5b75505Sopenharmony_cistatic int ikev2_process_idi(struct ikev2_responder_data *data, 458e5b75505Sopenharmony_ci const u8 *idi, size_t idi_len) 459e5b75505Sopenharmony_ci{ 460e5b75505Sopenharmony_ci u8 id_type; 461e5b75505Sopenharmony_ci 462e5b75505Sopenharmony_ci if (idi == NULL) { 463e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "IKEV2: No IDi received"); 464e5b75505Sopenharmony_ci return -1; 465e5b75505Sopenharmony_ci } 466e5b75505Sopenharmony_ci 467e5b75505Sopenharmony_ci if (idi_len < 4) { 468e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "IKEV2: Too short IDi payload"); 469e5b75505Sopenharmony_ci return -1; 470e5b75505Sopenharmony_ci } 471e5b75505Sopenharmony_ci 472e5b75505Sopenharmony_ci id_type = idi[0]; 473e5b75505Sopenharmony_ci idi += 4; 474e5b75505Sopenharmony_ci idi_len -= 4; 475e5b75505Sopenharmony_ci 476e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "IKEV2: IDi ID Type %d", id_type); 477e5b75505Sopenharmony_ci wpa_hexdump_ascii(MSG_DEBUG, "IKEV2: IDi", idi, idi_len); 478e5b75505Sopenharmony_ci os_free(data->IDi); 479e5b75505Sopenharmony_ci data->IDi = os_memdup(idi, idi_len); 480e5b75505Sopenharmony_ci if (data->IDi == NULL) 481e5b75505Sopenharmony_ci return -1; 482e5b75505Sopenharmony_ci data->IDi_len = idi_len; 483e5b75505Sopenharmony_ci data->IDi_type = id_type; 484e5b75505Sopenharmony_ci 485e5b75505Sopenharmony_ci return 0; 486e5b75505Sopenharmony_ci} 487e5b75505Sopenharmony_ci 488e5b75505Sopenharmony_ci 489e5b75505Sopenharmony_cistatic int ikev2_process_cert(struct ikev2_responder_data *data, 490e5b75505Sopenharmony_ci const u8 *cert, size_t cert_len) 491e5b75505Sopenharmony_ci{ 492e5b75505Sopenharmony_ci u8 cert_encoding; 493e5b75505Sopenharmony_ci 494e5b75505Sopenharmony_ci if (cert == NULL) { 495e5b75505Sopenharmony_ci if (data->peer_auth == PEER_AUTH_CERT) { 496e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "IKEV2: No Certificate received"); 497e5b75505Sopenharmony_ci return -1; 498e5b75505Sopenharmony_ci } 499e5b75505Sopenharmony_ci return 0; 500e5b75505Sopenharmony_ci } 501e5b75505Sopenharmony_ci 502e5b75505Sopenharmony_ci if (cert_len < 1) { 503e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "IKEV2: No Cert Encoding field"); 504e5b75505Sopenharmony_ci return -1; 505e5b75505Sopenharmony_ci } 506e5b75505Sopenharmony_ci 507e5b75505Sopenharmony_ci cert_encoding = cert[0]; 508e5b75505Sopenharmony_ci cert++; 509e5b75505Sopenharmony_ci cert_len--; 510e5b75505Sopenharmony_ci 511e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "IKEV2: Cert Encoding %d", cert_encoding); 512e5b75505Sopenharmony_ci wpa_hexdump(MSG_MSGDUMP, "IKEV2: Certificate Data", cert, cert_len); 513e5b75505Sopenharmony_ci 514e5b75505Sopenharmony_ci /* TODO: validate certificate */ 515e5b75505Sopenharmony_ci 516e5b75505Sopenharmony_ci return 0; 517e5b75505Sopenharmony_ci} 518e5b75505Sopenharmony_ci 519e5b75505Sopenharmony_ci 520e5b75505Sopenharmony_cistatic int ikev2_process_auth_cert(struct ikev2_responder_data *data, 521e5b75505Sopenharmony_ci u8 method, const u8 *auth, size_t auth_len) 522e5b75505Sopenharmony_ci{ 523e5b75505Sopenharmony_ci if (method != AUTH_RSA_SIGN) { 524e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "IKEV2: Unsupported authentication " 525e5b75505Sopenharmony_ci "method %d", method); 526e5b75505Sopenharmony_ci return -1; 527e5b75505Sopenharmony_ci } 528e5b75505Sopenharmony_ci 529e5b75505Sopenharmony_ci /* TODO: validate AUTH */ 530e5b75505Sopenharmony_ci return 0; 531e5b75505Sopenharmony_ci} 532e5b75505Sopenharmony_ci 533e5b75505Sopenharmony_ci 534e5b75505Sopenharmony_cistatic int ikev2_process_auth_secret(struct ikev2_responder_data *data, 535e5b75505Sopenharmony_ci u8 method, const u8 *auth, 536e5b75505Sopenharmony_ci size_t auth_len) 537e5b75505Sopenharmony_ci{ 538e5b75505Sopenharmony_ci u8 auth_data[IKEV2_MAX_HASH_LEN]; 539e5b75505Sopenharmony_ci const struct ikev2_prf_alg *prf; 540e5b75505Sopenharmony_ci 541e5b75505Sopenharmony_ci if (method != AUTH_SHARED_KEY_MIC) { 542e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "IKEV2: Unsupported authentication " 543e5b75505Sopenharmony_ci "method %d", method); 544e5b75505Sopenharmony_ci return -1; 545e5b75505Sopenharmony_ci } 546e5b75505Sopenharmony_ci 547e5b75505Sopenharmony_ci /* msg | Nr | prf(SK_pi,IDi') */ 548e5b75505Sopenharmony_ci if (ikev2_derive_auth_data(data->proposal.prf, data->i_sign_msg, 549e5b75505Sopenharmony_ci data->IDi, data->IDi_len, data->IDi_type, 550e5b75505Sopenharmony_ci &data->keys, 1, data->shared_secret, 551e5b75505Sopenharmony_ci data->shared_secret_len, 552e5b75505Sopenharmony_ci data->r_nonce, data->r_nonce_len, 553e5b75505Sopenharmony_ci data->key_pad, data->key_pad_len, 554e5b75505Sopenharmony_ci auth_data) < 0) { 555e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "IKEV2: Could not derive AUTH data"); 556e5b75505Sopenharmony_ci return -1; 557e5b75505Sopenharmony_ci } 558e5b75505Sopenharmony_ci 559e5b75505Sopenharmony_ci wpabuf_free(data->i_sign_msg); 560e5b75505Sopenharmony_ci data->i_sign_msg = NULL; 561e5b75505Sopenharmony_ci 562e5b75505Sopenharmony_ci prf = ikev2_get_prf(data->proposal.prf); 563e5b75505Sopenharmony_ci if (prf == NULL) 564e5b75505Sopenharmony_ci return -1; 565e5b75505Sopenharmony_ci 566e5b75505Sopenharmony_ci if (auth_len != prf->hash_len || 567e5b75505Sopenharmony_ci os_memcmp_const(auth, auth_data, auth_len) != 0) { 568e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "IKEV2: Invalid Authentication Data"); 569e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "IKEV2: Received Authentication Data", 570e5b75505Sopenharmony_ci auth, auth_len); 571e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "IKEV2: Expected Authentication Data", 572e5b75505Sopenharmony_ci auth_data, prf->hash_len); 573e5b75505Sopenharmony_ci data->error_type = AUTHENTICATION_FAILED; 574e5b75505Sopenharmony_ci data->state = NOTIFY; 575e5b75505Sopenharmony_ci return -1; 576e5b75505Sopenharmony_ci } 577e5b75505Sopenharmony_ci 578e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "IKEV2: Server authenticated successfully " 579e5b75505Sopenharmony_ci "using shared keys"); 580e5b75505Sopenharmony_ci 581e5b75505Sopenharmony_ci return 0; 582e5b75505Sopenharmony_ci} 583e5b75505Sopenharmony_ci 584e5b75505Sopenharmony_ci 585e5b75505Sopenharmony_cistatic int ikev2_process_auth(struct ikev2_responder_data *data, 586e5b75505Sopenharmony_ci const u8 *auth, size_t auth_len) 587e5b75505Sopenharmony_ci{ 588e5b75505Sopenharmony_ci u8 auth_method; 589e5b75505Sopenharmony_ci 590e5b75505Sopenharmony_ci if (auth == NULL) { 591e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "IKEV2: No Authentication Payload"); 592e5b75505Sopenharmony_ci return -1; 593e5b75505Sopenharmony_ci } 594e5b75505Sopenharmony_ci 595e5b75505Sopenharmony_ci if (auth_len < 4) { 596e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "IKEV2: Too short Authentication " 597e5b75505Sopenharmony_ci "Payload"); 598e5b75505Sopenharmony_ci return -1; 599e5b75505Sopenharmony_ci } 600e5b75505Sopenharmony_ci 601e5b75505Sopenharmony_ci auth_method = auth[0]; 602e5b75505Sopenharmony_ci auth += 4; 603e5b75505Sopenharmony_ci auth_len -= 4; 604e5b75505Sopenharmony_ci 605e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "IKEV2: Auth Method %d", auth_method); 606e5b75505Sopenharmony_ci wpa_hexdump(MSG_MSGDUMP, "IKEV2: Authentication Data", auth, auth_len); 607e5b75505Sopenharmony_ci 608e5b75505Sopenharmony_ci switch (data->peer_auth) { 609e5b75505Sopenharmony_ci case PEER_AUTH_CERT: 610e5b75505Sopenharmony_ci return ikev2_process_auth_cert(data, auth_method, auth, 611e5b75505Sopenharmony_ci auth_len); 612e5b75505Sopenharmony_ci case PEER_AUTH_SECRET: 613e5b75505Sopenharmony_ci return ikev2_process_auth_secret(data, auth_method, auth, 614e5b75505Sopenharmony_ci auth_len); 615e5b75505Sopenharmony_ci } 616e5b75505Sopenharmony_ci 617e5b75505Sopenharmony_ci return -1; 618e5b75505Sopenharmony_ci} 619e5b75505Sopenharmony_ci 620e5b75505Sopenharmony_ci 621e5b75505Sopenharmony_cistatic int ikev2_process_sa_auth_decrypted(struct ikev2_responder_data *data, 622e5b75505Sopenharmony_ci u8 next_payload, 623e5b75505Sopenharmony_ci u8 *payload, size_t payload_len) 624e5b75505Sopenharmony_ci{ 625e5b75505Sopenharmony_ci struct ikev2_payloads pl; 626e5b75505Sopenharmony_ci 627e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "IKEV2: Processing decrypted payloads"); 628e5b75505Sopenharmony_ci 629e5b75505Sopenharmony_ci if (ikev2_parse_payloads(&pl, next_payload, payload, payload + 630e5b75505Sopenharmony_ci payload_len) < 0) { 631e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "IKEV2: Failed to parse decrypted " 632e5b75505Sopenharmony_ci "payloads"); 633e5b75505Sopenharmony_ci return -1; 634e5b75505Sopenharmony_ci } 635e5b75505Sopenharmony_ci 636e5b75505Sopenharmony_ci if (ikev2_process_idi(data, pl.idi, pl.idi_len) < 0 || 637e5b75505Sopenharmony_ci ikev2_process_cert(data, pl.cert, pl.cert_len) < 0 || 638e5b75505Sopenharmony_ci ikev2_process_auth(data, pl.auth, pl.auth_len) < 0) 639e5b75505Sopenharmony_ci return -1; 640e5b75505Sopenharmony_ci 641e5b75505Sopenharmony_ci return 0; 642e5b75505Sopenharmony_ci} 643e5b75505Sopenharmony_ci 644e5b75505Sopenharmony_ci 645e5b75505Sopenharmony_cistatic int ikev2_process_sa_auth(struct ikev2_responder_data *data, 646e5b75505Sopenharmony_ci const struct ikev2_hdr *hdr, 647e5b75505Sopenharmony_ci struct ikev2_payloads *pl) 648e5b75505Sopenharmony_ci{ 649e5b75505Sopenharmony_ci u8 *decrypted; 650e5b75505Sopenharmony_ci size_t decrypted_len; 651e5b75505Sopenharmony_ci int ret; 652e5b75505Sopenharmony_ci 653e5b75505Sopenharmony_ci decrypted = ikev2_decrypt_payload(data->proposal.encr, 654e5b75505Sopenharmony_ci data->proposal.integ, 655e5b75505Sopenharmony_ci &data->keys, 1, hdr, pl->encrypted, 656e5b75505Sopenharmony_ci pl->encrypted_len, &decrypted_len); 657e5b75505Sopenharmony_ci if (decrypted == NULL) 658e5b75505Sopenharmony_ci return -1; 659e5b75505Sopenharmony_ci 660e5b75505Sopenharmony_ci ret = ikev2_process_sa_auth_decrypted(data, pl->encr_next_payload, 661e5b75505Sopenharmony_ci decrypted, decrypted_len); 662e5b75505Sopenharmony_ci os_free(decrypted); 663e5b75505Sopenharmony_ci 664e5b75505Sopenharmony_ci return ret; 665e5b75505Sopenharmony_ci} 666e5b75505Sopenharmony_ci 667e5b75505Sopenharmony_ci 668e5b75505Sopenharmony_cistatic int ikev2_validate_rx_state(struct ikev2_responder_data *data, 669e5b75505Sopenharmony_ci u8 exchange_type, u32 message_id) 670e5b75505Sopenharmony_ci{ 671e5b75505Sopenharmony_ci switch (data->state) { 672e5b75505Sopenharmony_ci case SA_INIT: 673e5b75505Sopenharmony_ci /* Expect to receive IKE_SA_INIT: HDR, SAi1, KEi, Ni */ 674e5b75505Sopenharmony_ci if (exchange_type != IKE_SA_INIT) { 675e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "IKEV2: Unexpected Exchange Type " 676e5b75505Sopenharmony_ci "%u in SA_INIT state", exchange_type); 677e5b75505Sopenharmony_ci return -1; 678e5b75505Sopenharmony_ci } 679e5b75505Sopenharmony_ci if (message_id != 0) { 680e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "IKEV2: Unexpected Message ID %u " 681e5b75505Sopenharmony_ci "in SA_INIT state", message_id); 682e5b75505Sopenharmony_ci return -1; 683e5b75505Sopenharmony_ci } 684e5b75505Sopenharmony_ci break; 685e5b75505Sopenharmony_ci case SA_AUTH: 686e5b75505Sopenharmony_ci /* Expect to receive IKE_SA_AUTH: 687e5b75505Sopenharmony_ci * HDR, SK {IDi, [CERT,] [CERTREQ,] [IDr,] 688e5b75505Sopenharmony_ci * AUTH, SAi2, TSi, TSr} 689e5b75505Sopenharmony_ci */ 690e5b75505Sopenharmony_ci if (exchange_type != IKE_SA_AUTH) { 691e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "IKEV2: Unexpected Exchange Type " 692e5b75505Sopenharmony_ci "%u in SA_AUTH state", exchange_type); 693e5b75505Sopenharmony_ci return -1; 694e5b75505Sopenharmony_ci } 695e5b75505Sopenharmony_ci if (message_id != 1) { 696e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "IKEV2: Unexpected Message ID %u " 697e5b75505Sopenharmony_ci "in SA_AUTH state", message_id); 698e5b75505Sopenharmony_ci return -1; 699e5b75505Sopenharmony_ci } 700e5b75505Sopenharmony_ci break; 701e5b75505Sopenharmony_ci case CHILD_SA: 702e5b75505Sopenharmony_ci if (exchange_type != CREATE_CHILD_SA) { 703e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "IKEV2: Unexpected Exchange Type " 704e5b75505Sopenharmony_ci "%u in CHILD_SA state", exchange_type); 705e5b75505Sopenharmony_ci return -1; 706e5b75505Sopenharmony_ci } 707e5b75505Sopenharmony_ci if (message_id != 2) { 708e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "IKEV2: Unexpected Message ID %u " 709e5b75505Sopenharmony_ci "in CHILD_SA state", message_id); 710e5b75505Sopenharmony_ci return -1; 711e5b75505Sopenharmony_ci } 712e5b75505Sopenharmony_ci break; 713e5b75505Sopenharmony_ci case NOTIFY: 714e5b75505Sopenharmony_ci case IKEV2_DONE: 715e5b75505Sopenharmony_ci case IKEV2_FAILED: 716e5b75505Sopenharmony_ci return -1; 717e5b75505Sopenharmony_ci } 718e5b75505Sopenharmony_ci 719e5b75505Sopenharmony_ci return 0; 720e5b75505Sopenharmony_ci} 721e5b75505Sopenharmony_ci 722e5b75505Sopenharmony_ci 723e5b75505Sopenharmony_ciint ikev2_responder_process(struct ikev2_responder_data *data, 724e5b75505Sopenharmony_ci const struct wpabuf *buf) 725e5b75505Sopenharmony_ci{ 726e5b75505Sopenharmony_ci const struct ikev2_hdr *hdr; 727e5b75505Sopenharmony_ci u32 length, message_id; 728e5b75505Sopenharmony_ci const u8 *pos, *end; 729e5b75505Sopenharmony_ci struct ikev2_payloads pl; 730e5b75505Sopenharmony_ci 731e5b75505Sopenharmony_ci wpa_printf(MSG_MSGDUMP, "IKEV2: Received message (len %lu)", 732e5b75505Sopenharmony_ci (unsigned long) wpabuf_len(buf)); 733e5b75505Sopenharmony_ci 734e5b75505Sopenharmony_ci if (wpabuf_len(buf) < sizeof(*hdr)) { 735e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "IKEV2: Too short frame to include HDR"); 736e5b75505Sopenharmony_ci return -1; 737e5b75505Sopenharmony_ci } 738e5b75505Sopenharmony_ci 739e5b75505Sopenharmony_ci data->error_type = 0; 740e5b75505Sopenharmony_ci hdr = (const struct ikev2_hdr *) wpabuf_head(buf); 741e5b75505Sopenharmony_ci end = wpabuf_head_u8(buf) + wpabuf_len(buf); 742e5b75505Sopenharmony_ci message_id = WPA_GET_BE32(hdr->message_id); 743e5b75505Sopenharmony_ci length = WPA_GET_BE32(hdr->length); 744e5b75505Sopenharmony_ci 745e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "IKEV2: IKE_SA Initiator's SPI", 746e5b75505Sopenharmony_ci hdr->i_spi, IKEV2_SPI_LEN); 747e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "IKEV2: IKE_SA Responder's SPI", 748e5b75505Sopenharmony_ci hdr->r_spi, IKEV2_SPI_LEN); 749e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "IKEV2: Next Payload: %u Version: 0x%x " 750e5b75505Sopenharmony_ci "Exchange Type: %u", 751e5b75505Sopenharmony_ci hdr->next_payload, hdr->version, hdr->exchange_type); 752e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "IKEV2: Message ID: %u Length: %u", 753e5b75505Sopenharmony_ci message_id, length); 754e5b75505Sopenharmony_ci 755e5b75505Sopenharmony_ci if (hdr->version != IKEV2_VERSION) { 756e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "IKEV2: Unsupported HDR version 0x%x " 757e5b75505Sopenharmony_ci "(expected 0x%x)", hdr->version, IKEV2_VERSION); 758e5b75505Sopenharmony_ci return -1; 759e5b75505Sopenharmony_ci } 760e5b75505Sopenharmony_ci 761e5b75505Sopenharmony_ci if (length != wpabuf_len(buf)) { 762e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "IKEV2: Invalid length (HDR: %lu != " 763e5b75505Sopenharmony_ci "RX: %lu)", (unsigned long) length, 764e5b75505Sopenharmony_ci (unsigned long) wpabuf_len(buf)); 765e5b75505Sopenharmony_ci return -1; 766e5b75505Sopenharmony_ci } 767e5b75505Sopenharmony_ci 768e5b75505Sopenharmony_ci if (ikev2_validate_rx_state(data, hdr->exchange_type, message_id) < 0) 769e5b75505Sopenharmony_ci return -1; 770e5b75505Sopenharmony_ci 771e5b75505Sopenharmony_ci if ((hdr->flags & (IKEV2_HDR_INITIATOR | IKEV2_HDR_RESPONSE)) != 772e5b75505Sopenharmony_ci IKEV2_HDR_INITIATOR) { 773e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "IKEV2: Unexpected Flags value 0x%x", 774e5b75505Sopenharmony_ci hdr->flags); 775e5b75505Sopenharmony_ci return -1; 776e5b75505Sopenharmony_ci } 777e5b75505Sopenharmony_ci 778e5b75505Sopenharmony_ci if (data->state != SA_INIT) { 779e5b75505Sopenharmony_ci if (os_memcmp(data->i_spi, hdr->i_spi, IKEV2_SPI_LEN) != 0) { 780e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "IKEV2: Unexpected IKE_SA " 781e5b75505Sopenharmony_ci "Initiator's SPI"); 782e5b75505Sopenharmony_ci return -1; 783e5b75505Sopenharmony_ci } 784e5b75505Sopenharmony_ci if (os_memcmp(data->r_spi, hdr->r_spi, IKEV2_SPI_LEN) != 0) { 785e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "IKEV2: Unexpected IKE_SA " 786e5b75505Sopenharmony_ci "Responder's SPI"); 787e5b75505Sopenharmony_ci return -1; 788e5b75505Sopenharmony_ci } 789e5b75505Sopenharmony_ci } 790e5b75505Sopenharmony_ci 791e5b75505Sopenharmony_ci pos = (const u8 *) (hdr + 1); 792e5b75505Sopenharmony_ci if (ikev2_parse_payloads(&pl, hdr->next_payload, pos, end) < 0) 793e5b75505Sopenharmony_ci return -1; 794e5b75505Sopenharmony_ci 795e5b75505Sopenharmony_ci if (data->state == SA_INIT) { 796e5b75505Sopenharmony_ci data->last_msg = LAST_MSG_SA_INIT; 797e5b75505Sopenharmony_ci if (ikev2_process_sa_init(data, hdr, &pl) < 0) { 798e5b75505Sopenharmony_ci if (data->state == NOTIFY) 799e5b75505Sopenharmony_ci return 0; 800e5b75505Sopenharmony_ci return -1; 801e5b75505Sopenharmony_ci } 802e5b75505Sopenharmony_ci wpabuf_free(data->i_sign_msg); 803e5b75505Sopenharmony_ci data->i_sign_msg = wpabuf_dup(buf); 804e5b75505Sopenharmony_ci } 805e5b75505Sopenharmony_ci 806e5b75505Sopenharmony_ci if (data->state == SA_AUTH) { 807e5b75505Sopenharmony_ci data->last_msg = LAST_MSG_SA_AUTH; 808e5b75505Sopenharmony_ci if (ikev2_process_sa_auth(data, hdr, &pl) < 0) { 809e5b75505Sopenharmony_ci if (data->state == NOTIFY) 810e5b75505Sopenharmony_ci return 0; 811e5b75505Sopenharmony_ci return -1; 812e5b75505Sopenharmony_ci } 813e5b75505Sopenharmony_ci } 814e5b75505Sopenharmony_ci 815e5b75505Sopenharmony_ci return 0; 816e5b75505Sopenharmony_ci} 817e5b75505Sopenharmony_ci 818e5b75505Sopenharmony_ci 819e5b75505Sopenharmony_cistatic void ikev2_build_hdr(struct ikev2_responder_data *data, 820e5b75505Sopenharmony_ci struct wpabuf *msg, u8 exchange_type, 821e5b75505Sopenharmony_ci u8 next_payload, u32 message_id) 822e5b75505Sopenharmony_ci{ 823e5b75505Sopenharmony_ci struct ikev2_hdr *hdr; 824e5b75505Sopenharmony_ci 825e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "IKEV2: Adding HDR"); 826e5b75505Sopenharmony_ci 827e5b75505Sopenharmony_ci /* HDR - RFC 4306, Sect. 3.1 */ 828e5b75505Sopenharmony_ci hdr = wpabuf_put(msg, sizeof(*hdr)); 829e5b75505Sopenharmony_ci os_memcpy(hdr->i_spi, data->i_spi, IKEV2_SPI_LEN); 830e5b75505Sopenharmony_ci os_memcpy(hdr->r_spi, data->r_spi, IKEV2_SPI_LEN); 831e5b75505Sopenharmony_ci hdr->next_payload = next_payload; 832e5b75505Sopenharmony_ci hdr->version = IKEV2_VERSION; 833e5b75505Sopenharmony_ci hdr->exchange_type = exchange_type; 834e5b75505Sopenharmony_ci hdr->flags = IKEV2_HDR_RESPONSE; 835e5b75505Sopenharmony_ci WPA_PUT_BE32(hdr->message_id, message_id); 836e5b75505Sopenharmony_ci} 837e5b75505Sopenharmony_ci 838e5b75505Sopenharmony_ci 839e5b75505Sopenharmony_cistatic int ikev2_build_sar1(struct ikev2_responder_data *data, 840e5b75505Sopenharmony_ci struct wpabuf *msg, u8 next_payload) 841e5b75505Sopenharmony_ci{ 842e5b75505Sopenharmony_ci struct ikev2_payload_hdr *phdr; 843e5b75505Sopenharmony_ci size_t plen; 844e5b75505Sopenharmony_ci struct ikev2_proposal *p; 845e5b75505Sopenharmony_ci struct ikev2_transform *t; 846e5b75505Sopenharmony_ci 847e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "IKEV2: Adding SAr1 payload"); 848e5b75505Sopenharmony_ci 849e5b75505Sopenharmony_ci /* SAr1 - RFC 4306, Sect. 2.7 and 3.3 */ 850e5b75505Sopenharmony_ci phdr = wpabuf_put(msg, sizeof(*phdr)); 851e5b75505Sopenharmony_ci phdr->next_payload = next_payload; 852e5b75505Sopenharmony_ci phdr->flags = 0; 853e5b75505Sopenharmony_ci 854e5b75505Sopenharmony_ci p = wpabuf_put(msg, sizeof(*p)); 855e5b75505Sopenharmony_ci p->proposal_num = data->proposal.proposal_num; 856e5b75505Sopenharmony_ci p->protocol_id = IKEV2_PROTOCOL_IKE; 857e5b75505Sopenharmony_ci p->num_transforms = 4; 858e5b75505Sopenharmony_ci 859e5b75505Sopenharmony_ci t = wpabuf_put(msg, sizeof(*t)); 860e5b75505Sopenharmony_ci t->type = 3; 861e5b75505Sopenharmony_ci t->transform_type = IKEV2_TRANSFORM_ENCR; 862e5b75505Sopenharmony_ci WPA_PUT_BE16(t->transform_id, data->proposal.encr); 863e5b75505Sopenharmony_ci if (data->proposal.encr == ENCR_AES_CBC) { 864e5b75505Sopenharmony_ci /* Transform Attribute: Key Len = 128 bits */ 865e5b75505Sopenharmony_ci wpabuf_put_be16(msg, 0x800e); /* AF=1, AttrType=14 */ 866e5b75505Sopenharmony_ci wpabuf_put_be16(msg, 128); /* 128-bit key */ 867e5b75505Sopenharmony_ci } 868e5b75505Sopenharmony_ci plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) t; 869e5b75505Sopenharmony_ci WPA_PUT_BE16(t->transform_length, plen); 870e5b75505Sopenharmony_ci 871e5b75505Sopenharmony_ci t = wpabuf_put(msg, sizeof(*t)); 872e5b75505Sopenharmony_ci t->type = 3; 873e5b75505Sopenharmony_ci WPA_PUT_BE16(t->transform_length, sizeof(*t)); 874e5b75505Sopenharmony_ci t->transform_type = IKEV2_TRANSFORM_PRF; 875e5b75505Sopenharmony_ci WPA_PUT_BE16(t->transform_id, data->proposal.prf); 876e5b75505Sopenharmony_ci 877e5b75505Sopenharmony_ci t = wpabuf_put(msg, sizeof(*t)); 878e5b75505Sopenharmony_ci t->type = 3; 879e5b75505Sopenharmony_ci WPA_PUT_BE16(t->transform_length, sizeof(*t)); 880e5b75505Sopenharmony_ci t->transform_type = IKEV2_TRANSFORM_INTEG; 881e5b75505Sopenharmony_ci WPA_PUT_BE16(t->transform_id, data->proposal.integ); 882e5b75505Sopenharmony_ci 883e5b75505Sopenharmony_ci t = wpabuf_put(msg, sizeof(*t)); 884e5b75505Sopenharmony_ci WPA_PUT_BE16(t->transform_length, sizeof(*t)); 885e5b75505Sopenharmony_ci t->transform_type = IKEV2_TRANSFORM_DH; 886e5b75505Sopenharmony_ci WPA_PUT_BE16(t->transform_id, data->proposal.dh); 887e5b75505Sopenharmony_ci 888e5b75505Sopenharmony_ci plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) p; 889e5b75505Sopenharmony_ci WPA_PUT_BE16(p->proposal_length, plen); 890e5b75505Sopenharmony_ci 891e5b75505Sopenharmony_ci plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr; 892e5b75505Sopenharmony_ci WPA_PUT_BE16(phdr->payload_length, plen); 893e5b75505Sopenharmony_ci 894e5b75505Sopenharmony_ci return 0; 895e5b75505Sopenharmony_ci} 896e5b75505Sopenharmony_ci 897e5b75505Sopenharmony_ci 898e5b75505Sopenharmony_cistatic int ikev2_build_ker(struct ikev2_responder_data *data, 899e5b75505Sopenharmony_ci struct wpabuf *msg, u8 next_payload) 900e5b75505Sopenharmony_ci{ 901e5b75505Sopenharmony_ci struct ikev2_payload_hdr *phdr; 902e5b75505Sopenharmony_ci size_t plen; 903e5b75505Sopenharmony_ci struct wpabuf *pv; 904e5b75505Sopenharmony_ci 905e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "IKEV2: Adding KEr payload"); 906e5b75505Sopenharmony_ci 907e5b75505Sopenharmony_ci pv = dh_init(data->dh, &data->r_dh_private); 908e5b75505Sopenharmony_ci if (pv == NULL) { 909e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "IKEV2: Failed to initialize DH"); 910e5b75505Sopenharmony_ci return -1; 911e5b75505Sopenharmony_ci } 912e5b75505Sopenharmony_ci 913e5b75505Sopenharmony_ci /* KEr - RFC 4306, Sect. 3.4 */ 914e5b75505Sopenharmony_ci phdr = wpabuf_put(msg, sizeof(*phdr)); 915e5b75505Sopenharmony_ci phdr->next_payload = next_payload; 916e5b75505Sopenharmony_ci phdr->flags = 0; 917e5b75505Sopenharmony_ci 918e5b75505Sopenharmony_ci wpabuf_put_be16(msg, data->proposal.dh); /* DH Group # */ 919e5b75505Sopenharmony_ci wpabuf_put(msg, 2); /* RESERVED */ 920e5b75505Sopenharmony_ci /* 921e5b75505Sopenharmony_ci * RFC 4306, Sect. 3.4: possible zero padding for public value to 922e5b75505Sopenharmony_ci * match the length of the prime. 923e5b75505Sopenharmony_ci */ 924e5b75505Sopenharmony_ci wpabuf_put(msg, data->dh->prime_len - wpabuf_len(pv)); 925e5b75505Sopenharmony_ci wpabuf_put_buf(msg, pv); 926e5b75505Sopenharmony_ci wpabuf_free(pv); 927e5b75505Sopenharmony_ci 928e5b75505Sopenharmony_ci plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr; 929e5b75505Sopenharmony_ci WPA_PUT_BE16(phdr->payload_length, plen); 930e5b75505Sopenharmony_ci return 0; 931e5b75505Sopenharmony_ci} 932e5b75505Sopenharmony_ci 933e5b75505Sopenharmony_ci 934e5b75505Sopenharmony_cistatic int ikev2_build_nr(struct ikev2_responder_data *data, 935e5b75505Sopenharmony_ci struct wpabuf *msg, u8 next_payload) 936e5b75505Sopenharmony_ci{ 937e5b75505Sopenharmony_ci struct ikev2_payload_hdr *phdr; 938e5b75505Sopenharmony_ci size_t plen; 939e5b75505Sopenharmony_ci 940e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "IKEV2: Adding Nr payload"); 941e5b75505Sopenharmony_ci 942e5b75505Sopenharmony_ci /* Nr - RFC 4306, Sect. 3.9 */ 943e5b75505Sopenharmony_ci phdr = wpabuf_put(msg, sizeof(*phdr)); 944e5b75505Sopenharmony_ci phdr->next_payload = next_payload; 945e5b75505Sopenharmony_ci phdr->flags = 0; 946e5b75505Sopenharmony_ci wpabuf_put_data(msg, data->r_nonce, data->r_nonce_len); 947e5b75505Sopenharmony_ci plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr; 948e5b75505Sopenharmony_ci WPA_PUT_BE16(phdr->payload_length, plen); 949e5b75505Sopenharmony_ci return 0; 950e5b75505Sopenharmony_ci} 951e5b75505Sopenharmony_ci 952e5b75505Sopenharmony_ci 953e5b75505Sopenharmony_cistatic int ikev2_build_idr(struct ikev2_responder_data *data, 954e5b75505Sopenharmony_ci struct wpabuf *msg, u8 next_payload) 955e5b75505Sopenharmony_ci{ 956e5b75505Sopenharmony_ci struct ikev2_payload_hdr *phdr; 957e5b75505Sopenharmony_ci size_t plen; 958e5b75505Sopenharmony_ci 959e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "IKEV2: Adding IDr payload"); 960e5b75505Sopenharmony_ci 961e5b75505Sopenharmony_ci if (data->IDr == NULL) { 962e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "IKEV2: No IDr available"); 963e5b75505Sopenharmony_ci return -1; 964e5b75505Sopenharmony_ci } 965e5b75505Sopenharmony_ci 966e5b75505Sopenharmony_ci /* IDr - RFC 4306, Sect. 3.5 */ 967e5b75505Sopenharmony_ci phdr = wpabuf_put(msg, sizeof(*phdr)); 968e5b75505Sopenharmony_ci phdr->next_payload = next_payload; 969e5b75505Sopenharmony_ci phdr->flags = 0; 970e5b75505Sopenharmony_ci wpabuf_put_u8(msg, ID_KEY_ID); 971e5b75505Sopenharmony_ci wpabuf_put(msg, 3); /* RESERVED */ 972e5b75505Sopenharmony_ci wpabuf_put_data(msg, data->IDr, data->IDr_len); 973e5b75505Sopenharmony_ci plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr; 974e5b75505Sopenharmony_ci WPA_PUT_BE16(phdr->payload_length, plen); 975e5b75505Sopenharmony_ci return 0; 976e5b75505Sopenharmony_ci} 977e5b75505Sopenharmony_ci 978e5b75505Sopenharmony_ci 979e5b75505Sopenharmony_cistatic int ikev2_build_auth(struct ikev2_responder_data *data, 980e5b75505Sopenharmony_ci struct wpabuf *msg, u8 next_payload) 981e5b75505Sopenharmony_ci{ 982e5b75505Sopenharmony_ci struct ikev2_payload_hdr *phdr; 983e5b75505Sopenharmony_ci size_t plen; 984e5b75505Sopenharmony_ci const struct ikev2_prf_alg *prf; 985e5b75505Sopenharmony_ci 986e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "IKEV2: Adding AUTH payload"); 987e5b75505Sopenharmony_ci 988e5b75505Sopenharmony_ci prf = ikev2_get_prf(data->proposal.prf); 989e5b75505Sopenharmony_ci if (prf == NULL) 990e5b75505Sopenharmony_ci return -1; 991e5b75505Sopenharmony_ci 992e5b75505Sopenharmony_ci /* Authentication - RFC 4306, Sect. 3.8 */ 993e5b75505Sopenharmony_ci phdr = wpabuf_put(msg, sizeof(*phdr)); 994e5b75505Sopenharmony_ci phdr->next_payload = next_payload; 995e5b75505Sopenharmony_ci phdr->flags = 0; 996e5b75505Sopenharmony_ci wpabuf_put_u8(msg, AUTH_SHARED_KEY_MIC); 997e5b75505Sopenharmony_ci wpabuf_put(msg, 3); /* RESERVED */ 998e5b75505Sopenharmony_ci 999e5b75505Sopenharmony_ci /* msg | Ni | prf(SK_pr,IDr') */ 1000e5b75505Sopenharmony_ci if (ikev2_derive_auth_data(data->proposal.prf, data->r_sign_msg, 1001e5b75505Sopenharmony_ci data->IDr, data->IDr_len, ID_KEY_ID, 1002e5b75505Sopenharmony_ci &data->keys, 0, data->shared_secret, 1003e5b75505Sopenharmony_ci data->shared_secret_len, 1004e5b75505Sopenharmony_ci data->i_nonce, data->i_nonce_len, 1005e5b75505Sopenharmony_ci data->key_pad, data->key_pad_len, 1006e5b75505Sopenharmony_ci wpabuf_put(msg, prf->hash_len)) < 0) { 1007e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "IKEV2: Could not derive AUTH data"); 1008e5b75505Sopenharmony_ci return -1; 1009e5b75505Sopenharmony_ci } 1010e5b75505Sopenharmony_ci wpabuf_free(data->r_sign_msg); 1011e5b75505Sopenharmony_ci data->r_sign_msg = NULL; 1012e5b75505Sopenharmony_ci 1013e5b75505Sopenharmony_ci plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr; 1014e5b75505Sopenharmony_ci WPA_PUT_BE16(phdr->payload_length, plen); 1015e5b75505Sopenharmony_ci return 0; 1016e5b75505Sopenharmony_ci} 1017e5b75505Sopenharmony_ci 1018e5b75505Sopenharmony_ci 1019e5b75505Sopenharmony_cistatic int ikev2_build_notification(struct ikev2_responder_data *data, 1020e5b75505Sopenharmony_ci struct wpabuf *msg, u8 next_payload) 1021e5b75505Sopenharmony_ci{ 1022e5b75505Sopenharmony_ci struct ikev2_payload_hdr *phdr; 1023e5b75505Sopenharmony_ci size_t plen; 1024e5b75505Sopenharmony_ci 1025e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "IKEV2: Adding Notification payload"); 1026e5b75505Sopenharmony_ci 1027e5b75505Sopenharmony_ci if (data->error_type == 0) { 1028e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "IKEV2: No Notify Message Type " 1029e5b75505Sopenharmony_ci "available"); 1030e5b75505Sopenharmony_ci return -1; 1031e5b75505Sopenharmony_ci } 1032e5b75505Sopenharmony_ci 1033e5b75505Sopenharmony_ci /* Notify - RFC 4306, Sect. 3.10 */ 1034e5b75505Sopenharmony_ci phdr = wpabuf_put(msg, sizeof(*phdr)); 1035e5b75505Sopenharmony_ci phdr->next_payload = next_payload; 1036e5b75505Sopenharmony_ci phdr->flags = 0; 1037e5b75505Sopenharmony_ci wpabuf_put_u8(msg, 0); /* Protocol ID: no existing SA */ 1038e5b75505Sopenharmony_ci wpabuf_put_u8(msg, 0); /* SPI Size */ 1039e5b75505Sopenharmony_ci wpabuf_put_be16(msg, data->error_type); 1040e5b75505Sopenharmony_ci 1041e5b75505Sopenharmony_ci switch (data->error_type) { 1042e5b75505Sopenharmony_ci case INVALID_KE_PAYLOAD: 1043e5b75505Sopenharmony_ci if (data->proposal.dh == -1) { 1044e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "IKEV2: No DH Group selected for " 1045e5b75505Sopenharmony_ci "INVALID_KE_PAYLOAD notifications"); 1046e5b75505Sopenharmony_ci return -1; 1047e5b75505Sopenharmony_ci } 1048e5b75505Sopenharmony_ci wpabuf_put_be16(msg, data->proposal.dh); 1049e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "IKEV2: INVALID_KE_PAYLOAD - request " 1050e5b75505Sopenharmony_ci "DH Group #%d", data->proposal.dh); 1051e5b75505Sopenharmony_ci break; 1052e5b75505Sopenharmony_ci case AUTHENTICATION_FAILED: 1053e5b75505Sopenharmony_ci /* no associated data */ 1054e5b75505Sopenharmony_ci break; 1055e5b75505Sopenharmony_ci default: 1056e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "IKEV2: Unsupported Notify Message Type " 1057e5b75505Sopenharmony_ci "%d", data->error_type); 1058e5b75505Sopenharmony_ci return -1; 1059e5b75505Sopenharmony_ci } 1060e5b75505Sopenharmony_ci 1061e5b75505Sopenharmony_ci plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr; 1062e5b75505Sopenharmony_ci WPA_PUT_BE16(phdr->payload_length, plen); 1063e5b75505Sopenharmony_ci return 0; 1064e5b75505Sopenharmony_ci} 1065e5b75505Sopenharmony_ci 1066e5b75505Sopenharmony_ci 1067e5b75505Sopenharmony_cistatic struct wpabuf * ikev2_build_sa_init(struct ikev2_responder_data *data) 1068e5b75505Sopenharmony_ci{ 1069e5b75505Sopenharmony_ci struct wpabuf *msg; 1070e5b75505Sopenharmony_ci 1071e5b75505Sopenharmony_ci /* build IKE_SA_INIT: HDR, SAr1, KEr, Nr, [CERTREQ], [SK{IDr}] */ 1072e5b75505Sopenharmony_ci 1073e5b75505Sopenharmony_ci if (os_get_random(data->r_spi, IKEV2_SPI_LEN)) 1074e5b75505Sopenharmony_ci return NULL; 1075e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "IKEV2: IKE_SA Responder's SPI", 1076e5b75505Sopenharmony_ci data->r_spi, IKEV2_SPI_LEN); 1077e5b75505Sopenharmony_ci 1078e5b75505Sopenharmony_ci data->r_nonce_len = IKEV2_NONCE_MIN_LEN; 1079e5b75505Sopenharmony_ci if (random_get_bytes(data->r_nonce, data->r_nonce_len)) 1080e5b75505Sopenharmony_ci return NULL; 1081e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "IKEV2: Nr", data->r_nonce, data->r_nonce_len); 1082e5b75505Sopenharmony_ci 1083e5b75505Sopenharmony_ci msg = wpabuf_alloc(sizeof(struct ikev2_hdr) + data->IDr_len + 1500); 1084e5b75505Sopenharmony_ci if (msg == NULL) 1085e5b75505Sopenharmony_ci return NULL; 1086e5b75505Sopenharmony_ci 1087e5b75505Sopenharmony_ci ikev2_build_hdr(data, msg, IKE_SA_INIT, IKEV2_PAYLOAD_SA, 0); 1088e5b75505Sopenharmony_ci if (ikev2_build_sar1(data, msg, IKEV2_PAYLOAD_KEY_EXCHANGE) || 1089e5b75505Sopenharmony_ci ikev2_build_ker(data, msg, IKEV2_PAYLOAD_NONCE) || 1090e5b75505Sopenharmony_ci ikev2_build_nr(data, msg, data->peer_auth == PEER_AUTH_SECRET ? 1091e5b75505Sopenharmony_ci IKEV2_PAYLOAD_ENCRYPTED : 1092e5b75505Sopenharmony_ci IKEV2_PAYLOAD_NO_NEXT_PAYLOAD)) { 1093e5b75505Sopenharmony_ci wpabuf_free(msg); 1094e5b75505Sopenharmony_ci return NULL; 1095e5b75505Sopenharmony_ci } 1096e5b75505Sopenharmony_ci 1097e5b75505Sopenharmony_ci if (ikev2_derive_keys(data)) { 1098e5b75505Sopenharmony_ci wpabuf_free(msg); 1099e5b75505Sopenharmony_ci return NULL; 1100e5b75505Sopenharmony_ci } 1101e5b75505Sopenharmony_ci 1102e5b75505Sopenharmony_ci if (data->peer_auth == PEER_AUTH_CERT) { 1103e5b75505Sopenharmony_ci /* TODO: CERTREQ with SHA-1 hashes of Subject Public Key Info 1104e5b75505Sopenharmony_ci * for trust agents */ 1105e5b75505Sopenharmony_ci } 1106e5b75505Sopenharmony_ci 1107e5b75505Sopenharmony_ci if (data->peer_auth == PEER_AUTH_SECRET) { 1108e5b75505Sopenharmony_ci struct wpabuf *plain = wpabuf_alloc(data->IDr_len + 1000); 1109e5b75505Sopenharmony_ci if (plain == NULL) { 1110e5b75505Sopenharmony_ci wpabuf_free(msg); 1111e5b75505Sopenharmony_ci return NULL; 1112e5b75505Sopenharmony_ci } 1113e5b75505Sopenharmony_ci if (ikev2_build_idr(data, plain, 1114e5b75505Sopenharmony_ci IKEV2_PAYLOAD_NO_NEXT_PAYLOAD) || 1115e5b75505Sopenharmony_ci ikev2_build_encrypted(data->proposal.encr, 1116e5b75505Sopenharmony_ci data->proposal.integ, 1117e5b75505Sopenharmony_ci &data->keys, 0, msg, plain, 1118e5b75505Sopenharmony_ci IKEV2_PAYLOAD_IDr)) { 1119e5b75505Sopenharmony_ci wpabuf_free(plain); 1120e5b75505Sopenharmony_ci wpabuf_free(msg); 1121e5b75505Sopenharmony_ci return NULL; 1122e5b75505Sopenharmony_ci } 1123e5b75505Sopenharmony_ci wpabuf_free(plain); 1124e5b75505Sopenharmony_ci } 1125e5b75505Sopenharmony_ci 1126e5b75505Sopenharmony_ci ikev2_update_hdr(msg); 1127e5b75505Sopenharmony_ci 1128e5b75505Sopenharmony_ci wpa_hexdump_buf(MSG_MSGDUMP, "IKEV2: Sending message (SA_INIT)", msg); 1129e5b75505Sopenharmony_ci 1130e5b75505Sopenharmony_ci data->state = SA_AUTH; 1131e5b75505Sopenharmony_ci 1132e5b75505Sopenharmony_ci wpabuf_free(data->r_sign_msg); 1133e5b75505Sopenharmony_ci data->r_sign_msg = wpabuf_dup(msg); 1134e5b75505Sopenharmony_ci 1135e5b75505Sopenharmony_ci return msg; 1136e5b75505Sopenharmony_ci} 1137e5b75505Sopenharmony_ci 1138e5b75505Sopenharmony_ci 1139e5b75505Sopenharmony_cistatic struct wpabuf * ikev2_build_sa_auth(struct ikev2_responder_data *data) 1140e5b75505Sopenharmony_ci{ 1141e5b75505Sopenharmony_ci struct wpabuf *msg, *plain; 1142e5b75505Sopenharmony_ci 1143e5b75505Sopenharmony_ci /* build IKE_SA_AUTH: HDR, SK {IDr, [CERT,] AUTH} */ 1144e5b75505Sopenharmony_ci 1145e5b75505Sopenharmony_ci msg = wpabuf_alloc(sizeof(struct ikev2_hdr) + data->IDr_len + 1000); 1146e5b75505Sopenharmony_ci if (msg == NULL) 1147e5b75505Sopenharmony_ci return NULL; 1148e5b75505Sopenharmony_ci ikev2_build_hdr(data, msg, IKE_SA_AUTH, IKEV2_PAYLOAD_ENCRYPTED, 1); 1149e5b75505Sopenharmony_ci 1150e5b75505Sopenharmony_ci plain = wpabuf_alloc(data->IDr_len + 1000); 1151e5b75505Sopenharmony_ci if (plain == NULL) { 1152e5b75505Sopenharmony_ci wpabuf_free(msg); 1153e5b75505Sopenharmony_ci return NULL; 1154e5b75505Sopenharmony_ci } 1155e5b75505Sopenharmony_ci 1156e5b75505Sopenharmony_ci if (ikev2_build_idr(data, plain, IKEV2_PAYLOAD_AUTHENTICATION) || 1157e5b75505Sopenharmony_ci ikev2_build_auth(data, plain, IKEV2_PAYLOAD_NO_NEXT_PAYLOAD) || 1158e5b75505Sopenharmony_ci ikev2_build_encrypted(data->proposal.encr, data->proposal.integ, 1159e5b75505Sopenharmony_ci &data->keys, 0, msg, plain, 1160e5b75505Sopenharmony_ci IKEV2_PAYLOAD_IDr)) { 1161e5b75505Sopenharmony_ci wpabuf_free(plain); 1162e5b75505Sopenharmony_ci wpabuf_free(msg); 1163e5b75505Sopenharmony_ci return NULL; 1164e5b75505Sopenharmony_ci } 1165e5b75505Sopenharmony_ci wpabuf_free(plain); 1166e5b75505Sopenharmony_ci 1167e5b75505Sopenharmony_ci wpa_hexdump_buf(MSG_MSGDUMP, "IKEV2: Sending message (SA_AUTH)", msg); 1168e5b75505Sopenharmony_ci 1169e5b75505Sopenharmony_ci data->state = IKEV2_DONE; 1170e5b75505Sopenharmony_ci 1171e5b75505Sopenharmony_ci return msg; 1172e5b75505Sopenharmony_ci} 1173e5b75505Sopenharmony_ci 1174e5b75505Sopenharmony_ci 1175e5b75505Sopenharmony_cistatic struct wpabuf * ikev2_build_notify(struct ikev2_responder_data *data) 1176e5b75505Sopenharmony_ci{ 1177e5b75505Sopenharmony_ci struct wpabuf *msg; 1178e5b75505Sopenharmony_ci 1179e5b75505Sopenharmony_ci msg = wpabuf_alloc(sizeof(struct ikev2_hdr) + 1000); 1180e5b75505Sopenharmony_ci if (msg == NULL) 1181e5b75505Sopenharmony_ci return NULL; 1182e5b75505Sopenharmony_ci if (data->last_msg == LAST_MSG_SA_AUTH) { 1183e5b75505Sopenharmony_ci /* HDR, SK{N} */ 1184e5b75505Sopenharmony_ci struct wpabuf *plain = wpabuf_alloc(100); 1185e5b75505Sopenharmony_ci if (plain == NULL) { 1186e5b75505Sopenharmony_ci wpabuf_free(msg); 1187e5b75505Sopenharmony_ci return NULL; 1188e5b75505Sopenharmony_ci } 1189e5b75505Sopenharmony_ci ikev2_build_hdr(data, msg, IKE_SA_AUTH, 1190e5b75505Sopenharmony_ci IKEV2_PAYLOAD_ENCRYPTED, 1); 1191e5b75505Sopenharmony_ci if (ikev2_build_notification(data, plain, 1192e5b75505Sopenharmony_ci IKEV2_PAYLOAD_NO_NEXT_PAYLOAD) || 1193e5b75505Sopenharmony_ci ikev2_build_encrypted(data->proposal.encr, 1194e5b75505Sopenharmony_ci data->proposal.integ, 1195e5b75505Sopenharmony_ci &data->keys, 0, msg, plain, 1196e5b75505Sopenharmony_ci IKEV2_PAYLOAD_NOTIFICATION)) { 1197e5b75505Sopenharmony_ci wpabuf_free(plain); 1198e5b75505Sopenharmony_ci wpabuf_free(msg); 1199e5b75505Sopenharmony_ci return NULL; 1200e5b75505Sopenharmony_ci } 1201e5b75505Sopenharmony_ci wpabuf_free(plain); 1202e5b75505Sopenharmony_ci data->state = IKEV2_FAILED; 1203e5b75505Sopenharmony_ci } else { 1204e5b75505Sopenharmony_ci /* HDR, N */ 1205e5b75505Sopenharmony_ci ikev2_build_hdr(data, msg, IKE_SA_INIT, 1206e5b75505Sopenharmony_ci IKEV2_PAYLOAD_NOTIFICATION, 0); 1207e5b75505Sopenharmony_ci if (ikev2_build_notification(data, msg, 1208e5b75505Sopenharmony_ci IKEV2_PAYLOAD_NO_NEXT_PAYLOAD)) { 1209e5b75505Sopenharmony_ci wpabuf_free(msg); 1210e5b75505Sopenharmony_ci return NULL; 1211e5b75505Sopenharmony_ci } 1212e5b75505Sopenharmony_ci data->state = SA_INIT; 1213e5b75505Sopenharmony_ci } 1214e5b75505Sopenharmony_ci 1215e5b75505Sopenharmony_ci ikev2_update_hdr(msg); 1216e5b75505Sopenharmony_ci 1217e5b75505Sopenharmony_ci wpa_hexdump_buf(MSG_MSGDUMP, "IKEV2: Sending message (Notification)", 1218e5b75505Sopenharmony_ci msg); 1219e5b75505Sopenharmony_ci 1220e5b75505Sopenharmony_ci return msg; 1221e5b75505Sopenharmony_ci} 1222e5b75505Sopenharmony_ci 1223e5b75505Sopenharmony_ci 1224e5b75505Sopenharmony_cistruct wpabuf * ikev2_responder_build(struct ikev2_responder_data *data) 1225e5b75505Sopenharmony_ci{ 1226e5b75505Sopenharmony_ci switch (data->state) { 1227e5b75505Sopenharmony_ci case SA_INIT: 1228e5b75505Sopenharmony_ci return ikev2_build_sa_init(data); 1229e5b75505Sopenharmony_ci case SA_AUTH: 1230e5b75505Sopenharmony_ci return ikev2_build_sa_auth(data); 1231e5b75505Sopenharmony_ci case CHILD_SA: 1232e5b75505Sopenharmony_ci return NULL; 1233e5b75505Sopenharmony_ci case NOTIFY: 1234e5b75505Sopenharmony_ci return ikev2_build_notify(data); 1235e5b75505Sopenharmony_ci case IKEV2_DONE: 1236e5b75505Sopenharmony_ci case IKEV2_FAILED: 1237e5b75505Sopenharmony_ci return NULL; 1238e5b75505Sopenharmony_ci } 1239e5b75505Sopenharmony_ci return NULL; 1240e5b75505Sopenharmony_ci} 1241