diff options
author | Atzm Watanabe <atzmism@gmail.com> | 2022-08-18 17:57:53 +0900 |
---|---|---|
committer | Beno�t Ganne <bganne@cisco.com> | 2024-02-09 14:19:31 +0000 |
commit | d4f405a70f28f6e5399a503c91da7ae8f90f94af (patch) | |
tree | a148ea35049fc74757e2f91fc1720bed015517e1 /src/plugins | |
parent | d9b4d9fb1ff1319c5e24800780a24e15a24cbb2f (diff) |
ikev2: accept rekey request for IKE SA
RFC 7296 describes the way to rekey IKE SAs: to rekey an IKE SA,
establish a new equivalent IKE SA with the peer to whom the old
IKE SA is shared using a CREATE_CHILD_SA within the existing IKE
SA. An IKE SA so created inherits all of the original IKE SA's
Child SAs, and the new IKE SA is used for all control messages
needed to maintain those Child SAs.
Type: improvement
Signed-off-by: Atzm Watanabe <atzmism@gmail.com>
Change-Id: Icdf43b67c38bf183913a28a08a85236ba16343af
Diffstat (limited to 'src/plugins')
-rw-r--r-- | src/plugins/ikev2/ikev2.c | 234 | ||||
-rw-r--r-- | src/plugins/ikev2/ikev2_payload.c | 30 | ||||
-rw-r--r-- | src/plugins/ikev2/ikev2_priv.h | 25 |
3 files changed, 265 insertions, 24 deletions
diff --git a/src/plugins/ikev2/ikev2.c b/src/plugins/ikev2/ikev2.c index ad36068c34d..4ee2f60b085 100644 --- a/src/plugins/ikev2/ikev2.c +++ b/src/plugins/ikev2/ikev2.c @@ -211,6 +211,8 @@ ikev2_select_proposal (ikev2_sa_proposal_t * proposals, rv->proposal_num = proposal->proposal_num; rv->protocol_id = proposal->protocol_id; RAND_bytes ((u8 *) & rv->spi, sizeof (rv->spi)); + if (rv->protocol_id != IKEV2_PROTOCOL_IKE) + rv->spi &= 0xffffffff; goto done; } else @@ -480,11 +482,10 @@ ikev2_complete_sa_data (ikev2_sa_t * sa, ikev2_sa_t * sai) } static void -ikev2_calc_keys (ikev2_sa_t * sa) +ikev2_calc_keys_internal (ikev2_sa_t *sa, u8 *skeyseed) { u8 *tmp; /* calculate SKEYSEED = prf(Ni | Nr, g^ir) */ - u8 *skeyseed = 0; u8 *s = 0; u16 integ_key_len = 0, salt_len = 0; ikev2_sa_transform_t *tr_encr, *tr_prf, *tr_integ; @@ -502,7 +503,6 @@ ikev2_calc_keys (ikev2_sa_t * sa) vec_append (s, sa->i_nonce); vec_append (s, sa->r_nonce); - skeyseed = ikev2_calc_prf (tr_prf, s, sa->dh_shared_key); /* Calculate S = Ni | Nr | SPIi | SPIr */ u64 *spi; @@ -520,7 +520,6 @@ ikev2_calc_keys (ikev2_sa_t * sa) salt_len * 2; keymat = ikev2_calc_prfplus (tr_prf, skeyseed, s, len); - vec_free (skeyseed); vec_free (s); int pos = 0; @@ -568,6 +567,41 @@ ikev2_calc_keys (ikev2_sa_t * sa) } static void +ikev2_calc_keys_rekey (ikev2_sa_t *sa_new, ikev2_sa_t *sa_old) +{ + u8 *s = 0, *skeyseed = 0; + ikev2_sa_transform_t *tr_prf = + ikev2_sa_get_td_for_type (sa_old->r_proposals, IKEV2_TRANSFORM_TYPE_PRF); + + vec_append (s, sa_new->dh_shared_key); + vec_append (s, sa_new->i_nonce); + vec_append (s, sa_new->r_nonce); + skeyseed = ikev2_calc_prf (tr_prf, sa_old->sk_d, s); + + ikev2_calc_keys_internal (sa_new, skeyseed); + + vec_free (skeyseed); + vec_free (s); +} + +static void +ikev2_calc_keys (ikev2_sa_t *sa) +{ + u8 *s = 0, *skeyseed = 0; + ikev2_sa_transform_t *tr_prf = + ikev2_sa_get_td_for_type (sa->r_proposals, IKEV2_TRANSFORM_TYPE_PRF); + + vec_append (s, sa->i_nonce); + vec_append (s, sa->r_nonce); + skeyseed = ikev2_calc_prf (tr_prf, s, sa->dh_shared_key); + + ikev2_calc_keys_internal (sa, skeyseed); + + vec_free (skeyseed); + vec_free (s); +} + +static void ikev2_calc_child_keys (ikev2_sa_t *sa, ikev2_child_sa_t *child, u8 kex) { u8 *s = 0; @@ -1410,6 +1444,110 @@ ikev2_process_create_child_sa_rekey (ikev2_sa_t *sa, ikev2_sa_t *sar, return 1; } +static void +ikev2_complete_sa_rekey (ikev2_sa_t *sa_new, ikev2_sa_t *sa_old, + ikev2_sa_rekey_t *sa_rekey) +{ + sa_new->del = 0; + sa_new->rekey = 0; + sa_new->new_child = 0; + sa_new->sa_rekey = 0; + sa_new->last_sa_init_req_packet_data = 0; + sa_new->last_sa_init_res_packet_data = 0; + sa_new->last_msg_id = ~0; + sa_new->last_res_packet_data = 0; + sa_new->last_init_msg_id = 0; + clib_memset (&sa_new->stats, 0, sizeof (sa_new->stats)); + + sa_new->ispi = sa_rekey->ispi; + sa_new->rspi = sa_rekey->rspi; + sa_new->i_nonce = sa_rekey->i_nonce; + sa_new->r_nonce = sa_rekey->r_nonce; + sa_new->dh_group = sa_rekey->dh_group; + sa_new->dh_shared_key = sa_rekey->dh_shared_key; + sa_new->dh_private_key = sa_rekey->dh_private_key; + sa_new->i_dh_data = sa_rekey->i_dh_data; + sa_new->r_dh_data = sa_rekey->r_dh_data; + sa_new->i_proposals = sa_rekey->i_proposals; + sa_new->r_proposals = sa_rekey->r_proposals; + + sa_new->sk_d = 0; + sa_new->sk_ai = 0; + sa_new->sk_ar = 0; + sa_new->sk_ei = 0; + sa_new->sk_er = 0; + sa_new->sk_pi = 0; + sa_new->sk_pr = 0; + ikev2_calc_keys_rekey (sa_new, sa_old); + + sa_new->i_auth.data = vec_dup (sa_old->i_auth.data); + sa_new->i_auth.key = sa_old->i_auth.key; + if (sa_new->i_auth.key) + EVP_PKEY_up_ref (sa_new->i_auth.key); + + sa_new->r_auth.data = vec_dup (sa_old->r_auth.data); + sa_new->r_auth.key = sa_old->r_auth.key; + if (sa_new->r_auth.key) + EVP_PKEY_up_ref (sa_new->r_auth.key); + + sa_new->i_id.data = vec_dup (sa_old->i_id.data); + sa_new->r_id.data = vec_dup (sa_old->r_id.data); + + sa_old->is_tun_itf_set = 0; + sa_old->tun_itf = ~0; + sa_old->old_id_expiration = 0; + sa_old->current_remote_id_mask = 0; + sa_old->old_remote_id = 0; + sa_old->old_remote_id_present = 0; + sa_old->childs = 0; + sa_old->sw_if_index = ~0; +} + +static void +ikev2_process_sa_rekey (ikev2_sa_t *sa_new, ikev2_sa_t *sa_old, + ikev2_sa_rekey_t *sa_rekey) +{ + ikev2_sa_transform_t *tr; + + if (ikev2_generate_sa_init_data (sa_new) != IKEV2_GENERATE_SA_INIT_OK) + { + sa_rekey->notify_type = IKEV2_NOTIFY_MSG_INVALID_KE_PAYLOAD; + return; + } + + sa_new->r_proposals = + ikev2_select_proposal (sa_new->i_proposals, IKEV2_PROTOCOL_IKE); + + tr = ikev2_sa_get_td_for_type (sa_new->r_proposals, IKEV2_TRANSFORM_TYPE_DH); + if (!tr || tr->dh_type != sa_new->dh_group) + { + sa_rekey->notify_type = IKEV2_NOTIFY_MSG_INVALID_KE_PAYLOAD; + return; + } + + sa_rekey->notify_type = 0; + sa_rekey->ispi = sa_new->i_proposals[0].spi; + sa_rekey->rspi = sa_new->r_proposals[0].spi; + sa_rekey->i_nonce = sa_new->i_nonce; + sa_rekey->r_nonce = sa_new->r_nonce; + sa_rekey->dh_group = sa_new->dh_group; + sa_rekey->dh_shared_key = sa_new->dh_shared_key; + sa_rekey->dh_private_key = sa_new->dh_private_key; + sa_rekey->i_dh_data = sa_new->i_dh_data; + sa_rekey->r_dh_data = sa_new->r_dh_data; + sa_rekey->i_proposals = sa_new->i_proposals; + sa_rekey->r_proposals = sa_new->r_proposals; + + sa_new->i_nonce = 0; + sa_new->r_nonce = 0; + sa_new->dh_shared_key = 0; + sa_new->dh_private_key = 0; + sa_new->i_dh_data = 0; + sa_new->r_dh_data = 0; + sa_new->i_proposals = 0; + sa_new->r_proposals = 0; +} + static int ikev2_process_create_child_sa_req (vlib_main_t * vm, ikev2_sa_t * sa, ike_header_t * ike, @@ -1515,7 +1653,9 @@ ikev2_process_create_child_sa_req (vlib_main_t * vm, p += plen; } - if (!proposal || proposal->protocol_id != IKEV2_PROTOCOL_ESP || !nonce) + if (!proposal || !nonce || + (proposal->protocol_id != IKEV2_PROTOCOL_ESP && + proposal->protocol_id != IKEV2_PROTOCOL_IKE)) goto cleanup_and_exit; if (sa->is_initiator) @@ -1571,6 +1711,16 @@ ikev2_process_create_child_sa_req (vlib_main_t * vm, vec_free (tsi); } } + else if (proposal[0].protocol_id == IKEV2_PROTOCOL_IKE) + { + ikev2_sa_rekey_t *sa_rekey; + if (tsi || tsr) + goto cleanup_and_exit; + sar.i_proposals = proposal; + vec_add (sar.i_nonce, nonce, nonce_len); + vec_add2 (sa->sa_rekey, sa_rekey, 1); + ikev2_process_sa_rekey (&sar, sa, sa_rekey); + } else { /* create new child SA */ @@ -2414,19 +2564,26 @@ ikev2_add_invalid_ke_payload (ikev2_sa_t *sa, ikev2_payload_chain_t *chain) } static void +ikev2_add_notify_payload (ikev2_sa_t *sa, ikev2_payload_chain_t *chain, + u16 notify_type) +{ + if (notify_type == IKEV2_NOTIFY_MSG_INVALID_KE_PAYLOAD) + ikev2_add_invalid_ke_payload (sa, chain); + else + ikev2_payload_add_notify (chain, notify_type, 0); +} + +static void ikev2_add_create_child_resp (ikev2_sa_t *sa, ikev2_rekey_t *rekey, ikev2_payload_chain_t *chain) { if (rekey->notify_type) { - if (rekey->notify_type == IKEV2_NOTIFY_MSG_INVALID_KE_PAYLOAD) - ikev2_add_invalid_ke_payload (sa, chain); - else - ikev2_payload_add_notify (chain, rekey->notify_type, 0); + ikev2_add_notify_payload (sa, chain, rekey->notify_type); return; } - ikev2_payload_add_sa (chain, rekey->r_proposal); + ikev2_payload_add_sa (chain, rekey->r_proposal, 0); ikev2_payload_add_nonce (chain, sa->r_nonce); if (rekey->kex) ikev2_payload_add_ke (chain, sa->dh_group, sa->r_dh_data); @@ -2482,7 +2639,7 @@ ikev2_generate_message (vlib_buffer_t *b, ikev2_sa_t *sa, ike_header_t *ike, ASSERT (udp); ike->rspi = clib_host_to_net_u64 (sa->rspi); - ikev2_payload_add_sa (chain, sa->r_proposals); + ikev2_payload_add_sa (chain, sa->r_proposals, 0); ikev2_payload_add_ke (chain, sa->dh_group, sa->r_dh_data); ikev2_payload_add_nonce (chain, sa->r_nonce); @@ -2510,7 +2667,7 @@ ikev2_generate_message (vlib_buffer_t *b, ikev2_sa_t *sa, ike_header_t *ike, { ikev2_payload_add_id (chain, &sa->r_id, IKEV2_PAYLOAD_IDR); ikev2_payload_add_auth (chain, &sa->r_auth); - ikev2_payload_add_sa (chain, sa->childs[0].r_proposals); + ikev2_payload_add_sa (chain, sa->childs[0].r_proposals, 0); ikev2_payload_add_ts (chain, sa->childs[0].tsi, IKEV2_PAYLOAD_TSI); ikev2_payload_add_ts (chain, sa->childs[0].tsr, IKEV2_PAYLOAD_TSR); } @@ -2555,7 +2712,7 @@ ikev2_generate_message (vlib_buffer_t *b, ikev2_sa_t *sa, ike_header_t *ike, if (sa->r_id.type != 0) ikev2_payload_add_id (chain, &sa->r_id, IKEV2_PAYLOAD_IDR); ikev2_payload_add_auth (chain, &sa->i_auth); - ikev2_payload_add_sa (chain, sa->childs[0].i_proposals); + ikev2_payload_add_sa (chain, sa->childs[0].i_proposals, 0); ikev2_payload_add_ts (chain, sa->childs[0].tsi, IKEV2_PAYLOAD_TSI); ikev2_payload_add_ts (chain, sa->childs[0].tsr, IKEV2_PAYLOAD_TSR); ikev2_payload_add_notify (chain, IKEV2_NOTIFY_MSG_INITIAL_CONTACT, @@ -2632,7 +2789,7 @@ ikev2_generate_message (vlib_buffer_t *b, ikev2_sa_t *sa, ike_header_t *ike, notify.spi = sa->childs[0].i_proposals->spi; *(u32 *) data = clib_host_to_net_u32 (notify.spi); - ikev2_payload_add_sa (chain, proposals); + ikev2_payload_add_sa (chain, proposals, 0); ikev2_payload_add_nonce (chain, sa->i_nonce); ikev2_payload_add_ts (chain, sa->childs[0].tsi, IKEV2_PAYLOAD_TSI); ikev2_payload_add_ts (chain, sa->childs[0].tsr, IKEV2_PAYLOAD_TSR); @@ -2651,6 +2808,19 @@ ikev2_generate_message (vlib_buffer_t *b, ikev2_sa_t *sa, ike_header_t *ike, ikev2_add_create_child_resp (sa, &sa->new_child[0], chain); vec_del1 (sa->new_child, 0); } + else if (vec_len (sa->sa_rekey) > 0) + { + if (sa->sa_rekey[0].notify_type) + ikev2_add_notify_payload (sa, chain, sa->sa_rekey[0].notify_type); + else + { + ikev2_payload_add_sa (chain, sa->sa_rekey[0].r_proposals, 1); + ikev2_payload_add_nonce (chain, sa->sa_rekey[0].r_nonce); + ikev2_payload_add_ke (chain, sa->sa_rekey[0].dh_group, + sa->sa_rekey[0].r_dh_data); + } + vec_del1 (sa->sa_rekey, 0); + } else if (sa->unsupported_cp) { u8 *data = vec_new (u8, 1); @@ -3456,6 +3626,38 @@ ikev2_node_internal (vlib_main_t *vm, vlib_node_runtime_t *node, vm, node->node_index, IKEV2_ERROR_NO_BUFF_SPACE, 1); } } + else if (vec_len (sa0->sa_rekey) > 0) + { + if (!sa0->sa_rekey[0].notify_type) + { + ikev2_sa_t *sar, *tmp = 0; + pool_get (ptd->sas, tmp); + sa0 = pool_elt_at_index (ptd->sas, p[0]); + /* swap old/new SAs to keep index and inherit IPsec SA */ + clib_memcpy_fast (tmp, sa0, sizeof (*tmp)); + sar = sa0; + sa0 = tmp; + hash_set (ptd->sa_by_rspi, sa0->rspi, sa0 - ptd->sas); + p = hash_get (ptd->sa_by_rspi, sa0->rspi); + ikev2_complete_sa_rekey (sar, sa0, &sa0->sa_rekey[0]); + hash_set (ptd->sa_by_rspi, sar->rspi, sar - ptd->sas); + } + if (ike_hdr_is_response (ike0)) + { + vec_free (sa0->sa_rekey); + } + else + { + stats->n_rekey_req++; + sa0->stats.n_rekey_req++; + ike0->flags = IKEV2_HDR_FLAG_RESPONSE; + slen = + ikev2_generate_message (b0, sa0, ike0, 0, udp0, stats); + if (~0 == slen) + vlib_node_increment_counter ( + vm, node->node_index, IKEV2_ERROR_NO_BUFF_SPACE, 1); + } + } } } else @@ -4526,7 +4728,7 @@ ikev2_initiate_sa_init (vlib_main_t * vm, u8 * name) proposals[0].protocol_id = IKEV2_PROTOCOL_IKE; /* Add and then cleanup proposal data */ - ikev2_payload_add_sa (chain, proposals); + ikev2_payload_add_sa (chain, proposals, 0); ikev2_sa_free_proposal_vector (&proposals); sa.is_initiator = 1; @@ -4560,6 +4762,7 @@ ikev2_initiate_sa_init (vlib_main_t * vm, u8 * name) sa.childs[0].i_proposals[0].protocol_id = IKEV2_PROTOCOL_ESP; RAND_bytes ((u8 *) & sa.childs[0].i_proposals[0].spi, sizeof (sa.childs[0].i_proposals[0].spi)); + sa.childs[0].i_proposals[0].spi &= 0xffffffff; /* Add NAT detection notification messages (mandatory) */ u8 *nat_detection_sha1 = ikev2_compute_nat_sha1 ( @@ -4807,6 +5010,7 @@ ikev2_rekey_child_sa_internal (vlib_main_t * vm, ikev2_sa_t * sa, /*need new ispi */ RAND_bytes ((u8 *) & proposals[0].spi, sizeof (proposals[0].spi)); + proposals[0].spi &= 0xffffffff; rekey->spi = proposals[0].spi; rekey->ispi = csa->i_proposals->spi; len = ikev2_generate_message (b0, sa, ike0, proposals, 0, 0); diff --git a/src/plugins/ikev2/ikev2_payload.c b/src/plugins/ikev2/ikev2_payload.c index 294864d8c43..689c502d4a3 100644 --- a/src/plugins/ikev2/ikev2_payload.c +++ b/src/plugins/ikev2/ikev2_payload.c @@ -167,8 +167,8 @@ ikev2_payload_add_notify_2 (ikev2_payload_chain_t * c, u16 msg_type, } void -ikev2_payload_add_sa (ikev2_payload_chain_t * c, - ikev2_sa_proposal_t * proposals) +ikev2_payload_add_sa (ikev2_payload_chain_t *c, ikev2_sa_proposal_t *proposals, + u8 force_spi) { ike_payload_header_t *ph; ike_sa_proposal_data_t *prop; @@ -184,7 +184,13 @@ ikev2_payload_add_sa (ikev2_payload_chain_t * c, vec_foreach (p, proposals) { - int spi_size = (p->protocol_id == IKEV2_PROTOCOL_ESP) ? 4 : 0; + int spi_size = 0; + + if (p->protocol_id == IKEV2_PROTOCOL_ESP) + spi_size = 4; + else if (force_spi && p->protocol_id == IKEV2_PROTOCOL_IKE) + spi_size = 8; + pr_data = vec_new (u8, sizeof (ike_sa_proposal_data_t) + spi_size); prop = (ike_sa_proposal_data_t *) pr_data; prop->last_or_more = proposals - p + 1 < vec_len (proposals) ? 2 : 0; @@ -193,8 +199,13 @@ ikev2_payload_add_sa (ikev2_payload_chain_t * c, prop->spi_size = spi_size; prop->num_transforms = vec_len (p->transforms); - if (spi_size) + if (spi_size == 4) prop->spi[0] = clib_host_to_net_u32 (p->spi); + else if (spi_size == 8) + { + u64 s = clib_host_to_net_u64 (p->spi); + clib_memcpy_fast (prop->spi, &s, sizeof (s)); + } vec_foreach (t, p->transforms) { @@ -384,8 +395,9 @@ ikev2_parse_sa_payload (ike_payload_header_t * ikep, u32 rlen) sap = (ike_sa_proposal_data_t *) & ikep->payload[proposal_ptr]; int i, transform_ptr; - /* IKE proposal should not have SPI */ - if (sap->protocol_id == IKEV2_PROTOCOL_IKE && sap->spi_size != 0) + /* IKE proposal should have 8 bytes or no SPI */ + if (sap->protocol_id == IKEV2_PROTOCOL_IKE && sap->spi_size != 0 && + sap->spi_size != 8) goto data_corrupted; /* IKE proposal should not have SPI */ @@ -404,6 +416,12 @@ ikev2_parse_sa_payload (ike_payload_header_t * ikep, u32 rlen) { proposal->spi = clib_net_to_host_u32 (sap->spi[0]); } + else if (sap->spi_size == 8) + { + u64 s; + clib_memcpy_fast (&s, &sap->spi[0], sizeof (s)); + proposal->spi = clib_net_to_host_u64 (s); + } for (i = 0; i < sap->num_transforms; i++) { diff --git a/src/plugins/ikev2/ikev2_priv.h b/src/plugins/ikev2/ikev2_priv.h index dca2fe80c57..a11538f92c7 100644 --- a/src/plugins/ikev2/ikev2_priv.h +++ b/src/plugins/ikev2/ikev2_priv.h @@ -243,7 +243,7 @@ typedef struct { u8 proposal_num; ikev2_protocol_id_t protocol_id:8; - u32 spi; + u64 spi; ikev2_sa_transform_t *transforms; } ikev2_sa_proposal_t; @@ -330,6 +330,22 @@ typedef struct typedef struct { + u16 notify_type; + u16 dh_group; + u64 ispi; + u64 rspi; + u8 *i_nonce; + u8 *r_nonce; + u8 *dh_shared_key; + u8 *dh_private_key; + u8 *i_dh_data; + u8 *r_dh_data; + ikev2_sa_proposal_t *i_proposals; + ikev2_sa_proposal_t *r_proposals; +} ikev2_sa_rekey_t; + +typedef struct +{ u16 msg_type; u8 protocol_id; u32 spi; @@ -432,6 +448,9 @@ typedef struct ikev2_rekey_t *new_child; + /* pending sa rekeyings */ + ikev2_sa_rekey_t *sa_rekey; + /* packet data */ u8 *last_sa_init_req_packet_data; u8 *last_sa_init_res_packet_data; @@ -601,8 +620,8 @@ void ikev2_payload_add_notify (ikev2_payload_chain_t * c, u16 msg_type, u8 * data); void ikev2_payload_add_notify_2 (ikev2_payload_chain_t * c, u16 msg_type, u8 * data, ikev2_notify_t * notify); -void ikev2_payload_add_sa (ikev2_payload_chain_t * c, - ikev2_sa_proposal_t * proposals); +void ikev2_payload_add_sa (ikev2_payload_chain_t *c, + ikev2_sa_proposal_t *proposals, u8 force_spi); void ikev2_payload_add_ke (ikev2_payload_chain_t * c, u16 dh_group, u8 * dh_data); void ikev2_payload_add_nonce (ikev2_payload_chain_t * c, u8 * nonce); |