diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/plugins/ikev2/ikev2.c | 259 | ||||
-rw-r--r-- | src/plugins/ikev2/ikev2.h | 2 | ||||
-rw-r--r-- | src/plugins/ikev2/ikev2_crypto.c | 6 | ||||
-rw-r--r-- | src/plugins/ikev2/ikev2_priv.h | 7 | ||||
-rw-r--r-- | src/vnet/ipsec/ipsec_sa.c | 26 |
5 files changed, 183 insertions, 117 deletions
diff --git a/src/plugins/ikev2/ikev2.c b/src/plugins/ikev2/ikev2.c index e90f5a3bd3b..d6988704b49 100644 --- a/src/plugins/ikev2/ikev2.c +++ b/src/plugins/ikev2/ikev2.c @@ -22,6 +22,8 @@ #include <vppinfra/random.h> #include <vnet/udp/udp.h> #include <vnet/ipsec/ipsec.h> +#include <vnet/ipsec/ipsec_tun.h> +#include <vnet/ipip/ipip.h> #include <plugins/ikev2/ikev2.h> #include <plugins/ikev2/ikev2_priv.h> #include <openssl/sha.h> @@ -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); @@ -1474,6 +1507,17 @@ ikev2_sa_auth_init (ikev2_sa_t * sa) vec_free (authmsg); } +static u32 +ikev2_mk_local_sa_id (u32 ti) +{ + return (0x80000000 | ti); +} + +static u32 +ikev2_mk_remote_sa_id (u32 ti) +{ + return (0xc0000000 | ti); +} static int ikev2_create_tunnel_interface (vnet_main_t * vnm, ikev2_sa_t * sa, @@ -1481,11 +1525,17 @@ ikev2_create_tunnel_interface (vnet_main_t * vnm, ikev2_sa_t * sa, { ikev2_main_t *km = &ikev2_main; ikev2_profile_t *p = 0; - ipsec_add_del_tunnel_args_t a; + ipsec_key_t loc_ckey, rem_ckey, loc_ikey, rem_ikey; ikev2_sa_transform_t *tr; ikev2_sa_proposal_t *proposals; - u8 encr_type = 0; - u8 integ_type = 0; + ipsec_sa_flags_t flags = 0; + ipsec_crypto_alg_t encr_type; + ipsec_integ_alg_t integ_type; + u32 local_spi, remote_spi; + u8 is_aead = 0; + u32 salt_local = 0, salt_remote = 0; + ip46_address_t local_ip, remote_ip; + int rv; if (!child->r_proposals) { @@ -1493,31 +1543,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 (&local_ip, &sa->iaddr); + ip46_address_set_ip4 (&remote_ip, &sa->raddr); proposals = child->i_proposals; - a.local_spi = child->r_proposals[0].spi; - a.remote_spi = child->i_proposals[0].spi; + local_spi = child->r_proposals[0].spi; + 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 (&local_ip, &sa->raddr); + ip46_address_set_ip4 (&remote_ip, &sa->iaddr); proposals = child->r_proposals; - a.local_spi = child->i_proposals[0].spi; - a.remote_spi = child->r_proposals[0].spi; + local_spi = child->i_proposals[0].spi; + remote_spi = child->r_proposals[0].spi; } - a.anti_replay = 1; + + 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) + flags |= IPSEC_SA_FLAG_USE_ESN; tr = ikev2_sa_get_td_for_type (proposals, IKEV2_TRANSFORM_TYPE_ENCR); if (tr) @@ -1541,7 +1588,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 +1607,7 @@ ikev2_create_tunnel_interface (vnet_main_t * vnm, ikev2_sa_t * sa, return 1; break; } + is_aead = 1; } else { @@ -1573,64 +1621,68 @@ ikev2_create_tunnel_interface (vnet_main_t * vnm, ikev2_sa_t * sa, return 1; } - 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; } 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 (&loc_ikey, child->sk_ai, vec_len (child->sk_ai)); + ipsec_mk_key (&rem_ikey, child->sk_ar, vec_len (child->sk_ar)); + ipsec_mk_key (&loc_ckey, child->sk_ei, vec_len (child->sk_ei)); + ipsec_mk_key (&rem_ckey, child->sk_er, vec_len (child->sk_er)); + if (is_aead) + { + salt_remote = child->salt_er; + 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 (&loc_ikey, child->sk_ar, vec_len (child->sk_ar)); + ipsec_mk_key (&rem_ikey, child->sk_ai, vec_len (child->sk_ai)); + ipsec_mk_key (&loc_ckey, child->sk_er, vec_len (child->sk_er)); + ipsec_mk_key (&rem_ckey, child->sk_ei, vec_len (child->sk_ei)); + if (is_aead) + { + salt_remote = child->salt_ei; + 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,7 +1704,28 @@ ikev2_create_tunnel_interface (vnet_main_t * vnm, ikev2_sa_t * sa, } } - ipsec_add_del_tunnel_if (&a); + rv = ipip_add_tunnel (IPIP_TRANSPORT_IP4, ~0, + &local_ip, &remote_ip, 0, 0, &child->sw_if_index); + + child->local_sa = ikev2_mk_local_sa_id (child->sw_if_index); + child->remote_sa = ikev2_mk_remote_sa_id (child->sw_if_index); + + rv |= ipsec_sa_add_and_lock (child->local_sa, + local_spi, + IPSEC_PROTOCOL_ESP, encr_type, + &loc_ckey, integ_type, &loc_ikey, flags, + 0, salt_local, &local_ip, &remote_ip, NULL); + rv |= ipsec_sa_add_and_lock (child->remote_sa, + remote_spi, + IPSEC_PROTOCOL_ESP, encr_type, + &rem_ckey, integ_type, &rem_ikey, + (flags | IPSEC_SA_FLAG_IS_INBOUND), + 0, salt_remote, &remote_ip, &local_ip, NULL); + + u32 *sas_in = NULL; + vec_add1 (sas_in, child->remote_sa); + rv |= + ipsec_tun_protect_update (child->sw_if_index, child->local_sa, sas_in); return 0; } @@ -1661,32 +1734,10 @@ 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; - - 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; - } - 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; - } - - ipsec_add_del_tunnel_if (&a); + ipsec_tun_protect_del (child->sw_if_index); + ipsec_sa_unlock_id (child->remote_sa); + ipsec_sa_unlock_id (child->local_sa); + ipip_del_tunnel (child->sw_if_index); return 0; } diff --git a/src/plugins/ikev2/ikev2.h b/src/plugins/ikev2/ikev2.h index f69f5dc3abe..fd669b3850f 100644 --- a/src/plugins/ikev2/ikev2.h +++ b/src/plugins/ikev2/ikev2.h @@ -222,7 +222,7 @@ typedef enum _(11, NULL, "null") \ _(12, AES_CBC, "aes-cbc") \ _(13, AES_CTR, "aes-ctr") \ - _(14, AES_GCM, "aes-gcm") + _(20, AES_GCM_16, "aes-gcm-16") typedef enum { diff --git a/src/plugins/ikev2/ikev2_crypto.c b/src/plugins/ikev2/ikev2_crypto.c index 3d076ed85ea..49629a5dab5 100644 --- a/src/plugins/ikev2/ikev2_crypto.c +++ b/src/plugins/ikev2/ikev2_crypto.c @@ -846,21 +846,21 @@ ikev2_crypto_init (ikev2_main_t * km) vec_add2 (km->supported_transforms, tr, 1); tr->type = IKEV2_TRANSFORM_TYPE_ENCR; - tr->encr_type = IKEV2_TRANSFORM_ENCR_TYPE_AES_GCM; + tr->encr_type = IKEV2_TRANSFORM_ENCR_TYPE_AES_GCM_16; tr->key_len = 256 / 8; tr->block_size = 128 / 8; tr->cipher = EVP_aes_256_gcm (); vec_add2 (km->supported_transforms, tr, 1); tr->type = IKEV2_TRANSFORM_TYPE_ENCR; - tr->encr_type = IKEV2_TRANSFORM_ENCR_TYPE_AES_GCM; + tr->encr_type = IKEV2_TRANSFORM_ENCR_TYPE_AES_GCM_16; tr->key_len = 192 / 8; tr->block_size = 128 / 8; tr->cipher = EVP_aes_192_gcm (); vec_add2 (km->supported_transforms, tr, 1); tr->type = IKEV2_TRANSFORM_TYPE_ENCR; - tr->encr_type = IKEV2_TRANSFORM_ENCR_TYPE_AES_GCM; + tr->encr_type = IKEV2_TRANSFORM_ENCR_TYPE_AES_GCM_16; tr->key_len = 128 / 8; tr->block_size = 128 / 8; tr->cipher = EVP_aes_128_gcm (); diff --git a/src/plugins/ikev2/ikev2_priv.h b/src/plugins/ikev2/ikev2_priv.h index 0fedc15310a..65080f0df3f 100644 --- a/src/plugins/ikev2/ikev2_priv.h +++ b/src/plugins/ikev2/ikev2_priv.h @@ -143,6 +143,13 @@ typedef struct u8 *sk_ar; u8 *sk_ei; u8 *sk_er; + u32 salt_ei; + u32 salt_er; + + /* installed data */ + u32 sw_if_index; + u32 local_sa; + u32 remote_sa; /* lifetime data */ f64 time_to_expiration; diff --git a/src/vnet/ipsec/ipsec_sa.c b/src/vnet/ipsec/ipsec_sa.c index 11d6b10c4a4..f22458da562 100644 --- a/src/vnet/ipsec/ipsec_sa.c +++ b/src/vnet/ipsec/ipsec_sa.c @@ -163,8 +163,11 @@ ipsec_sa_add_and_lock (u32 id, sa->protocol = proto; sa->flags = flags; sa->salt = salt; - ipsec_sa_set_integ_alg (sa, integ_alg); - clib_memcpy (&sa->integ_key, ik, sizeof (sa->integ_key)); + if (integ_alg != IPSEC_INTEG_ALG_NONE) + { + ipsec_sa_set_integ_alg (sa, integ_alg); + clib_memcpy (&sa->integ_key, ik, sizeof (sa->integ_key)); + } ipsec_sa_set_crypto_alg (sa, crypto_alg); clib_memcpy (&sa->crypto_key, ck, sizeof (sa->crypto_key)); ip46_address_copy (&sa->tunnel_src_addr, tun_src); @@ -179,13 +182,17 @@ ipsec_sa_add_and_lock (u32 id, return VNET_API_ERROR_KEY_LENGTH; } - sa->integ_key_index = vnet_crypto_key_add (vm, - im->integ_algs[integ_alg].alg, - (u8 *) ik->data, ik->len); - if (~0 == sa->integ_key_index) + if (integ_alg != IPSEC_INTEG_ALG_NONE) { - pool_put (im->sad, sa); - return VNET_API_ERROR_KEY_LENGTH; + sa->integ_key_index = vnet_crypto_key_add (vm, + im-> + integ_algs[integ_alg].alg, + (u8 *) ik->data, ik->len); + if (~0 == sa->integ_key_index) + { + pool_put (im->sad, sa); + return VNET_API_ERROR_KEY_LENGTH; + } } err = ipsec_check_support_cb (im, sa); @@ -291,7 +298,8 @@ ipsec_sa_del (ipsec_sa_t * sa) dpo_reset (&sa->dpo); } vnet_crypto_key_del (vm, sa->crypto_key_index); - vnet_crypto_key_del (vm, sa->integ_key_index); + if (sa->integ_alg != IPSEC_INTEG_ALG_NONE) + vnet_crypto_key_del (vm, sa->integ_key_index); pool_put (im->sad, sa); } |