diff options
author | Atzm Watanabe <atzmism@gmail.com> | 2022-08-12 14:29:31 +0900 |
---|---|---|
committer | Beno�t Ganne <bganne@cisco.com> | 2022-08-18 08:03:13 +0000 |
commit | c65921f7744a0da09ede876b6588628e3a188529 (patch) | |
tree | fb004fb74260e71a18d245d691c78cc81bb37889 /src/plugins/ikev2/ikev2.c | |
parent | 138f65c5b7796c6401cde6ff92edc85f02c367a4 (diff) |
ikev2: accept key exchange on CREATE_CHILD_SA
In RFC 7296, CREATE_CHILD_SA Exchange may contain the KE payload
to enable stronger guarantees of forward secrecy.
When the KEi payload is included in the CREATE_CHILD_SA request,
responder should reply with the KEr payload and complete the key
exchange, in accordance with the RFC.
Type: improvement
Signed-off-by: Atzm Watanabe <atzmism@gmail.com>
Change-Id: I13cf6cf24359c11c3366757e585195bb7e999638
Diffstat (limited to 'src/plugins/ikev2/ikev2.c')
-rw-r--r-- | src/plugins/ikev2/ikev2.c | 188 |
1 files changed, 125 insertions, 63 deletions
diff --git a/src/plugins/ikev2/ikev2.c b/src/plugins/ikev2/ikev2.c index 5c1aa58814e..c1b7efdc98e 100644 --- a/src/plugins/ikev2/ikev2.c +++ b/src/plugins/ikev2/ikev2.c @@ -568,7 +568,7 @@ ikev2_calc_keys (ikev2_sa_t * sa) } static void -ikev2_calc_child_keys (ikev2_sa_t * sa, ikev2_child_sa_t * child) +ikev2_calc_child_keys (ikev2_sa_t *sa, ikev2_child_sa_t *child, u8 kex) { u8 *s = 0; u16 integ_key_len = 0; @@ -587,6 +587,8 @@ ikev2_calc_child_keys (ikev2_sa_t * sa, ikev2_child_sa_t * child) else salt_len = sizeof (u32); + if (kex) + vec_append (s, sa->dh_shared_key); vec_append (s, sa->i_nonce); vec_append (s, sa->r_nonce); /* calculate PRFplus */ @@ -1360,6 +1362,55 @@ ikev2_process_informational_req (vlib_main_t * vm, } static int +ikev2_process_create_child_sa_rekey (ikev2_sa_t *sa, ikev2_sa_t *sar, + ikev2_rekey_t *rekey, + ikev2_sa_proposal_t *proposal, + ikev2_ts_t *tsi, ikev2_ts_t *tsr, + const u8 *nonce, int nonce_len) +{ + ikev2_sa_transform_t *tr; + + rekey->i_proposal = proposal; + rekey->r_proposal = ikev2_select_proposal (proposal, IKEV2_PROTOCOL_ESP); + + if (sar->dh_group) + { + tr = + ikev2_sa_get_td_for_type (rekey->r_proposal, IKEV2_TRANSFORM_TYPE_DH); + + if (!tr || tr->dh_type != sar->dh_group) + { + rekey->notify_type = IKEV2_NOTIFY_MSG_INVALID_KE_PAYLOAD; + ikev2_sa_free_proposal_vector (&rekey->r_proposal); + return 0; + } + + vec_free (sa->dh_shared_key); + vec_free (sa->dh_private_key); + vec_free (sa->i_dh_data); + vec_free (sa->r_dh_data); + + sa->dh_group = sar->dh_group; + sa->i_dh_data = sar->i_dh_data; + sar->i_dh_data = 0; + + ikev2_generate_dh (sa, tr); + rekey->kex = 1; + } + + vec_reset_length (sa->i_nonce); + vec_add (sa->i_nonce, nonce, nonce_len); + + vec_validate (sa->r_nonce, nonce_len - 1); + RAND_bytes ((u8 *) sa->r_nonce, nonce_len); + + rekey->tsi = tsi; + rekey->tsr = tsr; + + return 1; +} + +static int ikev2_process_create_child_sa_req (vlib_main_t * vm, ikev2_sa_t * sa, ike_header_t * ike, u32 len) @@ -1378,6 +1429,9 @@ ikev2_process_create_child_sa_req (vlib_main_t * vm, u16 plen; const u8 *nonce = 0; int nonce_len = 0; + ikev2_sa_t sar; + + clib_memset (&sar, 0, sizeof (sar)); if (sa->is_initiator) src = ip_addr_v4 (&sa->raddr).as_u32; @@ -1407,6 +1461,12 @@ ikev2_process_create_child_sa_req (vlib_main_t * vm, { proposal = ikev2_parse_sa_payload (ikep, current_length); } + else if (payload == IKEV2_PAYLOAD_KE) + { + if (!ikev2_parse_ke_payload (ikep, current_length, &sar, + &sar.i_dh_data)) + goto cleanup_and_exit; + } else if (payload == IKEV2_PAYLOAD_NOTIFY) { ikev2_notify_t *n0; @@ -1493,6 +1553,7 @@ ikev2_process_create_child_sa_req (vlib_main_t * vm, } vec_add2 (sa->rekey, rekey, 1); rekey->notify_type = 0; + rekey->kex = 0; rekey->protocol_id = n->protocol_id; rekey->spi = n->spi; if (sa->old_remote_id_present) @@ -1502,17 +1563,12 @@ ikev2_process_create_child_sa_req (vlib_main_t * vm, vec_free (tsr); vec_free (tsi); } - else + else if (!ikev2_process_create_child_sa_rekey ( + sa, &sar, rekey, proposal, tsi, tsr, nonce, nonce_len)) { - rekey->i_proposal = proposal; - rekey->r_proposal = - ikev2_select_proposal (proposal, IKEV2_PROTOCOL_ESP); - /* update Ni */ - vec_reset_length (sa->i_nonce); - vec_add (sa->i_nonce, nonce, nonce_len); - /* generate new Nr */ - vec_validate (sa->r_nonce, nonce_len - 1); - RAND_bytes ((u8 *) sa->r_nonce, nonce_len); + vec_free (proposal); + vec_free (tsr); + vec_free (tsi); } } else @@ -1520,20 +1576,18 @@ ikev2_process_create_child_sa_req (vlib_main_t * vm, /* create new child SA */ vec_add2 (sa->new_child, rekey, 1); rekey->notify_type = 0; - rekey->i_proposal = proposal; - rekey->r_proposal = - ikev2_select_proposal (proposal, IKEV2_PROTOCOL_ESP); - /* update Ni */ - vec_reset_length (sa->i_nonce); - vec_add (sa->i_nonce, nonce, nonce_len); - /* generate new Nr */ - vec_validate (sa->r_nonce, nonce_len - 1); - RAND_bytes ((u8 *) sa->r_nonce, nonce_len); + rekey->kex = 0; + if (!ikev2_process_create_child_sa_rekey ( + sa, &sar, rekey, proposal, tsi, tsr, nonce, nonce_len)) + { + vec_free (proposal); + vec_free (tsr); + vec_free (tsi); + } } - rekey->tsi = tsi; - rekey->tsr = tsr; } vec_free (n); + ikev2_sa_free_all_vec (&sar); return 1; cleanup_and_exit: @@ -1541,6 +1595,7 @@ cleanup_and_exit: vec_free (proposal); vec_free (tsr); vec_free (tsi); + ikev2_sa_free_all_vec (&sar); return 0; } @@ -2013,10 +2068,9 @@ err0: } static int -ikev2_create_tunnel_interface (vlib_main_t * vm, - ikev2_sa_t * sa, - ikev2_child_sa_t * child, u32 sa_index, - u32 child_index, u8 is_rekey) +ikev2_create_tunnel_interface (vlib_main_t *vm, ikev2_sa_t *sa, + ikev2_child_sa_t *child, u32 sa_index, + u32 child_index, u8 is_rekey, u8 kex) { u32 thread_index = vlib_get_thread_index (); ikev2_main_t *km = &ikev2_main; @@ -2159,7 +2213,7 @@ ikev2_create_tunnel_interface (vlib_main_t * vm, } a.integ_type = integ_type; - ikev2_calc_child_keys (sa, child); + ikev2_calc_child_keys (sa, child, kex); if (sa->is_initiator) { @@ -2346,6 +2400,40 @@ ikev2_delete_tunnel_interface (vnet_main_t * vnm, ikev2_sa_t * sa, return 0; } +static void +ikev2_add_invalid_ke_payload (ikev2_sa_t *sa, ikev2_payload_chain_t *chain) +{ + u8 *data = vec_new (u8, 2); + ikev2_sa_transform_t *tr_dh = + ikev2_sa_get_td_for_type (sa->r_proposals, IKEV2_TRANSFORM_TYPE_DH); + ASSERT (tr_dh && tr_dh->dh_type); + data[0] = (tr_dh->dh_type >> 8) & 0xff; + data[1] = (tr_dh->dh_type) & 0xff; + ikev2_payload_add_notify (chain, IKEV2_NOTIFY_MSG_INVALID_KE_PAYLOAD, data); + vec_free (data); +} + +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); + return; + } + + ikev2_payload_add_sa (chain, rekey->r_proposal); + ikev2_payload_add_nonce (chain, sa->r_nonce); + if (rekey->kex) + ikev2_payload_add_ke (chain, sa->dh_group, sa->r_dh_data); + ikev2_payload_add_ts (chain, rekey->tsi, IKEV2_PAYLOAD_TSI); + ikev2_payload_add_ts (chain, rekey->tsr, IKEV2_PAYLOAD_TSR); +} + static u32 ikev2_generate_message (vlib_buffer_t *b, ikev2_sa_t *sa, ike_header_t *ike, void *user, udp_header_t *udp, ikev2_stats_t *stats) @@ -2376,20 +2464,7 @@ ikev2_generate_message (vlib_buffer_t *b, ikev2_sa_t *sa, ike_header_t *ike, } else if (sa->dh_group == IKEV2_TRANSFORM_DH_TYPE_NONE) { - u8 *data = vec_new (u8, 2); - ikev2_sa_transform_t *tr_dh; - tr_dh = - ikev2_sa_get_td_for_type (sa->r_proposals, - IKEV2_TRANSFORM_TYPE_DH); - ASSERT (tr_dh && tr_dh->dh_type); - - data[0] = (tr_dh->dh_type >> 8) & 0xff; - data[1] = (tr_dh->dh_type) & 0xff; - - ikev2_payload_add_notify (chain, - IKEV2_NOTIFY_MSG_INVALID_KE_PAYLOAD, - data); - vec_free (data); + ikev2_add_invalid_ke_payload (sa, chain); ikev2_set_state (sa, IKEV2_STATE_NOTIFY_AND_DELETE); } else if (sa->state == IKEV2_STATE_NOTIFY_AND_DELETE) @@ -2568,27 +2643,12 @@ ikev2_generate_message (vlib_buffer_t *b, ikev2_sa_t *sa, ike_header_t *ike, } else if (vec_len (sa->rekey) > 0) { - if (sa->rekey[0].notify_type) - ikev2_payload_add_notify (chain, sa->rekey[0].notify_type, 0); - else - { - ikev2_payload_add_sa (chain, sa->rekey[0].r_proposal); - ikev2_payload_add_nonce (chain, sa->r_nonce); - ikev2_payload_add_ts (chain, sa->rekey[0].tsi, - IKEV2_PAYLOAD_TSI); - ikev2_payload_add_ts (chain, sa->rekey[0].tsr, - IKEV2_PAYLOAD_TSR); - } + ikev2_add_create_child_resp (sa, &sa->rekey[0], chain); vec_del1 (sa->rekey, 0); } else if (vec_len (sa->new_child) > 0) { - ikev2_payload_add_sa (chain, sa->new_child[0].r_proposal); - ikev2_payload_add_nonce (chain, sa->r_nonce); - ikev2_payload_add_ts (chain, sa->new_child[0].tsi, - IKEV2_PAYLOAD_TSI); - ikev2_payload_add_ts (chain, sa->new_child[0].tsr, - IKEV2_PAYLOAD_TSR); + ikev2_add_create_child_resp (sa, &sa->new_child[0], chain); vec_del1 (sa->new_child, 0); } else if (sa->unsupported_cp) @@ -3211,9 +3271,8 @@ ikev2_node_internal (vlib_main_t *vm, vlib_node_runtime_t *node, ikev2_initial_contact_cleanup (ptd, sa0); ikev2_sa_match_ts (sa0); if (sa0->state != IKEV2_STATE_TS_UNACCEPTABLE) - ikev2_create_tunnel_interface (vm, sa0, - &sa0->childs[0], - p[0], 0, 0); + ikev2_create_tunnel_interface (vm, sa0, &sa0->childs[0], + p[0], 0, 0, 0); } if (sa0->is_initiator) @@ -3353,7 +3412,8 @@ ikev2_node_internal (vlib_main_t *vm, vlib_node_runtime_t *node, child->tsi = sa0->rekey[0].tsi; child->tsr = sa0->rekey[0].tsr; ikev2_create_tunnel_interface (vm, sa0, child, p[0], - child - sa0->childs, 1); + child - sa0->childs, 1, + sa0->rekey[0].kex); } if (ike_hdr_is_response (ike0)) { @@ -3382,7 +3442,8 @@ ikev2_node_internal (vlib_main_t *vm, vlib_node_runtime_t *node, c->tsi = sa0->new_child[0].tsi; c->tsr = sa0->new_child[0].tsr; ikev2_create_tunnel_interface (vm, sa0, c, p[0], - c - sa0->childs, 0); + c - sa0->childs, 0, + sa0->new_child[0].kex); if (ike_hdr_is_request (ike0)) { ike0->flags = IKEV2_HDR_FLAG_RESPONSE; @@ -4736,6 +4797,7 @@ ikev2_rekey_child_sa_internal (vlib_main_t * vm, ikev2_sa_t * sa, ikev2_rekey_t *rekey; vec_reset_length (sa->rekey); vec_add2 (sa->rekey, rekey, 1); + rekey->kex = 0; ikev2_sa_proposal_t *proposals = vec_dup (csa->i_proposals); /*need new ispi */ |