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