4ad8699121db4f2d57e7a1efe155e4334273ae45
[vpp.git] / vnet / vnet / ipsec / 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 <vnet/ipsec/ikev2.h>
25 #include <vnet/ipsec/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   u8   ts_type;
39   u8   protocol_id;
40   u16  selector_len;
41   u16  start_port;
42   u16  end_port;
43   ip4_address_t start_addr;
44   ip4_address_t end_addr;
45 }) ikev2_ts_payload_entry_t;
46
47 typedef CLIB_PACKED (struct {
48   u8   nextpayload;
49   u8   flags;
50   u16  length;
51   u8   num_ts;
52   u8   reserved[3];
53   ikev2_ts_payload_entry_t ts[0];
54 }) ike_ts_payload_header_t;
55
56 typedef CLIB_PACKED (struct {
57   u8   last_or_more;
58   u8   reserved;
59   u16  proposal_len;
60   u8   proposal_num;
61   u8   protocol_id;
62   u8   spi_size;
63   u8   num_transforms;
64   u32  spi[0];
65 }) ike_sa_proposal_data_t;
66
67 typedef CLIB_PACKED (struct {
68   u8   last_or_more;
69   u8   reserved;
70   u16  transform_len;
71   u8   transform_type;
72   u8   reserved2;
73   u16  transform_id;
74   u8   attributes[0];
75 }) ike_sa_transform_data_t;
76
77 typedef CLIB_PACKED (struct {
78   u8   nextpayload;
79   u8   flags;
80   u16  length;
81   u8   protocol_id;
82   u8   spi_size;
83   u16  num_of_spi;
84   u32   spi[0];
85 }) ike_delete_payload_header_t;
86
87 static ike_payload_header_t *
88 ikev2_payload_add_hdr(ikev2_payload_chain_t * c, u8 payload_type, int len)
89 {
90   ike_payload_header_t * hdr = (ike_payload_header_t *) &c->data[c->last_hdr_off];
91   u8 * tmp;
92
93   if (c->data)
94     hdr->nextpayload = payload_type;
95   else
96     c->first_payload_type = payload_type;
97
98   c->last_hdr_off = vec_len(c->data);
99   vec_add2(c->data, tmp, len);
100   hdr = (ike_payload_header_t *) tmp;
101   memset(hdr, 0, len);
102
103   hdr->length = clib_host_to_net_u16(len);
104
105   return hdr;
106 }
107
108 static void
109 ikev2_payload_add_data(ikev2_payload_chain_t * c, u8 * data)
110 {
111   u16 len;
112   ike_payload_header_t * hdr;
113
114   vec_append(c->data, data);
115   hdr = (ike_payload_header_t *) &c->data[c->last_hdr_off];
116   len = clib_net_to_host_u16(hdr->length);
117   hdr->length = clib_host_to_net_u16(len + vec_len(data));
118 }
119
120 void
121 ikev2_payload_add_notify(ikev2_payload_chain_t * c, u16 msg_type, u8 * data)
122 {
123   ike_notify_payload_header_t * n;
124
125   n = (ike_notify_payload_header_t *) ikev2_payload_add_hdr(c, IKEV2_PAYLOAD_NOTIFY, sizeof (*n));
126   n->msg_type = clib_host_to_net_u16(msg_type);
127   ikev2_payload_add_data(c, data);
128 }
129
130 void
131 ikev2_payload_add_sa(ikev2_payload_chain_t * c, ikev2_sa_proposal_t * proposals)
132 {
133   ike_payload_header_t * ph;
134   ike_sa_proposal_data_t * prop;
135   ike_sa_transform_data_t * tr;
136   ikev2_sa_proposal_t * p;
137   ikev2_sa_transform_t * t;
138
139   u8 * tmp;
140   u8 * pr_data = 0;
141   u8 * tr_data = 0;
142
143   ikev2_payload_add_hdr(c, IKEV2_PAYLOAD_SA, sizeof (*ph));
144
145   vec_foreach(p, proposals)
146     {
147       int spi_size = (p->protocol_id == IKEV2_PROTOCOL_ESP) ? 4 : 0;
148       pr_data = vec_new(u8, sizeof(ike_sa_proposal_data_t) + spi_size);
149       prop = (ike_sa_proposal_data_t *) pr_data;
150       prop->last_or_more = proposals - p + 1 < vec_len(proposals) ? 2 : 0;
151       prop->protocol_id = p->protocol_id;
152       prop->proposal_num = p->proposal_num;
153       prop->spi_size = spi_size;
154       prop->num_transforms = vec_len(p->transforms);
155
156       if (spi_size)
157         prop->spi[0] = clib_host_to_net_u32(p->spi);
158
159       DBG_PLD("proposal num %u protocol_id %u last_or_more %u spi_size %u%s%U",
160                prop->proposal_num, prop->protocol_id, prop->last_or_more,
161                prop->spi_size, prop->spi_size ? " spi_data " : "",
162                format_hex_bytes, prop->spi, prop->spi_size);
163
164       vec_foreach(t, p->transforms)
165         {
166           vec_add2(tr_data, tmp, sizeof(*tr) + vec_len(t->attrs));
167           tr = (ike_sa_transform_data_t *) tmp;
168           tr->last_or_more = ((t - p->transforms) + 1 < vec_len(p->transforms)) ? 3 : 0;
169           tr->transform_type = t->type;
170           tr->transform_id = clib_host_to_net_u16(t->transform_id);
171           tr->transform_len = clib_host_to_net_u16(sizeof(*tr) + vec_len(t->attrs));
172
173           if (vec_len(t->attrs) > 0)
174             clib_memcpy(tr->attributes, t->attrs, vec_len(t->attrs));
175
176           DBG_PLD("transform type %U transform_id %u last_or_more %u attr_size %u%s%U",
177                   format_ikev2_transform_type, tr->transform_type,
178                   t->transform_id, tr->last_or_more, vec_len(t->attrs),
179                   vec_len(t->attrs) ? " attrs " : "",
180                   format_hex_bytes, tr->attributes, vec_len(t->attrs));
181         }
182
183       prop->proposal_len = clib_host_to_net_u16(vec_len(tr_data) + vec_len(pr_data));
184       ikev2_payload_add_data(c, pr_data);
185       ikev2_payload_add_data(c, tr_data);
186       vec_free(pr_data);
187       vec_free(tr_data);
188     }
189 }
190
191 void
192 ikev2_payload_add_ke(ikev2_payload_chain_t * c, u16 dh_group, u8 * dh_data)
193 {
194   ike_ke_payload_header_t * ke;
195   ke = (ike_ke_payload_header_t *) ikev2_payload_add_hdr(c, IKEV2_PAYLOAD_KE,
196                                                          sizeof (*ke));
197
198   ke->dh_group = clib_host_to_net_u16(dh_group);
199   ikev2_payload_add_data(c, dh_data);
200 }
201
202 void
203 ikev2_payload_add_nonce(ikev2_payload_chain_t * c, u8 * nonce)
204 {
205   ikev2_payload_add_hdr(c, IKEV2_PAYLOAD_NONCE, sizeof (ike_payload_header_t));
206   ikev2_payload_add_data(c, nonce);
207 }
208
209 void
210 ikev2_payload_add_id(ikev2_payload_chain_t *c, ikev2_id_t * id, u8 type)
211 {
212   ike_id_payload_header_t * idp;
213   idp = (ike_id_payload_header_t *) ikev2_payload_add_hdr(c, type, sizeof (*idp));
214
215   idp->id_type = id->type;
216   ikev2_payload_add_data(c, id->data);
217 }
218
219 void
220 ikev2_payload_add_delete(ikev2_payload_chain_t *c, ikev2_delete_t * d)
221 {
222   ike_delete_payload_header_t * dp;
223   u16 num_of_spi = vec_len(d);
224   ikev2_delete_t * d2;
225   dp = (ike_delete_payload_header_t *) ikev2_payload_add_hdr(c, IKEV2_PAYLOAD_DELETE,
226                                                              sizeof (*dp));
227
228   if (d[0].protocol_id == IKEV2_PROTOCOL_IKE)
229     {
230       dp->protocol_id = 1;
231     }
232   else
233     {
234       dp->protocol_id = d[0].protocol_id;
235       dp->spi_size = 4;
236       dp->num_of_spi = clib_host_to_net_u16(num_of_spi);
237       vec_foreach(d2, d)
238         {
239           u8 * data = vec_new(u8, 4);
240           u32 spi = clib_host_to_net_u32(d2->spi);
241           clib_memcpy(data, &spi, 4);
242           ikev2_payload_add_data(c, data);
243           vec_free(data);
244         }
245     }
246 }
247
248 void
249 ikev2_payload_add_auth(ikev2_payload_chain_t *c, ikev2_auth_t * auth)
250 {
251   ike_auth_payload_header_t * ap;
252   ap = (ike_auth_payload_header_t *) ikev2_payload_add_hdr(c, IKEV2_PAYLOAD_AUTH,
253                                                            sizeof (*ap));
254
255   ap->auth_method = auth->method;
256   ikev2_payload_add_data(c, auth->data);
257 }
258
259 void
260 ikev2_payload_add_ts(ikev2_payload_chain_t * c, ikev2_ts_t * ts, u8 type)
261 {
262   ike_ts_payload_header_t * tsh;
263   ikev2_ts_t *ts2;
264   u8 * data = 0, * tmp;
265
266   tsh = (ike_ts_payload_header_t *) ikev2_payload_add_hdr(c, type, sizeof (*tsh));
267   tsh->num_ts = vec_len(ts);
268
269   vec_foreach(ts2, ts)
270     {
271       ASSERT(ts2->ts_type == 7); /*TS_IPV4_ADDR_RANGE */
272       ikev2_ts_payload_entry_t * entry;
273       vec_add2(data, tmp, sizeof(*entry));
274       entry = (ikev2_ts_payload_entry_t *) tmp;
275       entry->ts_type = ts2->ts_type;
276       entry->protocol_id = ts2->protocol_id;
277       entry->selector_len = clib_host_to_net_u16(16);
278       entry->start_port = clib_host_to_net_u16(ts2->start_port);
279       entry->end_port = clib_host_to_net_u16(ts2->end_port);
280       entry->start_addr.as_u32 = ts2->start_addr.as_u32;
281       entry->end_addr.as_u32 = ts2->end_addr.as_u32;
282     }
283
284   ikev2_payload_add_data(c, data);
285   vec_free(data);
286 }
287
288 void
289 ikev2_payload_chain_add_padding(ikev2_payload_chain_t * c, int bs)
290 {
291   u8 * tmp __attribute__((unused));
292   u8 pad_len = (vec_len(c->data) / bs + 1) * bs - vec_len(c->data);
293   vec_add2(c->data, tmp, pad_len);
294   c->data[vec_len(c->data)-1] = pad_len - 1;
295 }
296
297 ikev2_sa_proposal_t *
298 ikev2_parse_sa_payload(ike_payload_header_t * ikep)
299 {
300   ikev2_sa_proposal_t * v = 0;
301   ikev2_sa_proposal_t * proposal;
302   ikev2_sa_transform_t * transform;
303
304   u32 plen = clib_net_to_host_u16(ikep->length);
305
306   ike_sa_proposal_data_t * sap;
307   int proposal_ptr = 0;
308
309   do
310     {
311       sap = (ike_sa_proposal_data_t *) &ikep->payload[proposal_ptr];
312       int i;
313       int transform_ptr;
314
315       DBG_PLD("proposal num %u len %u last_or_more %u id %u "
316               "spi_size %u num_transforms %u",
317               sap->proposal_num, clib_net_to_host_u16(sap->proposal_len),
318               sap->last_or_more, sap->protocol_id, sap->spi_size,
319               sap->num_transforms);
320
321       /* IKE proposal should not have SPI */
322       if (sap->protocol_id == IKEV2_PROTOCOL_IKE && sap->spi_size != 0)
323         goto data_corrupted;
324
325       /* IKE proposal should not have SPI */
326       if (sap->protocol_id == IKEV2_PROTOCOL_ESP && sap->spi_size != 4)
327         goto data_corrupted;
328
329       transform_ptr = proposal_ptr + sizeof(*sap) + sap->spi_size;
330
331       vec_add2(v, proposal, 1);
332       proposal->proposal_num = sap->proposal_num;
333       proposal->protocol_id = sap->protocol_id;
334
335       if (sap->spi_size == 4) {
336         proposal->spi = clib_net_to_host_u32(sap->spi[0]);
337       }
338
339       for(i=0; i< sap->num_transforms; i++)
340         {
341           ike_sa_transform_data_t * tr = (ike_sa_transform_data_t *) &ikep->payload[transform_ptr];
342           u16 tlen = clib_net_to_host_u16(tr->transform_len);
343
344           if (tlen < sizeof(*tr))
345             goto data_corrupted;
346
347           vec_add2(proposal->transforms, transform, 1);
348
349           transform->type = tr->transform_type;
350           transform->transform_id = clib_net_to_host_u16(tr->transform_id);
351           if (tlen > sizeof(*tr))
352             vec_add(transform->attrs, tr->attributes, tlen - sizeof(*tr));
353
354           DBG_PLD("transform num %u len %u last_or_more %u type %U id %u%s%U",
355                   i, tlen, tr->last_or_more,
356                   format_ikev2_sa_transform, transform,
357                   clib_net_to_host_u16(tr->transform_id),
358                   tlen > sizeof(*tr) ? " attrs " : "",
359                   format_hex_bytes, tr->attributes, tlen - sizeof (*tr));
360
361           transform_ptr += tlen;
362         }
363
364       proposal_ptr += clib_net_to_host_u16(sap->proposal_len);
365     }
366   while (proposal_ptr < (plen - sizeof(*ikep)) && sap->last_or_more == 2);
367
368   /* data validation */
369   if (proposal_ptr != (plen - sizeof(*ikep)) || sap->last_or_more)
370       goto data_corrupted;
371
372   return v;
373
374 data_corrupted:
375   DBG_PLD("SA payload data corrupted");
376   ikev2_sa_free_proposal_vector(&v);
377   return 0;
378 }
379
380 ikev2_ts_t *
381 ikev2_parse_ts_payload(ike_payload_header_t * ikep)
382 {
383   ike_ts_payload_header_t * tsp = (ike_ts_payload_header_t *) ikep;
384   ikev2_ts_t * r = 0, *ts;
385   u8 i;
386
387   for (i = 0; i < tsp->num_ts; i++)
388     {
389       if (tsp->ts[i].ts_type != 7) /*  TS_IPV4_ADDR_RANGE */
390         {
391           DBG_PLD("unsupported TS type received (%u)", tsp->ts[i].ts_type);
392           continue;
393         }
394
395       vec_add2(r, ts, 1);
396       ts->ts_type           = tsp->ts[i].ts_type;
397       ts->protocol_id       = tsp->ts[i].protocol_id;
398       ts->start_port        = tsp->ts[i].start_port;
399       ts->end_port          = tsp->ts[i].end_port;
400       ts->start_addr.as_u32 = tsp->ts[i].start_addr.as_u32;
401       ts->end_addr.as_u32   = tsp->ts[i].end_addr.as_u32;
402     }
403   return r;
404 }
405
406 ikev2_notify_t *
407 ikev2_parse_notify_payload(ike_payload_header_t * ikep)
408 {
409   ike_notify_payload_header_t * n = (ike_notify_payload_header_t *) ikep;
410   u32 plen = clib_net_to_host_u16(ikep->length);
411   ikev2_notify_t * r = 0;
412   u32 spi;
413
414   DBG_PLD("msg_type %U len %u%s%U",
415           format_ikev2_notify_msg_type, clib_net_to_host_u16(n->msg_type),
416           plen, plen > sizeof(*n) ? " data ":"",
417           format_hex_bytes, n->payload, plen - sizeof(*n));
418
419   r = vec_new(ikev2_notify_t, 1);
420   r->msg_type = clib_net_to_host_u16(n->msg_type);
421   r->protocol_id = n->protocol_id;
422
423   if (n->spi_size == 4)
424     {
425       clib_memcpy(&spi, n->payload, n->spi_size);
426       r->spi = clib_net_to_host_u32(spi);
427       DBG_PLD("spi %lx", r->spi);
428     }
429   else if (n->spi_size == 0)
430     {
431       r->spi = 0;
432     }
433   else
434     {
435       clib_warning("invalid SPI Size %d", n->spi_size);
436     }
437
438   if (plen > (sizeof(*n) + n->spi_size))
439     {
440       vec_add(r->data, n->payload + n->spi_size, plen - sizeof(*n) - n->spi_size);
441     }
442
443   return r;
444 }
445
446 void
447 ikev2_parse_vendor_payload(ike_payload_header_t * ikep)
448 {
449   u32 plen = clib_net_to_host_u16(ikep->length);
450   int i;
451   int is_string = 1;
452
453   for(i=0; i < plen - 4; i++)
454     if (!isprint(ikep->payload[i]))
455       is_string = 0;
456
457   DBG_PLD("len %u data %s:%U",
458           plen,
459           is_string ? "string":"hex",
460           is_string ? format_ascii_bytes : format_hex_bytes,
461           ikep->payload, plen - sizeof(*ikep));
462 }
463
464 ikev2_delete_t *
465 ikev2_parse_delete_payload(ike_payload_header_t * ikep)
466 {
467   ike_delete_payload_header_t * d = (ike_delete_payload_header_t *) ikep;
468   u32 plen = clib_net_to_host_u16(ikep->length);
469   ikev2_delete_t * r = 0, * del;
470   u16 num_of_spi = clib_net_to_host_u16(d->num_of_spi);
471   u16 i = 0;
472
473   DBG_PLD("protocol_id %u spi_size %u num_of_spi %u len %u%s%U",
474           d->protocol_id, d->spi_size, num_of_spi,
475           plen, plen > sizeof(d) ? " data ":"",
476           format_hex_bytes, d->spi, plen - sizeof(*d));
477
478   if (d->protocol_id == IKEV2_PROTOCOL_IKE)
479     {
480       r = vec_new(ikev2_delete_t, 1);
481       r->protocol_id = 1;
482     }
483   else
484     {
485       r = vec_new(ikev2_delete_t, num_of_spi);
486       vec_foreach(del, r)
487         {
488           del->protocol_id = d->protocol_id;
489           del->spi = clib_net_to_host_u32(d->spi[i++]);
490         }
491     }
492
493   return r;
494 }