blob: 296654ecbac374a9e4c0fd20686f2498b21acf1a [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
2 * Copyright (c) 2015 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include <vlib/vlib.h>
17#include <vnet/vnet.h>
18#include <vnet/pg/pg.h>
19#include <vppinfra/error.h>
Dave Barach68b0fb02017-02-28 15:15:56 -050020#include <vnet/udp/udp.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070021#include <vnet/ipsec/ipsec.h>
22#include <vnet/ipsec/ikev2.h>
23#include <vnet/ipsec/ikev2_priv.h>
Radu Nicolaucb33dc22017-02-16 16:49:46 +000024#include <openssl/sha.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070025
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -070026static int ikev2_delete_tunnel_interface (vnet_main_t * vnm,
27 ikev2_sa_t * sa,
28 ikev2_child_sa_t * child);
Ed Warnickecb9cada2015-12-08 15:45:58 -070029
Ed Warnickecb9cada2015-12-08 15:45:58 -070030#define ikev2_set_state(sa, v) do { \
31 (sa)->state = v; \
32 clib_warning("sa state changed to " #v); \
33 } while(0);
34
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -070035typedef struct
36{
Ed Warnickecb9cada2015-12-08 15:45:58 -070037 u32 next_index;
38 u32 sw_if_index;
39} ikev2_trace_t;
40
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -070041static u8 *
42format_ikev2_trace (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -070043{
44 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
45 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -070046 ikev2_trace_t *t = va_arg (*args, ikev2_trace_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -070047
48 s = format (s, "ikev2: sw_if_index %d, next index %d",
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -070049 t->sw_if_index, t->next_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -070050 return s;
51}
52
Jean-Mickael Guerin8941ec22016-03-04 14:14:21 +010053static vlib_node_registration_t ikev2_node;
Ed Warnickecb9cada2015-12-08 15:45:58 -070054
55#define foreach_ikev2_error \
56_(PROCESSED, "IKEv2 packets processed") \
57_(IKE_SA_INIT_RETRANSMIT, "IKE_SA_INIT retransmit ") \
58_(IKE_SA_INIT_IGNORE, "IKE_SA_INIT ignore (IKE SA already auth)") \
59_(IKE_REQ_RETRANSMIT, "IKE request retransmit") \
60_(IKE_REQ_IGNORE, "IKE request ignore (old msgid)") \
61_(NOT_IKEV2, "Non IKEv2 packets received")
62
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -070063typedef enum
64{
Ed Warnickecb9cada2015-12-08 15:45:58 -070065#define _(sym,str) IKEV2_ERROR_##sym,
66 foreach_ikev2_error
67#undef _
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -070068 IKEV2_N_ERROR,
Ed Warnickecb9cada2015-12-08 15:45:58 -070069} ikev2_error_t;
70
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -070071static char *ikev2_error_strings[] = {
Ed Warnickecb9cada2015-12-08 15:45:58 -070072#define _(sym,string) string,
73 foreach_ikev2_error
74#undef _
75};
76
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -070077typedef enum
78{
Ed Warnickecb9cada2015-12-08 15:45:58 -070079 IKEV2_NEXT_IP4_LOOKUP,
80 IKEV2_NEXT_ERROR_DROP,
81 IKEV2_N_NEXT,
82} ikev2_next_t;
83
84static ikev2_sa_transform_t *
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -070085ikev2_find_transform_data (ikev2_sa_transform_t * t)
Ed Warnickecb9cada2015-12-08 15:45:58 -070086{
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -070087 ikev2_main_t *km = &ikev2_main;
88 ikev2_sa_transform_t *td;
Ed Warnickecb9cada2015-12-08 15:45:58 -070089
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -070090 vec_foreach (td, km->supported_transforms)
91 {
92 if (td->type != t->type)
93 continue;
Ed Warnickecb9cada2015-12-08 15:45:58 -070094
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -070095 if (td->transform_id != t->transform_id)
96 continue;
Ed Warnickecb9cada2015-12-08 15:45:58 -070097
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -070098 if (td->type == IKEV2_TRANSFORM_TYPE_ENCR)
99 {
100 if (vec_len (t->attrs) != 4 || t->attrs[0] != 0x80
101 || t->attrs[1] != 14)
102 continue;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700103
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700104 if (((t->attrs[2] << 8 | t->attrs[3]) / 8) != td->key_len)
105 continue;
106 }
107 return td;
108 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700109 return 0;
110}
111
112static ikev2_sa_proposal_t *
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700113ikev2_select_proposal (ikev2_sa_proposal_t * proposals,
114 ikev2_protocol_id_t prot_id)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700115{
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700116 ikev2_sa_proposal_t *rv = 0;
117 ikev2_sa_proposal_t *proposal;
118 ikev2_sa_transform_t *transform, *new_t;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700119 u8 mandatory_bitmap, optional_bitmap;
120
121 if (prot_id == IKEV2_PROTOCOL_IKE)
122 {
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700123 mandatory_bitmap = (1 << IKEV2_TRANSFORM_TYPE_ENCR) |
124 (1 << IKEV2_TRANSFORM_TYPE_PRF) |
125 (1 << IKEV2_TRANSFORM_TYPE_INTEG) | (1 << IKEV2_TRANSFORM_TYPE_DH);
126 optional_bitmap = mandatory_bitmap;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700127 }
128 else if (prot_id == IKEV2_PROTOCOL_ESP)
129 {
130 mandatory_bitmap = (1 << IKEV2_TRANSFORM_TYPE_ENCR) |
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700131 (1 << IKEV2_TRANSFORM_TYPE_ESN);
132 optional_bitmap = mandatory_bitmap |
133 (1 << IKEV2_TRANSFORM_TYPE_INTEG) | (1 << IKEV2_TRANSFORM_TYPE_DH);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700134 }
135 else if (prot_id == IKEV2_PROTOCOL_AH)
136 {
137 mandatory_bitmap = (1 << IKEV2_TRANSFORM_TYPE_INTEG) |
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700138 (1 << IKEV2_TRANSFORM_TYPE_ESN);
139 optional_bitmap = mandatory_bitmap | (1 << IKEV2_TRANSFORM_TYPE_DH);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700140 }
141 else
142 return 0;
143
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700144 vec_add2 (rv, proposal, 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700145
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700146 vec_foreach (proposal, proposals)
147 {
148 u8 bitmap = 0;
149 if (proposal->protocol_id != prot_id)
150 continue;
151
152 vec_foreach (transform, proposal->transforms)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700153 {
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700154 if ((1 << transform->type) & bitmap)
155 continue;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700156
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700157 if (ikev2_find_transform_data (transform))
158 {
159 bitmap |= 1 << transform->type;
160 vec_add2 (rv->transforms, new_t, 1);
161 clib_memcpy (new_t, transform, sizeof (*new_t));
162 new_t->attrs = vec_dup (transform->attrs);
163 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700164 }
165
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700166 clib_warning ("bitmap is %x mandatory is %x optional is %x",
167 bitmap, mandatory_bitmap, optional_bitmap);
168
169 if ((bitmap & mandatory_bitmap) == mandatory_bitmap &&
170 (bitmap & ~optional_bitmap) == 0)
171 {
172 rv->proposal_num = proposal->proposal_num;
173 rv->protocol_id = proposal->protocol_id;
174 RAND_bytes ((u8 *) & rv->spi, sizeof (rv->spi));
175 goto done;
176 }
177 else
178 {
179 vec_free (rv->transforms);
180 }
181 }
182
183 vec_free (rv);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700184done:
185 return rv;
186}
187
188ikev2_sa_transform_t *
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700189ikev2_sa_get_td_for_type (ikev2_sa_proposal_t * p,
190 ikev2_transform_type_t type)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700191{
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700192 ikev2_sa_transform_t *t;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700193
194 if (!p)
195 return 0;
196
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700197 vec_foreach (t, p->transforms)
198 {
199 if (t->type == type)
200 return ikev2_find_transform_data (t);
201 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700202 return 0;
203}
204
205ikev2_child_sa_t *
Radu Nicolaucb33dc22017-02-16 16:49:46 +0000206ikev2_sa_get_child (ikev2_sa_t * sa, u32 spi, ikev2_protocol_id_t prot_id,
207 int by_initiator)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700208{
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700209 ikev2_child_sa_t *c;
210 vec_foreach (c, sa->childs)
211 {
Radu Nicolaucb33dc22017-02-16 16:49:46 +0000212 ikev2_sa_proposal_t *proposal =
213 by_initiator ? &c->i_proposals[0] : &c->r_proposals[0];
214 if (proposal && proposal->spi == spi && proposal->protocol_id == prot_id)
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700215 return c;
216 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700217
218 return 0;
219}
220
221void
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700222ikev2_sa_free_proposal_vector (ikev2_sa_proposal_t ** v)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700223{
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700224 ikev2_sa_proposal_t *p;
225 ikev2_sa_transform_t *t;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700226
227 if (!*v)
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700228 return;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700229
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700230 vec_foreach (p, *v)
231 {
232 vec_foreach (t, p->transforms)
233 {
234 vec_free (t->attrs);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700235 }
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700236 vec_free (p->transforms);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700237 }
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700238 vec_free (*v);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700239};
240
241static void
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700242ikev2_sa_free_all_child_sa (ikev2_child_sa_t ** childs)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700243{
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700244 ikev2_child_sa_t *c;
245 vec_foreach (c, *childs)
246 {
247 ikev2_sa_free_proposal_vector (&c->r_proposals);
248 ikev2_sa_free_proposal_vector (&c->i_proposals);
249 vec_free (c->sk_ai);
250 vec_free (c->sk_ar);
251 vec_free (c->sk_ei);
252 vec_free (c->sk_er);
253 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700254
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700255 vec_free (*childs);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700256}
257
258static void
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700259ikev2_sa_del_child_sa (ikev2_sa_t * sa, ikev2_child_sa_t * child)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700260{
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700261 ikev2_sa_free_proposal_vector (&child->r_proposals);
262 ikev2_sa_free_proposal_vector (&child->i_proposals);
263 vec_free (child->sk_ai);
264 vec_free (child->sk_ar);
265 vec_free (child->sk_ei);
266 vec_free (child->sk_er);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700267
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700268 vec_del1 (sa->childs, child - sa->childs);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700269}
270
271static void
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700272ikev2_sa_free_all_vec (ikev2_sa_t * sa)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700273{
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700274 vec_free (sa->i_nonce);
275 vec_free (sa->i_dh_data);
276 vec_free (sa->dh_shared_key);
Radu Nicolaucb33dc22017-02-16 16:49:46 +0000277 vec_free (sa->dh_private_key);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700278
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700279 ikev2_sa_free_proposal_vector (&sa->r_proposals);
280 ikev2_sa_free_proposal_vector (&sa->i_proposals);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700281
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700282 vec_free (sa->sk_d);
283 vec_free (sa->sk_ai);
284 vec_free (sa->sk_ar);
285 vec_free (sa->sk_ei);
286 vec_free (sa->sk_er);
287 vec_free (sa->sk_pi);
288 vec_free (sa->sk_pr);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700289
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700290 vec_free (sa->i_id.data);
291 vec_free (sa->i_auth.data);
292 vec_free (sa->r_id.data);
293 vec_free (sa->r_auth.data);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700294 if (sa->r_auth.key)
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700295 EVP_PKEY_free (sa->r_auth.key);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700296
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700297 vec_free (sa->del);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700298
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700299 ikev2_sa_free_all_child_sa (&sa->childs);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700300}
301
302static void
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700303ikev2_delete_sa (ikev2_sa_t * sa)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700304{
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700305 ikev2_main_t *km = &ikev2_main;
Damjan Marion586afd72017-04-05 19:18:20 +0200306 u32 thread_index = vlib_get_thread_index ();
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700307 uword *p;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700308
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700309 ikev2_sa_free_all_vec (sa);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700310
Damjan Marion586afd72017-04-05 19:18:20 +0200311 p = hash_get (km->per_thread_data[thread_index].sa_by_rspi, sa->rspi);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700312 if (p)
313 {
Damjan Marion586afd72017-04-05 19:18:20 +0200314 hash_unset (km->per_thread_data[thread_index].sa_by_rspi, sa->rspi);
315 pool_put (km->per_thread_data[thread_index].sas, sa);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700316 }
317}
318
319static void
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700320ikev2_generate_sa_init_data (ikev2_sa_t * sa)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700321{
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700322 ikev2_sa_transform_t *t = 0, *t2;
323 ikev2_main_t *km = &ikev2_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700324
325 if (sa->dh_group == IKEV2_TRANSFORM_DH_TYPE_NONE)
326 {
327 return;
328 }
329
330 /* check if received DH group is on our list of supported groups */
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700331 vec_foreach (t2, km->supported_transforms)
332 {
333 if (t2->type == IKEV2_TRANSFORM_TYPE_DH && sa->dh_group == t2->dh_type)
334 {
335 t = t2;
336 break;
337 }
338 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700339
340 if (!t)
341 {
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700342 clib_warning ("unknown dh data group %u (data len %u)", sa->dh_group,
343 vec_len (sa->i_dh_data));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700344 sa->dh_group = IKEV2_TRANSFORM_DH_TYPE_NONE;
345 return;
346 }
347
Radu Nicolaucb33dc22017-02-16 16:49:46 +0000348 if (sa->is_initiator)
349 {
350 /* generate rspi */
351 RAND_bytes ((u8 *) & sa->ispi, 8);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700352
Radu Nicolaucb33dc22017-02-16 16:49:46 +0000353 /* generate nonce */
354 sa->i_nonce = vec_new (u8, IKEV2_NONCE_SIZE);
355 RAND_bytes ((u8 *) sa->i_nonce, IKEV2_NONCE_SIZE);
356 }
357 else
358 {
359 /* generate rspi */
360 RAND_bytes ((u8 *) & sa->rspi, 8);
361
362 /* generate nonce */
363 sa->r_nonce = vec_new (u8, IKEV2_NONCE_SIZE);
364 RAND_bytes ((u8 *) sa->r_nonce, IKEV2_NONCE_SIZE);
365 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700366
367 /* generate dh keys */
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700368 ikev2_generate_dh (sa, t);
Radu Nicolaucb33dc22017-02-16 16:49:46 +0000369
370}
371
372static void
373ikev2_complete_sa_data (ikev2_sa_t * sa, ikev2_sa_t * sai)
374{
375 ikev2_sa_transform_t *t = 0, *t2;
376 ikev2_main_t *km = &ikev2_main;
377
378
379 /*move some data to the new SA */
380#define _(A) ({void* __tmp__ = (A); (A) = 0; __tmp__;})
381 sa->i_nonce = _(sai->i_nonce);
382 sa->i_dh_data = _(sai->i_dh_data);
383 sa->dh_private_key = _(sai->dh_private_key);
384 sa->iaddr.as_u32 = sai->iaddr.as_u32;
385 sa->raddr.as_u32 = sai->raddr.as_u32;
386 sa->is_initiator = sai->is_initiator;
387 sa->profile = sai->profile;
388 sa->i_id.type = sai->i_id.type;
389 sa->i_id.data = _(sai->i_id.data);
390 sa->i_auth.method = sai->i_auth.method;
391 sa->i_auth.hex = sai->i_auth.hex;
392 sa->i_auth.data = _(sai->i_auth.data);
393 sa->i_auth.key = _(sai->i_auth.key);
394 sa->last_sa_init_req_packet_data = _(sai->last_sa_init_req_packet_data);
395 sa->childs = _(sai->childs);
396#undef _
397
398
399 if (sa->dh_group == IKEV2_TRANSFORM_DH_TYPE_NONE)
400 {
401 return;
402 }
403
404 /* check if received DH group is on our list of supported groups */
405 vec_foreach (t2, km->supported_transforms)
406 {
407 if (t2->type == IKEV2_TRANSFORM_TYPE_DH && sa->dh_group == t2->dh_type)
408 {
409 t = t2;
410 break;
411 }
412 }
413
414 if (!t)
415 {
416 clib_warning ("unknown dh data group %u (data len %u)", sa->dh_group,
417 vec_len (sa->i_dh_data));
418 sa->dh_group = IKEV2_TRANSFORM_DH_TYPE_NONE;
419 return;
420 }
421
422
423 /* generate dh keys */
424 ikev2_complete_dh (sa, t);
425
Ed Warnickecb9cada2015-12-08 15:45:58 -0700426}
427
428static void
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700429ikev2_calc_keys (ikev2_sa_t * sa)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700430{
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700431 u8 *tmp;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700432 /* calculate SKEYSEED = prf(Ni | Nr, g^ir) */
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700433 u8 *skeyseed = 0;
434 u8 *s = 0;
435 ikev2_sa_transform_t *tr_encr, *tr_prf, *tr_integ;
436 tr_encr =
437 ikev2_sa_get_td_for_type (sa->r_proposals, IKEV2_TRANSFORM_TYPE_ENCR);
438 tr_prf =
439 ikev2_sa_get_td_for_type (sa->r_proposals, IKEV2_TRANSFORM_TYPE_PRF);
440 tr_integ =
441 ikev2_sa_get_td_for_type (sa->r_proposals, IKEV2_TRANSFORM_TYPE_INTEG);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700442
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700443 vec_append (s, sa->i_nonce);
444 vec_append (s, sa->r_nonce);
445 skeyseed = ikev2_calc_prf (tr_prf, s, sa->dh_shared_key);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700446
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700447 /* Calculate S = Ni | Nr | SPIi | SPIr */
448 u64 *spi;
449 vec_add2 (s, tmp, 2 * sizeof (*spi));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700450 spi = (u64 *) tmp;
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700451 spi[0] = clib_host_to_net_u64 (sa->ispi);
452 spi[1] = clib_host_to_net_u64 (sa->rspi);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700453
454 /* calculate PRFplus */
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700455 u8 *keymat;
456 int len = tr_prf->key_trunc + /* SK_d */
457 tr_integ->key_len * 2 + /* SK_ai, SK_ar */
458 tr_encr->key_len * 2 + /* SK_ei, SK_er */
459 tr_prf->key_len * 2; /* SK_pi, SK_pr */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700460
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700461 keymat = ikev2_calc_prfplus (tr_prf, skeyseed, s, len);
462 vec_free (skeyseed);
463 vec_free (s);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700464
465 int pos = 0;
466
467 /* SK_d */
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700468 sa->sk_d = vec_new (u8, tr_prf->key_trunc);
469 clib_memcpy (sa->sk_d, keymat + pos, tr_prf->key_trunc);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700470 pos += tr_prf->key_trunc;
471
472 /* SK_ai */
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700473 sa->sk_ai = vec_new (u8, tr_integ->key_len);
474 clib_memcpy (sa->sk_ai, keymat + pos, tr_integ->key_len);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700475 pos += tr_integ->key_len;
476
477 /* SK_ar */
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700478 sa->sk_ar = vec_new (u8, tr_integ->key_len);
479 clib_memcpy (sa->sk_ar, keymat + pos, tr_integ->key_len);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700480 pos += tr_integ->key_len;
481
482 /* SK_ei */
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700483 sa->sk_ei = vec_new (u8, tr_encr->key_len);
484 clib_memcpy (sa->sk_ei, keymat + pos, tr_encr->key_len);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700485 pos += tr_encr->key_len;
486
487 /* SK_er */
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700488 sa->sk_er = vec_new (u8, tr_encr->key_len);
489 clib_memcpy (sa->sk_er, keymat + pos, tr_encr->key_len);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700490 pos += tr_encr->key_len;
491
492 /* SK_pi */
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700493 sa->sk_pi = vec_new (u8, tr_prf->key_len);
494 clib_memcpy (sa->sk_pi, keymat + pos, tr_prf->key_len);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700495 pos += tr_prf->key_len;
496
497 /* SK_pr */
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700498 sa->sk_pr = vec_new (u8, tr_prf->key_len);
499 clib_memcpy (sa->sk_pr, keymat + pos, tr_prf->key_len);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700500 pos += tr_prf->key_len;
501
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700502 vec_free (keymat);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700503}
504
505static void
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700506ikev2_calc_child_keys (ikev2_sa_t * sa, ikev2_child_sa_t * child)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700507{
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700508 u8 *s = 0;
509 ikev2_sa_transform_t *tr_prf, *ctr_encr, *ctr_integ;
510 tr_prf =
511 ikev2_sa_get_td_for_type (sa->r_proposals, IKEV2_TRANSFORM_TYPE_PRF);
512 ctr_encr =
513 ikev2_sa_get_td_for_type (child->r_proposals, IKEV2_TRANSFORM_TYPE_ENCR);
514 ctr_integ =
515 ikev2_sa_get_td_for_type (child->r_proposals, IKEV2_TRANSFORM_TYPE_INTEG);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700516
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700517 vec_append (s, sa->i_nonce);
518 vec_append (s, sa->r_nonce);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700519 /* calculate PRFplus */
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700520 u8 *keymat;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700521 int len = ctr_encr->key_len * 2 + ctr_integ->key_len * 2;
522
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700523 keymat = ikev2_calc_prfplus (tr_prf, sa->sk_d, s, len);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700524
525 int pos = 0;
526
527 /* SK_ei */
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700528 child->sk_ei = vec_new (u8, ctr_encr->key_len);
529 clib_memcpy (child->sk_ei, keymat + pos, ctr_encr->key_len);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700530 pos += ctr_encr->key_len;
531
532 /* SK_ai */
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700533 child->sk_ai = vec_new (u8, ctr_integ->key_len);
534 clib_memcpy (child->sk_ai, keymat + pos, ctr_integ->key_len);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700535 pos += ctr_integ->key_len;
536
537 /* SK_er */
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700538 child->sk_er = vec_new (u8, ctr_encr->key_len);
539 clib_memcpy (child->sk_er, keymat + pos, ctr_encr->key_len);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700540 pos += ctr_encr->key_len;
541
542 /* SK_ar */
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700543 child->sk_ar = vec_new (u8, ctr_integ->key_len);
544 clib_memcpy (child->sk_ar, keymat + pos, ctr_integ->key_len);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700545 pos += ctr_integ->key_len;
546
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700547 ASSERT (pos == len);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700548
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700549 vec_free (keymat);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700550}
551
552static void
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700553ikev2_process_sa_init_req (vlib_main_t * vm, ikev2_sa_t * sa,
554 ike_header_t * ike)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700555{
556 int p = 0;
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700557 u32 len = clib_net_to_host_u32 (ike->length);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700558 u8 payload = ike->nextpayload;
559
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700560 clib_warning ("ispi %lx rspi %lx nextpayload %x version %x "
561 "exchange %x flags %x msgid %x length %u",
562 clib_net_to_host_u64 (ike->ispi),
563 clib_net_to_host_u64 (ike->rspi),
564 payload, ike->version,
565 ike->exchange, ike->flags,
566 clib_net_to_host_u32 (ike->msgid), len);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700567
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700568 sa->ispi = clib_net_to_host_u64 (ike->ispi);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700569
570 /* store whole IKE payload - needed for PSK auth */
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700571 vec_free (sa->last_sa_init_req_packet_data);
572 vec_add (sa->last_sa_init_req_packet_data, ike, len);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700573
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700574 while (p < len && payload != IKEV2_PAYLOAD_NONE)
575 {
576 ike_payload_header_t *ikep = (ike_payload_header_t *) & ike->payload[p];
577 u32 plen = clib_net_to_host_u16 (ikep->length);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700578
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700579 if (plen < sizeof (ike_payload_header_t))
580 return;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700581
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700582 if (payload == IKEV2_PAYLOAD_SA)
583 {
584 ikev2_sa_free_proposal_vector (&sa->i_proposals);
585 sa->i_proposals = ikev2_parse_sa_payload (ikep);
586 }
587 else if (payload == IKEV2_PAYLOAD_KE)
588 {
589 ike_ke_payload_header_t *ke = (ike_ke_payload_header_t *) ikep;
590 sa->dh_group = clib_net_to_host_u16 (ke->dh_group);
591 vec_free (sa->i_dh_data);
592 vec_add (sa->i_dh_data, ke->payload, plen - sizeof (*ke));
593 }
594 else if (payload == IKEV2_PAYLOAD_NONCE)
595 {
596 vec_free (sa->i_nonce);
597 vec_add (sa->i_nonce, ikep->payload, plen - sizeof (*ikep));
598 }
599 else if (payload == IKEV2_PAYLOAD_NOTIFY)
600 {
601 ikev2_notify_t *n = ikev2_parse_notify_payload (ikep);
602 vec_free (n);
603 }
604 else if (payload == IKEV2_PAYLOAD_VENDOR)
605 {
606 ikev2_parse_vendor_payload (ikep);
607 }
608 else
609 {
610 clib_warning ("unknown payload %u flags %x length %u", payload,
611 ikep->flags, plen);
612 if (ikep->flags & IKEV2_PAYLOAD_FLAG_CRITICAL)
613 {
614 ikev2_set_state (sa, IKEV2_STATE_NOTIFY_AND_DELETE);
615 sa->unsupported_cp = payload;
616 return;
617 }
618 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700619
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700620 payload = ikep->nextpayload;
621 p += plen;
622 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700623
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700624 ikev2_set_state (sa, IKEV2_STATE_SA_INIT);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700625}
626
Radu Nicolaucb33dc22017-02-16 16:49:46 +0000627static void
628ikev2_process_sa_init_resp (vlib_main_t * vm, ikev2_sa_t * sa,
629 ike_header_t * ike)
630{
631 int p = 0;
632 u32 len = clib_net_to_host_u32 (ike->length);
633 u8 payload = ike->nextpayload;
634
635 clib_warning ("ispi %lx rspi %lx nextpayload %x version %x "
636 "exchange %x flags %x msgid %x length %u",
637 clib_net_to_host_u64 (ike->ispi),
638 clib_net_to_host_u64 (ike->rspi),
639 payload, ike->version,
640 ike->exchange, ike->flags,
641 clib_net_to_host_u32 (ike->msgid), len);
642
643 sa->ispi = clib_net_to_host_u64 (ike->ispi);
644 sa->rspi = clib_net_to_host_u64 (ike->rspi);
645
646 /* store whole IKE payload - needed for PSK auth */
647 vec_free (sa->last_sa_init_res_packet_data);
648 vec_add (sa->last_sa_init_res_packet_data, ike, len);
649
650 while (p < len && payload != IKEV2_PAYLOAD_NONE)
651 {
652 ike_payload_header_t *ikep = (ike_payload_header_t *) & ike->payload[p];
653 u32 plen = clib_net_to_host_u16 (ikep->length);
654
655 if (plen < sizeof (ike_payload_header_t))
656 return;
657
658 if (payload == IKEV2_PAYLOAD_SA)
659 {
660 ikev2_sa_free_proposal_vector (&sa->r_proposals);
661 sa->r_proposals = ikev2_parse_sa_payload (ikep);
662 if (sa->r_proposals)
663 {
664 ikev2_set_state (sa, IKEV2_STATE_SA_INIT);
665 ike->msgid =
666 clib_host_to_net_u32 (clib_net_to_host_u32 (ike->msgid) + 1);
667 }
668 }
669 else if (payload == IKEV2_PAYLOAD_KE)
670 {
671 ike_ke_payload_header_t *ke = (ike_ke_payload_header_t *) ikep;
672 sa->dh_group = clib_net_to_host_u16 (ke->dh_group);
673 vec_free (sa->r_dh_data);
674 vec_add (sa->r_dh_data, ke->payload, plen - sizeof (*ke));
675 }
676 else if (payload == IKEV2_PAYLOAD_NONCE)
677 {
678 vec_free (sa->r_nonce);
679 vec_add (sa->r_nonce, ikep->payload, plen - sizeof (*ikep));
680 }
681 else if (payload == IKEV2_PAYLOAD_NOTIFY)
682 {
683 ikev2_notify_t *n = ikev2_parse_notify_payload (ikep);
684 vec_free (n);
685 }
686 else if (payload == IKEV2_PAYLOAD_VENDOR)
687 {
688 ikev2_parse_vendor_payload (ikep);
689 }
690 else
691 {
692 clib_warning ("unknown payload %u flags %x length %u", payload,
693 ikep->flags, plen);
694 if (ikep->flags & IKEV2_PAYLOAD_FLAG_CRITICAL)
695 {
696 ikev2_set_state (sa, IKEV2_STATE_NOTIFY_AND_DELETE);
697 sa->unsupported_cp = payload;
698 return;
699 }
700 }
701
702 payload = ikep->nextpayload;
703 p += plen;
704 }
705}
706
Ed Warnickecb9cada2015-12-08 15:45:58 -0700707static u8 *
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700708ikev2_decrypt_sk_payload (ikev2_sa_t * sa, ike_header_t * ike, u8 * payload)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700709{
710 int p = 0;
711 u8 last_payload = 0;
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700712 u8 *hmac = 0;
713 u32 len = clib_net_to_host_u32 (ike->length);
714 ike_payload_header_t *ikep = 0;
Benoît Ganned5304452016-04-08 22:25:05 -0700715 u32 plen = 0;
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700716 ikev2_sa_transform_t *tr_integ;
717 tr_integ =
718 ikev2_sa_get_td_for_type (sa->r_proposals, IKEV2_TRANSFORM_TYPE_INTEG);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700719
720 while (p < len &&
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700721 *payload != IKEV2_PAYLOAD_NONE && last_payload != IKEV2_PAYLOAD_SK)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700722 {
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700723 ikep = (ike_payload_header_t *) & ike->payload[p];
724 plen = clib_net_to_host_u16 (ikep->length);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700725
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700726 if (plen < sizeof (*ikep))
727 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700728
729 if (*payload == IKEV2_PAYLOAD_SK)
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700730 {
731 clib_warning ("received IKEv2 payload SK, len %u", plen - 4);
732 last_payload = *payload;
733 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700734 else
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700735 {
736 clib_warning ("unknown payload %u flags %x length %u", payload,
737 ikep->flags, plen);
738 if (ikep->flags & IKEV2_PAYLOAD_FLAG_CRITICAL)
739 {
740 sa->unsupported_cp = *payload;
741 return 0;
742 }
743 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700744
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700745 *payload = ikep->nextpayload;
746 p += plen;
747 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700748
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700749 if (last_payload != IKEV2_PAYLOAD_SK)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700750 {
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700751 clib_warning ("Last payload must be SK");
Ed Warnickecb9cada2015-12-08 15:45:58 -0700752 return 0;
753 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700754
Radu Nicolaucb33dc22017-02-16 16:49:46 +0000755 hmac =
756 ikev2_calc_integr (tr_integ, sa->is_initiator ? sa->sk_ar : sa->sk_ai,
757 (u8 *) ike, len - tr_integ->key_trunc);
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700758
759 plen = plen - sizeof (*ikep) - tr_integ->key_trunc;
760
761 if (memcmp (hmac, &ikep->payload[plen], tr_integ->key_trunc))
762 {
763 clib_warning ("message integrity check failed");
764 vec_free (hmac);
765 return 0;
766 }
767 vec_free (hmac);
768
769 return ikev2_decrypt_data (sa, ikep->payload, plen);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700770}
771
772static void
773ikev2_initial_contact_cleanup (ikev2_sa_t * sa)
774{
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700775 ikev2_main_t *km = &ikev2_main;
776 ikev2_sa_t *tmp;
777 u32 i, *delete = 0;
778 ikev2_child_sa_t *c;
Damjan Marion586afd72017-04-05 19:18:20 +0200779 u32 thread_index = vlib_get_thread_index ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700780
781 if (!sa->initial_contact)
782 return;
783
784 /* find old IKE SAs with the same authenticated identity */
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700785 /* *INDENT-OFF* */
Damjan Marion586afd72017-04-05 19:18:20 +0200786 pool_foreach (tmp, km->per_thread_data[thread_index].sas, ({
Ed Warnickecb9cada2015-12-08 15:45:58 -0700787 if (tmp->i_id.type != sa->i_id.type ||
788 vec_len(tmp->i_id.data) != vec_len(sa->i_id.data) ||
789 memcmp(sa->i_id.data, tmp->i_id.data, vec_len(sa->i_id.data)))
790 continue;
791
792 if (sa->rspi != tmp->rspi)
Damjan Marion586afd72017-04-05 19:18:20 +0200793 vec_add1(delete, tmp - km->per_thread_data[thread_index].sas);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700794 }));
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700795 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700796
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700797 for (i = 0; i < vec_len (delete); i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700798 {
Damjan Marion586afd72017-04-05 19:18:20 +0200799 tmp =
800 pool_elt_at_index (km->per_thread_data[thread_index].sas, delete[i]);
801 vec_foreach (c,
802 tmp->childs) ikev2_delete_tunnel_interface (km->vnet_main,
803 tmp, c);
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700804 ikev2_delete_sa (tmp);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700805 }
806
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700807 vec_free (delete);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700808 sa->initial_contact = 0;
809}
810
811static void
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700812ikev2_process_auth_req (vlib_main_t * vm, ikev2_sa_t * sa, ike_header_t * ike)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700813{
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700814 ikev2_child_sa_t *first_child_sa;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700815 int p = 0;
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700816 u32 len = clib_net_to_host_u32 (ike->length);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700817 u8 payload = ike->nextpayload;
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700818 u8 *plaintext = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700819
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700820 ike_payload_header_t *ikep;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700821 u32 plen;
822
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700823 clib_warning ("ispi %lx rspi %lx nextpayload %x version %x "
824 "exchange %x flags %x msgid %x length %u",
825 clib_net_to_host_u64 (ike->ispi),
826 clib_net_to_host_u64 (ike->rspi),
827 payload, ike->version,
828 ike->exchange, ike->flags,
829 clib_net_to_host_u32 (ike->msgid), len);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700830
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700831 ikev2_calc_keys (sa);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700832
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700833 plaintext = ikev2_decrypt_sk_payload (sa, ike, &payload);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700834
835 if (!plaintext)
836 {
837 if (sa->unsupported_cp)
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700838 ikev2_set_state (sa, IKEV2_STATE_NOTIFY_AND_DELETE);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700839 goto cleanup_and_exit;
840 }
841
Radu Nicolaucb33dc22017-02-16 16:49:46 +0000842 /* select or create 1st child SA */
843 if (sa->is_initiator)
844 {
845 first_child_sa = &sa->childs[0];
846 }
847 else
848 {
849 ikev2_sa_free_all_child_sa (&sa->childs);
850 vec_add2 (sa->childs, first_child_sa, 1);
851 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700852
853
854 /* process encrypted payload */
855 p = 0;
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700856 while (p < vec_len (plaintext) && payload != IKEV2_PAYLOAD_NONE)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700857 {
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700858 ikep = (ike_payload_header_t *) & plaintext[p];
859 plen = clib_net_to_host_u16 (ikep->length);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700860
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700861 if (plen < sizeof (ike_payload_header_t))
862 goto cleanup_and_exit;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700863
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700864 if (payload == IKEV2_PAYLOAD_SA) /* 33 */
865 {
866 clib_warning ("received payload SA, len %u", plen - sizeof (*ikep));
Radu Nicolaucb33dc22017-02-16 16:49:46 +0000867 if (sa->is_initiator)
868 {
869 ikev2_sa_free_proposal_vector (&first_child_sa->r_proposals);
870 first_child_sa->r_proposals = ikev2_parse_sa_payload (ikep);
871 }
872 else
873 {
874 ikev2_sa_free_proposal_vector (&first_child_sa->i_proposals);
875 first_child_sa->i_proposals = ikev2_parse_sa_payload (ikep);
876 }
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700877 }
Matthew Smith1e19ee42017-04-26 15:42:39 -0500878 else if (payload == IKEV2_PAYLOAD_IDI) /* 35 */
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700879 {
880 ike_id_payload_header_t *id = (ike_id_payload_header_t *) ikep;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700881
Matthew Smith1e19ee42017-04-26 15:42:39 -0500882 sa->i_id.type = id->id_type;
883 vec_free (sa->i_id.data);
884 vec_add (sa->i_id.data, id->payload, plen - sizeof (*id));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700885
Matthew Smith1e19ee42017-04-26 15:42:39 -0500886 clib_warning ("received payload IDi, len %u id_type %u",
887 plen - sizeof (*id), id->id_type);
888 }
889 else if (payload == IKEV2_PAYLOAD_IDR) /* 36 */
890 {
891 ike_id_payload_header_t *id = (ike_id_payload_header_t *) ikep;
892
893 sa->r_id.type = id->id_type;
894 vec_free (sa->r_id.data);
895 vec_add (sa->r_id.data, id->payload, plen - sizeof (*id));
896
897 clib_warning ("received payload IDr len %u id_type %u",
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700898 plen - sizeof (*id), id->id_type);
899 }
900 else if (payload == IKEV2_PAYLOAD_AUTH) /* 39 */
901 {
902 ike_auth_payload_header_t *a = (ike_auth_payload_header_t *) ikep;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700903
Radu Nicolaucb33dc22017-02-16 16:49:46 +0000904 if (sa->is_initiator)
905 {
906 sa->r_auth.method = a->auth_method;
907 vec_free (sa->r_auth.data);
908 vec_add (sa->r_auth.data, a->payload, plen - sizeof (*a));
909 }
910 else
911 {
912 sa->i_auth.method = a->auth_method;
913 vec_free (sa->i_auth.data);
914 vec_add (sa->i_auth.data, a->payload, plen - sizeof (*a));
915 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700916
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700917 clib_warning ("received payload AUTH, len %u auth_type %u",
918 plen - sizeof (*a), a->auth_method);
919 }
920 else if (payload == IKEV2_PAYLOAD_NOTIFY) /* 41 */
921 {
922 ikev2_notify_t *n = ikev2_parse_notify_payload (ikep);
923 if (n->msg_type == IKEV2_NOTIFY_MSG_INITIAL_CONTACT)
924 {
925 sa->initial_contact = 1;
926 }
927 vec_free (n);
928 }
929 else if (payload == IKEV2_PAYLOAD_VENDOR) /* 43 */
930 {
931 ikev2_parse_vendor_payload (ikep);
932 }
933 else if (payload == IKEV2_PAYLOAD_TSI) /* 44 */
934 {
935 clib_warning ("received payload TSi, len %u",
936 plen - sizeof (*ikep));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700937
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700938 vec_free (first_child_sa->tsi);
939 first_child_sa->tsi = ikev2_parse_ts_payload (ikep);
940 }
941 else if (payload == IKEV2_PAYLOAD_TSR) /* 45 */
942 {
943 clib_warning ("received payload TSr, len %u",
944 plen - sizeof (*ikep));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700945
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700946 vec_free (first_child_sa->tsr);
947 first_child_sa->tsr = ikev2_parse_ts_payload (ikep);
948 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700949 else
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700950 {
951 clib_warning ("unknown payload %u flags %x length %u data %u",
952 payload, ikep->flags, plen - 4,
953 format_hex_bytes, ikep->payload, plen - 4);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700954
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700955 if (ikep->flags & IKEV2_PAYLOAD_FLAG_CRITICAL)
956 {
957 ikev2_set_state (sa, IKEV2_STATE_NOTIFY_AND_DELETE);
958 sa->unsupported_cp = payload;
959 return;
960 }
961 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700962
963 payload = ikep->nextpayload;
964 p += plen;
965 }
966
967cleanup_and_exit:
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700968 vec_free (plaintext);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700969}
970
971static void
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700972ikev2_process_informational_req (vlib_main_t * vm, ikev2_sa_t * sa,
973 ike_header_t * ike)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700974{
975 int p = 0;
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700976 u32 len = clib_net_to_host_u32 (ike->length);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700977 u8 payload = ike->nextpayload;
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700978 u8 *plaintext = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700979
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700980 ike_payload_header_t *ikep;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700981 u32 plen;
982
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700983 clib_warning ("ispi %lx rspi %lx nextpayload %x version %x "
984 "exchange %x flags %x msgid %x length %u",
985 clib_net_to_host_u64 (ike->ispi),
986 clib_net_to_host_u64 (ike->rspi),
987 payload, ike->version,
988 ike->exchange, ike->flags,
989 clib_net_to_host_u32 (ike->msgid), len);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700990
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700991 plaintext = ikev2_decrypt_sk_payload (sa, ike, &payload);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700992
993 if (!plaintext)
994 goto cleanup_and_exit;
995
996 /* process encrypted payload */
997 p = 0;
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700998 while (p < vec_len (plaintext) && payload != IKEV2_PAYLOAD_NONE)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700999 {
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001000 ikep = (ike_payload_header_t *) & plaintext[p];
1001 plen = clib_net_to_host_u16 (ikep->length);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001002
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001003 if (plen < sizeof (ike_payload_header_t))
1004 goto cleanup_and_exit;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001005
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001006 if (payload == IKEV2_PAYLOAD_NOTIFY) /* 41 */
1007 {
1008 ikev2_notify_t *n = ikev2_parse_notify_payload (ikep);
1009 if (n->msg_type == IKEV2_NOTIFY_MSG_AUTHENTICATION_FAILED)
1010 ikev2_set_state (sa, IKEV2_STATE_AUTH_FAILED);
1011 vec_free (n);
1012 }
1013 else if (payload == IKEV2_PAYLOAD_DELETE) /* 42 */
1014 {
1015 sa->del = ikev2_parse_delete_payload (ikep);
1016 }
1017 else if (payload == IKEV2_PAYLOAD_VENDOR) /* 43 */
1018 {
1019 ikev2_parse_vendor_payload (ikep);
1020 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001021 else
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001022 {
1023 clib_warning ("unknown payload %u flags %x length %u data %u",
1024 payload, ikep->flags, plen - 4,
1025 format_hex_bytes, ikep->payload, plen - 4);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001026
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001027 if (ikep->flags & IKEV2_PAYLOAD_FLAG_CRITICAL)
1028 {
1029 sa->unsupported_cp = payload;
1030 return;
1031 }
1032 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001033
1034 payload = ikep->nextpayload;
1035 p += plen;
1036 }
1037
1038cleanup_and_exit:
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001039 vec_free (plaintext);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001040}
1041
1042static void
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001043ikev2_process_create_child_sa_req (vlib_main_t * vm, ikev2_sa_t * sa,
1044 ike_header_t * ike)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001045{
1046 int p = 0;
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001047 u32 len = clib_net_to_host_u32 (ike->length);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001048 u8 payload = ike->nextpayload;
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001049 u8 *plaintext = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001050 u8 rekeying = 0;
Radu Nicolaucb33dc22017-02-16 16:49:46 +00001051 u8 nonce[IKEV2_NONCE_SIZE];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001052
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001053 ike_payload_header_t *ikep;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001054 u32 plen;
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001055 ikev2_notify_t *n = 0;
1056 ikev2_ts_t *tsi = 0;
1057 ikev2_ts_t *tsr = 0;
1058 ikev2_sa_proposal_t *proposal = 0;
1059 ikev2_child_sa_t *child_sa;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001060
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001061 clib_warning ("ispi %lx rspi %lx nextpayload %x version %x "
1062 "exchange %x flags %x msgid %x length %u",
1063 clib_net_to_host_u64 (ike->ispi),
1064 clib_net_to_host_u64 (ike->rspi),
1065 payload, ike->version,
1066 ike->exchange, ike->flags,
1067 clib_net_to_host_u32 (ike->msgid), len);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001068
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001069 plaintext = ikev2_decrypt_sk_payload (sa, ike, &payload);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001070
1071 if (!plaintext)
1072 goto cleanup_and_exit;
1073
1074 /* process encrypted payload */
1075 p = 0;
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001076 while (p < vec_len (plaintext) && payload != IKEV2_PAYLOAD_NONE)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001077 {
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001078 ikep = (ike_payload_header_t *) & plaintext[p];
1079 plen = clib_net_to_host_u16 (ikep->length);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001080
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001081 if (plen < sizeof (ike_payload_header_t))
1082 goto cleanup_and_exit;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001083
1084 else if (payload == IKEV2_PAYLOAD_SA)
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001085 {
1086 proposal = ikev2_parse_sa_payload (ikep);
1087 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001088 else if (payload == IKEV2_PAYLOAD_NOTIFY)
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001089 {
1090 n = ikev2_parse_notify_payload (ikep);
1091 if (n->msg_type == IKEV2_NOTIFY_MSG_REKEY_SA)
1092 {
1093 rekeying = 1;
1094 }
1095 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001096 else if (payload == IKEV2_PAYLOAD_DELETE)
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001097 {
1098 sa->del = ikev2_parse_delete_payload (ikep);
1099 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001100 else if (payload == IKEV2_PAYLOAD_VENDOR)
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001101 {
1102 ikev2_parse_vendor_payload (ikep);
1103 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001104 else if (payload == IKEV2_PAYLOAD_NONCE)
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001105 {
Radu Nicolaucb33dc22017-02-16 16:49:46 +00001106 clib_memcpy (nonce, ikep->payload, plen - sizeof (*ikep));
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001107 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001108 else if (payload == IKEV2_PAYLOAD_TSI)
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001109 {
1110 tsi = ikev2_parse_ts_payload (ikep);
1111 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001112 else if (payload == IKEV2_PAYLOAD_TSR)
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001113 {
1114 tsr = ikev2_parse_ts_payload (ikep);
1115 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001116 else
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001117 {
1118 clib_warning ("unknown payload %u flags %x length %u data %u",
1119 payload, ikep->flags, plen - 4,
1120 format_hex_bytes, ikep->payload, plen - 4);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001121
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001122 if (ikep->flags & IKEV2_PAYLOAD_FLAG_CRITICAL)
1123 {
1124 sa->unsupported_cp = payload;
1125 return;
1126 }
1127 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001128
1129 payload = ikep->nextpayload;
1130 p += plen;
1131 }
1132
Radu Nicolaucb33dc22017-02-16 16:49:46 +00001133 if (sa->is_initiator && proposal->protocol_id == IKEV2_PROTOCOL_ESP)
1134 {
1135 ikev2_rekey_t *rekey = &sa->rekey[0];
1136 rekey->protocol_id = proposal->protocol_id;
1137 rekey->i_proposal =
1138 ikev2_select_proposal (proposal, IKEV2_PROTOCOL_ESP);
1139 rekey->i_proposal->spi = rekey->spi;
1140 rekey->r_proposal = proposal;
1141 rekey->tsi = tsi;
1142 rekey->tsr = tsr;
1143 /* update Nr */
1144 vec_free (sa->r_nonce);
1145 vec_add (sa->r_nonce, nonce, IKEV2_NONCE_SIZE);
1146 child_sa = ikev2_sa_get_child (sa, rekey->ispi, IKEV2_PROTOCOL_ESP, 1);
1147 if (child_sa)
1148 {
1149 child_sa->rekey_retries = 0;
1150 }
1151 }
1152 else if (rekeying)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001153 {
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001154 ikev2_rekey_t *rekey;
Radu Nicolaucb33dc22017-02-16 16:49:46 +00001155 child_sa = ikev2_sa_get_child (sa, n->spi, n->protocol_id, 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001156 if (!child_sa)
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001157 {
1158 clib_warning ("child SA spi %lx not found", n->spi);
1159 goto cleanup_and_exit;
1160 }
1161 vec_add2 (sa->rekey, rekey, 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001162 rekey->protocol_id = n->protocol_id;
1163 rekey->spi = n->spi;
1164 rekey->i_proposal = proposal;
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001165 rekey->r_proposal =
1166 ikev2_select_proposal (proposal, IKEV2_PROTOCOL_ESP);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001167 rekey->tsi = tsi;
1168 rekey->tsr = tsr;
1169 /* update Ni */
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001170 vec_free (sa->i_nonce);
Radu Nicolaucb33dc22017-02-16 16:49:46 +00001171 vec_add (sa->i_nonce, nonce, IKEV2_NONCE_SIZE);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001172 /* generate new Nr */
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001173 vec_free (sa->r_nonce);
1174 sa->r_nonce = vec_new (u8, IKEV2_NONCE_SIZE);
1175 RAND_bytes ((u8 *) sa->r_nonce, IKEV2_NONCE_SIZE);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001176 }
1177
1178cleanup_and_exit:
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001179 vec_free (plaintext);
1180 vec_free (n);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001181}
1182
1183static u8 *
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001184ikev2_sa_generate_authmsg (ikev2_sa_t * sa, int is_responder)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001185{
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001186 u8 *authmsg = 0;
1187 u8 *data;
1188 u8 *nonce;
1189 ikev2_id_t *id;
1190 u8 *key;
1191 u8 *packet_data;
1192 ikev2_sa_transform_t *tr_prf;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001193
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001194 tr_prf =
1195 ikev2_sa_get_td_for_type (sa->r_proposals, IKEV2_TRANSFORM_TYPE_PRF);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001196
1197 if (is_responder)
1198 {
1199 id = &sa->r_id;
1200 key = sa->sk_pr;
1201 nonce = sa->i_nonce;
1202 packet_data = sa->last_sa_init_res_packet_data;
1203 }
1204 else
1205 {
1206 id = &sa->i_id;
1207 key = sa->sk_pi;
1208 nonce = sa->r_nonce;
1209 packet_data = sa->last_sa_init_req_packet_data;
1210 }
1211
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001212 data = vec_new (u8, 4);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001213 data[0] = id->type;
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001214 vec_append (data, id->data);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001215
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001216 u8 *id_hash = ikev2_calc_prf (tr_prf, key, data);
1217 vec_append (authmsg, packet_data);
1218 vec_append (authmsg, nonce);
1219 vec_append (authmsg, id_hash);
1220 vec_free (id_hash);
1221 vec_free (data);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001222
1223 return authmsg;
1224}
1225
1226static int
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001227ikev2_ts_cmp (ikev2_ts_t * ts1, ikev2_ts_t * ts2)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001228{
1229 if (ts1->ts_type == ts2->ts_type && ts1->protocol_id == ts2->protocol_id &&
1230 ts1->start_port == ts2->start_port && ts1->end_port == ts2->end_port &&
1231 ts1->start_addr.as_u32 == ts2->start_addr.as_u32 &&
1232 ts1->end_addr.as_u32 == ts2->end_addr.as_u32)
1233 return 1;
1234
1235 return 0;
1236}
1237
1238static void
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001239ikev2_sa_match_ts (ikev2_sa_t * sa)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001240{
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001241 ikev2_main_t *km = &ikev2_main;
1242 ikev2_profile_t *p;
Radu Nicolaucb33dc22017-02-16 16:49:46 +00001243 ikev2_ts_t *ts, *p_tsi, *p_tsr, *tsi = 0, *tsr = 0;
1244 ikev2_id_t *id;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001245
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001246 /* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001247 pool_foreach (p, km->profiles, ({
1248
Radu Nicolaucb33dc22017-02-16 16:49:46 +00001249 if (sa->is_initiator)
1250 {
1251 p_tsi = &p->loc_ts;
1252 p_tsr = &p->rem_ts;
1253 id = &sa->r_id;
1254 }
1255 else
1256 {
1257 p_tsi = &p->rem_ts;
1258 p_tsr = &p->loc_ts;
1259 id = &sa->i_id;
1260 }
1261
Ed Warnickecb9cada2015-12-08 15:45:58 -07001262 /* check id */
Radu Nicolaucb33dc22017-02-16 16:49:46 +00001263 if (p->rem_id.type != id->type ||
1264 vec_len(p->rem_id.data) != vec_len(id->data) ||
1265 memcmp(p->rem_id.data, id->data, vec_len(p->rem_id.data)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001266 continue;
1267
1268 vec_foreach(ts, sa->childs[0].tsi)
1269 {
Radu Nicolaucb33dc22017-02-16 16:49:46 +00001270 if (ikev2_ts_cmp(p_tsi, ts))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001271 {
1272 tsi = vec_dup(ts);
1273 break;
1274 }
1275 }
1276
1277 vec_foreach(ts, sa->childs[0].tsr)
1278 {
Radu Nicolaucb33dc22017-02-16 16:49:46 +00001279 if (ikev2_ts_cmp(p_tsr, ts))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001280 {
1281 tsr = vec_dup(ts);
1282 break;
1283 }
1284 }
1285
1286 break;
1287 }));
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001288 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001289
1290 if (tsi && tsr)
1291 {
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001292 vec_free (sa->childs[0].tsi);
1293 vec_free (sa->childs[0].tsr);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001294 sa->childs[0].tsi = tsi;
1295 sa->childs[0].tsr = tsr;
1296 }
1297 else
1298 {
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001299 vec_free (tsi);
1300 vec_free (tsr);
1301 ikev2_set_state (sa, IKEV2_STATE_TS_UNACCEPTABLE);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001302 }
1303}
1304
1305static void
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001306ikev2_sa_auth (ikev2_sa_t * sa)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001307{
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001308 ikev2_main_t *km = &ikev2_main;
1309 ikev2_profile_t *p, *sel_p = 0;
1310 u8 *authmsg, *key_pad, *psk = 0, *auth = 0;
1311 ikev2_sa_transform_t *tr_prf;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001312
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001313 tr_prf =
1314 ikev2_sa_get_td_for_type (sa->r_proposals, IKEV2_TRANSFORM_TYPE_PRF);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001315
1316 /* only shared key and rsa signature */
1317 if (!(sa->i_auth.method == IKEV2_AUTH_METHOD_SHARED_KEY_MIC ||
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001318 sa->i_auth.method == IKEV2_AUTH_METHOD_RSA_SIG))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001319 {
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001320 clib_warning ("unsupported authentication method %u",
1321 sa->i_auth.method);
1322 ikev2_set_state (sa, IKEV2_STATE_AUTH_FAILED);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001323 return;
1324 }
1325
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001326 key_pad = format (0, "%s", IKEV2_KEY_PAD);
Radu Nicolaucb33dc22017-02-16 16:49:46 +00001327 authmsg = ikev2_sa_generate_authmsg (sa, sa->is_initiator);
1328
1329 ikev2_id_t *sa_id;
1330 ikev2_auth_t *sa_auth;
1331
1332 if (sa->is_initiator)
1333 {
1334 sa_id = &sa->r_id;
1335 sa_auth = &sa->r_auth;
1336 }
1337 else
1338 {
1339 sa_id = &sa->i_id;
1340 sa_auth = &sa->i_auth;
1341 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001342
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001343 /* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001344 pool_foreach (p, km->profiles, ({
1345
1346 /* check id */
Radu Nicolaucb33dc22017-02-16 16:49:46 +00001347 if (p->rem_id.type != sa_id->type ||
1348 vec_len(p->rem_id.data) != vec_len(sa_id->data) ||
1349 memcmp(p->rem_id.data, sa_id->data, vec_len(p->rem_id.data)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001350 continue;
1351
Radu Nicolaucb33dc22017-02-16 16:49:46 +00001352 if (sa_auth->method == IKEV2_AUTH_METHOD_SHARED_KEY_MIC)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001353 {
1354 if (!p->auth.data ||
1355 p->auth.method != IKEV2_AUTH_METHOD_SHARED_KEY_MIC)
1356 continue;
1357
1358 psk = ikev2_calc_prf(tr_prf, p->auth.data, key_pad);
1359 auth = ikev2_calc_prf(tr_prf, psk, authmsg);
1360
Radu Nicolaucb33dc22017-02-16 16:49:46 +00001361 if (!memcmp(auth, sa_auth->data, vec_len(sa_auth->data)))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001362 {
1363 ikev2_set_state(sa, IKEV2_STATE_AUTHENTICATED);
1364 vec_free(auth);
1365 sel_p = p;
1366 break;
1367 }
1368
1369 }
Radu Nicolaucb33dc22017-02-16 16:49:46 +00001370 else if (sa_auth->method == IKEV2_AUTH_METHOD_RSA_SIG)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001371 {
1372 if (p->auth.method != IKEV2_AUTH_METHOD_RSA_SIG)
1373 continue;
1374
Radu Nicolaucb33dc22017-02-16 16:49:46 +00001375 if (ikev2_verify_sign(p->auth.key, sa_auth->data, authmsg) == 1)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001376 {
1377 ikev2_set_state(sa, IKEV2_STATE_AUTHENTICATED);
1378 sel_p = p;
1379 break;
1380 }
1381 }
1382
1383 vec_free(auth);
1384 vec_free(psk);
1385 }));
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001386 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001387
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001388 vec_free (authmsg);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001389
1390 if (sa->state == IKEV2_STATE_AUTHENTICATED)
1391 {
Radu Nicolaucb33dc22017-02-16 16:49:46 +00001392 if (!sa->is_initiator)
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001393 {
Radu Nicolaucb33dc22017-02-16 16:49:46 +00001394 vec_free (sa->r_id.data);
1395 sa->r_id.data = vec_dup (sel_p->loc_id.data);
1396 sa->r_id.type = sel_p->loc_id.type;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001397
Radu Nicolaucb33dc22017-02-16 16:49:46 +00001398 /* generate our auth data */
1399 authmsg = ikev2_sa_generate_authmsg (sa, 1);
1400 if (sel_p->auth.method == IKEV2_AUTH_METHOD_SHARED_KEY_MIC)
1401 {
1402 sa->r_auth.data = ikev2_calc_prf (tr_prf, psk, authmsg);
1403 sa->r_auth.method = IKEV2_AUTH_METHOD_SHARED_KEY_MIC;
1404 }
1405 else if (sel_p->auth.method == IKEV2_AUTH_METHOD_RSA_SIG)
1406 {
1407 sa->r_auth.data = ikev2_calc_sign (km->pkey, authmsg);
1408 sa->r_auth.method = IKEV2_AUTH_METHOD_RSA_SIG;
1409 }
1410 vec_free (authmsg);
1411
1412 /* select transforms for 1st child sa */
1413 ikev2_sa_free_proposal_vector (&sa->childs[0].r_proposals);
1414 sa->childs[0].r_proposals =
1415 ikev2_select_proposal (sa->childs[0].i_proposals,
1416 IKEV2_PROTOCOL_ESP);
1417 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001418 }
1419 else
1420 {
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001421 ikev2_set_state (sa, IKEV2_STATE_AUTH_FAILED);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001422 }
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001423 vec_free (psk);
1424 vec_free (key_pad);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001425}
1426
Radu Nicolaucb33dc22017-02-16 16:49:46 +00001427
1428static void
1429ikev2_sa_auth_init (ikev2_sa_t * sa)
1430{
1431 ikev2_main_t *km = &ikev2_main;
1432 u8 *authmsg, *key_pad, *psk = 0, *auth = 0;
1433 ikev2_sa_transform_t *tr_prf;
1434
1435 tr_prf =
1436 ikev2_sa_get_td_for_type (sa->r_proposals, IKEV2_TRANSFORM_TYPE_PRF);
1437
1438 /* only shared key and rsa signature */
1439 if (!(sa->i_auth.method == IKEV2_AUTH_METHOD_SHARED_KEY_MIC ||
1440 sa->i_auth.method == IKEV2_AUTH_METHOD_RSA_SIG))
1441 {
1442 clib_warning ("unsupported authentication method %u",
1443 sa->i_auth.method);
1444 ikev2_set_state (sa, IKEV2_STATE_AUTH_FAILED);
1445 return;
1446 }
1447
1448 key_pad = format (0, "%s", IKEV2_KEY_PAD);
1449 authmsg = ikev2_sa_generate_authmsg (sa, 0);
1450 psk = ikev2_calc_prf (tr_prf, sa->i_auth.data, key_pad);
1451 auth = ikev2_calc_prf (tr_prf, psk, authmsg);
1452
1453
1454 if (sa->i_auth.method == IKEV2_AUTH_METHOD_SHARED_KEY_MIC)
1455 {
1456 sa->i_auth.data = ikev2_calc_prf (tr_prf, psk, authmsg);
1457 sa->i_auth.method = IKEV2_AUTH_METHOD_SHARED_KEY_MIC;
1458 }
1459 else if (sa->i_auth.method == IKEV2_AUTH_METHOD_RSA_SIG)
1460 {
1461 sa->i_auth.data = ikev2_calc_sign (km->pkey, authmsg);
1462 sa->i_auth.method = IKEV2_AUTH_METHOD_RSA_SIG;
1463 }
1464
1465 vec_free (psk);
1466 vec_free (key_pad);
1467 vec_free (auth);
1468 vec_free (authmsg);
1469}
1470
1471
Ed Warnickecb9cada2015-12-08 15:45:58 -07001472static int
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001473ikev2_create_tunnel_interface (vnet_main_t * vnm, ikev2_sa_t * sa,
1474 ikev2_child_sa_t * child)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001475{
1476 ipsec_add_del_tunnel_args_t a;
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001477 ikev2_sa_transform_t *tr;
Radu Nicolaucb33dc22017-02-16 16:49:46 +00001478 ikev2_sa_proposal_t *proposals;
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001479 u8 encr_type = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001480
1481 if (!child->r_proposals)
1482 {
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001483 ikev2_set_state (sa, IKEV2_STATE_NO_PROPOSAL_CHOSEN);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001484 return 1;
1485 }
1486
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001487 memset (&a, 0, sizeof (a));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001488 a.is_add = 1;
Radu Nicolaucb33dc22017-02-16 16:49:46 +00001489 if (sa->is_initiator)
1490 {
1491 a.local_ip.as_u32 = sa->iaddr.as_u32;
1492 a.remote_ip.as_u32 = sa->raddr.as_u32;
1493 proposals = child->i_proposals;
1494 a.local_spi = child->r_proposals[0].spi;
1495 a.remote_spi = child->i_proposals[0].spi;
1496 }
1497 else
1498 {
1499 a.local_ip.as_u32 = sa->raddr.as_u32;
1500 a.remote_ip.as_u32 = sa->iaddr.as_u32;
1501 proposals = child->r_proposals;
1502 a.local_spi = child->i_proposals[0].spi;
1503 a.remote_spi = child->r_proposals[0].spi;
1504 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001505 a.anti_replay = 1;
1506
Radu Nicolaucb33dc22017-02-16 16:49:46 +00001507 tr = ikev2_sa_get_td_for_type (proposals, IKEV2_TRANSFORM_TYPE_ESN);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001508 if (tr)
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001509 a.esn = tr->esn_type;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001510 else
1511 a.esn = 0;
1512
Radu Nicolaucb33dc22017-02-16 16:49:46 +00001513 tr = ikev2_sa_get_td_for_type (proposals, IKEV2_TRANSFORM_TYPE_ENCR);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001514 if (tr)
1515 {
1516 if (tr->encr_type == IKEV2_TRANSFORM_ENCR_TYPE_AES_CBC && tr->key_len)
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001517 {
1518 switch (tr->key_len)
1519 {
1520 case 16:
1521 encr_type = IPSEC_CRYPTO_ALG_AES_CBC_128;
1522 break;
1523 case 24:
1524 encr_type = IPSEC_CRYPTO_ALG_AES_CBC_192;
1525 break;
1526 case 32:
1527 encr_type = IPSEC_CRYPTO_ALG_AES_CBC_256;
1528 break;
1529 default:
1530 ikev2_set_state (sa, IKEV2_STATE_NO_PROPOSAL_CHOSEN);
1531 return 1;
1532 break;
1533 }
1534 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001535 else
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001536 {
1537 ikev2_set_state (sa, IKEV2_STATE_NO_PROPOSAL_CHOSEN);
1538 return 1;
1539 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001540 }
1541 else
1542 {
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001543 ikev2_set_state (sa, IKEV2_STATE_NO_PROPOSAL_CHOSEN);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001544 return 1;
1545 }
1546
Radu Nicolaucb33dc22017-02-16 16:49:46 +00001547 tr = ikev2_sa_get_td_for_type (proposals, IKEV2_TRANSFORM_TYPE_INTEG);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001548 if (tr)
1549 {
1550 if (tr->integ_type != IKEV2_TRANSFORM_INTEG_TYPE_AUTH_HMAC_SHA1_96)
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001551 {
1552 ikev2_set_state (sa, IKEV2_STATE_NO_PROPOSAL_CHOSEN);
1553 return 1;
1554 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001555 }
1556 else
1557 {
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001558 ikev2_set_state (sa, IKEV2_STATE_NO_PROPOSAL_CHOSEN);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001559 return 1;
1560 }
1561
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001562 ikev2_calc_child_keys (sa, child);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001563
Radu Nicolaucb33dc22017-02-16 16:49:46 +00001564 u8 *loc_ckey, *rem_ckey, *loc_ikey, *rem_ikey;
1565 if (sa->is_initiator)
1566 {
1567 loc_ikey = child->sk_ai;
1568 rem_ikey = child->sk_ar;
1569 loc_ckey = child->sk_ei;
1570 rem_ckey = child->sk_er;
1571 }
1572 else
1573 {
1574 loc_ikey = child->sk_ar;
1575 rem_ikey = child->sk_ai;
1576 loc_ckey = child->sk_er;
1577 rem_ckey = child->sk_ei;
1578 }
1579
Matthew Smith2838a232016-06-21 16:05:09 -05001580 a.integ_alg = IPSEC_INTEG_ALG_SHA1_96;
Radu Nicolaucb33dc22017-02-16 16:49:46 +00001581 a.local_integ_key_len = vec_len (loc_ikey);
1582 clib_memcpy (a.local_integ_key, loc_ikey, a.local_integ_key_len);
1583 a.remote_integ_key_len = vec_len (rem_ikey);
1584 clib_memcpy (a.remote_integ_key, rem_ikey, a.remote_integ_key_len);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001585
Matthew Smith2838a232016-06-21 16:05:09 -05001586 a.crypto_alg = encr_type;
Radu Nicolaucb33dc22017-02-16 16:49:46 +00001587 a.local_crypto_key_len = vec_len (loc_ckey);
1588 clib_memcpy (a.local_crypto_key, loc_ckey, a.local_crypto_key_len);
1589 a.remote_crypto_key_len = vec_len (rem_ckey);
1590 clib_memcpy (a.remote_crypto_key, rem_ckey, a.remote_crypto_key_len);
1591
1592 if (sa->profile && sa->profile->lifetime)
1593 {
1594 child->time_to_expiration = vlib_time_now (vnm->vlib_main)
1595 + sa->profile->lifetime;
1596 if (sa->profile->lifetime_jitter)
1597 {
1598 child->time_to_expiration +=
1599 1 + (rand () % sa->profile->lifetime_jitter);
1600 }
1601 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001602
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001603 ipsec_add_del_tunnel_if (&a);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001604
1605 return 0;
1606}
1607
1608static int
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001609ikev2_delete_tunnel_interface (vnet_main_t * vnm, ikev2_sa_t * sa,
1610 ikev2_child_sa_t * child)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001611{
1612 ipsec_add_del_tunnel_args_t a;
1613
Radu Nicolaucb33dc22017-02-16 16:49:46 +00001614 if (sa->is_initiator)
1615 {
1616 if (!vec_len (child->i_proposals))
1617 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001618
Radu Nicolaucb33dc22017-02-16 16:49:46 +00001619 a.is_add = 0;
1620 a.local_ip.as_u32 = sa->iaddr.as_u32;
1621 a.remote_ip.as_u32 = sa->raddr.as_u32;
1622 a.local_spi = child->r_proposals[0].spi;
1623 a.remote_spi = child->i_proposals[0].spi;
1624 }
1625 else
1626 {
1627 if (!vec_len (child->r_proposals))
1628 return 0;
1629
1630 a.is_add = 0;
1631 a.local_ip.as_u32 = sa->raddr.as_u32;
1632 a.remote_ip.as_u32 = sa->iaddr.as_u32;
1633 a.local_spi = child->i_proposals[0].spi;
1634 a.remote_spi = child->r_proposals[0].spi;
1635 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001636
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001637 ipsec_add_del_tunnel_if (&a);
Matthew Smith2838a232016-06-21 16:05:09 -05001638 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001639}
1640
1641static u32
Radu Nicolaucb33dc22017-02-16 16:49:46 +00001642ikev2_generate_message (ikev2_sa_t * sa, ike_header_t * ike, void *user)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001643{
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001644 v8 *integ = 0;
1645 ike_payload_header_t *ph;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001646 u16 plen;
1647 u32 tlen = 0;
1648
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001649 ikev2_sa_transform_t *tr_encr, *tr_integ;
1650 tr_encr =
1651 ikev2_sa_get_td_for_type (sa->r_proposals, IKEV2_TRANSFORM_TYPE_ENCR);
1652 tr_integ =
1653 ikev2_sa_get_td_for_type (sa->r_proposals, IKEV2_TRANSFORM_TYPE_INTEG);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001654
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001655 ikev2_payload_chain_t *chain = 0;
1656 ikev2_payload_new_chain (chain);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001657
1658 if (ike->exchange == IKEV2_EXCHANGE_SA_INIT)
1659 {
1660 if (sa->r_proposals == 0)
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001661 {
1662 ikev2_payload_add_notify (chain,
1663 IKEV2_NOTIFY_MSG_NO_PROPOSAL_CHOSEN, 0);
1664 ikev2_set_state (sa, IKEV2_STATE_NOTIFY_AND_DELETE);
1665 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001666 else if (sa->dh_group == IKEV2_TRANSFORM_DH_TYPE_NONE)
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001667 {
1668 u8 *data = vec_new (u8, 2);
1669 ikev2_sa_transform_t *tr_dh;
1670 tr_dh =
1671 ikev2_sa_get_td_for_type (sa->r_proposals,
1672 IKEV2_TRANSFORM_TYPE_DH);
1673 ASSERT (tr_dh && tr_dh->dh_type);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001674
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001675 data[0] = (tr_dh->dh_type >> 8) & 0xff;
1676 data[1] = (tr_dh->dh_type) & 0xff;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001677
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001678 ikev2_payload_add_notify (chain,
1679 IKEV2_NOTIFY_MSG_INVALID_KE_PAYLOAD,
1680 data);
1681 vec_free (data);
1682 ikev2_set_state (sa, IKEV2_STATE_NOTIFY_AND_DELETE);
1683 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001684 else if (sa->state == IKEV2_STATE_NOTIFY_AND_DELETE)
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001685 {
1686 u8 *data = vec_new (u8, 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001687
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001688 data[0] = sa->unsupported_cp;
1689 ikev2_payload_add_notify (chain,
1690 IKEV2_NOTIFY_MSG_UNSUPPORTED_CRITICAL_PAYLOAD,
1691 data);
1692 vec_free (data);
1693 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001694 else
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001695 {
1696 ike->rspi = clib_host_to_net_u64 (sa->rspi);
1697 ikev2_payload_add_sa (chain, sa->r_proposals);
1698 ikev2_payload_add_ke (chain, sa->dh_group, sa->r_dh_data);
1699 ikev2_payload_add_nonce (chain, sa->r_nonce);
1700 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001701 }
1702 else if (ike->exchange == IKEV2_EXCHANGE_IKE_AUTH)
1703 {
1704 if (sa->state == IKEV2_STATE_AUTHENTICATED)
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001705 {
1706 ikev2_payload_add_id (chain, &sa->r_id, IKEV2_PAYLOAD_IDR);
1707 ikev2_payload_add_auth (chain, &sa->r_auth);
1708 ikev2_payload_add_sa (chain, sa->childs[0].r_proposals);
1709 ikev2_payload_add_ts (chain, sa->childs[0].tsi, IKEV2_PAYLOAD_TSI);
1710 ikev2_payload_add_ts (chain, sa->childs[0].tsr, IKEV2_PAYLOAD_TSR);
1711 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001712 else if (sa->state == IKEV2_STATE_AUTH_FAILED)
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001713 {
1714 ikev2_payload_add_notify (chain,
1715 IKEV2_NOTIFY_MSG_AUTHENTICATION_FAILED,
1716 0);
1717 ikev2_set_state (sa, IKEV2_STATE_NOTIFY_AND_DELETE);
1718 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001719 else if (sa->state == IKEV2_STATE_TS_UNACCEPTABLE)
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001720 {
1721 ikev2_payload_add_notify (chain, IKEV2_NOTIFY_MSG_TS_UNACCEPTABLE,
1722 0);
1723 ikev2_payload_add_id (chain, &sa->r_id, IKEV2_PAYLOAD_IDR);
1724 ikev2_payload_add_auth (chain, &sa->r_auth);
1725 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001726 else if (sa->state == IKEV2_STATE_NO_PROPOSAL_CHOSEN)
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001727 {
1728 ikev2_payload_add_notify (chain,
1729 IKEV2_NOTIFY_MSG_NO_PROPOSAL_CHOSEN, 0);
1730 ikev2_payload_add_id (chain, &sa->r_id, IKEV2_PAYLOAD_IDR);
1731 ikev2_payload_add_auth (chain, &sa->r_auth);
1732 ikev2_payload_add_ts (chain, sa->childs[0].tsi, IKEV2_PAYLOAD_TSI);
1733 ikev2_payload_add_ts (chain, sa->childs[0].tsr, IKEV2_PAYLOAD_TSR);
1734 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001735 else if (sa->state == IKEV2_STATE_NOTIFY_AND_DELETE)
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001736 {
1737 u8 *data = vec_new (u8, 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001738
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001739 data[0] = sa->unsupported_cp;
1740 ikev2_payload_add_notify (chain,
1741 IKEV2_NOTIFY_MSG_UNSUPPORTED_CRITICAL_PAYLOAD,
1742 data);
1743 vec_free (data);
1744 }
Radu Nicolaucb33dc22017-02-16 16:49:46 +00001745 else if (sa->state == IKEV2_STATE_SA_INIT)
1746 {
1747 ikev2_payload_add_id (chain, &sa->i_id, IKEV2_PAYLOAD_IDI);
1748 ikev2_payload_add_auth (chain, &sa->i_auth);
1749 ikev2_payload_add_sa (chain, sa->childs[0].i_proposals);
1750 ikev2_payload_add_ts (chain, sa->childs[0].tsi, IKEV2_PAYLOAD_TSI);
1751 ikev2_payload_add_ts (chain, sa->childs[0].tsr, IKEV2_PAYLOAD_TSR);
1752 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001753 else
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001754 {
1755 ikev2_set_state (sa, IKEV2_STATE_DELETED);
1756 goto done;
1757 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001758 }
1759 else if (ike->exchange == IKEV2_EXCHANGE_INFORMATIONAL)
1760 {
1761 /* if pending delete */
1762 if (sa->del)
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001763 {
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001764 if (sa->del[0].protocol_id == IKEV2_PROTOCOL_IKE)
1765 {
Radu Nicolaucb33dc22017-02-16 16:49:46 +00001766 if (sa->is_initiator)
1767 ikev2_payload_add_delete (chain, sa->del);
1768
1769 /* The response to a request that deletes the IKE SA is an empty
1770 INFORMATIONAL response. */
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001771 ikev2_set_state (sa, IKEV2_STATE_NOTIFY_AND_DELETE);
1772 }
1773 /* The response to a request that deletes ESP or AH SAs will contain
1774 delete payloads for the paired SAs going in the other direction. */
1775 else
1776 {
1777 ikev2_payload_add_delete (chain, sa->del);
1778 }
1779 vec_free (sa->del);
1780 sa->del = 0;
1781 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001782 /* received N(AUTHENTICATION_FAILED) */
1783 else if (sa->state == IKEV2_STATE_AUTH_FAILED)
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001784 {
1785 ikev2_set_state (sa, IKEV2_STATE_DELETED);
1786 goto done;
1787 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001788 /* received unsupported critical payload */
1789 else if (sa->unsupported_cp)
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001790 {
1791 u8 *data = vec_new (u8, 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001792
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001793 data[0] = sa->unsupported_cp;
1794 ikev2_payload_add_notify (chain,
1795 IKEV2_NOTIFY_MSG_UNSUPPORTED_CRITICAL_PAYLOAD,
1796 data);
1797 vec_free (data);
1798 sa->unsupported_cp = 0;
1799 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001800 /* else send empty response */
1801 }
1802 else if (ike->exchange == IKEV2_EXCHANGE_CREATE_CHILD_SA)
1803 {
Radu Nicolaucb33dc22017-02-16 16:49:46 +00001804 if (sa->is_initiator)
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001805 {
Ed Warnickecb9cada2015-12-08 15:45:58 -07001806
Radu Nicolaucb33dc22017-02-16 16:49:46 +00001807 ikev2_sa_proposal_t *proposals = (ikev2_sa_proposal_t *) user;
1808 ikev2_notify_t notify;
1809 u8 *data = vec_new (u8, 4);
1810 memset (&notify, 0, sizeof (notify));
1811 notify.protocol_id = IKEV2_PROTOCOL_ESP;
1812 notify.spi = sa->childs[0].i_proposals->spi;
1813 *(u32 *) data = clib_host_to_net_u32 (notify.spi);
1814
1815 ikev2_payload_add_sa (chain, proposals);
1816 ikev2_payload_add_nonce (chain, sa->i_nonce);
1817 ikev2_payload_add_ts (chain, sa->childs[0].tsi, IKEV2_PAYLOAD_TSI);
1818 ikev2_payload_add_ts (chain, sa->childs[0].tsr, IKEV2_PAYLOAD_TSR);
1819 ikev2_payload_add_notify_2 (chain, IKEV2_NOTIFY_MSG_REKEY_SA, data,
1820 &notify);
1821
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001822 vec_free (data);
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001823 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001824 else
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001825 {
Radu Nicolaucb33dc22017-02-16 16:49:46 +00001826 if (sa->rekey)
1827 {
1828 ikev2_payload_add_sa (chain, sa->rekey[0].r_proposal);
1829 ikev2_payload_add_nonce (chain, sa->r_nonce);
1830 ikev2_payload_add_ts (chain, sa->rekey[0].tsi,
1831 IKEV2_PAYLOAD_TSI);
1832 ikev2_payload_add_ts (chain, sa->rekey[0].tsr,
1833 IKEV2_PAYLOAD_TSR);
1834 vec_del1 (sa->rekey, 0);
1835 }
1836 else if (sa->unsupported_cp)
1837 {
1838 u8 *data = vec_new (u8, 1);
1839
1840 data[0] = sa->unsupported_cp;
1841 ikev2_payload_add_notify (chain,
1842 IKEV2_NOTIFY_MSG_UNSUPPORTED_CRITICAL_PAYLOAD,
1843 data);
1844 vec_free (data);
1845 sa->unsupported_cp = 0;
1846 }
1847 else
1848 {
1849 ikev2_payload_add_notify (chain,
1850 IKEV2_NOTIFY_MSG_NO_ADDITIONAL_SAS,
1851 0);
1852 }
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001853 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001854 }
1855
1856 /* IKEv2 header */
1857 ike->version = IKE_VERSION_2;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001858 ike->nextpayload = IKEV2_PAYLOAD_SK;
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001859 tlen = sizeof (*ike);
Radu Nicolaucb33dc22017-02-16 16:49:46 +00001860 if (sa->is_initiator)
1861 {
1862 ike->flags = IKEV2_HDR_FLAG_INITIATOR;
1863 sa->last_init_msg_id = clib_net_to_host_u32 (ike->msgid);
1864 }
1865 else
1866 {
1867 ike->flags = IKEV2_HDR_FLAG_RESPONSE;
1868 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001869
1870
1871 if (ike->exchange == IKEV2_EXCHANGE_SA_INIT)
1872 {
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001873 tlen += vec_len (chain->data);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001874 ike->nextpayload = chain->first_payload_type;
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001875 ike->length = clib_host_to_net_u32 (tlen);
1876 clib_memcpy (ike->payload, chain->data, vec_len (chain->data));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001877
1878 /* store whole IKE payload - needed for PSK auth */
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001879 vec_free (sa->last_sa_init_res_packet_data);
1880 vec_add (sa->last_sa_init_res_packet_data, ike, tlen);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001881 }
1882 else
1883 {
1884
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001885 ikev2_payload_chain_add_padding (chain, tr_encr->block_size);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001886
1887 /* SK payload */
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001888 plen = sizeof (*ph);
1889 ph = (ike_payload_header_t *) & ike->payload[0];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001890 ph->nextpayload = chain->first_payload_type;
1891 ph->flags = 0;
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001892 int enc_len = ikev2_encrypt_data (sa, chain->data, ph->payload);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001893 plen += enc_len;
1894
1895 /* add space for hmac */
1896 plen += tr_integ->key_trunc;
1897 tlen += plen;
1898
1899 /* payload and total length */
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001900 ph->length = clib_host_to_net_u16 (plen);
1901 ike->length = clib_host_to_net_u32 (tlen);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001902
1903 /* calc integrity data for whole packet except hash itself */
Radu Nicolaucb33dc22017-02-16 16:49:46 +00001904 integ =
1905 ikev2_calc_integr (tr_integ, sa->is_initiator ? sa->sk_ai : sa->sk_ar,
1906 (u8 *) ike, tlen - tr_integ->key_trunc);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001907
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001908 clib_memcpy (ike->payload + tlen - tr_integ->key_trunc - sizeof (*ike),
1909 integ, tr_integ->key_trunc);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001910
1911 /* store whole IKE payload - needed for retransmit */
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001912 vec_free (sa->last_res_packet_data);
1913 vec_add (sa->last_res_packet_data, ike, tlen);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001914 }
1915
1916done:
1917 ikev2_payload_destroy_chain (chain);
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001918 vec_free (integ);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001919 return tlen;
1920}
1921
1922static int
1923ikev2_retransmit_sa_init (ike_header_t * ike,
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001924 ip4_address_t iaddr, ip4_address_t raddr)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001925{
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001926 ikev2_main_t *km = &ikev2_main;
1927 ikev2_sa_t *sa;
Damjan Marion586afd72017-04-05 19:18:20 +02001928 u32 thread_index = vlib_get_thread_index ();
Ed Warnickecb9cada2015-12-08 15:45:58 -07001929
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001930 /* *INDENT-OFF* */
Damjan Marion586afd72017-04-05 19:18:20 +02001931 pool_foreach (sa, km->per_thread_data[thread_index].sas, ({
Ed Warnickecb9cada2015-12-08 15:45:58 -07001932 if (sa->ispi == clib_net_to_host_u64(ike->ispi) &&
1933 sa->iaddr.as_u32 == iaddr.as_u32 &&
1934 sa->raddr.as_u32 == raddr.as_u32)
1935 {
1936 int p = 0;
1937 u32 len = clib_net_to_host_u32(ike->length);
1938 u8 payload = ike->nextpayload;
1939
1940 while (p < len && payload!= IKEV2_PAYLOAD_NONE) {
1941 ike_payload_header_t * ikep = (ike_payload_header_t *) &ike->payload[p];
1942 u32 plen = clib_net_to_host_u16(ikep->length);
1943
1944 if (plen < sizeof(ike_payload_header_t))
1945 return -1;
1946
1947 if (payload == IKEV2_PAYLOAD_NONCE)
1948 {
1949 if (!memcmp(sa->i_nonce, ikep->payload, plen - sizeof(*ikep)))
1950 {
1951 /* req is retransmit */
1952 if (sa->state == IKEV2_STATE_SA_INIT)
1953 {
1954 ike_header_t * tmp;
1955 tmp = (ike_header_t*)sa->last_sa_init_res_packet_data;
1956 ike->ispi = tmp->ispi;
1957 ike->rspi = tmp->rspi;
1958 ike->nextpayload = tmp->nextpayload;
1959 ike->version = tmp->version;
1960 ike->exchange = tmp->exchange;
1961 ike->flags = tmp->flags;
1962 ike->msgid = tmp->msgid;
1963 ike->length = tmp->length;
Damjan Marionf1213b82016-03-13 02:22:06 +01001964 clib_memcpy(ike->payload, tmp->payload,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001965 clib_net_to_host_u32(tmp->length) - sizeof(*ike));
1966 clib_warning("IKE_SA_INIT retransmit from %U to %U",
1967 format_ip4_address, &raddr,
1968 format_ip4_address, &iaddr);
1969 return 1;
1970 }
1971 /* else ignore req */
1972 else
1973 {
1974 clib_warning("IKE_SA_INIT ignore from %U to %U",
1975 format_ip4_address, &raddr,
1976 format_ip4_address, &iaddr);
1977 return -1;
1978 }
1979 }
1980 }
1981 payload = ikep->nextpayload;
1982 p+=plen;
1983 }
1984 }
1985 }));
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001986 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001987
1988 /* req is not retransmit */
1989 return 0;
1990}
1991
1992static int
1993ikev2_retransmit_resp (ikev2_sa_t * sa, ike_header_t * ike)
1994{
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07001995 u32 msg_id = clib_net_to_host_u32 (ike->msgid);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001996
1997 /* new req */
1998 if (msg_id > sa->last_msg_id)
1999 {
2000 sa->last_msg_id = msg_id;
2001 return 0;
2002 }
2003 /* retransmitted req */
2004 else if (msg_id == sa->last_msg_id)
2005 {
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002006 ike_header_t *tmp;
2007 tmp = (ike_header_t *) sa->last_res_packet_data;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002008 ike->ispi = tmp->ispi;
2009 ike->rspi = tmp->rspi;
2010 ike->nextpayload = tmp->nextpayload;
2011 ike->version = tmp->version;
2012 ike->exchange = tmp->exchange;
2013 ike->flags = tmp->flags;
2014 ike->msgid = tmp->msgid;
2015 ike->length = tmp->length;
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002016 clib_memcpy (ike->payload, tmp->payload,
2017 clib_net_to_host_u32 (tmp->length) - sizeof (*ike));
2018 clib_warning ("IKE msgid %u retransmit from %U to %U",
2019 msg_id,
2020 format_ip4_address, &sa->raddr,
2021 format_ip4_address, &sa->iaddr);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002022 return 1;
2023 }
2024 /* old req ignore */
2025 else
2026 {
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002027 clib_warning ("IKE msgid %u req ignore from %U to %U",
2028 msg_id,
2029 format_ip4_address, &sa->raddr,
2030 format_ip4_address, &sa->iaddr);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002031 return -1;
2032 }
2033}
2034
2035static uword
2036ikev2_node_fn (vlib_main_t * vm,
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002037 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002038{
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002039 u32 n_left_from, *from, *to_next;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002040 ikev2_next_t next_index;
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002041 ikev2_main_t *km = &ikev2_main;
Damjan Marion586afd72017-04-05 19:18:20 +02002042 u32 thread_index = vlib_get_thread_index ();
Ed Warnickecb9cada2015-12-08 15:45:58 -07002043
2044 from = vlib_frame_vector_args (frame);
2045 n_left_from = frame->n_vectors;
2046 next_index = node->cached_next_index;
2047
2048 while (n_left_from > 0)
2049 {
2050 u32 n_left_to_next;
2051
2052 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2053
2054 while (n_left_from > 0 && n_left_to_next > 0)
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002055 {
2056 u32 bi0;
2057 vlib_buffer_t *b0;
2058 u32 next0 = IKEV2_NEXT_ERROR_DROP;
2059 u32 sw_if_index0;
2060 ip4_header_t *ip40;
2061 udp_header_t *udp0;
2062 ike_header_t *ike0;
2063 ikev2_sa_t *sa0 = 0;
Damjan Marion3f54b182016-08-16 11:27:02 +02002064 ikev2_sa_t sa; /* temporary store for SA */
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002065 int len = 0;
2066 int r;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002067
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002068 /* speculatively enqueue b0 to the current next frame */
2069 bi0 = from[0];
2070 to_next[0] = bi0;
2071 from += 1;
2072 to_next += 1;
2073 n_left_from -= 1;
2074 n_left_to_next -= 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002075
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002076 b0 = vlib_get_buffer (vm, bi0);
2077 ike0 = vlib_buffer_get_current (b0);
2078 vlib_buffer_advance (b0, -sizeof (*udp0));
2079 udp0 = vlib_buffer_get_current (b0);
2080 vlib_buffer_advance (b0, -sizeof (*ip40));
2081 ip40 = vlib_buffer_get_current (b0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002082
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002083 if (ike0->version != IKE_VERSION_2)
2084 {
2085 vlib_node_increment_counter (vm, ikev2_node.index,
2086 IKEV2_ERROR_NOT_IKEV2, 1);
2087 goto dispatch0;
2088 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002089
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002090 if (ike0->exchange == IKEV2_EXCHANGE_SA_INIT)
2091 {
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002092 sa0 = &sa;
2093 memset (sa0, 0, sizeof (*sa0));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002094
Radu Nicolaucb33dc22017-02-16 16:49:46 +00002095 if (ike0->flags & IKEV2_HDR_FLAG_INITIATOR)
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002096 {
Radu Nicolaucb33dc22017-02-16 16:49:46 +00002097 if (ike0->rspi == 0)
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002098 {
Radu Nicolaucb33dc22017-02-16 16:49:46 +00002099 sa0->raddr.as_u32 = ip40->dst_address.as_u32;
2100 sa0->iaddr.as_u32 = ip40->src_address.as_u32;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002101
Radu Nicolaucb33dc22017-02-16 16:49:46 +00002102 r = ikev2_retransmit_sa_init (ike0, sa0->iaddr,
2103 sa0->raddr);
2104 if (r == 1)
2105 {
2106 vlib_node_increment_counter (vm, ikev2_node.index,
2107 IKEV2_ERROR_IKE_SA_INIT_RETRANSMIT,
2108 1);
2109 len = clib_net_to_host_u32 (ike0->length);
2110 goto dispatch0;
2111 }
2112 else if (r == -1)
2113 {
2114 vlib_node_increment_counter (vm, ikev2_node.index,
2115 IKEV2_ERROR_IKE_SA_INIT_IGNORE,
2116 1);
2117 goto dispatch0;
2118 }
2119
2120 ikev2_process_sa_init_req (vm, sa0, ike0);
2121
2122 if (sa0->state == IKEV2_STATE_SA_INIT)
2123 {
2124 ikev2_sa_free_proposal_vector (&sa0->r_proposals);
2125 sa0->r_proposals =
2126 ikev2_select_proposal (sa0->i_proposals,
2127 IKEV2_PROTOCOL_IKE);
2128 ikev2_generate_sa_init_data (sa0);
2129 }
2130
2131 if (sa0->state == IKEV2_STATE_SA_INIT
2132 || sa0->state == IKEV2_STATE_NOTIFY_AND_DELETE)
2133 {
2134 len = ikev2_generate_message (sa0, ike0, 0);
2135 }
2136
2137 if (sa0->state == IKEV2_STATE_SA_INIT)
2138 {
2139 /* add SA to the pool */
Damjan Marion586afd72017-04-05 19:18:20 +02002140 pool_get (km->per_thread_data[thread_index].sas,
2141 sa0);
Radu Nicolaucb33dc22017-02-16 16:49:46 +00002142 clib_memcpy (sa0, &sa, sizeof (*sa0));
Damjan Marion586afd72017-04-05 19:18:20 +02002143 hash_set (km->
2144 per_thread_data[thread_index].sa_by_rspi,
Radu Nicolaucb33dc22017-02-16 16:49:46 +00002145 sa0->rspi,
Damjan Marion586afd72017-04-05 19:18:20 +02002146 sa0 -
2147 km->per_thread_data[thread_index].sas);
Radu Nicolaucb33dc22017-02-16 16:49:46 +00002148 }
2149 else
2150 {
2151 ikev2_sa_free_all_vec (sa0);
2152 }
2153 }
2154 }
2155 else
2156 {
2157 ikev2_process_sa_init_resp (vm, sa0, ike0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002158
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002159 if (sa0->state == IKEV2_STATE_SA_INIT)
2160 {
Radu Nicolaucb33dc22017-02-16 16:49:46 +00002161 ike0->exchange = IKEV2_EXCHANGE_IKE_AUTH;
2162 uword *p = hash_get (km->sa_by_ispi, ike0->ispi);
2163 if (p)
2164 {
2165 ikev2_sa_t *sai =
2166 pool_elt_at_index (km->sais, p[0]);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002167
Radu Nicolaucb33dc22017-02-16 16:49:46 +00002168 ikev2_complete_sa_data (sa0, sai);
2169 ikev2_calc_keys (sa0);
2170 ikev2_sa_auth_init (sa0);
2171 len = ikev2_generate_message (sa0, ike0, 0);
2172 }
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002173 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002174
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002175 if (sa0->state == IKEV2_STATE_SA_INIT)
2176 {
2177 /* add SA to the pool */
Damjan Marion586afd72017-04-05 19:18:20 +02002178 pool_get (km->per_thread_data[thread_index].sas, sa0);
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002179 clib_memcpy (sa0, &sa, sizeof (*sa0));
Damjan Marion586afd72017-04-05 19:18:20 +02002180 hash_set (km->per_thread_data[thread_index].sa_by_rspi,
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002181 sa0->rspi,
Damjan Marion586afd72017-04-05 19:18:20 +02002182 sa0 - km->per_thread_data[thread_index].sas);
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002183 }
2184 else
2185 {
2186 ikev2_sa_free_all_vec (sa0);
2187 }
2188 }
2189 }
2190 else if (ike0->exchange == IKEV2_EXCHANGE_IKE_AUTH)
2191 {
2192 uword *p;
Damjan Marion586afd72017-04-05 19:18:20 +02002193 p = hash_get (km->per_thread_data[thread_index].sa_by_rspi,
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002194 clib_net_to_host_u64 (ike0->rspi));
2195 if (p)
2196 {
Damjan Marion586afd72017-04-05 19:18:20 +02002197 sa0 =
2198 pool_elt_at_index (km->per_thread_data[thread_index].sas,
2199 p[0]);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002200
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002201 r = ikev2_retransmit_resp (sa0, ike0);
2202 if (r == 1)
2203 {
2204 vlib_node_increment_counter (vm, ikev2_node.index,
2205 IKEV2_ERROR_IKE_REQ_RETRANSMIT,
2206 1);
2207 len = clib_net_to_host_u32 (ike0->length);
2208 goto dispatch0;
2209 }
2210 else if (r == -1)
2211 {
2212 vlib_node_increment_counter (vm, ikev2_node.index,
2213 IKEV2_ERROR_IKE_REQ_IGNORE,
2214 1);
2215 goto dispatch0;
2216 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002217
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002218 ikev2_process_auth_req (vm, sa0, ike0);
2219 ikev2_sa_auth (sa0);
2220 if (sa0->state == IKEV2_STATE_AUTHENTICATED)
2221 {
2222 ikev2_initial_contact_cleanup (sa0);
2223 ikev2_sa_match_ts (sa0);
2224 if (sa0->state != IKEV2_STATE_TS_UNACCEPTABLE)
2225 ikev2_create_tunnel_interface (km->vnet_main, sa0,
2226 &sa0->childs[0]);
2227 }
Radu Nicolaucb33dc22017-02-16 16:49:46 +00002228
2229 if (sa0->is_initiator)
2230 {
2231 uword *p = hash_get (km->sa_by_ispi, ike0->ispi);
2232 if (p)
2233 {
2234 ikev2_sa_t *sai =
2235 pool_elt_at_index (km->sais, p[0]);
2236 hash_unset (km->sa_by_ispi, sai->ispi);
2237 ikev2_sa_free_all_vec (sai);
2238 pool_put (km->sais, sai);
2239 }
2240 }
2241 else
2242 {
2243 len = ikev2_generate_message (sa0, ike0, 0);
2244 }
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002245 }
2246 }
2247 else if (ike0->exchange == IKEV2_EXCHANGE_INFORMATIONAL)
2248 {
2249 uword *p;
Damjan Marion586afd72017-04-05 19:18:20 +02002250 p = hash_get (km->per_thread_data[thread_index].sa_by_rspi,
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002251 clib_net_to_host_u64 (ike0->rspi));
2252 if (p)
2253 {
Damjan Marion586afd72017-04-05 19:18:20 +02002254 sa0 =
2255 pool_elt_at_index (km->per_thread_data[thread_index].sas,
2256 p[0]);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002257
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002258 r = ikev2_retransmit_resp (sa0, ike0);
2259 if (r == 1)
2260 {
2261 vlib_node_increment_counter (vm, ikev2_node.index,
2262 IKEV2_ERROR_IKE_REQ_RETRANSMIT,
2263 1);
2264 len = clib_net_to_host_u32 (ike0->length);
2265 goto dispatch0;
2266 }
2267 else if (r == -1)
2268 {
2269 vlib_node_increment_counter (vm, ikev2_node.index,
2270 IKEV2_ERROR_IKE_REQ_IGNORE,
2271 1);
2272 goto dispatch0;
2273 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002274
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002275 ikev2_process_informational_req (vm, sa0, ike0);
2276 if (sa0->del)
2277 {
2278 if (sa0->del[0].protocol_id != IKEV2_PROTOCOL_IKE)
2279 {
2280 ikev2_delete_t *d, *tmp, *resp = 0;
2281 vec_foreach (d, sa0->del)
2282 {
2283 ikev2_child_sa_t *ch_sa;
2284 ch_sa = ikev2_sa_get_child (sa0, d->spi,
Radu Nicolaucb33dc22017-02-16 16:49:46 +00002285 d->protocol_id,
2286 !sa0->is_initiator);
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002287 if (ch_sa)
2288 {
2289 ikev2_delete_tunnel_interface (km->vnet_main,
2290 sa0, ch_sa);
Radu Nicolaucb33dc22017-02-16 16:49:46 +00002291 if (!sa0->is_initiator)
2292 {
2293 vec_add2 (resp, tmp, 1);
2294 tmp->protocol_id = d->protocol_id;
2295 tmp->spi = ch_sa->r_proposals[0].spi;
2296 }
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002297 ikev2_sa_del_child_sa (sa0, ch_sa);
2298 }
2299 }
Radu Nicolaucb33dc22017-02-16 16:49:46 +00002300 if (!sa0->is_initiator)
2301 {
2302 vec_free (sa0->del);
2303 sa0->del = resp;
2304 }
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002305 }
2306 }
Radu Nicolaucb33dc22017-02-16 16:49:46 +00002307 if (!sa0->is_initiator)
2308 {
2309 len = ikev2_generate_message (sa0, ike0, 0);
2310 }
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002311 }
2312 }
2313 else if (ike0->exchange == IKEV2_EXCHANGE_CREATE_CHILD_SA)
2314 {
2315 uword *p;
Damjan Marion586afd72017-04-05 19:18:20 +02002316 p = hash_get (km->per_thread_data[thread_index].sa_by_rspi,
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002317 clib_net_to_host_u64 (ike0->rspi));
2318 if (p)
2319 {
Damjan Marion586afd72017-04-05 19:18:20 +02002320 sa0 =
2321 pool_elt_at_index (km->per_thread_data[thread_index].sas,
2322 p[0]);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002323
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002324 r = ikev2_retransmit_resp (sa0, ike0);
2325 if (r == 1)
2326 {
2327 vlib_node_increment_counter (vm, ikev2_node.index,
2328 IKEV2_ERROR_IKE_REQ_RETRANSMIT,
2329 1);
2330 len = clib_net_to_host_u32 (ike0->length);
2331 goto dispatch0;
2332 }
2333 else if (r == -1)
2334 {
2335 vlib_node_increment_counter (vm, ikev2_node.index,
2336 IKEV2_ERROR_IKE_REQ_IGNORE,
2337 1);
2338 goto dispatch0;
2339 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002340
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002341 ikev2_process_create_child_sa_req (vm, sa0, ike0);
2342 if (sa0->rekey)
2343 {
2344 if (sa0->rekey[0].protocol_id != IKEV2_PROTOCOL_IKE)
2345 {
2346 ikev2_child_sa_t *child;
2347 vec_add2 (sa0->childs, child, 1);
2348 child->r_proposals = sa0->rekey[0].r_proposal;
2349 child->i_proposals = sa0->rekey[0].i_proposal;
2350 child->tsi = sa0->rekey[0].tsi;
2351 child->tsr = sa0->rekey[0].tsr;
2352 ikev2_create_tunnel_interface (km->vnet_main, sa0,
2353 child);
2354 }
Radu Nicolaucb33dc22017-02-16 16:49:46 +00002355 if (sa0->is_initiator)
2356 {
2357 vec_del1 (sa0->rekey, 0);
2358 }
2359 else
2360 {
2361 len = ikev2_generate_message (sa0, ike0, 0);
2362 }
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002363 }
2364 }
2365 }
2366 else
2367 {
2368 clib_warning ("IKEv2 exchange %u packet received from %U to %U",
2369 ike0->exchange,
2370 format_ip4_address, ip40->src_address.as_u8,
2371 format_ip4_address, ip40->dst_address.as_u8);
2372 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002373
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002374 dispatch0:
2375 /* if we are sending packet back, rewrite headers */
2376 if (len)
2377 {
2378 next0 = IKEV2_NEXT_IP4_LOOKUP;
Radu Nicolaucb33dc22017-02-16 16:49:46 +00002379 if (sa0->is_initiator)
2380 {
2381 ip40->dst_address.as_u32 = sa0->raddr.as_u32;
2382 ip40->src_address.as_u32 = sa0->iaddr.as_u32;
2383 }
2384 else
2385 {
2386 ip40->dst_address.as_u32 = sa0->iaddr.as_u32;
2387 ip40->src_address.as_u32 = sa0->raddr.as_u32;
2388 }
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002389 udp0->length =
2390 clib_host_to_net_u16 (len + sizeof (udp_header_t));
2391 udp0->checksum = 0;
2392 b0->current_length =
2393 len + sizeof (ip4_header_t) + sizeof (udp_header_t);
2394 ip40->length = clib_host_to_net_u16 (b0->current_length);
2395 ip40->checksum = ip4_header_checksum (ip40);
2396 }
2397 /* delete sa */
2398 if (sa0 && (sa0->state == IKEV2_STATE_DELETED ||
2399 sa0->state == IKEV2_STATE_NOTIFY_AND_DELETE))
2400 {
2401 ikev2_child_sa_t *c;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002402
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002403 vec_foreach (c, sa0->childs)
2404 ikev2_delete_tunnel_interface (km->vnet_main, sa0, c);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002405
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002406 ikev2_delete_sa (sa0);
2407 }
2408 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002409
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002410 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
2411 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
2412 {
2413 ikev2_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
2414 t->sw_if_index = sw_if_index0;
2415 t->next_index = next0;
2416 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002417
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002418 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
2419 n_left_to_next, bi0, next0);
2420 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002421
2422 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2423 }
2424
2425 vlib_node_increment_counter (vm, ikev2_node.index,
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002426 IKEV2_ERROR_PROCESSED, frame->n_vectors);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002427 return frame->n_vectors;
2428}
2429
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002430/* *INDENT-OFF* */
Jean-Mickael Guerin8941ec22016-03-04 14:14:21 +01002431VLIB_REGISTER_NODE (ikev2_node,static) = {
Ed Warnickecb9cada2015-12-08 15:45:58 -07002432 .function = ikev2_node_fn,
2433 .name = "ikev2",
2434 .vector_size = sizeof (u32),
2435 .format_trace = format_ikev2_trace,
2436 .type = VLIB_NODE_TYPE_INTERNAL,
2437
2438 .n_errors = ARRAY_LEN(ikev2_error_strings),
2439 .error_strings = ikev2_error_strings,
2440
2441 .n_next_nodes = IKEV2_N_NEXT,
2442
2443 .next_nodes = {
2444 [IKEV2_NEXT_IP4_LOOKUP] = "ip4-lookup",
2445 [IKEV2_NEXT_ERROR_DROP] = "error-drop",
2446 },
2447};
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002448/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002449
2450
Radu Nicolaucb33dc22017-02-16 16:49:46 +00002451static clib_error_t *
2452ikev2_set_initiator_proposals (vlib_main_t * vm, ikev2_sa_t * sa,
2453 ikev2_transforms_set * ts,
2454 ikev2_sa_proposal_t ** proposals, int is_ike)
2455{
2456 clib_error_t *r;
2457 ikev2_main_t *km = &ikev2_main;
2458 ikev2_sa_proposal_t *proposal;
2459 vec_add2 (*proposals, proposal, 1);
2460 ikev2_sa_transform_t *td;
2461 int error;
2462
2463 /* Encryption */
2464 error = 1;
2465 vec_foreach (td, km->supported_transforms)
2466 {
2467 if (td->type == IKEV2_TRANSFORM_TYPE_ENCR
2468 && td->encr_type == IKEV2_TRANSFORM_ENCR_TYPE_AES_CBC
2469 && td->key_len == ts->crypto_key_size / 8)
2470 {
2471 u16 attr[2];
2472 attr[0] = clib_host_to_net_u16 (14 | (1 << 15));
2473 attr[1] = clib_host_to_net_u16 (td->key_len << 3);
2474 vec_add (td->attrs, (u8 *) attr, 4);
2475 vec_add1 (proposal->transforms, *td);
2476 td->attrs = 0;
2477
2478 error = 0;
2479 break;
2480 }
2481 }
2482 if (error)
2483 {
2484 r = clib_error_return (0, "Unsupported algorithm");
2485 return r;
2486 }
2487
2488 /* Integrity */
2489 error = 1;
2490 vec_foreach (td, km->supported_transforms)
2491 {
2492 if (td->type == IKEV2_TRANSFORM_TYPE_INTEG
2493 && td->integ_type == IKEV2_TRANSFORM_INTEG_TYPE_AUTH_HMAC_SHA1_96)
2494 {
2495 vec_add1 (proposal->transforms, *td);
2496 error = 0;
2497 break;
2498 }
2499 }
2500 if (error)
2501 {
2502 r = clib_error_return (0, "Unsupported algorithm");
2503 return r;
2504 }
2505
2506 /* PRF */
2507 if (is_ike)
2508 {
2509 error = 1;
2510 vec_foreach (td, km->supported_transforms)
2511 {
2512 if (td->type == IKEV2_TRANSFORM_TYPE_PRF
2513 && td->prf_type == IKEV2_TRANSFORM_PRF_TYPE_PRF_HMAC_SHA1)
2514 {
2515 vec_add1 (proposal->transforms, *td);
2516 error = 0;
2517 break;
2518 }
2519 }
2520 if (error)
2521 {
2522 r = clib_error_return (0, "Unsupported algorithm");
2523 return r;
2524 }
2525 }
2526
2527 /* DH */
2528 error = 1;
2529 vec_foreach (td, km->supported_transforms)
2530 {
2531 if (td->type == IKEV2_TRANSFORM_TYPE_DH && td->dh_type == ts->dh_type)
2532 {
2533 vec_add1 (proposal->transforms, *td);
2534 if (is_ike)
2535 {
2536 sa->dh_group = td->dh_type;
2537 }
2538 error = 0;
2539 break;
2540 }
2541 }
2542 if (error)
2543 {
2544 r = clib_error_return (0, "Unsupported algorithm");
2545 return r;
2546 }
2547
2548 if (!is_ike)
2549 {
2550 error = 1;
2551 vec_foreach (td, km->supported_transforms)
2552 {
2553 if (td->type == IKEV2_TRANSFORM_TYPE_ESN)
2554 {
2555 vec_add1 (proposal->transforms, *td);
2556 error = 0;
2557 break;
2558 }
2559 }
2560 if (error)
2561 {
2562 r = clib_error_return (0, "Unsupported algorithm");
2563 return r;
2564 }
2565 }
2566
2567
2568 return 0;
2569}
2570
Ed Warnickecb9cada2015-12-08 15:45:58 -07002571static ikev2_profile_t *
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002572ikev2_profile_index_by_name (u8 * name)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002573{
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002574 ikev2_main_t *km = &ikev2_main;
2575 uword *p;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002576
2577 p = mhash_get (&km->profile_index_by_name, name);
2578 if (!p)
2579 return 0;
2580
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002581 return pool_elt_at_index (km->profiles, p[0]);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002582}
2583
Radu Nicolaucb33dc22017-02-16 16:49:46 +00002584
2585static void
2586ikev2_send_ike (vlib_main_t * vm, ip4_address_t * src, ip4_address_t * dst,
2587 u32 bi0, u32 len)
2588{
2589 ip4_header_t *ip40;
2590 udp_header_t *udp0;
2591 vlib_buffer_t *b0;
2592 vlib_frame_t *f;
2593 u32 *to_next;
2594
2595 b0 = vlib_get_buffer (vm, bi0);
2596 vlib_buffer_advance (b0, -sizeof (udp_header_t));
2597 udp0 = vlib_buffer_get_current (b0);
2598 vlib_buffer_advance (b0, -sizeof (ip4_header_t));
2599 ip40 = vlib_buffer_get_current (b0);
2600
2601
2602 ip40->ip_version_and_header_length = 0x45;
2603 ip40->tos = 0;
2604 ip40->fragment_id = 0;
2605 ip40->flags_and_fragment_offset = 0;
2606 ip40->ttl = 0xff;
2607 ip40->protocol = IP_PROTOCOL_UDP;
2608 ip40->dst_address.as_u32 = dst->as_u32;
2609 ip40->src_address.as_u32 = src->as_u32;
2610 udp0->dst_port = clib_host_to_net_u16 (500);
2611 udp0->src_port = clib_host_to_net_u16 (500);
2612 udp0->length = clib_host_to_net_u16 (len + sizeof (udp_header_t));
2613 udp0->checksum = 0;
2614 b0->current_length = len + sizeof (ip4_header_t) + sizeof (udp_header_t);
2615 ip40->length = clib_host_to_net_u16 (b0->current_length);
2616 ip40->checksum = ip4_header_checksum (ip40);
2617
2618
2619 /* send the request */
2620 f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
2621 to_next = vlib_frame_vector_args (f);
2622 to_next[0] = bi0;
2623 f->n_vectors = 1;
2624 vlib_put_frame_to_node (vm, ip4_lookup_node.index, f);
2625
2626}
2627
2628static u32
2629ikev2_get_new_ike_header_buff (vlib_main_t * vm, ike_header_t ** ike)
2630{
2631 u32 bi0;
2632 if (vlib_buffer_alloc (vm, &bi0, 1) != 1)
2633 {
2634 *ike = 0;
2635 return 0;
2636 }
2637 vlib_buffer_t *b0 = vlib_get_buffer (vm, bi0);
2638 *ike = vlib_buffer_get_current (b0);
2639 return bi0;
2640}
2641
Ed Warnickecb9cada2015-12-08 15:45:58 -07002642clib_error_t *
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002643ikev2_set_local_key (vlib_main_t * vm, u8 * file)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002644{
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002645 ikev2_main_t *km = &ikev2_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002646
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002647 km->pkey = ikev2_load_key_file (file);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002648 if (km->pkey == NULL)
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002649 return clib_error_return (0, "load key '%s' failed", file);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002650
2651 return 0;
2652}
2653
2654clib_error_t *
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002655ikev2_add_del_profile (vlib_main_t * vm, u8 * name, int is_add)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002656{
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002657 ikev2_main_t *km = &ikev2_main;
2658 ikev2_profile_t *p;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002659
2660 if (is_add)
2661 {
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002662 if (ikev2_profile_index_by_name (name))
2663 return clib_error_return (0, "policy %v already exists", name);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002664
2665 pool_get (km->profiles, p);
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002666 memset (p, 0, sizeof (*p));
2667 p->name = vec_dup (name);
Radu Nicolaucb33dc22017-02-16 16:49:46 +00002668 p->responder.sw_if_index = ~0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002669 uword index = p - km->profiles;
2670 mhash_set_mem (&km->profile_index_by_name, name, &index, 0);
2671 }
2672 else
2673 {
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002674 p = ikev2_profile_index_by_name (name);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002675 if (!p)
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002676 return clib_error_return (0, "policy %v does not exists", name);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002677
2678 vec_free (p->name);
2679 pool_put (km->profiles, p);
2680 mhash_unset (&km->profile_index_by_name, name, 0);
2681 }
2682 return 0;
2683}
2684
2685clib_error_t *
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002686ikev2_set_profile_auth (vlib_main_t * vm, u8 * name, u8 auth_method,
2687 u8 * auth_data, u8 data_hex_format)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002688{
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002689 ikev2_profile_t *p;
2690 clib_error_t *r;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002691
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002692 p = ikev2_profile_index_by_name (name);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002693
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002694 if (!p)
2695 {
2696 r = clib_error_return (0, "unknown profile %v", name);
2697 return r;
2698 }
2699 vec_free (p->auth.data);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002700 p->auth.method = auth_method;
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002701 p->auth.data = vec_dup (auth_data);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002702 p->auth.hex = data_hex_format;
2703
2704 if (auth_method == IKEV2_AUTH_METHOD_RSA_SIG)
2705 {
Matus Fabian698b9522016-09-13 23:15:56 -07002706 vec_add1 (p->auth.data, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002707 if (p->auth.key)
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002708 EVP_PKEY_free (p->auth.key);
2709 p->auth.key = ikev2_load_cert_file (auth_data);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002710 if (p->auth.key == NULL)
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002711 return clib_error_return (0, "load cert '%s' failed", auth_data);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002712 }
2713
2714 return 0;
2715}
2716
2717clib_error_t *
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002718ikev2_set_profile_id (vlib_main_t * vm, u8 * name, u8 id_type, u8 * data,
2719 int is_local)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002720{
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002721 ikev2_profile_t *p;
2722 clib_error_t *r;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002723
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002724 if (id_type > IKEV2_ID_TYPE_ID_RFC822_ADDR
2725 && id_type < IKEV2_ID_TYPE_ID_KEY_ID)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002726 {
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002727 r = clib_error_return (0, "unsupported identity type %U",
2728 format_ikev2_id_type, id_type);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002729 return r;
2730 }
2731
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002732 p = ikev2_profile_index_by_name (name);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002733
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002734 if (!p)
2735 {
2736 r = clib_error_return (0, "unknown profile %v", name);
2737 return r;
2738 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002739
2740 if (is_local)
2741 {
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002742 vec_free (p->loc_id.data);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002743 p->loc_id.type = id_type;
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002744 p->loc_id.data = vec_dup (data);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002745 }
2746 else
2747 {
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002748 vec_free (p->rem_id.data);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002749 p->rem_id.type = id_type;
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002750 p->rem_id.data = vec_dup (data);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002751 }
2752
2753 return 0;
2754}
2755
2756clib_error_t *
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002757ikev2_set_profile_ts (vlib_main_t * vm, u8 * name, u8 protocol_id,
2758 u16 start_port, u16 end_port, ip4_address_t start_addr,
2759 ip4_address_t end_addr, int is_local)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002760{
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002761 ikev2_profile_t *p;
2762 clib_error_t *r;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002763
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002764 p = ikev2_profile_index_by_name (name);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002765
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002766 if (!p)
2767 {
2768 r = clib_error_return (0, "unknown profile %v", name);
2769 return r;
2770 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002771
2772 if (is_local)
2773 {
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07002774 p->loc_ts.start_addr.as_u32 = start_addr.as_u32;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002775 p->loc_ts.end_addr.as_u32 = end_addr.as_u32;
2776 p->loc_ts.start_port = start_port;
2777 p->loc_ts.end_port = end_port;
2778 p->loc_ts.protocol_id = protocol_id;
2779 p->loc_ts.ts_type = 7;
2780 }
2781 else
2782 {
2783 p->rem_ts.start_addr.as_u32 = start_addr.as_u32;
2784 p->rem_ts.end_addr.as_u32 = end_addr.as_u32;
2785 p->rem_ts.start_port = start_port;
2786 p->rem_ts.end_port = end_port;
2787 p->rem_ts.protocol_id = protocol_id;
2788 p->rem_ts.ts_type = 7;
2789 }
2790
2791 return 0;
2792}
2793
2794
2795clib_error_t *
Radu Nicolaucb33dc22017-02-16 16:49:46 +00002796ikev2_set_profile_responder (vlib_main_t * vm, u8 * name,
2797 u32 sw_if_index, ip4_address_t ip4)
2798{
2799 ikev2_profile_t *p;
2800 clib_error_t *r;
2801
2802 p = ikev2_profile_index_by_name (name);
2803
2804 if (!p)
2805 {
2806 r = clib_error_return (0, "unknown profile %v", name);
2807 return r;
2808 }
2809
2810 p->responder.sw_if_index = sw_if_index;
2811 p->responder.ip4 = ip4;
2812
2813 return 0;
2814}
2815
2816clib_error_t *
2817ikev2_set_profile_ike_transforms (vlib_main_t * vm, u8 * name,
2818 ikev2_transform_encr_type_t crypto_alg,
2819 ikev2_transform_integ_type_t integ_alg,
2820 ikev2_transform_dh_type_t dh_type,
2821 u32 crypto_key_size)
2822{
2823 ikev2_profile_t *p;
2824 clib_error_t *r;
2825
2826 p = ikev2_profile_index_by_name (name);
2827
2828 if (!p)
2829 {
2830 r = clib_error_return (0, "unknown profile %v", name);
2831 return r;
2832 }
2833
2834 p->ike_ts.crypto_alg = crypto_alg;
2835 p->ike_ts.integ_alg = integ_alg;
2836 p->ike_ts.dh_type = dh_type;
2837 p->ike_ts.crypto_key_size = crypto_key_size;
2838 return 0;
2839}
2840
2841clib_error_t *
2842ikev2_set_profile_esp_transforms (vlib_main_t * vm, u8 * name,
2843 ikev2_transform_encr_type_t crypto_alg,
2844 ikev2_transform_integ_type_t integ_alg,
2845 ikev2_transform_dh_type_t dh_type,
2846 u32 crypto_key_size)
2847{
2848 ikev2_profile_t *p;
2849 clib_error_t *r;
2850
2851 p = ikev2_profile_index_by_name (name);
2852
2853 if (!p)
2854 {
2855 r = clib_error_return (0, "unknown profile %v", name);
2856 return r;
2857 }
2858
2859 p->esp_ts.crypto_alg = crypto_alg;
2860 p->esp_ts.integ_alg = integ_alg;
2861 p->esp_ts.dh_type = dh_type;
2862 p->esp_ts.crypto_key_size = crypto_key_size;
2863 return 0;
2864}
2865
2866clib_error_t *
2867ikev2_set_profile_sa_lifetime (vlib_main_t * vm, u8 * name,
2868 u64 lifetime, u32 jitter, u32 handover,
2869 u64 maxdata)
2870{
2871 ikev2_profile_t *p;
2872 clib_error_t *r;
2873
2874 p = ikev2_profile_index_by_name (name);
2875
2876 if (!p)
2877 {
2878 r = clib_error_return (0, "unknown profile %v", name);
2879 return r;
2880 }
2881
2882 p->lifetime = lifetime;
2883 p->lifetime_jitter = jitter;
2884 p->handover = handover;
2885 p->lifetime_maxdata = maxdata;
2886 return 0;
2887}
2888
2889clib_error_t *
2890ikev2_initiate_sa_init (vlib_main_t * vm, u8 * name)
2891{
2892 ikev2_profile_t *p;
2893 clib_error_t *r;
2894 ip4_main_t *im = &ip4_main;
2895 ikev2_main_t *km = &ikev2_main;
2896
2897 p = ikev2_profile_index_by_name (name);
2898
2899 if (!p)
2900 {
2901 r = clib_error_return (0, "unknown profile %v", name);
2902 return r;
2903 }
2904
2905 if (p->responder.sw_if_index == ~0 || p->responder.ip4.data_u32 == 0)
2906 {
2907 r = clib_error_return (0, "responder not set for profile %v", name);
2908 return r;
2909 }
2910
2911
2912 /* Create the Initiator Request */
2913 {
2914 ike_header_t *ike0;
2915 u32 bi0 = 0;
2916 ip_lookup_main_t *lm = &im->lookup_main;
2917 u32 if_add_index0;
2918 int len = sizeof (ike_header_t);
2919
2920 /* Get own iface IP */
2921 if_add_index0 =
2922 lm->if_address_pool_index_by_sw_if_index[p->responder.sw_if_index];
2923 ip_interface_address_t *if_add =
2924 pool_elt_at_index (lm->if_address_pool, if_add_index0);
2925 ip4_address_t *if_ip = ip_interface_address_get_address (lm, if_add);
2926
2927 bi0 = ikev2_get_new_ike_header_buff (vm, &ike0);
2928
2929 /* Prepare the SA and the IKE payload */
2930 ikev2_sa_t sa;
2931 memset (&sa, 0, sizeof (ikev2_sa_t));
2932 ikev2_payload_chain_t *chain = 0;
2933 ikev2_payload_new_chain (chain);
2934
2935 /* Build the IKE proposal payload */
2936 ikev2_sa_proposal_t *proposals = 0;
2937 ikev2_set_initiator_proposals (vm, &sa, &p->ike_ts, &proposals, 1);
2938 proposals[0].proposal_num = 1;
2939 proposals[0].protocol_id = IKEV2_PROTOCOL_IKE;
2940
2941 /* Add and then cleanup proposal data */
2942 ikev2_payload_add_sa (chain, proposals);
2943 ikev2_sa_free_proposal_vector (&proposals);
2944
2945 sa.is_initiator = 1;
2946 sa.profile = p;
2947 sa.state = IKEV2_STATE_SA_INIT;
2948 ikev2_generate_sa_init_data (&sa);
2949 ikev2_payload_add_ke (chain, sa.dh_group, sa.i_dh_data);
2950 ikev2_payload_add_nonce (chain, sa.i_nonce);
2951
2952 /* Build the child SA proposal */
2953 vec_resize (sa.childs, 1);
2954 ikev2_set_initiator_proposals (vm, &sa, &p->esp_ts,
2955 &sa.childs[0].i_proposals, 0);
2956 sa.childs[0].i_proposals[0].proposal_num = 1;
2957 sa.childs[0].i_proposals[0].protocol_id = IKEV2_PROTOCOL_ESP;
2958 RAND_bytes ((u8 *) & sa.childs[0].i_proposals[0].spi,
2959 sizeof (sa.childs[0].i_proposals[0].spi));
2960
2961
2962
2963 /* Add NAT detection notification messages (mandatory) */
2964 u8 nat_detection_source[8 + 8 + 4 + 2];
2965 u8 *nat_detection_sha1 = vec_new (u8, 20);
2966
2967 u64 tmpspi = clib_host_to_net_u64 (sa.ispi);
2968 clib_memcpy (&nat_detection_source[0], &tmpspi, sizeof (tmpspi));
2969 tmpspi = clib_host_to_net_u64 (sa.rspi);
2970 clib_memcpy (&nat_detection_source[8], &tmpspi, sizeof (tmpspi));
2971 u16 tmpport = clib_host_to_net_u16 (500);
2972 clib_memcpy (&nat_detection_source[8 + 8 + 4], &tmpport,
2973 sizeof (tmpport));
2974 u32 tmpip = clib_host_to_net_u32 (if_ip->as_u32);
2975 clib_memcpy (&nat_detection_source[8 + 8], &tmpip, sizeof (tmpip));
2976 SHA1 (nat_detection_source, sizeof (nat_detection_source),
2977 nat_detection_sha1);
2978 ikev2_payload_add_notify (chain, IKEV2_NOTIFY_MSG_NAT_DETECTION_SOURCE_IP,
2979 nat_detection_sha1);
2980 tmpip = clib_host_to_net_u32 (p->responder.ip4.as_u32);
2981 clib_memcpy (&nat_detection_source[8 + 8], &tmpip, sizeof (tmpip));
2982 SHA1 (nat_detection_source, sizeof (nat_detection_source),
2983 nat_detection_sha1);
2984 ikev2_payload_add_notify (chain,
2985 IKEV2_NOTIFY_MSG_NAT_DETECTION_DESTINATION_IP,
2986 nat_detection_sha1);
2987 vec_free (nat_detection_sha1);
2988
2989 u8 *sig_hash_algo = vec_new (u8, 8);
2990 u64 tmpsig = clib_host_to_net_u64 (0x0001000200030004);
2991 clib_memcpy (sig_hash_algo, &tmpsig, sizeof (tmpsig));
2992 ikev2_payload_add_notify (chain,
2993 IKEV2_NOTIFY_MSG_SIGNATURE_HASH_ALGORITHMS,
2994 sig_hash_algo);
2995 vec_free (sig_hash_algo);
2996
2997
2998 /* Buffer update and bolierplate */
2999 len += vec_len (chain->data);
3000 ike0->nextpayload = chain->first_payload_type;
3001 ike0->length = clib_host_to_net_u32 (len);
3002 clib_memcpy (ike0->payload, chain->data, vec_len (chain->data));
3003 ikev2_payload_destroy_chain (chain);
3004
3005 ike0->version = IKE_VERSION_2;
3006 ike0->flags = IKEV2_HDR_FLAG_INITIATOR;
3007 ike0->exchange = IKEV2_EXCHANGE_SA_INIT;
3008 ike0->ispi = sa.ispi;
3009
3010 /* store whole IKE payload - needed for PSK auth */
3011 vec_free (sa.last_sa_init_req_packet_data);
3012 vec_add (sa.last_sa_init_req_packet_data, ike0, len);
3013
3014 /* add data to the SA then add it to the pool */
3015 sa.iaddr.as_u32 = if_ip->as_u32;
3016 sa.raddr.as_u32 = p->responder.ip4.as_u32;
3017 sa.i_id.type = p->loc_id.type;
3018 sa.i_id.data = vec_dup (p->loc_id.data);
3019 sa.i_auth.method = p->auth.method;
3020 sa.i_auth.hex = p->auth.hex;
3021 sa.i_auth.data = vec_dup (p->auth.data);
3022 sa.i_auth.key = vec_dup (p->auth.key);
3023 vec_add (sa.childs[0].tsi, &p->loc_ts, 1);
3024 vec_add (sa.childs[0].tsr, &p->rem_ts, 1);
3025
3026 /* add SA to the pool */
3027 ikev2_sa_t *sa0 = 0;
3028 pool_get (km->sais, sa0);
3029 clib_memcpy (sa0, &sa, sizeof (*sa0));
3030 hash_set (km->sa_by_ispi, sa0->ispi, sa0 - km->sais);
3031
3032 ikev2_send_ike (vm, if_ip, &p->responder.ip4, bi0, len);
3033
3034 }
3035
3036 return 0;
3037}
3038
3039static void
3040ikev2_delete_child_sa_internal (vlib_main_t * vm, ikev2_sa_t * sa,
3041 ikev2_child_sa_t * csa)
3042{
3043 /* Create the Initiator notification for child SA removal */
3044 ikev2_main_t *km = &ikev2_main;
3045 ike_header_t *ike0;
3046 u32 bi0 = 0;
3047 int len;
3048
3049 bi0 = ikev2_get_new_ike_header_buff (vm, &ike0);
3050
3051
3052 ike0->exchange = IKEV2_EXCHANGE_INFORMATIONAL;
3053 ike0->ispi = clib_host_to_net_u64 (sa->ispi);
3054 ike0->rspi = clib_host_to_net_u64 (sa->rspi);
3055 vec_resize (sa->del, 1);
3056 sa->del->protocol_id = IKEV2_PROTOCOL_ESP;
3057 sa->del->spi = csa->i_proposals->spi;
3058 ike0->msgid = clib_host_to_net_u32 (sa->last_init_msg_id + 1);
3059 sa->last_init_msg_id = clib_net_to_host_u32 (ike0->msgid);
3060 len = ikev2_generate_message (sa, ike0, 0);
3061
3062 ikev2_send_ike (vm, &sa->iaddr, &sa->raddr, bi0, len);
3063
3064 /* delete local child SA */
3065 ikev2_delete_tunnel_interface (km->vnet_main, sa, csa);
3066 ikev2_sa_del_child_sa (sa, csa);
3067}
3068
3069clib_error_t *
3070ikev2_initiate_delete_child_sa (vlib_main_t * vm, u32 ispi)
3071{
3072 clib_error_t *r;
3073 ikev2_main_t *km = &ikev2_main;
3074 ikev2_main_per_thread_data_t *tkm;
3075 ikev2_sa_t *fsa = 0;
3076 ikev2_child_sa_t *fchild = 0;
3077
3078 /* Search for the child SA */
3079 vec_foreach (tkm, km->per_thread_data)
3080 {
3081 ikev2_sa_t *sa;
3082 if (fchild)
3083 break;
3084 /* *INDENT-OFF* */
3085 pool_foreach (sa, tkm->sas, ({
3086 fchild = ikev2_sa_get_child(sa, ispi, IKEV2_PROTOCOL_ESP, 1);
3087 if (fchild)
3088 {
3089 fsa = sa;
3090 break;
3091 }
3092 }));
3093 /* *INDENT-ON* */
3094 }
3095
3096 if (!fchild || !fsa)
3097 {
3098 r = clib_error_return (0, "Child SA not found");
3099 return r;
3100 }
3101 else
3102 {
3103 ikev2_delete_child_sa_internal (vm, fsa, fchild);
3104 }
3105
3106 return 0;
3107}
3108
3109clib_error_t *
3110ikev2_initiate_delete_ike_sa (vlib_main_t * vm, u64 ispi)
3111{
3112 clib_error_t *r;
3113 ikev2_main_t *km = &ikev2_main;
3114 ikev2_main_per_thread_data_t *tkm;
3115 ikev2_sa_t *fsa = 0;
3116 ikev2_main_per_thread_data_t *ftkm = 0;
3117
3118 /* Search for the IKE SA */
3119 vec_foreach (tkm, km->per_thread_data)
3120 {
3121 ikev2_sa_t *sa;
3122 if (fsa)
3123 break;
3124 /* *INDENT-OFF* */
3125 pool_foreach (sa, tkm->sas, ({
3126 if (sa->ispi == ispi)
3127 {
3128 fsa = sa;
3129 ftkm = tkm;
3130 break;
3131 }
3132 }));
3133 /* *INDENT-ON* */
3134 }
3135
3136 if (!fsa)
3137 {
3138 r = clib_error_return (0, "IKE SA not found");
3139 return r;
3140 }
3141
3142
3143 /* Create the Initiator notification for IKE SA removal */
3144 {
3145 ike_header_t *ike0;
3146 u32 bi0 = 0;
3147 int len;
3148
3149 bi0 = ikev2_get_new_ike_header_buff (vm, &ike0);
3150
3151
3152 ike0->exchange = IKEV2_EXCHANGE_INFORMATIONAL;
3153 ike0->ispi = clib_host_to_net_u64 (fsa->ispi);
3154 ike0->rspi = clib_host_to_net_u64 (fsa->rspi);
3155 vec_resize (fsa->del, 1);
3156 fsa->del->protocol_id = IKEV2_PROTOCOL_IKE;
3157 fsa->del->spi = ispi;
3158 ike0->msgid = clib_host_to_net_u32 (fsa->last_init_msg_id + 1);
3159 fsa->last_init_msg_id = clib_net_to_host_u32 (ike0->msgid);
3160 len = ikev2_generate_message (fsa, ike0, 0);
3161
3162 ikev2_send_ike (vm, &fsa->iaddr, &fsa->raddr, bi0, len);
3163 }
3164
3165
3166 /* delete local SA */
3167 ikev2_child_sa_t *c;
3168 vec_foreach (c, fsa->childs)
3169 {
3170 ikev2_delete_tunnel_interface (km->vnet_main, fsa, c);
3171 ikev2_sa_del_child_sa (fsa, c);
3172 }
3173 ikev2_sa_free_all_vec (fsa);
3174 uword *p = hash_get (ftkm->sa_by_rspi, fsa->rspi);
3175 if (p)
3176 {
3177 hash_unset (ftkm->sa_by_rspi, fsa->rspi);
3178 pool_put (ftkm->sas, fsa);
3179 }
3180
3181
3182 return 0;
3183}
3184
3185static void
3186ikev2_rekey_child_sa_internal (vlib_main_t * vm, ikev2_sa_t * sa,
3187 ikev2_child_sa_t * csa)
3188{
3189 /* Create the Initiator request for create child SA */
3190 ike_header_t *ike0;
3191 u32 bi0 = 0;
3192 int len;
3193
3194
3195 bi0 = ikev2_get_new_ike_header_buff (vm, &ike0);
3196
3197
3198 ike0->version = IKE_VERSION_2;
3199 ike0->flags = IKEV2_HDR_FLAG_INITIATOR;
3200 ike0->exchange = IKEV2_EXCHANGE_CREATE_CHILD_SA;
3201 ike0->ispi = clib_host_to_net_u64 (sa->ispi);
3202 ike0->rspi = clib_host_to_net_u64 (sa->rspi);
3203 ike0->msgid = clib_host_to_net_u32 (sa->last_init_msg_id + 1);
3204 sa->last_init_msg_id = clib_net_to_host_u32 (ike0->msgid);
3205
3206 ikev2_rekey_t *rekey;
3207 vec_add2 (sa->rekey, rekey, 1);
3208 ikev2_sa_proposal_t *proposals = vec_dup (csa->i_proposals);
3209
3210 /*need new ispi */
3211 RAND_bytes ((u8 *) & proposals[0].spi, sizeof (proposals[0].spi));
3212 rekey->spi = proposals[0].spi;
3213 rekey->ispi = csa->i_proposals->spi;
3214 len = ikev2_generate_message (sa, ike0, proposals);
3215 ikev2_send_ike (vm, &sa->iaddr, &sa->raddr, bi0, len);
3216 vec_free (proposals);
3217}
3218
3219clib_error_t *
3220ikev2_initiate_rekey_child_sa (vlib_main_t * vm, u32 ispi)
3221{
3222 clib_error_t *r;
3223 ikev2_main_t *km = &ikev2_main;
3224 ikev2_main_per_thread_data_t *tkm;
3225 ikev2_sa_t *fsa = 0;
3226 ikev2_child_sa_t *fchild = 0;
3227
3228 /* Search for the child SA */
3229 vec_foreach (tkm, km->per_thread_data)
3230 {
3231 ikev2_sa_t *sa;
3232 if (fchild)
3233 break;
3234 /* *INDENT-OFF* */
3235 pool_foreach (sa, tkm->sas, ({
3236 fchild = ikev2_sa_get_child(sa, ispi, IKEV2_PROTOCOL_ESP, 1);
3237 if (fchild)
3238 {
3239 fsa = sa;
3240 break;
3241 }
3242 }));
3243 /* *INDENT-ON* */
3244 }
3245
3246 if (!fchild || !fsa)
3247 {
3248 r = clib_error_return (0, "Child SA not found");
3249 return r;
3250 }
3251 else
3252 {
3253 ikev2_rekey_child_sa_internal (vm, fsa, fchild);
3254 }
3255
3256 return 0;
3257}
3258
3259clib_error_t *
Ed Warnickecb9cada2015-12-08 15:45:58 -07003260ikev2_init (vlib_main_t * vm)
3261{
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07003262 ikev2_main_t *km = &ikev2_main;
3263 clib_error_t *error;
3264 vlib_thread_main_t *tm = vlib_get_thread_main ();
Matthew Smith2838a232016-06-21 16:05:09 -05003265 int thread_id;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003266
3267 memset (km, 0, sizeof (ikev2_main_t));
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07003268 km->vnet_main = vnet_get_main ();
Ed Warnickecb9cada2015-12-08 15:45:58 -07003269 km->vlib_main = vm;
3270
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07003271 ikev2_crypto_init (km);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003272
Ed Warnickecb9cada2015-12-08 15:45:58 -07003273 mhash_init_vec_string (&km->profile_index_by_name, sizeof (uword));
3274
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07003275 vec_validate (km->per_thread_data, tm->n_vlib_mains - 1);
Matthew Smith2838a232016-06-21 16:05:09 -05003276 for (thread_id = 0; thread_id < tm->n_vlib_mains - 1; thread_id++)
3277 {
3278 km->per_thread_data[thread_id].sa_by_rspi =
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07003279 hash_create (0, sizeof (uword));
Matthew Smith2838a232016-06-21 16:05:09 -05003280 }
3281
Radu Nicolaucb33dc22017-02-16 16:49:46 +00003282 km->sa_by_ispi = hash_create (0, sizeof (uword));
3283
3284
Ed Warnickecb9cada2015-12-08 15:45:58 -07003285 if ((error = vlib_call_init_function (vm, ikev2_cli_init)))
3286 return error;
3287
3288 udp_register_dst_port (vm, 500, ikev2_node.index, 1);
3289
3290 return 0;
3291}
3292
3293
Radu Nicolaucb33dc22017-02-16 16:49:46 +00003294static u8
3295ikev2_mngr_process_child_sa (ikev2_sa_t * sa, ikev2_child_sa_t * csa)
3296{
3297 ikev2_main_t *km = &ikev2_main;
3298 vlib_main_t *vm = km->vlib_main;
3299 f64 now = vlib_time_now (vm);
3300 u8 res = 0;
3301
3302 if (sa->is_initiator && sa->profile && csa->time_to_expiration
3303 && now > csa->time_to_expiration)
3304 {
3305 if (!csa->is_expired || csa->rekey_retries > 0)
3306 {
3307 ikev2_rekey_child_sa_internal (vm, sa, csa);
3308 csa->time_to_expiration = now + sa->profile->handover;
3309 csa->is_expired = 1;
3310 if (csa->rekey_retries == 0)
3311 {
3312 csa->rekey_retries = 5;
3313 }
3314 else if (csa->rekey_retries > 0)
3315 {
3316 csa->rekey_retries--;
3317 clib_warning ("Rekeing Child SA 0x%x, retries left %d",
3318 csa->i_proposals->spi, csa->rekey_retries);
3319 if (csa->rekey_retries == 0)
3320 {
3321 csa->rekey_retries = -1;
3322 }
3323 }
3324 res |= 1;
3325 }
3326 else
3327 {
3328 csa->time_to_expiration = 0;
3329 ikev2_delete_child_sa_internal (vm, sa, csa);
3330 res |= 1;
3331 }
3332 }
3333
3334 return res;
3335}
3336
3337static void
3338ikev2_mngr_process_ipsec_sa (ipsec_sa_t * ipsec_sa)
3339{
3340 ikev2_main_t *km = &ikev2_main;
3341 vlib_main_t *vm = km->vlib_main;
3342 ikev2_main_per_thread_data_t *tkm;
3343 ikev2_sa_t *fsa = 0;
3344 ikev2_child_sa_t *fchild = 0;
3345 f64 now = vlib_time_now (vm);
3346
3347 /* Search for the SA and child SA */
3348 vec_foreach (tkm, km->per_thread_data)
3349 {
3350 ikev2_sa_t *sa;
3351 if (fchild)
3352 break;
3353 /* *INDENT-OFF* */
3354 pool_foreach (sa, tkm->sas, ({
3355 fchild = ikev2_sa_get_child(sa, ipsec_sa->spi, IKEV2_PROTOCOL_ESP, 1);
3356 if (fchild)
3357 {
3358 fsa = sa;
3359 break;
3360 }
3361 }));
3362 /* *INDENT-ON* */
3363 }
3364
3365 if (fchild && fsa && fsa->profile && fsa->profile->lifetime_maxdata)
3366 {
3367 if (!fchild->is_expired
3368 && ipsec_sa->total_data_size > fsa->profile->lifetime_maxdata)
3369 {
3370 fchild->time_to_expiration = now;
3371 }
3372 }
3373}
3374
3375static vlib_node_registration_t ikev2_mngr_process_node;
3376
3377static uword
3378ikev2_mngr_process_fn (vlib_main_t * vm, vlib_node_runtime_t * rt,
3379 vlib_frame_t * f)
3380{
3381 ikev2_main_t *km = &ikev2_main;
3382 ipsec_main_t *im = &ipsec_main;
3383
3384 while (1)
3385 {
3386 u8 req_sent = 0;
3387 vlib_process_wait_for_event_or_clock (vm, 1);
3388 vlib_process_get_events (vm, NULL);
3389
3390 /* process ike child sas */
3391 ikev2_main_per_thread_data_t *tkm;
3392 vec_foreach (tkm, km->per_thread_data)
3393 {
3394 ikev2_sa_t *sa;
3395 /* *INDENT-OFF* */
3396 pool_foreach (sa, tkm->sas, ({
3397 ikev2_child_sa_t *c;
3398 vec_foreach (c, sa->childs)
3399 {
3400 req_sent |= ikev2_mngr_process_child_sa(sa, c);
3401 }
3402 }));
3403 /* *INDENT-ON* */
3404 }
3405
3406 /* process ipsec sas */
3407 ipsec_sa_t *sa;
3408 /* *INDENT-OFF* */
3409 pool_foreach (sa, im->sad, ({
3410 ikev2_mngr_process_ipsec_sa(sa);
3411 }));
3412 /* *INDENT-ON* */
3413
3414 if (req_sent)
3415 {
3416 vlib_process_wait_for_event_or_clock (vm, 5);
3417 vlib_process_get_events (vm, NULL);
3418 req_sent = 0;
3419 }
3420
3421 }
3422 return 0;
3423}
3424
3425/* *INDENT-OFF* */
3426VLIB_REGISTER_NODE (ikev2_mngr_process_node, static) = {
3427 .function = ikev2_mngr_process_fn,
3428 .type = VLIB_NODE_TYPE_PROCESS,
3429 .name =
3430 "ikev2-manager-process",
3431};
3432
3433/* *INDENT-ON* */
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -07003434
3435/*
3436 * fd.io coding-style-patch-verification: ON
3437 *
3438 * Local Variables:
3439 * eval: (c-set-style "gnu")
3440 * End:
3441 */