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