X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fplugins%2Fikev2%2Fikev2.c;h=a260bb166174c78d41cbd713222bc6b12beb3d0d;hb=9534696b4;hp=e90f5a3bd3b77f3a8dc46dee2ed4feb0983b6678;hpb=1890e9ce57a4b6dbc732f8f11d78001bea7c5855;p=vpp.git diff --git a/src/plugins/ikev2/ikev2.c b/src/plugins/ikev2/ikev2.c index e90f5a3bd3b..a260bb16617 100644 --- a/src/plugins/ikev2/ikev2.c +++ b/src/plugins/ikev2/ikev2.c @@ -15,6 +15,7 @@ #include #include +#include #include #include #include @@ -22,6 +23,8 @@ #include #include #include +#include +#include #include #include #include @@ -243,19 +246,24 @@ ikev2_sa_free_proposal_vector (ikev2_sa_proposal_t ** v) vec_free (*v); }; +static void +ikev2_sa_free_child_sa (ikev2_child_sa_t * c) +{ + ikev2_sa_free_proposal_vector (&c->r_proposals); + ikev2_sa_free_proposal_vector (&c->i_proposals); + vec_free (c->sk_ai); + vec_free (c->sk_ar); + vec_free (c->sk_ei); + vec_free (c->sk_er); + vec_free (c->tsi); + vec_free (c->tsr); +} + static void ikev2_sa_free_all_child_sa (ikev2_child_sa_t ** childs) { ikev2_child_sa_t *c; - vec_foreach (c, *childs) - { - ikev2_sa_free_proposal_vector (&c->r_proposals); - ikev2_sa_free_proposal_vector (&c->i_proposals); - vec_free (c->sk_ai); - vec_free (c->sk_ar); - vec_free (c->sk_ei); - vec_free (c->sk_er); - } + vec_foreach (c, *childs) ikev2_sa_free_child_sa (c); vec_free (*childs); } @@ -263,13 +271,7 @@ ikev2_sa_free_all_child_sa (ikev2_child_sa_t ** childs) static void ikev2_sa_del_child_sa (ikev2_sa_t * sa, ikev2_child_sa_t * child) { - ikev2_sa_free_proposal_vector (&child->r_proposals); - ikev2_sa_free_proposal_vector (&child->i_proposals); - vec_free (child->sk_ai); - vec_free (child->sk_ar); - vec_free (child->sk_ei); - vec_free (child->sk_er); - + ikev2_sa_free_child_sa (child); vec_del1 (sa->childs, child - sa->childs); } @@ -438,6 +440,7 @@ ikev2_calc_keys (ikev2_sa_t * sa) /* calculate SKEYSEED = prf(Ni | Nr, g^ir) */ u8 *skeyseed = 0; u8 *s = 0; + u16 integ_key_len = 0; ikev2_sa_transform_t *tr_encr, *tr_prf, *tr_integ; tr_encr = ikev2_sa_get_td_for_type (sa->r_proposals, IKEV2_TRANSFORM_TYPE_ENCR); @@ -446,6 +449,9 @@ ikev2_calc_keys (ikev2_sa_t * sa) tr_integ = ikev2_sa_get_td_for_type (sa->r_proposals, IKEV2_TRANSFORM_TYPE_INTEG); + if (tr_integ) + integ_key_len = tr_integ->key_len; + vec_append (s, sa->i_nonce); vec_append (s, sa->r_nonce); skeyseed = ikev2_calc_prf (tr_prf, s, sa->dh_shared_key); @@ -460,7 +466,7 @@ ikev2_calc_keys (ikev2_sa_t * sa) /* calculate PRFplus */ u8 *keymat; int len = tr_prf->key_trunc + /* SK_d */ - tr_integ->key_len * 2 + /* SK_ai, SK_ar */ + integ_key_len * 2 + /* SK_ai, SK_ar */ tr_encr->key_len * 2 + /* SK_ei, SK_er */ tr_prf->key_len * 2; /* SK_pi, SK_pr */ @@ -475,15 +481,18 @@ ikev2_calc_keys (ikev2_sa_t * sa) clib_memcpy_fast (sa->sk_d, keymat + pos, tr_prf->key_trunc); pos += tr_prf->key_trunc; - /* SK_ai */ - sa->sk_ai = vec_new (u8, tr_integ->key_len); - clib_memcpy_fast (sa->sk_ai, keymat + pos, tr_integ->key_len); - pos += tr_integ->key_len; + if (integ_key_len) + { + /* SK_ai */ + sa->sk_ai = vec_new (u8, integ_key_len); + clib_memcpy_fast (sa->sk_ai, keymat + pos, integ_key_len); + pos += integ_key_len; - /* SK_ar */ - sa->sk_ar = vec_new (u8, tr_integ->key_len); - clib_memcpy_fast (sa->sk_ar, keymat + pos, tr_integ->key_len); - pos += tr_integ->key_len; + /* SK_ar */ + sa->sk_ar = vec_new (u8, integ_key_len); + clib_memcpy_fast (sa->sk_ar, keymat + pos, integ_key_len); + pos += integ_key_len; + } /* SK_ei */ sa->sk_ei = vec_new (u8, tr_encr->key_len); @@ -512,6 +521,9 @@ static void ikev2_calc_child_keys (ikev2_sa_t * sa, ikev2_child_sa_t * child) { u8 *s = 0; + u16 integ_key_len = 0; + u8 salt_len = 0; + ikev2_sa_transform_t *tr_prf, *ctr_encr, *ctr_integ; tr_prf = ikev2_sa_get_td_for_type (sa->r_proposals, IKEV2_TRANSFORM_TYPE_PRF); @@ -520,11 +532,16 @@ ikev2_calc_child_keys (ikev2_sa_t * sa, ikev2_child_sa_t * child) ctr_integ = ikev2_sa_get_td_for_type (child->r_proposals, IKEV2_TRANSFORM_TYPE_INTEG); + if (ctr_integ) + integ_key_len = ctr_integ->key_len; + else + salt_len = sizeof (u32); + vec_append (s, sa->i_nonce); vec_append (s, sa->r_nonce); /* calculate PRFplus */ u8 *keymat; - int len = ctr_encr->key_len * 2 + ctr_integ->key_len * 2; + int len = ctr_encr->key_len * 2 + integ_key_len * 2 + salt_len * 2; keymat = ikev2_calc_prfplus (tr_prf, sa->sk_d, s, len); @@ -535,20 +552,36 @@ ikev2_calc_child_keys (ikev2_sa_t * sa, ikev2_child_sa_t * child) clib_memcpy_fast (child->sk_ei, keymat + pos, ctr_encr->key_len); pos += ctr_encr->key_len; - /* SK_ai */ - child->sk_ai = vec_new (u8, ctr_integ->key_len); - clib_memcpy_fast (child->sk_ai, keymat + pos, ctr_integ->key_len); - pos += ctr_integ->key_len; + if (ctr_integ) + { + /* SK_ai */ + child->sk_ai = vec_new (u8, ctr_integ->key_len); + clib_memcpy_fast (child->sk_ai, keymat + pos, ctr_integ->key_len); + pos += ctr_integ->key_len; + } + else + { + clib_memcpy (&child->salt_ei, keymat + pos, salt_len); + pos += salt_len; + } /* SK_er */ child->sk_er = vec_new (u8, ctr_encr->key_len); clib_memcpy_fast (child->sk_er, keymat + pos, ctr_encr->key_len); pos += ctr_encr->key_len; - /* SK_ar */ - child->sk_ar = vec_new (u8, ctr_integ->key_len); - clib_memcpy_fast (child->sk_ar, keymat + pos, ctr_integ->key_len); - pos += ctr_integ->key_len; + if (ctr_integ) + { + /* SK_ar */ + child->sk_ar = vec_new (u8, integ_key_len); + clib_memcpy_fast (child->sk_ar, keymat + pos, integ_key_len); + pos += integ_key_len; + } + else + { + clib_memcpy (&child->salt_er, keymat + pos, salt_len); + pos += salt_len; + } ASSERT (pos == len); @@ -1275,7 +1308,7 @@ ikev2_sa_match_ts (ikev2_sa_t * sa) { if (ikev2_ts_cmp(p_tsi, ts)) { - tsi = vec_dup(ts); + vec_add1 (tsi, ts[0]); break; } } @@ -1284,7 +1317,7 @@ ikev2_sa_match_ts (ikev2_sa_t * sa) { if (ikev2_ts_cmp(p_tsr, ts)) { - tsr = vec_dup(ts); + vec_add1 (tsr, ts[0]); break; } } @@ -1474,18 +1507,79 @@ ikev2_sa_auth_init (ikev2_sa_t * sa) vec_free (authmsg); } +static u32 +ikev2_mk_local_sa_id (u32 sai, u32 ci, u32 ti) +{ + return (0x80000000 | (ti << 24) | (sai << 12) | ci); +} + +static u32 +ikev2_mk_remote_sa_id (u32 sai, u32 ci, u32 ti) +{ + return (0xc0000000 | (ti << 24) | (sai << 12) | ci); +} + +typedef struct +{ + u32 salt_local; + u32 salt_remote; + u32 local_sa_id; + u32 remote_sa_id; + ipsec_sa_flags_t flags; + u32 local_spi; + u32 remote_spi; + ipsec_crypto_alg_t encr_type; + ipsec_integ_alg_t integ_type; + ip46_address_t local_ip; + ip46_address_t remote_ip; + ipsec_key_t loc_ckey, rem_ckey, loc_ikey, rem_ikey; +} ikev2_add_ipsec_tunnel_args_t; + +static void +ikev2_add_tunnel_from_main (ikev2_add_ipsec_tunnel_args_t * a) +{ + u32 sw_if_index; + int rv; + + rv = ipip_add_tunnel (IPIP_TRANSPORT_IP4, ~0, + &a->local_ip, &a->remote_ip, 0, + IPIP_TUNNEL_FLAG_NONE, IP_DSCP_CS0, &sw_if_index); + + rv |= ipsec_sa_add_and_lock (a->local_sa_id, + a->local_spi, + IPSEC_PROTOCOL_ESP, a->encr_type, + &a->loc_ckey, a->integ_type, &a->loc_ikey, + a->flags, 0, a->salt_local, &a->local_ip, + &a->remote_ip, NULL); + rv |= ipsec_sa_add_and_lock (a->remote_sa_id, a->remote_spi, + IPSEC_PROTOCOL_ESP, a->encr_type, &a->rem_ckey, + a->integ_type, &a->rem_ikey, + (a->flags | IPSEC_SA_FLAG_IS_INBOUND), 0, + a->salt_remote, &a->remote_ip, + &a->local_ip, NULL); + + u32 *sas_in = NULL; + vec_add1 (sas_in, a->remote_sa_id); + rv |= ipsec_tun_protect_update (sw_if_index, a->local_sa_id, sas_in); +} static int -ikev2_create_tunnel_interface (vnet_main_t * vnm, ikev2_sa_t * sa, - ikev2_child_sa_t * child) +ikev2_create_tunnel_interface (vnet_main_t * vnm, + u32 thread_index, + ikev2_sa_t * sa, + ikev2_child_sa_t * child, u32 sa_index, + u32 child_index) { ikev2_main_t *km = &ikev2_main; + ipsec_crypto_alg_t encr_type; + ipsec_integ_alg_t integ_type; ikev2_profile_t *p = 0; - ipsec_add_del_tunnel_args_t a; ikev2_sa_transform_t *tr; ikev2_sa_proposal_t *proposals; - u8 encr_type = 0; - u8 integ_type = 0; + u8 is_aead = 0; + ikev2_add_ipsec_tunnel_args_t a; + + clib_memset (&a, 0, sizeof (a)); if (!child->r_proposals) { @@ -1493,31 +1587,28 @@ ikev2_create_tunnel_interface (vnet_main_t * vnm, ikev2_sa_t * sa, return 1; } - clib_memset (&a, 0, sizeof (a)); - a.is_add = 1; if (sa->is_initiator) { - a.local_ip.ip4.as_u32 = sa->iaddr.as_u32; - a.remote_ip.ip4.as_u32 = sa->raddr.as_u32; + ip46_address_set_ip4 (&a.local_ip, &sa->iaddr); + ip46_address_set_ip4 (&a.remote_ip, &sa->raddr); proposals = child->i_proposals; a.local_spi = child->r_proposals[0].spi; a.remote_spi = child->i_proposals[0].spi; } else { - a.local_ip.ip4.as_u32 = sa->raddr.as_u32; - a.remote_ip.ip4.as_u32 = sa->iaddr.as_u32; + ip46_address_set_ip4 (&a.local_ip, &sa->raddr); + ip46_address_set_ip4 (&a.remote_ip, &sa->iaddr); proposals = child->r_proposals; a.local_spi = child->i_proposals[0].spi; a.remote_spi = child->r_proposals[0].spi; } - a.anti_replay = 1; + + a.flags = IPSEC_SA_FLAG_USE_ANTI_REPLAY; tr = ikev2_sa_get_td_for_type (proposals, IKEV2_TRANSFORM_TYPE_ESN); - if (tr) - a.esn = tr->esn_type; - else - a.esn = 0; + if (tr && tr->esn_type) + a.flags |= IPSEC_SA_FLAG_USE_ESN; tr = ikev2_sa_get_td_for_type (proposals, IKEV2_TRANSFORM_TYPE_ENCR); if (tr) @@ -1541,7 +1632,7 @@ ikev2_create_tunnel_interface (vnet_main_t * vnm, ikev2_sa_t * sa, break; } } - else if (tr->encr_type == IKEV2_TRANSFORM_ENCR_TYPE_AES_GCM + else if (tr->encr_type == IKEV2_TRANSFORM_ENCR_TYPE_AES_GCM_16 && tr->key_len) { switch (tr->key_len) @@ -1560,6 +1651,7 @@ ikev2_create_tunnel_interface (vnet_main_t * vnm, ikev2_sa_t * sa, return 1; break; } + is_aead = 1; } else { @@ -1572,65 +1664,71 @@ ikev2_create_tunnel_interface (vnet_main_t * vnm, ikev2_sa_t * sa, ikev2_set_state (sa, IKEV2_STATE_NO_PROPOSAL_CHOSEN); return 1; } + a.encr_type = encr_type; - tr = ikev2_sa_get_td_for_type (proposals, IKEV2_TRANSFORM_TYPE_INTEG); - if (tr) + if (!is_aead) { - switch (tr->integ_type) - { - case IKEV2_TRANSFORM_INTEG_TYPE_AUTH_HMAC_SHA2_256_128: - integ_type = IPSEC_INTEG_ALG_SHA_256_128; - break; - case IKEV2_TRANSFORM_INTEG_TYPE_AUTH_HMAC_SHA2_384_192: - integ_type = IPSEC_INTEG_ALG_SHA_384_192; - break; - case IKEV2_TRANSFORM_INTEG_TYPE_AUTH_HMAC_SHA2_512_256: - integ_type = IPSEC_INTEG_ALG_SHA_512_256; - break; - case IKEV2_TRANSFORM_INTEG_TYPE_AUTH_HMAC_SHA1_96: - integ_type = IPSEC_INTEG_ALG_SHA1_96; - break; - default: + tr = ikev2_sa_get_td_for_type (proposals, IKEV2_TRANSFORM_TYPE_INTEG); + if (tr) + { + switch (tr->integ_type) + { + case IKEV2_TRANSFORM_INTEG_TYPE_AUTH_HMAC_SHA2_256_128: + integ_type = IPSEC_INTEG_ALG_SHA_256_128; + break; + case IKEV2_TRANSFORM_INTEG_TYPE_AUTH_HMAC_SHA2_384_192: + integ_type = IPSEC_INTEG_ALG_SHA_384_192; + break; + case IKEV2_TRANSFORM_INTEG_TYPE_AUTH_HMAC_SHA2_512_256: + integ_type = IPSEC_INTEG_ALG_SHA_512_256; + break; + case IKEV2_TRANSFORM_INTEG_TYPE_AUTH_HMAC_SHA1_96: + integ_type = IPSEC_INTEG_ALG_SHA1_96; + break; + default: + ikev2_set_state (sa, IKEV2_STATE_NO_PROPOSAL_CHOSEN); + return 1; + } + } + else + { ikev2_set_state (sa, IKEV2_STATE_NO_PROPOSAL_CHOSEN); return 1; } } else { - ikev2_set_state (sa, IKEV2_STATE_NO_PROPOSAL_CHOSEN); - return 1; + integ_type = IPSEC_INTEG_ALG_NONE; } + a.integ_type = integ_type; ikev2_calc_child_keys (sa, child); - u8 *loc_ckey, *rem_ckey, *loc_ikey, *rem_ikey; if (sa->is_initiator) { - loc_ikey = child->sk_ai; - rem_ikey = child->sk_ar; - loc_ckey = child->sk_ei; - rem_ckey = child->sk_er; + ipsec_mk_key (&a.loc_ikey, child->sk_ai, vec_len (child->sk_ai)); + ipsec_mk_key (&a.rem_ikey, child->sk_ar, vec_len (child->sk_ar)); + ipsec_mk_key (&a.loc_ckey, child->sk_ei, vec_len (child->sk_ei)); + ipsec_mk_key (&a.rem_ckey, child->sk_er, vec_len (child->sk_er)); + if (is_aead) + { + a.salt_remote = child->salt_er; + a.salt_local = child->salt_ei; + } } else { - loc_ikey = child->sk_ar; - rem_ikey = child->sk_ai; - loc_ckey = child->sk_er; - rem_ckey = child->sk_ei; + ipsec_mk_key (&a.loc_ikey, child->sk_ar, vec_len (child->sk_ar)); + ipsec_mk_key (&a.rem_ikey, child->sk_ai, vec_len (child->sk_ai)); + ipsec_mk_key (&a.loc_ckey, child->sk_er, vec_len (child->sk_er)); + ipsec_mk_key (&a.rem_ckey, child->sk_ei, vec_len (child->sk_ei)); + if (is_aead) + { + a.salt_remote = child->salt_ei; + a.salt_local = child->salt_er; + } } - a.integ_alg = integ_type; - a.local_integ_key_len = vec_len (loc_ikey); - clib_memcpy_fast (a.local_integ_key, loc_ikey, a.local_integ_key_len); - a.remote_integ_key_len = vec_len (rem_ikey); - clib_memcpy_fast (a.remote_integ_key, rem_ikey, a.remote_integ_key_len); - - a.crypto_alg = encr_type; - a.local_crypto_key_len = vec_len (loc_ckey); - clib_memcpy_fast (a.local_crypto_key, loc_ckey, a.local_crypto_key_len); - a.remote_crypto_key_len = vec_len (rem_ckey); - clib_memcpy_fast (a.remote_crypto_key, rem_ckey, a.remote_crypto_key_len); - if (sa->is_profile_index_set) p = pool_elt_at_index (km->profiles, sa->profile_index); @@ -1652,41 +1750,80 @@ ikev2_create_tunnel_interface (vnet_main_t * vnm, ikev2_sa_t * sa, } } - ipsec_add_del_tunnel_if (&a); + if (thread_index & 0xffffffc0) + clib_warning ("error: thread index exceeds max range 0x3f!"); + + if (child_index & 0xfffff000 || sa_index & 0xfffff000) + clib_warning ("error: sa/child index exceeds max range 0xfff!"); + child->local_sa_id = + a.local_sa_id = + ikev2_mk_local_sa_id (sa_index, child_index, thread_index); + child->remote_sa_id = + a.remote_sa_id = + ikev2_mk_remote_sa_id (sa_index, child_index, thread_index); + + vl_api_rpc_call_main_thread (ikev2_add_tunnel_from_main, + (u8 *) & a, sizeof (a)); return 0; } +typedef struct +{ + ip46_address_t local_ip; + ip46_address_t remote_ip; + u32 remote_sa_id; + u32 local_sa_id; +} ikev2_del_ipsec_tunnel_args_t; + +static void +ikev2_del_tunnel_from_main (ikev2_del_ipsec_tunnel_args_t * a) +{ + /* *INDENT-OFF* */ + ipip_tunnel_key_t key = { + .src = a->local_ip, + .dst = a->remote_ip, + .transport = IPIP_TRANSPORT_IP4, + .fib_index = 0, + }; + ipip_tunnel_t *ipip; + /* *INDENT-ON* */ + + ipip = ipip_tunnel_db_find (&key); + + if (ipip) + { + ipsec_tun_protect_del (ipip->sw_if_index); + ipsec_sa_unlock_id (a->remote_sa_id); + ipsec_sa_unlock_id (a->local_sa_id); + ipip_del_tunnel (ipip->sw_if_index); + } +} + static int ikev2_delete_tunnel_interface (vnet_main_t * vnm, ikev2_sa_t * sa, ikev2_child_sa_t * child) { - ipsec_add_del_tunnel_args_t a; + ikev2_del_ipsec_tunnel_args_t a; + + clib_memset (&a, 0, sizeof (a)); if (sa->is_initiator) { - if (!vec_len (child->i_proposals)) - return 0; - - a.is_add = 0; - a.local_ip.ip4.as_u32 = sa->iaddr.as_u32; - a.remote_ip.ip4.as_u32 = sa->raddr.as_u32; - a.local_spi = child->r_proposals[0].spi; - a.remote_spi = child->i_proposals[0].spi; + ip46_address_set_ip4 (&a.local_ip, &sa->iaddr); + ip46_address_set_ip4 (&a.remote_ip, &sa->raddr); } else { - if (!vec_len (child->r_proposals)) - return 0; - - a.is_add = 0; - a.local_ip.ip4.as_u32 = sa->raddr.as_u32; - a.remote_ip.ip4.as_u32 = sa->iaddr.as_u32; - a.local_spi = child->i_proposals[0].spi; - a.remote_spi = child->r_proposals[0].spi; + ip46_address_set_ip4 (&a.local_ip, &sa->raddr); + ip46_address_set_ip4 (&a.remote_ip, &sa->iaddr); } - ipsec_add_del_tunnel_if (&a); + a.remote_sa_id = child->remote_sa_id; + a.local_sa_id = child->local_sa_id; + + vl_api_rpc_call_main_thread (ikev2_del_tunnel_from_main, (u8 *) & a, + sizeof (a)); return 0; } @@ -2275,8 +2412,10 @@ ikev2_node_fn (vlib_main_t * vm, ikev2_initial_contact_cleanup (sa0); ikev2_sa_match_ts (sa0); if (sa0->state != IKEV2_STATE_TS_UNACCEPTABLE) - ikev2_create_tunnel_interface (km->vnet_main, sa0, - &sa0->childs[0]); + ikev2_create_tunnel_interface (km->vnet_main, + thread_index, sa0, + &sa0->childs[0], + p[0], 0); } if (sa0->is_initiator) @@ -2402,8 +2541,10 @@ ikev2_node_fn (vlib_main_t * vm, child->i_proposals = sa0->rekey[0].i_proposal; child->tsi = sa0->rekey[0].tsi; child->tsr = sa0->rekey[0].tsr; - ikev2_create_tunnel_interface (km->vnet_main, sa0, - child); + ikev2_create_tunnel_interface (km->vnet_main, + thread_index, sa0, + child, p[0], + child - sa0->childs); } if (sa0->is_initiator) {