📄 ikev2.c
字号:
return 0;}static int ikev2_process_auth_secret(struct ikev2_initiator_data *data, u8 method, const u8 *auth, size_t auth_len){ u8 auth_data[IKEV2_MAX_HASH_LEN]; const struct ikev2_prf_alg *prf; if (method != AUTH_SHARED_KEY_MIC) { wpa_printf(MSG_INFO, "IKEV2: Unsupported authentication " "method %d", method); return -1; } /* msg | Ni | prf(SK_pr,IDr') */ if (ikev2_derive_auth_data(data->proposal.prf, data->r_sign_msg, data->IDr, data->IDr_len, data->IDr_type, &data->keys, 0, data->shared_secret, data->shared_secret_len, data->i_nonce, data->i_nonce_len, data->key_pad, data->key_pad_len, auth_data) < 0) { wpa_printf(MSG_INFO, "IKEV2: Could not derive AUTH data"); return -1; } wpabuf_free(data->r_sign_msg); data->r_sign_msg = NULL; prf = ikev2_get_prf(data->proposal.prf); if (prf == NULL) return -1; if (auth_len != prf->hash_len || os_memcmp(auth, auth_data, auth_len) != 0) { wpa_printf(MSG_INFO, "IKEV2: Invalid Authentication Data"); wpa_hexdump(MSG_DEBUG, "IKEV2: Received Authentication Data", auth, auth_len); wpa_hexdump(MSG_DEBUG, "IKEV2: Expected Authentication Data", auth_data, prf->hash_len); return -1; } wpa_printf(MSG_DEBUG, "IKEV2: Peer authenticated successfully " "using shared keys"); return 0;}static int ikev2_process_auth(struct ikev2_initiator_data *data, const u8 *auth, size_t auth_len){ u8 auth_method; if (auth == NULL) { wpa_printf(MSG_INFO, "IKEV2: No Authentication Payload"); return -1; } if (auth_len < 4) { wpa_printf(MSG_INFO, "IKEV2: Too short Authentication " "Payload"); return -1; } auth_method = auth[0]; auth += 4; auth_len -= 4; wpa_printf(MSG_DEBUG, "IKEV2: Auth Method %d", auth_method); wpa_hexdump(MSG_MSGDUMP, "IKEV2: Authentication Data", auth, auth_len); switch (data->peer_auth) { case PEER_AUTH_CERT: return ikev2_process_auth_cert(data, auth_method, auth, auth_len); case PEER_AUTH_SECRET: return ikev2_process_auth_secret(data, auth_method, auth, auth_len); } return -1;}static int ikev2_process_sa_auth_decrypted(struct ikev2_initiator_data *data, u8 next_payload, u8 *payload, size_t payload_len){ struct ikev2_payloads pl; wpa_printf(MSG_DEBUG, "IKEV2: Processing decrypted payloads"); if (ikev2_parse_payloads(&pl, next_payload, payload, payload + payload_len) < 0) { wpa_printf(MSG_INFO, "IKEV2: Failed to parse decrypted " "payloads"); return -1; } if (ikev2_process_idr(data, pl.idr, pl.idr_len) < 0 || ikev2_process_cert(data, pl.cert, pl.cert_len) < 0 || ikev2_process_auth(data, pl.auth, pl.auth_len) < 0) return -1; return 0;}static int ikev2_process_sa_auth(struct ikev2_initiator_data *data, const struct ikev2_hdr *hdr, struct ikev2_payloads *pl){ u8 *decrypted; size_t decrypted_len; int ret; decrypted = ikev2_decrypt_payload(data->proposal.encr, data->proposal.integ, &data->keys, 0, hdr, pl->encrypted, pl->encrypted_len, &decrypted_len); if (decrypted == NULL) return -1; ret = ikev2_process_sa_auth_decrypted(data, pl->encr_next_payload, decrypted, decrypted_len); os_free(decrypted); if (ret == 0 && !data->unknown_user) { wpa_printf(MSG_DEBUG, "IKEV2: Authentication completed"); data->state = IKEV2_DONE; } return ret;}static int ikev2_validate_rx_state(struct ikev2_initiator_data *data, u8 exchange_type, u32 message_id){ switch (data->state) { case SA_INIT: /* Expect to receive IKE_SA_INIT: HDR, SAr, KEr, Nr, [CERTREQ], * [SK{IDr}] */ if (exchange_type != IKE_SA_INIT) { wpa_printf(MSG_INFO, "IKEV2: Unexpected Exchange Type " "%u in SA_INIT state", exchange_type); return -1; } if (message_id != 0) { wpa_printf(MSG_INFO, "IKEV2: Unexpected Message ID %u " "in SA_INIT state", message_id); return -1; } break; case SA_AUTH: /* Expect to receive IKE_SA_AUTH: * HDR, SK {IDr, [CERT,] [CERTREQ,] [NFID,] AUTH} */ if (exchange_type != IKE_SA_AUTH) { wpa_printf(MSG_INFO, "IKEV2: Unexpected Exchange Type " "%u in SA_AUTH state", exchange_type); return -1; } if (message_id != 1) { wpa_printf(MSG_INFO, "IKEV2: Unexpected Message ID %u " "in SA_AUTH state", message_id); return -1; } break; case CHILD_SA: if (exchange_type != CREATE_CHILD_SA) { wpa_printf(MSG_INFO, "IKEV2: Unexpected Exchange Type " "%u in CHILD_SA state", exchange_type); return -1; } if (message_id != 2) { wpa_printf(MSG_INFO, "IKEV2: Unexpected Message ID %u " "in CHILD_SA state", message_id); return -1; } break; case IKEV2_DONE: return -1; } return 0;}int ikev2_initiator_process(struct ikev2_initiator_data *data, const struct wpabuf *buf){ const struct ikev2_hdr *hdr; u32 length, message_id; const u8 *pos, *end; struct ikev2_payloads pl; wpa_printf(MSG_MSGDUMP, "IKEV2: Received message (len %lu)", (unsigned long) wpabuf_len(buf)); if (wpabuf_len(buf) < sizeof(*hdr)) { wpa_printf(MSG_INFO, "IKEV2: Too short frame to include HDR"); return -1; } hdr = (const struct ikev2_hdr *) wpabuf_head(buf); end = wpabuf_head_u8(buf) + wpabuf_len(buf); message_id = WPA_GET_BE32(hdr->message_id); length = WPA_GET_BE32(hdr->length); wpa_hexdump(MSG_DEBUG, "IKEV2: IKE_SA Initiator's SPI", hdr->i_spi, IKEV2_SPI_LEN); wpa_hexdump(MSG_DEBUG, "IKEV2: IKE_SA Initiator's SPI", hdr->r_spi, IKEV2_SPI_LEN); wpa_printf(MSG_DEBUG, "IKEV2: Next Payload: %u Version: 0x%x " "Exchange Type: %u", hdr->next_payload, hdr->version, hdr->exchange_type); wpa_printf(MSG_DEBUG, "IKEV2: Message ID: %u Length: %u", message_id, length); if (hdr->version != IKEV2_VERSION) { wpa_printf(MSG_INFO, "IKEV2: Unsupported HDR version 0x%x " "(expected 0x%x)", hdr->version, IKEV2_VERSION); return -1; } if (length != wpabuf_len(buf)) { wpa_printf(MSG_INFO, "IKEV2: Invalid length (HDR: %lu != " "RX: %lu)", (unsigned long) length, (unsigned long) wpabuf_len(buf)); return -1; } if (ikev2_validate_rx_state(data, hdr->exchange_type, message_id) < 0) return -1; if ((hdr->flags & (IKEV2_HDR_INITIATOR | IKEV2_HDR_RESPONSE)) != IKEV2_HDR_RESPONSE) { wpa_printf(MSG_INFO, "IKEV2: Unexpected Flags value 0x%x", hdr->flags); return -1; } if (data->state != SA_INIT) { if (os_memcmp(data->i_spi, hdr->i_spi, IKEV2_SPI_LEN) != 0) { wpa_printf(MSG_INFO, "IKEV2: Unexpected IKE_SA " "Initiator's SPI"); return -1; } if (os_memcmp(data->r_spi, hdr->r_spi, IKEV2_SPI_LEN) != 0) { wpa_printf(MSG_INFO, "IKEV2: Unexpected IKE_SA " "Responder's SPI"); return -1; } } pos = (const u8 *) (hdr + 1); if (ikev2_parse_payloads(&pl, hdr->next_payload, pos, end) < 0) return -1; switch (data->state) { case SA_INIT: if (ikev2_process_sa_init(data, hdr, &pl) < 0) return -1; wpabuf_free(data->r_sign_msg); data->r_sign_msg = wpabuf_dup(buf); break; case SA_AUTH: if (ikev2_process_sa_auth(data, hdr, &pl) < 0) return -1; break; case CHILD_SA: case IKEV2_DONE: break; } return 0;}static void ikev2_build_hdr(struct ikev2_initiator_data *data, struct wpabuf *msg, u8 exchange_type, u8 next_payload, u32 message_id){ struct ikev2_hdr *hdr; wpa_printf(MSG_DEBUG, "IKEV2: Adding HDR"); /* HDR - RFC 4306, Sect. 3.1 */ hdr = wpabuf_put(msg, sizeof(*hdr)); os_memcpy(hdr->i_spi, data->i_spi, IKEV2_SPI_LEN); os_memcpy(hdr->r_spi, data->r_spi, IKEV2_SPI_LEN); hdr->next_payload = next_payload; hdr->version = IKEV2_VERSION; hdr->exchange_type = exchange_type; hdr->flags = IKEV2_HDR_INITIATOR; WPA_PUT_BE32(hdr->message_id, message_id);}static int ikev2_build_sai(struct ikev2_initiator_data *data, struct wpabuf *msg, u8 next_payload){ struct ikev2_payload_hdr *phdr; size_t plen; struct ikev2_proposal *p; struct ikev2_transform *t; wpa_printf(MSG_DEBUG, "IKEV2: Adding SAi payload"); /* SAi1 - RFC 4306, Sect. 2.7 and 3.3 */ phdr = wpabuf_put(msg, sizeof(*phdr)); phdr->next_payload = next_payload; phdr->flags = 0; /* TODO: support for multiple proposals */ p = wpabuf_put(msg, sizeof(*p)); p->proposal_num = data->proposal.proposal_num; p->protocol_id = IKEV2_PROTOCOL_IKE; p->num_transforms = 4; t = wpabuf_put(msg, sizeof(*t)); t->type = 3; t->transform_type = IKEV2_TRANSFORM_ENCR; WPA_PUT_BE16(t->transform_id, data->proposal.encr); if (data->proposal.encr == ENCR_AES_CBC) { /* Transform Attribute: Key Len = 128 bits */ wpabuf_put_be16(msg, 0x800e); /* AF=1, AttrType=14 */ wpabuf_put_be16(msg, 128); /* 128-bit key */ } plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) t; WPA_PUT_BE16(t->transform_length, plen); t = wpabuf_put(msg, sizeof(*t)); t->type = 3; WPA_PUT_BE16(t->transform_length, sizeof(*t)); t->transform_type = IKEV2_TRANSFORM_PRF; WPA_PUT_BE16(t->transform_id, data->proposal.prf); t = wpabuf_put(msg, sizeof(*t)); t->type = 3; WPA_PUT_BE16(t->transform_length, sizeof(*t)); t->transform_type = IKEV2_TRANSFORM_INTEG; WPA_PUT_BE16(t->transform_id, data->proposal.integ); t = wpabuf_put(msg, sizeof(*t)); WPA_PUT_BE16(t->transform_length, sizeof(*t)); t->transform_type = IKEV2_TRANSFORM_DH; WPA_PUT_BE16(t->transform_id, data->proposal.dh); plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) p; WPA_PUT_BE16(p->proposal_length, plen); plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr; WPA_PUT_BE16(phdr->payload_length, plen); return 0;}static int ikev2_build_kei(struct ikev2_initiator_data *data, struct wpabuf *msg, u8 next_payload){ struct ikev2_payload_hdr *phdr; size_t plen; struct wpabuf *pv; wpa_printf(MSG_DEBUG, "IKEV2: Adding KEi payload"); data->dh = dh_groups_get(data->proposal.dh); pv = dh_init(data->dh, &data->i_dh_private); if (pv == NULL) { wpa_printf(MSG_DEBUG, "IKEV2: Failed to initialize DH"); return -1; } /* KEi - RFC 4306, Sect. 3.4 */ phdr = wpabuf_put(msg, sizeof(*phdr)); phdr->next_payload = next_payload; phdr->flags = 0; wpabuf_put_be16(msg, data->proposal.dh); /* DH Group # */ wpabuf_put(msg, 2); /* RESERVED */ /* * RFC 4306, Sect. 3.4: possible zero padding for public value to * match the length of the prime. */ wpabuf_put(msg, data->dh->prime_len - wpabuf_len(pv)); wpabuf_put_buf(msg, pv); os_free(pv); plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr; WPA_PUT_BE16(phdr->payload_length, plen); return 0;}static int ikev2_build_ni(struct ikev2_initiator_data *data, struct wpabuf *msg, u8 next_payload){ struct ikev2_payload_hdr *phdr; size_t plen; wpa_printf(MSG_DEBUG, "IKEV2: Adding Ni payload"); /* Ni - RFC 4306, Sect. 3.9 */ phdr = wpabuf_put(msg, sizeof(*phdr)); phdr->next_payload = next_payload; phdr->flags = 0; wpabuf_put_data(msg, data->i_nonce, data->i_nonce_len); plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr; WPA_PUT_BE16(phdr->payload_length, plen); return 0;}static int ikev2_build_idi(struct ikev2_initiator_data *data, struct wpabuf *msg, u8 next_payload){ struct ikev2_payload_hdr *phdr; size_t plen; wpa_printf(MSG_DEBUG, "IKEV2: Adding IDi payload"); if (data->IDi == NULL) { wpa_printf(MSG_INFO, "IKEV2: No IDi available"); return -1; } /* IDi - RFC 4306, Sect. 3.5 */ phdr = wpabuf_put(msg, sizeof(*phdr)); phdr->next_payload = next_payload; phdr->flags = 0; wpabuf_put_u8(msg, ID_KEY_ID); wpabuf_put(msg, 3); /* RESERVED */ wpabuf_put_data(msg, data->IDi, data->IDi_len); plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr; WPA_PUT_BE16(phdr->payload_length, plen); return 0;}static int ikev2_build_auth(struct ikev2_initiator_data *data, struct wpabuf *msg, u8 next_payload){ struct ikev2_payload_hdr *phdr; size_t plen; const struct ikev2_prf_alg *prf; wpa_printf(MSG_DEBUG, "IKEV2: Adding AUTH payload"); prf = ikev2_get_prf(data->proposal.prf); if (prf == NULL) return -1; /* Authentication - RFC 4306, Sect. 3.8 */ phdr = wpabuf_put(msg, sizeof(*phdr)); phdr->next_payload = next_payload; phdr->flags = 0; wpabuf_put_u8(msg, AUTH_SHARED_KEY_MIC); wpabuf_put(msg, 3); /* RESERVED */ /* msg | Nr | prf(SK_pi,IDi') */ if (ikev2_derive_auth_data(data->proposal.prf, data->i_sign_msg, data->IDi, data->IDi_len, ID_KEY_ID, &data->keys, 1, data->shared_secret, data->shared_secret_len, data->r_nonce, data->r_nonce_len, data->key_pad, data->key_pad_len, wpabuf_put(msg, prf->hash_len)) < 0) { wpa_printf(MSG_INFO, "IKEV2: Could not derive AUTH data"); return -1; } wpabuf_free(data->i_sign_msg); data->i_sign_msg = NULL; plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr; WPA_PUT_BE16(phdr->payload_length, plen); return 0;}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_auth(struct ikev2_initiator_data *data){ struct wpabuf *msg, *plain; const u8 *secret; size_t secret_len; secret = data->get_shared_secret(data->cb_ctx, data->IDr, data->IDr_len, &secret_len); if (secret == NULL) { wpa_printf(MSG_INFO, "IKEV2: Could not get shared secret - " "use fake value"); /* RFC 5106, Sect. 7: * Use a random key to fake AUTH generation in order to prevent * probing of user identities. */ data->unknown_user = 1; os_free(data->shared_secret); data->shared_secret = os_malloc(16); if (data->shared_secret == NULL) return NULL; data->shared_secret_len = 16; if (os_get_random(data->shared_secret, 16)) return NULL; } else { os_free(data->shared_secret); data->shared_secret = os_malloc(secret_len); if (data->shared_secret == NULL) return NULL; os_memcpy(data->shared_secret, secret, secret_len); data->shared_secret_len = secret_len; } /* build IKE_SA_AUTH: HDR, SK {IDi, [CERT,] [CERTREQ,] AUTH} */ msg = wpabuf_alloc(sizeof(struct ikev2_hdr) + data->IDr_len + 1000); if (msg == NULL) return NULL; ikev2_build_hdr(data, msg, IKE_SA_AUTH, IKEV2_PAYLOAD_ENCRYPTED, 1); plain = wpabuf_alloc(data->IDr_len + 1000); if (plain == NULL) { wpabuf_free(msg); return NULL; } if (ikev2_build_idi(data, plain, IKEV2_PAYLOAD_AUTHENTICATION) || ikev2_build_auth(data, plain, IKEV2_PAYLOAD_NO_NEXT_PAYLOAD) || ikev2_build_encrypted(data->proposal.encr, data->proposal.integ, &data->keys, 1, msg, plain, IKEV2_PAYLOAD_IDi)) { wpabuf_free(plain); wpabuf_free(msg); return NULL; } wpabuf_free(plain); wpa_hexdump_buf(MSG_MSGDUMP, "IKEV2: Sending message (SA_AUTH)", msg); return msg;}struct wpabuf * ikev2_initiator_build(struct ikev2_initiator_data *data){ switch (data->state) { case SA_INIT: return ikev2_build_sa_init(data); case SA_AUTH: return ikev2_build_sa_auth(data); case CHILD_SA: return NULL; case IKEV2_DONE: return NULL; } return NULL;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -