virtio: Add RX queue full statisitics
[vpp.git] / src / plugins / ikev2 / ikev2_payload.c
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>
25 #include <plugins/ikev2/ikev2_priv.h>
26
27 typedef CLIB_PACKED (struct {
28   u8 nextpayload;
29   u8 flags;
30   u16 length;
31   u8 protocol_id;
32   u8 spi_size;
33   u16 msg_type;
34   u8 payload[0];
35 }) ike_notify_payload_header_t;
36
37 typedef CLIB_PACKED (struct {
38   ip4_address_t start_addr;
39   ip4_address_t end_addr;
40 }) ikev2_ip4_addr_pair_t;
41
42 typedef CLIB_PACKED (struct {
43   ip6_address_t start_addr;
44   ip6_address_t end_addr;
45 }) ikev2_ip6_addr_pair_t;
46
47 typedef CLIB_PACKED (struct {
48   u8 ts_type;
49   u8 protocol_id;
50   u16 selector_len;
51   u16 start_port;
52   u16 end_port;
53   u8 addr_pair[0];
54 }) ikev2_ts_payload_entry_t;
55
56 typedef CLIB_PACKED (struct {
57   u8 nextpayload;
58   u8 flags;
59   u16 length;
60   u8 num_ts;
61   u8 reserved[3];
62   ikev2_ts_payload_entry_t ts[0];
63 }) ike_ts_payload_header_t;
64
65 typedef CLIB_PACKED (struct {
66   u8 last_or_more;
67   u8 reserved;
68   u16 proposal_len;
69   u8 proposal_num;
70   u8 protocol_id;
71   u8 spi_size;
72   u8 num_transforms; u32 spi[0];
73 }) ike_sa_proposal_data_t;
74
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
85 typedef CLIB_PACKED (struct {
86   u8 nextpayload;
87   u8 flags;
88   u16 length;
89   u8 protocol_id;
90   u8 spi_size;
91   u16 num_of_spi;
92   u32 spi[0];
93 }) ike_delete_payload_header_t;
94
95 static ike_payload_header_t *
96 ikev2_payload_add_hdr (ikev2_payload_chain_t * c, u8 payload_type, int len)
97 {
98   ike_payload_header_t *hdr =
99     (ike_payload_header_t *) & c->data[c->last_hdr_off];
100   u8 *tmp;
101
102   if (c->data)
103     hdr->nextpayload = payload_type;
104   else
105     c->first_payload_type = payload_type;
106
107   c->last_hdr_off = vec_len (c->data);
108   vec_add2 (c->data, tmp, len);
109   hdr = (ike_payload_header_t *) tmp;
110   clib_memset (hdr, 0, len);
111
112   hdr->length = clib_host_to_net_u16 (len);
113
114   return hdr;
115 }
116
117 static void
118 ikev2_payload_add_data (ikev2_payload_chain_t * c, u8 * data)
119 {
120   u16 len;
121   ike_payload_header_t *hdr;
122
123   vec_append (c->data, data);
124   hdr = (ike_payload_header_t *) & c->data[c->last_hdr_off];
125   len = clib_net_to_host_u16 (hdr->length);
126   hdr->length = clib_host_to_net_u16 (len + vec_len (data));
127 }
128
129 void
130 ikev2_payload_add_notify (ikev2_payload_chain_t * c, u16 msg_type, u8 * data)
131 {
132   ikev2_payload_add_notify_2(c, msg_type, data, 0);
133 }
134
135 void
136 ikev2_payload_add_notify_2 (ikev2_payload_chain_t * c, u16 msg_type,
137                                u8 * data, ikev2_notify_t * notify)
138 {
139   ike_notify_payload_header_t *n;
140
141   n =
142     (ike_notify_payload_header_t *) ikev2_payload_add_hdr (c,
143                                                            IKEV2_PAYLOAD_NOTIFY,
144                                                            sizeof (*n));
145   n->msg_type = clib_host_to_net_u16 (msg_type);
146   if (notify)
147     {
148       n->protocol_id = notify->protocol_id;
149       if (notify->spi)
150         {
151           n->spi_size = 4;
152         }
153     }
154   ikev2_payload_add_data (c, data);
155 }
156
157 void
158 ikev2_payload_add_sa (ikev2_payload_chain_t *c, ikev2_sa_proposal_t *proposals,
159                       u8 force_spi)
160 {
161   ike_payload_header_t *ph;
162   ike_sa_proposal_data_t *prop;
163   ike_sa_transform_data_t *tr;
164   ikev2_sa_proposal_t *p;
165   ikev2_sa_transform_t *t;
166
167   u8 *tmp;
168   u8 *pr_data = 0;
169   u8 *tr_data = 0;
170
171   ikev2_payload_add_hdr (c, IKEV2_PAYLOAD_SA, sizeof (*ph));
172
173   vec_foreach (p, proposals)
174   {
175     int spi_size = 0;
176
177     if (p->protocol_id == IKEV2_PROTOCOL_ESP)
178       spi_size = 4;
179     else if (force_spi && p->protocol_id == IKEV2_PROTOCOL_IKE)
180       spi_size = 8;
181
182     pr_data = vec_new (u8, sizeof (ike_sa_proposal_data_t) + spi_size);
183     prop = (ike_sa_proposal_data_t *) pr_data;
184     prop->last_or_more = proposals - p + 1 < vec_len (proposals) ? 2 : 0;
185     prop->protocol_id = p->protocol_id;
186     prop->proposal_num = p->proposal_num;
187     prop->spi_size = spi_size;
188     prop->num_transforms = vec_len (p->transforms);
189
190     if (spi_size == 4)
191       prop->spi[0] = clib_host_to_net_u32 (p->spi);
192     else if (spi_size == 8)
193       {
194         u64 s = clib_host_to_net_u64 (p->spi);
195         clib_memcpy_fast (prop->spi, &s, sizeof (s));
196       }
197
198     vec_foreach (t, p->transforms)
199     {
200       vec_add2 (tr_data, tmp, sizeof (*tr) + vec_len (t->attrs));
201       tr = (ike_sa_transform_data_t *) tmp;
202       tr->last_or_more =
203         ((t - p->transforms) + 1 < vec_len (p->transforms)) ? 3 : 0;
204       tr->transform_type = t->type;
205       tr->transform_id = clib_host_to_net_u16 (t->transform_id);
206       tr->transform_len =
207         clib_host_to_net_u16 (sizeof (*tr) + vec_len (t->attrs));
208
209       if (vec_len (t->attrs) > 0)
210         clib_memcpy_fast (tr->attributes, t->attrs, vec_len (t->attrs));
211     }
212
213     prop->proposal_len =
214       clib_host_to_net_u16 (vec_len (tr_data) + vec_len (pr_data));
215     ikev2_payload_add_data (c, pr_data);
216     ikev2_payload_add_data (c, tr_data);
217     vec_free (pr_data);
218     vec_free (tr_data);
219   }
220 }
221
222 void
223 ikev2_payload_add_ke (ikev2_payload_chain_t * c, u16 dh_group, u8 * dh_data)
224 {
225   ike_ke_payload_header_t *ke;
226   ke = (ike_ke_payload_header_t *) ikev2_payload_add_hdr (c, IKEV2_PAYLOAD_KE,
227                                                           sizeof (*ke));
228
229   ke->dh_group = clib_host_to_net_u16 (dh_group);
230   ikev2_payload_add_data (c, dh_data);
231 }
232
233 void
234 ikev2_payload_add_nonce (ikev2_payload_chain_t * c, u8 * nonce)
235 {
236   ikev2_payload_add_hdr (c, IKEV2_PAYLOAD_NONCE,
237                          sizeof (ike_payload_header_t));
238   ikev2_payload_add_data (c, nonce);
239 }
240
241 void
242 ikev2_payload_add_id (ikev2_payload_chain_t * c, ikev2_id_t * id, u8 type)
243 {
244   ike_id_payload_header_t *idp;
245   idp =
246     (ike_id_payload_header_t *) ikev2_payload_add_hdr (c, type,
247                                                        sizeof (*idp));
248
249   idp->id_type = id->type;
250   ikev2_payload_add_data (c, id->data);
251 }
252
253 void
254 ikev2_payload_add_delete (ikev2_payload_chain_t * c, ikev2_delete_t * d)
255 {
256   ike_delete_payload_header_t *dp;
257   u16 num_of_spi = vec_len (d);
258   ikev2_delete_t *d2;
259   dp =
260     (ike_delete_payload_header_t *) ikev2_payload_add_hdr (c,
261                                                            IKEV2_PAYLOAD_DELETE,
262                                                            sizeof (*dp));
263
264   if (d[0].protocol_id == IKEV2_PROTOCOL_IKE)
265     {
266       dp->protocol_id = 1;
267     }
268   else
269     {
270       dp->protocol_id = d[0].protocol_id;
271       dp->spi_size = 4;
272       dp->num_of_spi = clib_host_to_net_u16 (num_of_spi);
273       vec_foreach (d2, d)
274       {
275         u8 *data = vec_new (u8, 4);
276         u32 spi = clib_host_to_net_u32 (d2->spi);
277         clib_memcpy (data, &spi, 4);
278         ikev2_payload_add_data (c, data);
279         vec_free (data);
280       }
281     }
282 }
283
284 void
285 ikev2_payload_add_auth (ikev2_payload_chain_t * c, ikev2_auth_t * auth)
286 {
287   ike_auth_payload_header_t *ap;
288   ap =
289     (ike_auth_payload_header_t *) ikev2_payload_add_hdr (c,
290                                                          IKEV2_PAYLOAD_AUTH,
291                                                          sizeof (*ap));
292
293   ap->auth_method = auth->method;
294   ikev2_payload_add_data (c, auth->data);
295 }
296
297 static void
298 ikev2_payload_add_ts_entry (u8 ** data, ikev2_ts_t * ts)
299 {
300   u8 * tmp;
301   ikev2_ts_payload_entry_t *entry;
302   int len = sizeof (*entry);
303
304   if (ts->ts_type == TS_IPV4_ADDR_RANGE)
305     len += sizeof (ikev2_ip4_addr_pair_t);
306   else
307     len += sizeof (ikev2_ip6_addr_pair_t);
308
309   vec_add2 (data[0], tmp, len);
310   entry = (ikev2_ts_payload_entry_t *) tmp;
311   entry->ts_type = ts->ts_type;
312   entry->protocol_id = ts->protocol_id;
313   entry->selector_len = clib_host_to_net_u16 (len);
314   entry->start_port = clib_host_to_net_u16 (ts->start_port);
315   entry->end_port = clib_host_to_net_u16 (ts->end_port);
316
317   if (ts->ts_type == TS_IPV4_ADDR_RANGE)
318   {
319     ikev2_ip4_addr_pair_t *pair = (ikev2_ip4_addr_pair_t*) entry->addr_pair;
320     ip_address_copy_addr (&pair->start_addr, &ts->start_addr);
321     ip_address_copy_addr (&pair->end_addr, &ts->end_addr);
322   }
323   else
324   {
325     ikev2_ip6_addr_pair_t *pair = (ikev2_ip6_addr_pair_t*) entry->addr_pair;
326     ip_address_copy_addr (&pair->start_addr, &ts->start_addr);
327     ip_address_copy_addr (&pair->end_addr, &ts->end_addr);
328   }
329 }
330
331 void
332 ikev2_payload_add_ts (ikev2_payload_chain_t * c, ikev2_ts_t * ts, u8 type)
333 {
334   ike_ts_payload_header_t *tsh;
335   ikev2_ts_t *ts2;
336   u8 *data = 0;
337
338   tsh =
339     (ike_ts_payload_header_t *) ikev2_payload_add_hdr (c, type,
340                                                        sizeof (*tsh));
341   tsh->num_ts = vec_len (ts);
342
343   vec_foreach (ts2, ts)
344   {
345     ASSERT (ts2->ts_type == TS_IPV4_ADDR_RANGE ||
346         ts2->ts_type == TS_IPV6_ADDR_RANGE);
347     ikev2_payload_add_ts_entry (&data, ts2);
348   }
349
350   ikev2_payload_add_data (c, data);
351   vec_free (data);
352 }
353
354 void
355 ikev2_payload_chain_add_padding (ikev2_payload_chain_t * c, int bs)
356 {
357   u8 *tmp __attribute__ ((unused));
358   u8 pad_len = (vec_len (c->data) / bs + 1) * bs - vec_len (c->data);
359   vec_add2 (c->data, tmp, pad_len);
360   c->data[vec_len (c->data) - 1] = pad_len - 1;
361 }
362
363 ikev2_sa_proposal_t *
364 ikev2_parse_sa_payload (ike_payload_header_t * ikep, u32 rlen)
365 {
366   ikev2_sa_proposal_t *v = 0;
367   ikev2_sa_proposal_t *proposal;
368   ikev2_sa_transform_t *transform;
369
370   u32 plen = clib_net_to_host_u16 (ikep->length);
371   ike_sa_proposal_data_t *sap;
372   int proposal_ptr = 0;
373
374   if (sizeof (*ikep) > rlen)
375     return 0;
376
377   rlen -= sizeof (*ikep);
378   do
379     {
380       if (proposal_ptr + sizeof (*sap) > rlen)
381         goto data_corrupted;
382
383       sap = (ike_sa_proposal_data_t *) & ikep->payload[proposal_ptr];
384       int i, transform_ptr;
385
386       /* IKE proposal should have 8 bytes or no SPI */
387       if (sap->protocol_id == IKEV2_PROTOCOL_IKE && sap->spi_size != 0 &&
388           sap->spi_size != 8)
389         goto data_corrupted;
390
391       /* IKE proposal should not have SPI */
392       if (sap->protocol_id == IKEV2_PROTOCOL_ESP && sap->spi_size != 4)
393         goto data_corrupted;
394
395       transform_ptr = proposal_ptr + sizeof (*sap) + sap->spi_size;
396       if (transform_ptr > rlen)
397         goto data_corrupted;
398
399       vec_add2 (v, proposal, 1);
400       proposal->proposal_num = sap->proposal_num;
401       proposal->protocol_id = sap->protocol_id;
402
403       if (sap->spi_size == 4)
404         {
405           proposal->spi = clib_net_to_host_u32 (sap->spi[0]);
406         }
407       else if (sap->spi_size == 8)
408         {
409           u64 s;
410           clib_memcpy_fast (&s, &sap->spi[0], sizeof (s));
411           proposal->spi = clib_net_to_host_u64 (s);
412         }
413
414       for (i = 0; i < sap->num_transforms; i++)
415         {
416           ike_sa_transform_data_t *tr =
417             (ike_sa_transform_data_t *) & ikep->payload[transform_ptr];
418           if (transform_ptr + sizeof (*tr) > rlen)
419             goto data_corrupted;
420           u16 tlen = clib_net_to_host_u16 (tr->transform_len);
421
422           if (tlen < sizeof (*tr))
423             goto data_corrupted;
424
425           vec_add2 (proposal->transforms, transform, 1);
426
427           transform->type = tr->transform_type;
428           transform->transform_id = clib_net_to_host_u16 (tr->transform_id);
429           if (transform_ptr + tlen > rlen)
430             goto data_corrupted;
431           if (tlen > sizeof (*tr))
432             vec_add (transform->attrs, tr->attributes, tlen - sizeof (*tr));
433           transform_ptr += tlen;
434         }
435
436       proposal_ptr += clib_net_to_host_u16 (sap->proposal_len);
437     }
438   while (proposal_ptr < (plen - sizeof (*ikep)) && sap->last_or_more == 2);
439
440   /* data validation */
441   if (proposal_ptr != (plen - sizeof (*ikep)) || sap->last_or_more)
442     goto data_corrupted;
443
444   return v;
445
446 data_corrupted:
447   ikev2_elog_detail ("SA payload data corrupted");
448   ikev2_sa_free_proposal_vector (&v);
449   return 0;
450 }
451
452 ikev2_ts_t *
453 ikev2_parse_ts_payload (ike_payload_header_t * ikep, u32 rlen)
454 {
455   ike_ts_payload_header_t *tsp = (ike_ts_payload_header_t *) ikep;
456   ikev2_ts_t *r = 0, *ts;
457   ikev2_ip4_addr_pair_t *pair4;
458   ikev2_ip6_addr_pair_t *pair6;
459   int p = 0, n_left;
460   ikev2_ts_payload_entry_t *pe;
461
462   if (sizeof (*tsp) > rlen)
463     return 0;
464
465   rlen -= sizeof (*tsp);
466   n_left = tsp->num_ts;
467
468   while (n_left && p + sizeof (*pe) < rlen)
469     {
470       pe = (ikev2_ts_payload_entry_t *) (((u8 *)tsp->ts) + p);
471       p += sizeof (*pe);
472
473       if (pe->ts_type != TS_IPV4_ADDR_RANGE &&
474           pe->ts_type != TS_IPV6_ADDR_RANGE)
475         {
476           ikev2_elog_uint (IKEV2_LOG_ERROR,
477               "unsupported TS type received (%u)", pe->ts_type);
478           return 0;
479         }
480
481       vec_add2 (r, ts, 1);
482       ts->ts_type = pe->ts_type;
483       ts->protocol_id = pe->protocol_id;
484       ts->start_port = pe->start_port;
485       ts->end_port = pe->end_port;
486
487       if (pe->ts_type == TS_IPV4_ADDR_RANGE)
488         {
489           pair4 = (ikev2_ip4_addr_pair_t*) pe->addr_pair;
490           ip_address_set (&ts->start_addr, &pair4->start_addr, AF_IP4);
491           ip_address_set (&ts->end_addr, &pair4->end_addr, AF_IP4);
492           p += sizeof (*pair4);
493         }
494       else
495         {
496           pair6 = (ikev2_ip6_addr_pair_t*) pe->addr_pair;
497           ip_address_set (&ts->start_addr, &pair6->start_addr, AF_IP6);
498           ip_address_set (&ts->end_addr, &pair6->end_addr, AF_IP6);
499           p += sizeof (*pair6);
500         }
501       n_left--;
502     }
503
504   if (n_left)
505     return 0;
506
507   return r;
508 }
509
510 ikev2_notify_t *
511 ikev2_parse_notify_payload (ike_payload_header_t * ikep, u32 rlen)
512 {
513   ike_notify_payload_header_t *n = (ike_notify_payload_header_t *) ikep;
514   u32 plen = clib_net_to_host_u16 (n->length);
515   ikev2_notify_t *r = 0;
516   u32 spi;
517
518   if (sizeof (*n) > rlen)
519     return 0;
520
521   r = vec_new (ikev2_notify_t, 1);
522   r->msg_type = clib_net_to_host_u16 (n->msg_type);
523   r->protocol_id = n->protocol_id;
524
525   if (n->spi_size == 4)
526     {
527       if (sizeof (spi) + sizeof (*n) > rlen)
528         goto cleanup;
529
530       clib_memcpy (&spi, n->payload, n->spi_size);
531       r->spi = clib_net_to_host_u32 (spi);
532     }
533   else if (n->spi_size == 0)
534     {
535       r->spi = 0;
536     }
537   else
538     {
539       clib_warning ("invalid SPI Size %d", n->spi_size);
540       goto cleanup;
541     }
542
543   if (plen > (sizeof (*n) + n->spi_size))
544     {
545       if (plen <= sizeof (*n) + n->spi_size)
546         goto cleanup;
547
548       u32 data_len = plen - sizeof (*n) - n->spi_size;
549       vec_add (r->data, n->payload + n->spi_size, data_len);
550     }
551   return r;
552
553 cleanup:
554   vec_free (r);
555   return 0;
556 }
557
558 void
559 ikev2_parse_vendor_payload (ike_payload_header_t * ikep)
560 {
561   u32 plen = clib_net_to_host_u16 (ikep->length);
562   ikev2_elog_uint (IKEV2_LOG_DEBUG, "vendor payload skipped, len %d", plen);
563 }
564
565 ikev2_delete_t *
566 ikev2_parse_delete_payload (ike_payload_header_t * ikep, u32 rlen)
567 {
568   ike_delete_payload_header_t * d = (ike_delete_payload_header_t *) ikep;
569   ikev2_delete_t *r = 0, *del;
570   u16 i, num_of_spi;
571
572   if (rlen < sizeof (*d))
573     return 0;
574
575   num_of_spi = clib_net_to_host_u16 (d->num_of_spi);
576   if (d->protocol_id == IKEV2_PROTOCOL_IKE)
577     {
578       r = vec_new (ikev2_delete_t, 1);
579       r->protocol_id = 1;
580     }
581   else
582     {
583       if (sizeof (*d) + num_of_spi * sizeof (u32) > rlen)
584         return 0;
585
586       for (i = 0; i < num_of_spi; i++)
587       {
588         vec_add2 (r, del, 1);
589         del->protocol_id = d->protocol_id;
590         del->spi = clib_net_to_host_u32 (d->spi[i]);
591       }
592     }
593
594   return r;
595 }
596
597 u8 *
598 ikev2_find_ike_notify_payload (ike_header_t * ike, u32 msg_type)
599 {
600   int p = 0;
601   ike_notify_payload_header_t *n;
602   ike_payload_header_t *ikep;
603   u32 payload = ike->nextpayload;
604
605   while (payload != IKEV2_PAYLOAD_NONE)
606     {
607       ikep = (ike_payload_header_t *) & ike->payload[p];
608       if (payload == IKEV2_PAYLOAD_NOTIFY)
609       {
610         n = (ike_notify_payload_header_t *)ikep;
611         if (n->msg_type == clib_net_to_host_u16 (msg_type))
612           return n->payload;
613       }
614       u16 plen = clib_net_to_host_u16 (ikep->length);
615       payload = ikep->nextpayload;
616       p += plen;
617     }
618   return 0;
619 }
620
621 /*
622  * fd.io coding-style-patch-verification: ON
623  *
624  * Local Variables:
625  * eval: (c-set-style "gnu")
626  * End:
627  */