FD.io VPP  v17.07-30-g839fa73
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 <vnet/ipsec/ikev2.h>
25 #include <vnet/ipsec/ikev2_priv.h>
26 
27 /* *INDENT-OFF* */
28 typedef CLIB_PACKED (struct
29  {
30  u8 nextpayload;
31  u8 flags;
32  u16 length;
33  u8 protocol_id;
34  u8 spi_size;
35  u16 msg_type;
36  u8 payload[0];}) ike_notify_payload_header_t;
37 /* *INDENT-ON* */
38 
39 /* *INDENT-OFF* */
40 typedef CLIB_PACKED (struct
41  {
42  u8 ts_type;
43  u8 protocol_id;
44  u16 selector_len;
45  u16 start_port;
46  u16 end_port;
47  ip4_address_t start_addr;
49 /* *INDENT-OFF* */
50 
51 /* *INDENT-OFF* */
52 typedef CLIB_PACKED (struct
53  {
54  u8 nextpayload;
55  u8 flags;
56  u16 length;
57  u8 num_ts;
58  u8 reserved[3];
60  ike_ts_payload_header_t;
61 /* *INDENT-OFF* */
62 
63 /* *INDENT-OFF* */
64 typedef CLIB_PACKED (struct {
65  u8 last_or_more;
66  u8 reserved;
67  u16 proposal_len;
68  u8 proposal_num;
69  u8 protocol_id;
70  u8 spi_size;
71  u8 num_transforms; u32 spi[0];
73 /* *INDENT-OFF* */
74 
75 /* *INDENT-OFF* */
76 typedef CLIB_PACKED (struct {
77  u8 last_or_more;
78  u8 reserved;
79  u16 transform_len;
80  u8 transform_type;
81  u8 reserved2;
82  u16 transform_id;
83  u8 attributes[0];
84 }) ike_sa_transform_data_t;
85 /* *INDENT-OFF* */
86 
87 /* *INDENT-OFF* */
88 typedef CLIB_PACKED (struct {
89  u8 nextpayload;
90  u8 flags;
91  u16 length;
92  u8 protocol_id;
93  u8 spi_size;
94  u16 num_of_spi;
95  u32 spi[0];
97 /* *INDENT-OFF* */
98 
99 static ike_payload_header_t *
101 {
102  ike_payload_header_t *hdr =
103  (ike_payload_header_t *) & c->data[c->last_hdr_off];
104  u8 *tmp;
105 
106  if (c->data)
107  hdr->nextpayload = payload_type;
108  else
109  c->first_payload_type = payload_type;
110 
111  c->last_hdr_off = vec_len (c->data);
112  vec_add2 (c->data, tmp, len);
113  hdr = (ike_payload_header_t *) tmp;
114  memset (hdr, 0, len);
115 
116  hdr->length = clib_host_to_net_u16 (len);
117 
118  return hdr;
119 }
120 
121 static void
123 {
124  u16 len;
125  ike_payload_header_t *hdr;
126 
127  vec_append (c->data, data);
128  hdr = (ike_payload_header_t *) & c->data[c->last_hdr_off];
129  len = clib_net_to_host_u16 (hdr->length);
130  hdr->length = clib_host_to_net_u16 (len + vec_len (data));
131 }
132 
133 void
135 {
136  ikev2_payload_add_notify_2(c, msg_type, data, 0);
137 }
138 
139 void
141  u8 * data, ikev2_notify_t * notify)
142 {
143  ike_notify_payload_header_t *n;
144 
145  n =
146  (ike_notify_payload_header_t *) ikev2_payload_add_hdr (c,
148  sizeof (*n));
149  n->msg_type = clib_host_to_net_u16 (msg_type);
150  if (notify)
151  {
152  n->protocol_id = notify->protocol_id;
153  if (notify->spi)
154  {
155  n->spi_size = 4;
156  }
157  }
158  ikev2_payload_add_data (c, data);
159 }
160 
161 void
163  ikev2_sa_proposal_t * proposals)
164 {
165  ike_payload_header_t *ph;
167  ike_sa_transform_data_t *tr;
170 
171  u8 *tmp;
172  u8 *pr_data = 0;
173  u8 *tr_data = 0;
174 
175  ikev2_payload_add_hdr (c, IKEV2_PAYLOAD_SA, sizeof (*ph));
176 
177  vec_foreach (p, proposals)
178  {
179  int spi_size = (p->protocol_id == IKEV2_PROTOCOL_ESP) ? 4 : 0;
180  pr_data = vec_new (u8, sizeof (ike_sa_proposal_data_t) + spi_size);
181  prop = (ike_sa_proposal_data_t *) pr_data;
182  prop->last_or_more = proposals - p + 1 < vec_len (proposals) ? 2 : 0;
183  prop->protocol_id = p->protocol_id;
184  prop->proposal_num = p->proposal_num;
185  prop->spi_size = spi_size;
186  prop->num_transforms = vec_len (p->transforms);
187 
188  if (spi_size)
189  prop->spi[0] = clib_host_to_net_u32 (p->spi);
190 
191  DBG_PLD ("proposal num %u protocol_id %u last_or_more %u spi_size %u%s%U",
192  prop->proposal_num, prop->protocol_id, prop->last_or_more,
193  prop->spi_size, prop->spi_size ? " spi_data " : "",
194  format_hex_bytes, prop->spi, prop->spi_size);
195 
196  vec_foreach (t, p->transforms)
197  {
198  vec_add2 (tr_data, tmp, sizeof (*tr) + vec_len (t->attrs));
199  tr = (ike_sa_transform_data_t *) tmp;
200  tr->last_or_more =
201  ((t - p->transforms) + 1 < vec_len (p->transforms)) ? 3 : 0;
202  tr->transform_type = t->type;
203  tr->transform_id = clib_host_to_net_u16 (t->transform_id);
204  tr->transform_len =
205  clib_host_to_net_u16 (sizeof (*tr) + vec_len (t->attrs));
206 
207  if (vec_len (t->attrs) > 0)
208  clib_memcpy (tr->attributes, t->attrs, vec_len (t->attrs));
209 
210  DBG_PLD
211  ("transform type %U transform_id %u last_or_more %u attr_size %u%s%U",
212  format_ikev2_transform_type, tr->transform_type, t->transform_id,
213  tr->last_or_more, vec_len (t->attrs),
214  vec_len (t->attrs) ? " attrs " : "", format_hex_bytes,
215  tr->attributes, vec_len (t->attrs));
216  }
217 
218  prop->proposal_len =
219  clib_host_to_net_u16 (vec_len (tr_data) + vec_len (pr_data));
220  ikev2_payload_add_data (c, pr_data);
221  ikev2_payload_add_data (c, tr_data);
222  vec_free (pr_data);
223  vec_free (tr_data);
224  }
225 }
226 
227 void
229 {
230  ike_ke_payload_header_t *ke;
231  ke = (ike_ke_payload_header_t *) ikev2_payload_add_hdr (c, IKEV2_PAYLOAD_KE,
232  sizeof (*ke));
233 
234  ke->dh_group = clib_host_to_net_u16 (dh_group);
235  ikev2_payload_add_data (c, dh_data);
236 }
237 
238 void
240 {
242  sizeof (ike_payload_header_t));
243  ikev2_payload_add_data (c, nonce);
244 }
245 
246 void
248 {
249  ike_id_payload_header_t *idp;
250  idp =
251  (ike_id_payload_header_t *) ikev2_payload_add_hdr (c, type,
252  sizeof (*idp));
253 
254  idp->id_type = id->type;
255  ikev2_payload_add_data (c, id->data);
256 }
257 
258 void
260 {
262  u16 num_of_spi = vec_len (d);
263  ikev2_delete_t *d2;
264  dp =
267  sizeof (*dp));
268 
269  if (d[0].protocol_id == IKEV2_PROTOCOL_IKE)
270  {
271  dp->protocol_id = 1;
272  }
273  else
274  {
275  dp->protocol_id = d[0].protocol_id;
276  dp->spi_size = 4;
277  dp->num_of_spi = clib_host_to_net_u16 (num_of_spi);
278  vec_foreach (d2, d)
279  {
280  u8 *data = vec_new (u8, 4);
281  u32 spi = clib_host_to_net_u32 (d2->spi);
282  clib_memcpy (data, &spi, 4);
283  ikev2_payload_add_data (c, data);
284  vec_free (data);
285  }
286  }
287 }
288 
289 void
291 {
292  ike_auth_payload_header_t *ap;
293  ap =
294  (ike_auth_payload_header_t *) ikev2_payload_add_hdr (c,
296  sizeof (*ap));
297 
298  ap->auth_method = auth->method;
299  ikev2_payload_add_data (c, auth->data);
300 }
301 
302 void
304 {
305  ike_ts_payload_header_t *tsh;
306  ikev2_ts_t *ts2;
307  u8 *data = 0, *tmp;
308 
309  tsh =
310  (ike_ts_payload_header_t *) ikev2_payload_add_hdr (c, type,
311  sizeof (*tsh));
312  tsh->num_ts = vec_len (ts);
313 
314  vec_foreach (ts2, ts)
315  {
316  ASSERT (ts2->ts_type == 7); /*TS_IPV4_ADDR_RANGE */
318  vec_add2 (data, tmp, sizeof (*entry));
319  entry = (ikev2_ts_payload_entry_t *) tmp;
320  entry->ts_type = ts2->ts_type;
321  entry->protocol_id = ts2->protocol_id;
322  entry->selector_len = clib_host_to_net_u16 (16);
323  entry->start_port = clib_host_to_net_u16 (ts2->start_port);
324  entry->end_port = clib_host_to_net_u16 (ts2->end_port);
325  entry->start_addr.as_u32 = ts2->start_addr.as_u32;
326  entry->end_addr.as_u32 = ts2->end_addr.as_u32;
327  }
328 
329  ikev2_payload_add_data (c, data);
330  vec_free (data);
331 }
332 
333 void
335 {
336  u8 *tmp __attribute__ ((unused));
337  u8 pad_len = (vec_len (c->data) / bs + 1) * bs - vec_len (c->data);
338  vec_add2 (c->data, tmp, pad_len);
339  c->data[vec_len (c->data) - 1] = pad_len - 1;
340 }
341 
343 ikev2_parse_sa_payload (ike_payload_header_t * ikep)
344 {
345  ikev2_sa_proposal_t *v = 0;
346  ikev2_sa_proposal_t *proposal;
347  ikev2_sa_transform_t *transform;
348 
349  u32 plen = clib_net_to_host_u16 (ikep->length);
350 
352  int proposal_ptr = 0;
353 
354  do
355  {
356  sap = (ike_sa_proposal_data_t *) & ikep->payload[proposal_ptr];
357  int i;
358  int transform_ptr;
359 
360  DBG_PLD ("proposal num %u len %u last_or_more %u id %u "
361  "spi_size %u num_transforms %u",
362  sap->proposal_num, clib_net_to_host_u16 (sap->proposal_len),
363  sap->last_or_more, sap->protocol_id, sap->spi_size,
364  sap->num_transforms);
365 
366  /* IKE proposal should not have SPI */
367  if (sap->protocol_id == IKEV2_PROTOCOL_IKE && sap->spi_size != 0)
368  goto data_corrupted;
369 
370  /* IKE proposal should not have SPI */
371  if (sap->protocol_id == IKEV2_PROTOCOL_ESP && sap->spi_size != 4)
372  goto data_corrupted;
373 
374  transform_ptr = proposal_ptr + sizeof (*sap) + sap->spi_size;
375 
376  vec_add2 (v, proposal, 1);
377  proposal->proposal_num = sap->proposal_num;
378  proposal->protocol_id = sap->protocol_id;
379 
380  if (sap->spi_size == 4)
381  {
382  proposal->spi = clib_net_to_host_u32 (sap->spi[0]);
383  }
384 
385  for (i = 0; i < sap->num_transforms; i++)
386  {
387  ike_sa_transform_data_t *tr =
388  (ike_sa_transform_data_t *) & ikep->payload[transform_ptr];
389  u16 tlen = clib_net_to_host_u16 (tr->transform_len);
390 
391  if (tlen < sizeof (*tr))
392  goto data_corrupted;
393 
394  vec_add2 (proposal->transforms, transform, 1);
395 
396  transform->type = tr->transform_type;
397  transform->transform_id = clib_net_to_host_u16 (tr->transform_id);
398  if (tlen > sizeof (*tr))
399  vec_add (transform->attrs, tr->attributes, tlen - sizeof (*tr));
400 
401  DBG_PLD
402  ("transform num %u len %u last_or_more %u type %U id %u%s%U", i,
403  tlen, tr->last_or_more, format_ikev2_sa_transform, transform,
404  clib_net_to_host_u16 (tr->transform_id),
405  tlen > sizeof (*tr) ? " attrs " : "", format_hex_bytes,
406  tr->attributes, tlen - sizeof (*tr));
407 
408  transform_ptr += tlen;
409  }
410 
411  proposal_ptr += clib_net_to_host_u16 (sap->proposal_len);
412  }
413  while (proposal_ptr < (plen - sizeof (*ikep)) && sap->last_or_more == 2);
414 
415  /* data validation */
416  if (proposal_ptr != (plen - sizeof (*ikep)) || sap->last_or_more)
417  goto data_corrupted;
418 
419  return v;
420 
421 data_corrupted:
422  DBG_PLD ("SA payload data corrupted");
424  return 0;
425 }
426 
427 ikev2_ts_t *
428 ikev2_parse_ts_payload (ike_payload_header_t * ikep)
429 {
430  ike_ts_payload_header_t *tsp = (ike_ts_payload_header_t *) ikep;
431  ikev2_ts_t *r = 0, *ts;
432  u8 i;
433 
434  for (i = 0; i < tsp->num_ts; i++)
435  {
436  if (tsp->ts[i].ts_type != 7) /* TS_IPV4_ADDR_RANGE */
437  {
438  DBG_PLD ("unsupported TS type received (%u)", tsp->ts[i].ts_type);
439  continue;
440  }
441 
442  vec_add2 (r, ts, 1);
443  ts->ts_type = tsp->ts[i].ts_type;
444  ts->protocol_id = tsp->ts[i].protocol_id;
445  ts->start_port = tsp->ts[i].start_port;
446  ts->end_port = tsp->ts[i].end_port;
447  ts->start_addr.as_u32 = tsp->ts[i].start_addr.as_u32;
448  ts->end_addr.as_u32 = tsp->ts[i].end_addr.as_u32;
449  }
450  return r;
451 }
452 
454 ikev2_parse_notify_payload (ike_payload_header_t * ikep)
455 {
456  ike_notify_payload_header_t *n = (ike_notify_payload_header_t *) ikep;
457  u32 plen = clib_net_to_host_u16 (ikep->length);
458  ikev2_notify_t *r = 0;
459  u32 spi;
460 
461  DBG_PLD ("msg_type %U len %u%s%U",
462  format_ikev2_notify_msg_type, clib_net_to_host_u16 (n->msg_type),
463  plen, plen > sizeof (*n) ? " data " : "",
464  format_hex_bytes, n->payload, plen - sizeof (*n));
465 
466  r = vec_new (ikev2_notify_t, 1);
467  r->msg_type = clib_net_to_host_u16 (n->msg_type);
468  r->protocol_id = n->protocol_id;
469 
470  if (n->spi_size == 4)
471  {
472  clib_memcpy (&spi, n->payload, n->spi_size);
473  r->spi = clib_net_to_host_u32 (spi);
474  DBG_PLD ("spi %lx", r->spi);
475  }
476  else if (n->spi_size == 0)
477  {
478  r->spi = 0;
479  }
480  else
481  {
482  clib_warning ("invalid SPI Size %d", n->spi_size);
483  }
484 
485  if (plen > (sizeof (*n) + n->spi_size))
486  {
487  vec_add (r->data, n->payload + n->spi_size,
488  plen - sizeof (*n) - n->spi_size);
489  }
490 
491  return r;
492 }
493 
494 void
495 ikev2_parse_vendor_payload (ike_payload_header_t * ikep)
496 {
497  u32 plen = clib_net_to_host_u16 (ikep->length);
498  int i;
499  int is_string = 1;
500 
501  for (i = 0; i < plen - 4; i++)
502  if (!isprint (ikep->payload[i]))
503  is_string = 0;
504 
505  DBG_PLD ("len %u data %s:%U",
506  plen,
507  is_string ? "string" : "hex",
508  is_string ? format_ascii_bytes : format_hex_bytes,
509  ikep->payload, plen - sizeof (*ikep));
510 }
511 
513 ikev2_parse_delete_payload (ike_payload_header_t * ikep)
514 {
516  u32 plen = clib_net_to_host_u16 (ikep->length);
517  ikev2_delete_t *r = 0, *del;
518  u16 num_of_spi = clib_net_to_host_u16 (d->num_of_spi);
519  u16 i = 0;
520 
521  DBG_PLD ("protocol_id %u spi_size %u num_of_spi %u len %u%s%U",
522  d->protocol_id, d->spi_size, num_of_spi,
523  plen, plen > sizeof (d) ? " data " : "",
524  format_hex_bytes, d->spi, plen - sizeof (*d));
525 
526  if (d->protocol_id == IKEV2_PROTOCOL_IKE)
527  {
528  r = vec_new (ikev2_delete_t, 1);
529  r->protocol_id = 1;
530  }
531  else
532  {
533  r = vec_new (ikev2_delete_t, num_of_spi);
534  vec_foreach (del, r)
535  {
536  del->protocol_id = d->protocol_id;
537  del->spi = clib_net_to_host_u32 (d->spi[i++]);
538  }
539  }
540 
541  return r;
542 }
543 
544 /*
545  * fd.io coding-style-patch-verification: ON
546  *
547  * Local Variables:
548  * eval: (c-set-style "gnu")
549  * End:
550  */
void ikev2_payload_add_nonce(ikev2_payload_chain_t *c, u8 *nonce)
ikev2_transform_type_t type
Definition: ikev2_priv.h:69
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:337
#define IKEV2_PAYLOAD_NONCE
Definition: ikev2.h:99
void ikev2_payload_add_notify(ikev2_payload_chain_t *c, u16 msg_type, u8 *data)
u8 * format_ascii_bytes(u8 *s, va_list *va)
Definition: std-formats.c:74
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)
ikev2_ts_t * ikev2_parse_ts_payload(ike_payload_header_t *ikep)
u8 * format_ikev2_sa_transform(u8 *s, va_list *args)
Definition: ikev2_format.c:25
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
#define vec_add2(V, P, N)
Add N elements to end of vector V, return pointer to new elements in P.
Definition: vec.h:561
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
ikev2_notify_t * ikev2_parse_notify_payload(ike_payload_header_t *ikep)
#define vec_add(V, E, N)
Add N elements to end of vector V (no header, unspecified alignment)
Definition: vec.h:599
#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:310
void ikev2_parse_vendor_payload(ike_payload_header_t *ikep)
ip4_address_t start_addr
Definition: ikev2_priv.h:106
u8 * format_hex_bytes(u8 *s, va_list *va)
Definition: std-formats.c:84
void ikev2_payload_add_id(ikev2_payload_chain_t *c, ikev2_id_t *id, u8 type)
#define IKEV2_PAYLOAD_NOTIFY
Definition: ikev2.h:100
ikev2_sa_transform_t * transforms
Definition: ikev2_priv.h:96
#define IKEV2_PAYLOAD_SA
Definition: ikev2.h:94
ike_sa_proposal_data_t
Definition: ikev2_payload.c:72
#define v
Definition: acl.c:320
u16 end_port
Definition: ikev2_priv.h:105
#define DBG_PLD(my_args...)
Definition: ikev2_priv.h:36
ip4_address_t end_addr
Definition: ikev2_priv.h:107
void ikev2_payload_add_delete(ikev2_payload_chain_t *c, ikev2_delete_t *d)
u8 * format_ikev2_notify_msg_type(u8 *s, va_list *args)
svmdb_client_t * c
ikev2_auth_method_t method
Definition: ikev2_priv.h:55
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:340
#define clib_warning(format, args...)
Definition: error.h:59
#define clib_memcpy(a, b, c)
Definition: string.h:69
static ike_payload_header_t * ikev2_payload_add_hdr(ikev2_payload_chain_t *c, u8 payload_type, int len)
#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:94
u8 protocol_id
Definition: ikev2_priv.h:102
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
ike_delete_payload_header_t
Definition: ikev2_payload.c:96
u8 * format_ikev2_transform_type(u8 *s, va_list *args)
void ikev2_sa_free_proposal_vector(ikev2_sa_proposal_t **v)
Definition: ikev2.c:222
#define IKEV2_PAYLOAD_AUTH
Definition: ikev2.h:98
#define vec_append(v1, v2)
Append v2 after v1.
Definition: vec.h:819
static void ikev2_payload_add_data(ikev2_payload_chain_t *c, u8 *data)
unsigned short u16
Definition: types.h:57
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
u16 start_port
Definition: ikev2_priv.h:104
unsigned char u8
Definition: types.h:56
void ikev2_payload_chain_add_padding(ikev2_payload_chain_t *c, int bs)
#define vec_foreach(var, vec)
Vector iterator.
u32 flags
Definition: vhost-user.h:76
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)