aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/ikev2/ikev2.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/ikev2/ikev2.c')
-rw-r--r--src/plugins/ikev2/ikev2.c119
1 files changed, 83 insertions, 36 deletions
diff --git a/src/plugins/ikev2/ikev2.c b/src/plugins/ikev2/ikev2.c
index 08a66cbf8fa..c11bd0f9b08 100644
--- a/src/plugins/ikev2/ikev2.c
+++ b/src/plugins/ikev2/ikev2.c
@@ -149,9 +149,8 @@ ikev2_select_proposal (ikev2_sa_proposal_t * proposals,
if (prot_id == IKEV2_PROTOCOL_IKE)
{
mandatory_bitmap = (1 << IKEV2_TRANSFORM_TYPE_ENCR) |
- (1 << IKEV2_TRANSFORM_TYPE_PRF) |
- (1 << IKEV2_TRANSFORM_TYPE_INTEG) | (1 << IKEV2_TRANSFORM_TYPE_DH);
- optional_bitmap = mandatory_bitmap;
+ (1 << IKEV2_TRANSFORM_TYPE_PRF) | (1 << IKEV2_TRANSFORM_TYPE_DH);
+ optional_bitmap = mandatory_bitmap | (1 << IKEV2_TRANSFORM_TYPE_INTEG);
}
else if (prot_id == IKEV2_PROTOCOL_ESP)
{
@@ -459,7 +458,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;
+ u16 integ_key_len = 0, salt_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);
@@ -470,6 +469,8 @@ ikev2_calc_keys (ikev2_sa_t * sa)
if (tr_integ)
integ_key_len = tr_integ->key_len;
+ else
+ salt_len = sizeof (u32);
vec_append (s, sa->i_nonce);
vec_append (s, sa->r_nonce);
@@ -487,7 +488,8 @@ ikev2_calc_keys (ikev2_sa_t * sa)
int len = tr_prf->key_trunc + /* SK_d */
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 */
+ tr_prf->key_len * 2 + /* SK_pi, SK_pr */
+ salt_len * 2;
keymat = ikev2_calc_prfplus (tr_prf, skeyseed, s, len);
vec_free (skeyseed);
@@ -514,14 +516,14 @@ ikev2_calc_keys (ikev2_sa_t * sa)
}
/* SK_ei */
- sa->sk_ei = vec_new (u8, tr_encr->key_len);
- clib_memcpy_fast (sa->sk_ei, keymat + pos, tr_encr->key_len);
- pos += tr_encr->key_len;
+ sa->sk_ei = vec_new (u8, tr_encr->key_len + salt_len);
+ clib_memcpy_fast (sa->sk_ei, keymat + pos, tr_encr->key_len + salt_len);
+ pos += tr_encr->key_len + salt_len;
/* SK_er */
- sa->sk_er = vec_new (u8, tr_encr->key_len);
- clib_memcpy_fast (sa->sk_er, keymat + pos, tr_encr->key_len);
- pos += tr_encr->key_len;
+ sa->sk_er = vec_new (u8, tr_encr->key_len + salt_len);
+ clib_memcpy_fast (sa->sk_er, keymat + pos, tr_encr->key_len + salt_len);
+ pos += tr_encr->key_len + salt_len;
/* SK_pi */
sa->sk_pi = vec_new (u8, tr_prf->key_len);
@@ -833,17 +835,22 @@ ikev2_process_sa_init_resp (vlib_main_t * vm, ikev2_sa_t * sa,
static u8 *
ikev2_decrypt_sk_payload (ikev2_sa_t * sa, ike_header_t * ike, u8 * payload)
{
+ ikev2_main_per_thread_data_t *ptd = ikev2_get_per_thread_data ();
int p = 0;
- u8 last_payload = 0;
+ u8 last_payload = 0, *plaintext = 0;
u8 *hmac = 0;
u32 len = clib_net_to_host_u32 (ike->length);
ike_payload_header_t *ikep = 0;
u32 plen = 0;
ikev2_sa_transform_t *tr_integ;
+ ikev2_sa_transform_t *tr_encr;
tr_integ =
ikev2_sa_get_td_for_type (sa->r_proposals, IKEV2_TRANSFORM_TYPE_INTEG);
+ tr_encr =
+ ikev2_sa_get_td_for_type (sa->r_proposals, IKEV2_TRANSFORM_TYPE_ENCR);
+ int is_aead = tr_encr->encr_type == IKEV2_TRANSFORM_ENCR_TYPE_AES_GCM_16;
- if (!sa->sk_ar || !sa->sk_ai)
+ if ((!sa->sk_ar || !sa->sk_ai) && !is_aead)
return 0;
while (p < len &&
@@ -880,21 +887,45 @@ ikev2_decrypt_sk_payload (ikev2_sa_t * sa, ike_header_t * ike, u8 * payload)
return 0;
}
- hmac =
- ikev2_calc_integr (tr_integ, sa->is_initiator ? sa->sk_ar : sa->sk_ai,
- (u8 *) ike, len - tr_integ->key_trunc);
+ if (is_aead)
+ {
+ if (plen < sizeof (*ikep) + IKEV2_GCM_ICV_SIZE)
+ return 0;
- plen = plen - sizeof (*ikep) - tr_integ->key_trunc;
+ plen -= sizeof (*ikep) + IKEV2_GCM_ICV_SIZE;
+ u8 *aad = (u8 *) ike;
+ u32 aad_len = ikep->payload - aad;
+ u8 *tag = ikep->payload + plen;
- if (memcmp (hmac, &ikep->payload[plen], tr_integ->key_trunc))
+ plaintext = ikev2_decrypt_aead_data (ptd, sa, tr_encr, ikep->payload,
+ plen, aad, aad_len, tag);
+ }
+ else
{
- ikev2_elog_error ("message integrity check failed");
+ if (len < tr_integ->key_trunc)
+ return 0;
+
+ hmac =
+ ikev2_calc_integr (tr_integ, sa->is_initiator ? sa->sk_ar : sa->sk_ai,
+ (u8 *) ike, len - tr_integ->key_trunc);
+
+ if (plen < sizeof (*ikep) + tr_integ->key_trunc)
+ return 0;
+
+ plen = plen - sizeof (*ikep) - tr_integ->key_trunc;
+
+ if (memcmp (hmac, &ikep->payload[plen], tr_integ->key_trunc))
+ {
+ ikev2_elog_error ("message integrity check failed");
+ vec_free (hmac);
+ return 0;
+ }
vec_free (hmac);
- return 0;
+
+ plaintext = ikev2_decrypt_data (ptd, sa, tr_encr, ikep->payload, plen);
}
- vec_free (hmac);
- return ikev2_decrypt_data (sa, ikep->payload, plen);
+ return plaintext;
}
static_always_inline int
@@ -2296,7 +2327,7 @@ ikev2_generate_message (ikev2_sa_t * sa, ike_header_t * ike, void *user,
}
else
{
-
+ ikev2_main_per_thread_data_t *ptd = ikev2_get_per_thread_data ();
ikev2_payload_chain_add_padding (chain, tr_encr->block_size);
/* SK payload */
@@ -2304,24 +2335,40 @@ ikev2_generate_message (ikev2_sa_t * sa, ike_header_t * ike, void *user,
ph = (ike_payload_header_t *) & ike->payload[0];
ph->nextpayload = chain->first_payload_type;
ph->flags = 0;
- int enc_len = ikev2_encrypt_data (sa, chain->data, ph->payload);
- plen += enc_len;
-
- /* add space for hmac */
- plen += tr_integ->key_trunc;
+ int is_aead =
+ tr_encr->encr_type == IKEV2_TRANSFORM_ENCR_TYPE_AES_GCM_16;
+ int iv_len = is_aead ? IKEV2_GCM_IV_SIZE : tr_encr->block_size;
+ plen += vec_len (chain->data) + iv_len;
+
+ /* add space for hmac/tag */
+ if (tr_integ)
+ plen += tr_integ->key_trunc;
+ else
+ plen += IKEV2_GCM_ICV_SIZE;
tlen += plen;
/* payload and total length */
ph->length = clib_host_to_net_u16 (plen);
ike->length = clib_host_to_net_u32 (tlen);
- /* calc integrity data for whole packet except hash itself */
- integ =
- ikev2_calc_integr (tr_integ, sa->is_initiator ? sa->sk_ai : sa->sk_ar,
- (u8 *) ike, tlen - tr_integ->key_trunc);
-
- clib_memcpy_fast (ike->payload + tlen - tr_integ->key_trunc -
- sizeof (*ike), integ, tr_integ->key_trunc);
+ if (is_aead)
+ {
+ ikev2_encrypt_aead_data (ptd, sa, tr_encr, chain->data,
+ ph->payload, (u8 *) ike,
+ sizeof (*ike) + sizeof (*ph),
+ ph->payload + plen - sizeof (*ph) -
+ IKEV2_GCM_ICV_SIZE);
+ }
+ else
+ {
+ ikev2_encrypt_data (ptd, sa, tr_encr, chain->data, ph->payload);
+ integ =
+ ikev2_calc_integr (tr_integ,
+ sa->is_initiator ? sa->sk_ai : sa->sk_ar,
+ (u8 *) ike, tlen - tr_integ->key_trunc);
+ clib_memcpy_fast (ike->payload + tlen - tr_integ->key_trunc -
+ sizeof (*ike), integ, tr_integ->key_trunc);
+ }
/* store whole IKE payload - needed for retransmit */
vec_free (sa->last_res_packet_data);
@@ -2988,7 +3035,7 @@ ikev2_set_initiator_proposals (vlib_main_t * vm, ikev2_sa_t * sa,
return r;
}
- if (is_ike || IKEV2_TRANSFORM_ENCR_TYPE_AES_GCM_16 != ts->crypto_alg)
+ if (IKEV2_TRANSFORM_INTEG_TYPE_NONE != ts->integ_alg)
{
/* Integrity */
error = 1;