static struct wpabuf * ikev2_build_notify(struct ikev2_responder_data *data) { struct wpabuf *msg; msg = wpabuf_alloc(sizeof(struct ikev2_hdr) + 1000); if (msg == NULL) return NULL; if (data->last_msg == LAST_MSG_SA_AUTH) { /* HDR, SK{N} */ struct wpabuf *plain = wpabuf_alloc(100); if (plain == NULL) { wpabuf_free(msg); return NULL; } ikev2_build_hdr(data, msg, IKE_SA_AUTH, IKEV2_PAYLOAD_ENCRYPTED, 1); if (ikev2_build_notification(data, plain, IKEV2_PAYLOAD_NO_NEXT_PAYLOAD) || ikev2_build_encrypted(data->proposal.encr, data->proposal.integ, &data->keys, 0, msg, plain, IKEV2_PAYLOAD_NOTIFICATION)) { wpabuf_free(plain); wpabuf_free(msg); return NULL; } wpabuf_free(plain); data->state = IKEV2_FAILED; } else { /* HDR, N */ ikev2_build_hdr(data, msg, IKE_SA_INIT, IKEV2_PAYLOAD_NOTIFICATION, 0); if (ikev2_build_notification(data, msg, IKEV2_PAYLOAD_NO_NEXT_PAYLOAD)) { wpabuf_free(msg); return NULL; } data->state = SA_INIT; } ikev2_update_hdr(msg); wpa_hexdump_buf(MSG_MSGDUMP, "IKEV2: Sending message (Notification)", msg); return msg; }
static struct wpabuf * ikev2_build_sa_init(struct ikev2_initiator_data *data) { struct wpabuf *msg; /* build IKE_SA_INIT: HDR, SAi, KEi, Ni */ if (os_get_random(data->i_spi, IKEV2_SPI_LEN)) return NULL; wpa_hexdump(MSG_DEBUG, "IKEV2: IKE_SA Initiator's SPI", data->i_spi, IKEV2_SPI_LEN); data->i_nonce_len = IKEV2_NONCE_MIN_LEN; if (os_get_random(data->i_nonce, data->i_nonce_len)) return NULL; wpa_hexdump(MSG_DEBUG, "IKEV2: Ni", data->i_nonce, data->i_nonce_len); msg = wpabuf_alloc(sizeof(struct ikev2_hdr) + 1000); if (msg == NULL) return NULL; ikev2_build_hdr(data, msg, IKE_SA_INIT, IKEV2_PAYLOAD_SA, 0); if (ikev2_build_sai(data, msg, IKEV2_PAYLOAD_KEY_EXCHANGE) || ikev2_build_kei(data, msg, IKEV2_PAYLOAD_NONCE) || ikev2_build_ni(data, msg, IKEV2_PAYLOAD_NO_NEXT_PAYLOAD)) { wpabuf_free(msg); return NULL; } ikev2_update_hdr(msg); wpa_hexdump_buf(MSG_MSGDUMP, "IKEV2: Sending message (SA_INIT)", msg); wpabuf_free(data->i_sign_msg); data->i_sign_msg = wpabuf_dup(msg); return msg; }
static struct wpabuf * ikev2_build_sa_init(struct ikev2_responder_data *data) { struct wpabuf *msg; /* build IKE_SA_INIT: HDR, SAr1, KEr, Nr, [CERTREQ], [SK{IDr}] */ if (os_get_random(data->r_spi, IKEV2_SPI_LEN)) return NULL; wpa_hexdump(MSG_DEBUG, "IKEV2: IKE_SA Responder's SPI", data->r_spi, IKEV2_SPI_LEN); data->r_nonce_len = IKEV2_NONCE_MIN_LEN; if (random_get_bytes(data->r_nonce, data->r_nonce_len)) return NULL; #ifdef CCNS_PL /* Zeros are removed incorrectly from the beginning of the nonces in * key derivation; as a workaround, make sure Nr does not start with * zero.. */ if (data->r_nonce[0] == 0) data->r_nonce[0] = 1; #endif /* CCNS_PL */ wpa_hexdump(MSG_DEBUG, "IKEV2: Nr", data->r_nonce, data->r_nonce_len); msg = wpabuf_alloc(sizeof(struct ikev2_hdr) + data->IDr_len + 1500); if (msg == NULL) return NULL; ikev2_build_hdr(data, msg, IKE_SA_INIT, IKEV2_PAYLOAD_SA, 0); if (ikev2_build_sar1(data, msg, IKEV2_PAYLOAD_KEY_EXCHANGE) || ikev2_build_ker(data, msg, IKEV2_PAYLOAD_NONCE) || ikev2_build_nr(data, msg, data->peer_auth == PEER_AUTH_SECRET ? IKEV2_PAYLOAD_ENCRYPTED : IKEV2_PAYLOAD_NO_NEXT_PAYLOAD)) { wpabuf_free(msg); return NULL; } if (ikev2_derive_keys(data)) { wpabuf_free(msg); return NULL; } if (data->peer_auth == PEER_AUTH_CERT) { /* TODO: CERTREQ with SHA-1 hashes of Subject Public Key Info * for trust agents */ } if (data->peer_auth == PEER_AUTH_SECRET) { struct wpabuf *plain = wpabuf_alloc(data->IDr_len + 1000); if (plain == NULL) { wpabuf_free(msg); return NULL; } if (ikev2_build_idr(data, plain, IKEV2_PAYLOAD_NO_NEXT_PAYLOAD) || ikev2_build_encrypted(data->proposal.encr, data->proposal.integ, &data->keys, 0, msg, plain, IKEV2_PAYLOAD_IDr)) { wpabuf_free(plain); wpabuf_free(msg); return NULL; } wpabuf_free(plain); } ikev2_update_hdr(msg); wpa_hexdump_buf(MSG_MSGDUMP, "IKEV2: Sending message (SA_INIT)", msg); data->state = SA_AUTH; wpabuf_free(data->r_sign_msg); data->r_sign_msg = wpabuf_dup(msg); return msg; }
int ikev2_build_encrypted(int encr_id, int integ_id, struct ikev2_keys *keys, int initiator, struct wpabuf *msg, struct wpabuf *plain, u8 next_payload) { struct ikev2_payload_hdr *phdr; size_t plen; size_t iv_len, pad_len; u8 *icv, *iv; const struct ikev2_integ_alg *integ_alg; const struct ikev2_encr_alg *encr_alg; const u8 *SK_e = initiator ? keys->SK_ei : keys->SK_er; const u8 *SK_a = initiator ? keys->SK_ai : keys->SK_ar; wpa_printf(MSG_DEBUG, "IKEV2: Adding Encrypted payload"); /* Encr - RFC 4306, Sect. 3.14 */ encr_alg = ikev2_get_encr(encr_id); if (encr_alg == NULL) { wpa_printf(MSG_INFO, "IKEV2: Unsupported encryption type"); return -1; } iv_len = encr_alg->block_size; integ_alg = ikev2_get_integ(integ_id); if (integ_alg == NULL) { wpa_printf(MSG_INFO, "IKEV2: Unsupported intergrity type"); return -1; } if (SK_e == NULL) { wpa_printf(MSG_INFO, "IKEV2: No SK_e available"); return -1; } if (SK_a == NULL) { wpa_printf(MSG_INFO, "IKEV2: No SK_a available"); return -1; } phdr = wpabuf_put(msg, sizeof(*phdr)); phdr->next_payload = next_payload; phdr->flags = 0; iv = wpabuf_put(msg, iv_len); if (random_get_bytes(iv, iv_len)) { wpa_printf(MSG_INFO, "IKEV2: Could not generate IV"); return -1; } pad_len = iv_len - (wpabuf_len(plain) + 1) % iv_len; if (pad_len == iv_len) pad_len = 0; wpabuf_put(plain, pad_len); wpabuf_put_u8(plain, pad_len); if (ikev2_encr_encrypt(encr_alg->id, SK_e, keys->SK_encr_len, iv, wpabuf_head(plain), wpabuf_mhead(plain), wpabuf_len(plain)) < 0) return -1; wpabuf_put_buf(msg, plain); /* Need to update all headers (Length fields) prior to hash func */ icv = wpabuf_put(msg, integ_alg->hash_len); plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr; WPA_PUT_BE16(phdr->payload_length, plen); ikev2_update_hdr(msg); return ikev2_integ_hash(integ_id, SK_a, keys->SK_integ_len, wpabuf_head(msg), wpabuf_len(msg) - integ_alg->hash_len, icv); return 0; }