FD.io VPP  v20.05-21-gb1500e9ff
Vector Packet Processing
ikev2_payload.c
Go to the documentation of this file.
1 /*
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 <ctype.h>
17 
18 #include <vnet/vnet.h>
19 #include <vnet/api_errno.h>
20 #include <vnet/ip/ip.h>
21 #include <vnet/interface.h>
22 
23 #include <vnet/ipsec/ipsec.h>
24 #include <plugins/ikev2/ikev2.h>
26 
27 /* *INDENT-OFF* */
28 typedef CLIB_PACKED (struct {
29  u8 nextpayload;
30  u8 flags;
31  u16 length;
32  u8 protocol_id;
33  u8 spi_size;
34  u16 msg_type;
35  u8 payload[0];
36 }) ike_notify_payload_header_t;
37 /* *INDENT-ON* */
38 
39 /* *INDENT-OFF* */
40 typedef CLIB_PACKED (struct {
41  u8 ts_type;
42  u8 protocol_id;
43  u16 selector_len;
44  u16 start_port;
45  u16 end_port;
46  ip4_address_t start_addr;
47  ip4_address_t end_addr;
49 /* *INDENT-OFF* */
50 
51 /* *INDENT-OFF* */
52 typedef CLIB_PACKED (struct {
53  u8 nextpayload;
54  u8 flags;
55  u16 length;
56  u8 num_ts;
57  u8 reserved[3];
59 }) ike_ts_payload_header_t;
60 /* *INDENT-OFF* */
61 
62 /* *INDENT-OFF* */
63 typedef CLIB_PACKED (struct {
64  u8 last_or_more;
65  u8 reserved;
66  u16 proposal_len;
67  u8 proposal_num;
68  u8 protocol_id;
69  u8 spi_size;
70  u8 num_transforms; u32 spi[0];
72 /* *INDENT-OFF* */
73 
74 /* *INDENT-OFF* */
75 typedef CLIB_PACKED (struct {
76  u8 last_or_more;
77  u8 reserved;
78  u16 transform_len;
79  u8 transform_type;
80  u8 reserved2;
81  u16 transform_id;
82  u8 attributes[0];
83 }) ike_sa_transform_data_t;
84 /* *INDENT-OFF* */
85 
86 /* *INDENT-OFF* */
87 typedef CLIB_PACKED (struct {
88  u8 nextpayload;
89  u8 flags;
90  u16 length;
91  u8 protocol_id;
92  u8 spi_size;
93  u16 num_of_spi;
94  u32 spi[0];
96 /* *INDENT-OFF* */
97 
98 static ike_payload_header_t *
100 {
101  ike_payload_header_t *hdr =
102  (ike_payload_header_t *) & c->data[c->last_hdr_off];
103  u8 *tmp;
104 
105  if (c->data)
106  hdr->nextpayload = payload_type;
107  else
108  c->first_payload_type = payload_type;
109 
110  c->last_hdr_off = vec_len (c->data);
111  vec_add2 (c->data, tmp, len);
112  hdr = (ike_payload_header_t *) tmp;
113  clib_memset (hdr, 0, len);
114 
115  hdr->length = clib_host_to_net_u16 (len);
116 
117  return hdr;
118 }
119 
120 static void
122 {
123  u16 len;
124  ike_payload_header_t *hdr;
125 
126  vec_append (c->data, data);
127  hdr = (ike_payload_header_t *) & c->data[c->last_hdr_off];
128  len = clib_net_to_host_u16 (hdr->length);
129  hdr->length = clib_host_to_net_u16 (len + vec_len (data));
130 }
131 
132 void
134 {
135  ikev2_payload_add_notify_2(c, msg_type, data, 0);
136 }
137 
138 void
140  u8 * data, ikev2_notify_t * notify)
141 {
142  ike_notify_payload_header_t *n;
143 
144  n =
145  (ike_notify_payload_header_t *) ikev2_payload_add_hdr (c,
147  sizeof (*n));
148  n->msg_type = clib_host_to_net_u16 (msg_type);
149  if (notify)
150  {
151  n->protocol_id = notify->protocol_id;
152  if (notify->spi)
153  {
154  n->spi_size = 4;
155  }
156  }
157  ikev2_payload_add_data (c, data);
158 }
159 
160 void
162  ikev2_sa_proposal_t * proposals)
163 {
164  ike_payload_header_t *ph;
166  ike_sa_transform_data_t *tr;
169 
170  u8 *tmp;
171  u8 *pr_data = 0;
172  u8 *tr_data = 0;
173 
174  ikev2_payload_add_hdr (c, IKEV2_PAYLOAD_SA, sizeof (*ph));
175 
176  vec_foreach (p, proposals)
177  {
178  int spi_size = (p->protocol_id == IKEV2_PROTOCOL_ESP) ? 4 : 0;
179  pr_data = vec_new (u8, sizeof (ike_sa_proposal_data_t) + spi_size);
180  prop = (ike_sa_proposal_data_t *) pr_data;
181  prop->last_or_more = proposals - p + 1 < vec_len (proposals) ? 2 : 0;
182  prop->protocol_id = p->protocol_id;
183  prop->proposal_num = p->proposal_num;
184  prop->spi_size = spi_size;
185  prop->num_transforms = vec_len (p->transforms);
186 
187  if (spi_size)
188  prop->spi[0] = clib_host_to_net_u32 (p->spi);
189 
190  vec_foreach (t, p->transforms)
191  {
192  vec_add2 (tr_data, tmp, sizeof (*tr) + vec_len (t->attrs));
193  tr = (ike_sa_transform_data_t *) tmp;
194  tr->last_or_more =
195  ((t - p->transforms) + 1 < vec_len (p->transforms)) ? 3 : 0;
196  tr->transform_type = t->type;
197  tr->transform_id = clib_host_to_net_u16 (t->transform_id);
198  tr->transform_len =
199  clib_host_to_net_u16 (sizeof (*tr) + vec_len (t->attrs));
200 
201  if (vec_len (t->attrs) > 0)
202  clib_memcpy_fast (tr->attributes, t->attrs, vec_len (t->attrs));
203  }
204 
205  prop->proposal_len =
206  clib_host_to_net_u16 (vec_len (tr_data) + vec_len (pr_data));
207  ikev2_payload_add_data (c, pr_data);
208  ikev2_payload_add_data (c, tr_data);
209  vec_free (pr_data);
210  vec_free (tr_data);
211  }
212 }
213 
214 void
216 {
217  ike_ke_payload_header_t *ke;
218  ke = (ike_ke_payload_header_t *) ikev2_payload_add_hdr (c, IKEV2_PAYLOAD_KE,
219  sizeof (*ke));
220 
221  ke->dh_group = clib_host_to_net_u16 (dh_group);
222  ikev2_payload_add_data (c, dh_data);
223 }
224 
225 void
227 {
229  sizeof (ike_payload_header_t));
230  ikev2_payload_add_data (c, nonce);
231 }
232 
233 void
235 {
236  ike_id_payload_header_t *idp;
237  idp =
238  (ike_id_payload_header_t *) ikev2_payload_add_hdr (c, type,
239  sizeof (*idp));
240 
241  idp->id_type = id->type;
242  ikev2_payload_add_data (c, id->data);
243 }
244 
245 void
247 {
249  u16 num_of_spi = vec_len (d);
250  ikev2_delete_t *d2;
251  dp =
254  sizeof (*dp));
255 
256  if (d[0].protocol_id == IKEV2_PROTOCOL_IKE)
257  {
258  dp->protocol_id = 1;
259  }
260  else
261  {
262  dp->protocol_id = d[0].protocol_id;
263  dp->spi_size = 4;
264  dp->num_of_spi = clib_host_to_net_u16 (num_of_spi);
265  vec_foreach (d2, d)
266  {
267  u8 *data = vec_new (u8, 4);
268  u32 spi = clib_host_to_net_u32 (d2->spi);
269  clib_memcpy (data, &spi, 4);
270  ikev2_payload_add_data (c, data);
271  vec_free (data);
272  }
273  }
274 }
275 
276 void
278 {
279  ike_auth_payload_header_t *ap;
280  ap =
281  (ike_auth_payload_header_t *) ikev2_payload_add_hdr (c,
283  sizeof (*ap));
284 
285  ap->auth_method = auth->method;
286  ikev2_payload_add_data (c, auth->data);
287 }
288 
289 void
291 {
292  ike_ts_payload_header_t *tsh;
293  ikev2_ts_t *ts2;
294  u8 *data = 0, *tmp;
295 
296  tsh =
297  (ike_ts_payload_header_t *) ikev2_payload_add_hdr (c, type,
298  sizeof (*tsh));
299  tsh->num_ts = vec_len (ts);
300 
301  vec_foreach (ts2, ts)
302  {
303  ASSERT (ts2->ts_type == 7); /*TS_IPV4_ADDR_RANGE */
305  vec_add2 (data, tmp, sizeof (*entry));
306  entry = (ikev2_ts_payload_entry_t *) tmp;
307  entry->ts_type = ts2->ts_type;
308  entry->protocol_id = ts2->protocol_id;
309  entry->selector_len = clib_host_to_net_u16 (16);
310  entry->start_port = clib_host_to_net_u16 (ts2->start_port);
311  entry->end_port = clib_host_to_net_u16 (ts2->end_port);
312  entry->start_addr.as_u32 = ts2->start_addr.as_u32;
313  entry->end_addr.as_u32 = ts2->end_addr.as_u32;
314  }
315 
316  ikev2_payload_add_data (c, data);
317  vec_free (data);
318 }
319 
320 void
322 {
323  u8 *tmp __attribute__ ((unused));
324  u8 pad_len = (vec_len (c->data) / bs + 1) * bs - vec_len (c->data);
325  vec_add2 (c->data, tmp, pad_len);
326  c->data[vec_len (c->data) - 1] = pad_len - 1;
327 }
328 
330 ikev2_parse_sa_payload (ike_payload_header_t * ikep)
331 {
332  ikev2_sa_proposal_t *v = 0;
333  ikev2_sa_proposal_t *proposal;
334  ikev2_sa_transform_t *transform;
335 
336  u32 plen = clib_net_to_host_u16 (ikep->length);
337 
339  int proposal_ptr = 0;
340 
341  do
342  {
343  sap = (ike_sa_proposal_data_t *) & ikep->payload[proposal_ptr];
344  int i;
345  int transform_ptr;
346 
347  /* IKE proposal should not have SPI */
348  if (sap->protocol_id == IKEV2_PROTOCOL_IKE && sap->spi_size != 0)
349  goto data_corrupted;
350 
351  /* IKE proposal should not have SPI */
352  if (sap->protocol_id == IKEV2_PROTOCOL_ESP && sap->spi_size != 4)
353  goto data_corrupted;
354 
355  transform_ptr = proposal_ptr + sizeof (*sap) + sap->spi_size;
356 
357  vec_add2 (v, proposal, 1);
358  proposal->proposal_num = sap->proposal_num;
359  proposal->protocol_id = sap->protocol_id;
360 
361  if (sap->spi_size == 4)
362  {
363  proposal->spi = clib_net_to_host_u32 (sap->spi[0]);
364  }
365 
366  for (i = 0; i < sap->num_transforms; i++)
367  {
368  ike_sa_transform_data_t *tr =
369  (ike_sa_transform_data_t *) & ikep->payload[transform_ptr];
370  u16 tlen = clib_net_to_host_u16 (tr->transform_len);
371 
372  if (tlen < sizeof (*tr))
373  goto data_corrupted;
374 
375  vec_add2 (proposal->transforms, transform, 1);
376 
377  transform->type = tr->transform_type;
378  transform->transform_id = clib_net_to_host_u16 (tr->transform_id);
379  if (tlen > sizeof (*tr))
380  vec_add (transform->attrs, tr->attributes, tlen - sizeof (*tr));
381  transform_ptr += tlen;
382  }
383 
384  proposal_ptr += clib_net_to_host_u16 (sap->proposal_len);
385  }
386  while (proposal_ptr < (plen - sizeof (*ikep)) && sap->last_or_more == 2);
387 
388  /* data validation */
389  if (proposal_ptr != (plen - sizeof (*ikep)) || sap->last_or_more)
390  goto data_corrupted;
391 
392  return v;
393 
394 data_corrupted:
395  ikev2_elog_detail ("SA payload data corrupted");
397  return 0;
398 }
399 
400 ikev2_ts_t *
401 ikev2_parse_ts_payload (ike_payload_header_t * ikep)
402 {
403  ike_ts_payload_header_t *tsp = (ike_ts_payload_header_t *) ikep;
404  ikev2_ts_t *r = 0, *ts;
405  u8 i;
406 
407  for (i = 0; i < tsp->num_ts; i++)
408  {
409  if (tsp->ts[i].ts_type != 7) /* TS_IPV4_ADDR_RANGE */
410  {
411  ikev2_elog_uint (IKEV2_LOG_ERROR,
412  "unsupported TS type received (%u)", tsp->ts[i].ts_type);
413  continue;
414  }
415 
416  vec_add2 (r, ts, 1);
417  ts->ts_type = tsp->ts[i].ts_type;
418  ts->protocol_id = tsp->ts[i].protocol_id;
419  ts->start_port = tsp->ts[i].start_port;
420  ts->end_port = tsp->ts[i].end_port;
421  ts->start_addr.as_u32 = tsp->ts[i].start_addr.as_u32;
422  ts->end_addr.as_u32 = tsp->ts[i].end_addr.as_u32;
423  }
424  return r;
425 }
426 
428 ikev2_parse_notify_payload (ike_payload_header_t * ikep)
429 {
430  ike_notify_payload_header_t *n = (ike_notify_payload_header_t *) ikep;
431  u32 plen = clib_net_to_host_u16 (ikep->length);
432  ikev2_notify_t *r = 0;
433  u32 spi;
434 
435  r = vec_new (ikev2_notify_t, 1);
436  r->msg_type = clib_net_to_host_u16 (n->msg_type);
437  r->protocol_id = n->protocol_id;
438 
439  if (n->spi_size == 4)
440  {
441  clib_memcpy (&spi, n->payload, n->spi_size);
442  r->spi = clib_net_to_host_u32 (spi);
443  }
444  else if (n->spi_size == 0)
445  {
446  r->spi = 0;
447  }
448  else
449  {
450  clib_warning ("invalid SPI Size %d", n->spi_size);
451  }
452 
453  if (plen > (sizeof (*n) + n->spi_size))
454  {
455  vec_add (r->data, n->payload + n->spi_size,
456  plen - sizeof (*n) - n->spi_size);
457  }
458 
459  return r;
460 }
461 
462 void
463 ikev2_parse_vendor_payload (ike_payload_header_t * ikep)
464 {
465  u32 plen = clib_net_to_host_u16 (ikep->length);
466  ikev2_elog_uint (IKEV2_LOG_DEBUG, "vendor payload skipped, len %d", plen);
467 }
468 
470 ikev2_parse_delete_payload (ike_payload_header_t * ikep)
471 {
473  ikev2_delete_t *r = 0, *del;
474  u16 num_of_spi = clib_net_to_host_u16 (d->num_of_spi);
475  u16 i = 0;
476 
477  if (d->protocol_id == IKEV2_PROTOCOL_IKE)
478  {
479  r = vec_new (ikev2_delete_t, 1);
480  r->protocol_id = 1;
481  }
482  else
483  {
484  r = vec_new (ikev2_delete_t, num_of_spi);
485  vec_foreach (del, r)
486  {
487  del->protocol_id = d->protocol_id;
488  del->spi = clib_net_to_host_u32 (d->spi[i++]);
489  }
490  }
491 
492  return r;
493 }
494 
495 /*
496  * fd.io coding-style-patch-verification: ON
497  *
498  * Local Variables:
499  * eval: (c-set-style "gnu")
500  * End:
501  */
u32 spi
void ikev2_payload_add_nonce(ikev2_payload_chain_t *c, u8 *nonce)
ikev2_transform_type_t type
Definition: ikev2_priv.h:229
#define IKEV2_PAYLOAD_NONCE
Definition: ikev2.h:99
void ikev2_payload_add_notify(ikev2_payload_chain_t *c, u16 msg_type, u8 *data)
void ikev2_payload_add_sa(ikev2_payload_chain_t *c, ikev2_sa_proposal_t *proposals)
ikev2_sa_proposal_t * ikev2_parse_sa_payload(ike_payload_header_t *ikep)
#define clib_memcpy_fast(a, b, c)
Definition: string.h:81
ikev2_ts_t * ikev2_parse_ts_payload(ike_payload_header_t *ikep)
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
#define vec_add2(V, P, N)
Add N elements to end of vector V, return pointer to new elements in P.
Definition: vec.h:628
void ikev2_payload_add_ke(ikev2_payload_chain_t *c, u16 dh_group, u8 *dh_data)
ikev2_ts_payload_entry_t
Definition: ikev2_payload.c:48
unsigned char u8
Definition: types.h:56
ikev2_notify_t * ikev2_parse_notify_payload(ike_payload_header_t *ikep)
#define clib_memcpy(d, s, n)
Definition: string.h:180
#define vec_add(V, E, N)
Add N elements to end of vector V (no header, unspecified alignment)
Definition: vec.h:666
#define IKEV2_PAYLOAD_DELETE
Definition: ikev2.h:101
#define vec_new(T, N)
Create new vector of given type and length (unspecified alignment, no header).
Definition: vec.h:350
void ikev2_parse_vendor_payload(ike_payload_header_t *ikep)
ip4_address_t start_addr
Definition: ikev2_priv.h:266
void ikev2_payload_add_id(ikev2_payload_chain_t *c, ikev2_id_t *id, u8 type)
#define IKEV2_PAYLOAD_NOTIFY
Definition: ikev2.h:100
unsigned int u32
Definition: types.h:88
#define ikev2_elog_detail(_msg)
Definition: ikev2_priv.h:190
ikev2_sa_transform_t * transforms
Definition: ikev2_priv.h:256
vl_api_fib_path_type_t type
Definition: fib_types.api:123
#define IKEV2_PAYLOAD_SA
Definition: ikev2.h:94
ike_sa_proposal_data_t
Definition: ikev2_payload.c:71
unsigned short u16
Definition: types.h:57
u16 end_port
Definition: ikev2_priv.h:265
ip4_address_t end_addr
Definition: ikev2_priv.h:267
typedef CLIB_PACKED(struct { u8 nextpayload;u8 flags;u16 length;u8 protocol_id;u8 spi_size;u16 msg_type;u8 payload[0];})
Definition: ikev2_payload.c:28
u8 len
Definition: ip_types.api:92
void ikev2_payload_add_delete(ikev2_payload_chain_t *c, ikev2_delete_t *d)
u32 flags
Definition: vhost_user.h:248
#define ikev2_elog_uint(_level, _format, _val)
Definition: ikev2_priv.h:113
svmdb_client_t * c
ikev2_auth_method_t method
Definition: ikev2_priv.h:215
sll srl srl sll sra u16x4 i
Definition: vector_sse42.h:317
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:380
#define clib_warning(format, args...)
Definition: error.h:59
static ike_payload_header_t * ikev2_payload_add_hdr(ikev2_payload_chain_t *c, u8 payload_type, int len)
Definition: ikev2_payload.c:99
#define IKEV2_PAYLOAD_KE
Definition: ikev2.h:95
void ikev2_payload_add_auth(ikev2_payload_chain_t *c, ikev2_auth_t *auth)
ikev2_protocol_id_t protocol_id
Definition: ikev2_priv.h:254
u8 protocol_id
Definition: ikev2_priv.h:262
#define ASSERT(truth)
ike_delete_payload_header_t
Definition: ikev2_payload.c:95
u8 data[128]
Definition: ipsec_types.api:89
void ikev2_sa_free_proposal_vector(ikev2_sa_proposal_t **v)
Definition: ikev2.c:230
#define IKEV2_PAYLOAD_AUTH
Definition: ikev2.h:98
#define vec_append(v1, v2)
Append v2 after v1.
Definition: vec.h:888
static void ikev2_payload_add_data(ikev2_payload_chain_t *c, u8 *data)
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
u16 start_port
Definition: ikev2_priv.h:264
void ikev2_payload_chain_add_padding(ikev2_payload_chain_t *c, int bs)
#define vec_foreach(var, vec)
Vector iterator.
void ikev2_payload_add_ts(ikev2_payload_chain_t *c, ikev2_ts_t *ts, u8 type)
void ikev2_payload_add_notify_2(ikev2_payload_chain_t *c, u16 msg_type, u8 *data, ikev2_notify_t *notify)
ikev2_delete_t * ikev2_parse_delete_payload(ike_payload_header_t *ikep)