payload: Use common prefixes for all payload type identifiers
[strongswan.git] / src / libcharon / encoding / payloads / sa_payload.c
1 /*
2 * Copyright (C) 2012 Tobias Brunner
3 * Copyright (C) 2005-2010 Martin Willi
4 * Copyright (C) 2005 Jan Hutter
5 * Hochschule fuer Technik Rapperswil
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 * for more details.
16 */
17
18 #include <stddef.h>
19
20 #include "sa_payload.h"
21
22 #include <encoding/payloads/encodings.h>
23 #include <collections/linked_list.h>
24 #include <daemon.h>
25
26 /* IKEv1 situation */
27 #define SIT_IDENTITY_ONLY 1
28
29 typedef struct private_sa_payload_t private_sa_payload_t;
30
31 /**
32 * Private data of an sa_payload_t object.
33 */
34 struct private_sa_payload_t {
35
36 /**
37 * Public sa_payload_t interface.
38 */
39 sa_payload_t public;
40
41 /**
42 * Next payload type.
43 */
44 u_int8_t next_payload;
45
46 /**
47 * Critical flag.
48 */
49 bool critical;
50
51 /**
52 * Reserved bits
53 */
54 bool reserved[8];
55
56 /**
57 * Length of this payload.
58 */
59 u_int16_t payload_length;
60
61 /**
62 * Proposals in this payload are stored in a linked_list_t.
63 */
64 linked_list_t *proposals;
65
66 /**
67 * Type of this payload, V1 or V2
68 */
69 payload_type_t type;
70
71 /**
72 * IKEv1 DOI
73 */
74 u_int32_t doi;
75
76 /**
77 * IKEv1 situation
78 */
79 u_int32_t situation;
80 };
81
82 /**
83 * Encoding rules for IKEv1 SA payload
84 */
85 static encoding_rule_t encodings_v1[] = {
86 /* 1 Byte next payload type, stored in the field next_payload */
87 { U_INT_8, offsetof(private_sa_payload_t, next_payload) },
88 /* 8 reserved bits */
89 { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[0]) },
90 { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[1]) },
91 { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[2]) },
92 { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[3]) },
93 { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[4]) },
94 { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[5]) },
95 { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[6]) },
96 { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[7]) },
97 /* Length of the whole SA payload*/
98 { PAYLOAD_LENGTH, offsetof(private_sa_payload_t, payload_length) },
99 /* DOI*/
100 { U_INT_32, offsetof(private_sa_payload_t, doi) },
101 /* Situation*/
102 { U_INT_32, offsetof(private_sa_payload_t, situation) },
103 /* Proposals are stored in a proposal substructure list */
104 { PAYLOAD_LIST + PLV1_PROPOSAL_SUBSTRUCTURE,
105 offsetof(private_sa_payload_t, proposals) },
106 };
107
108 /*
109 1 2 3
110 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
111 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
112 ! Next Payload ! RESERVED ! Payload Length !
113 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
114 ! DOI !
115 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
116 ! Situation !
117 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
118 ! !
119 ~ <Proposals> ~
120 ! !
121 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
122 */
123
124 /**
125 * Encoding rules for IKEv2 SA payload
126 */
127 static encoding_rule_t encodings_v2[] = {
128 /* 1 Byte next payload type, stored in the field next_payload */
129 { U_INT_8, offsetof(private_sa_payload_t, next_payload) },
130 /* the critical bit */
131 { FLAG, offsetof(private_sa_payload_t, critical) },
132 /* 7 Bit reserved bits */
133 { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[0]) },
134 { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[1]) },
135 { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[2]) },
136 { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[3]) },
137 { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[4]) },
138 { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[5]) },
139 { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[6]) },
140 /* Length of the whole SA payload*/
141 { PAYLOAD_LENGTH, offsetof(private_sa_payload_t, payload_length) },
142 /* Proposals are stored in a proposal substructure list */
143 { PAYLOAD_LIST + PLV2_PROPOSAL_SUBSTRUCTURE,
144 offsetof(private_sa_payload_t, proposals) },
145 };
146
147 /*
148 1 2 3
149 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
150 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
151 ! Next Payload !C! RESERVED ! Payload Length !
152 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
153 ! !
154 ~ <Proposals> ~
155 ! !
156 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
157 */
158
159 METHOD(payload_t, verify, status_t,
160 private_sa_payload_t *this)
161 {
162 int expected_number = 0, current_number;
163 status_t status = SUCCESS;
164 enumerator_t *enumerator;
165 proposal_substructure_t *substruct;
166
167 if (this->type == PLV2_SECURITY_ASSOCIATION)
168 {
169 expected_number = 1;
170 }
171
172 /* check proposal numbering */
173 enumerator = this->proposals->create_enumerator(this->proposals);
174 while (enumerator->enumerate(enumerator, (void**)&substruct))
175 {
176 current_number = substruct->get_proposal_number(substruct);
177 if (current_number < expected_number)
178 {
179 DBG1(DBG_ENC, "proposal number smaller than previous");
180 status = FAILED;
181 break;
182 }
183
184 status = substruct->payload_interface.verify(&substruct->payload_interface);
185 if (status != SUCCESS)
186 {
187 DBG1(DBG_ENC, "PROPOSAL_SUBSTRUCTURE verification failed");
188 break;
189 }
190 expected_number = current_number;
191 }
192 enumerator->destroy(enumerator);
193 return status;
194 }
195
196 METHOD(payload_t, get_encoding_rules, int,
197 private_sa_payload_t *this, encoding_rule_t **rules)
198 {
199 if (this->type == PLV1_SECURITY_ASSOCIATION)
200 {
201 *rules = encodings_v1;
202 return countof(encodings_v1);
203 }
204 *rules = encodings_v2;
205 return countof(encodings_v2);
206 }
207
208 METHOD(payload_t, get_header_length, int,
209 private_sa_payload_t *this)
210 {
211 if (this->type == PLV1_SECURITY_ASSOCIATION)
212 {
213 return 12;
214 }
215 return 4;
216 }
217
218 METHOD(payload_t, get_type, payload_type_t,
219 private_sa_payload_t *this)
220 {
221 return this->type;
222 }
223
224 METHOD(payload_t, get_next_type, payload_type_t,
225 private_sa_payload_t *this)
226 {
227 return this->next_payload;
228 }
229
230 METHOD(payload_t, set_next_type, void,
231 private_sa_payload_t *this,payload_type_t type)
232 {
233 this->next_payload = type;
234 }
235
236 /**
237 * recompute length of the payload.
238 */
239 static void compute_length(private_sa_payload_t *this)
240 {
241 enumerator_t *enumerator;
242 payload_t *current;
243
244 this->payload_length = get_header_length(this);
245
246 enumerator = this->proposals->create_enumerator(this->proposals);
247 while (enumerator->enumerate(enumerator, (void **)&current))
248 {
249 this->payload_length += current->get_length(current);
250 }
251 enumerator->destroy(enumerator);
252 }
253
254 METHOD(payload_t, get_length, size_t,
255 private_sa_payload_t *this)
256 {
257 return this->payload_length;
258 }
259
260 /**
261 * Create a transform substructure from a proposal, add to payload
262 */
263 static void add_proposal_v2(private_sa_payload_t *this, proposal_t *proposal)
264 {
265 proposal_substructure_t *substruct, *last;
266 u_int count;
267
268 substruct = proposal_substructure_create_from_proposal_v2(proposal);
269 count = this->proposals->get_count(this->proposals);
270 if (count > 0)
271 {
272 this->proposals->get_last(this->proposals, (void**)&last);
273 /* last transform is now not anymore last one */
274 last->set_is_last_proposal(last, FALSE);
275 }
276 substruct->set_is_last_proposal(substruct, TRUE);
277 if (proposal->get_number(proposal))
278 { /* use the selected proposals number, if any */
279 substruct->set_proposal_number(substruct, proposal->get_number(proposal));
280 }
281 else
282 {
283 substruct->set_proposal_number(substruct, count + 1);
284 }
285 this->proposals->insert_last(this->proposals, substruct);
286 compute_length(this);
287 }
288
289 METHOD(sa_payload_t, get_proposals, linked_list_t*,
290 private_sa_payload_t *this)
291 {
292 int struct_number = 0;
293 int ignore_struct_number = 0;
294 enumerator_t *enumerator;
295 proposal_substructure_t *substruct;
296 linked_list_t *substructs, *list;
297
298 if (this->type == PLV1_SECURITY_ASSOCIATION)
299 { /* IKEv1 proposals start with 0 */
300 struct_number = ignore_struct_number = -1;
301 }
302
303 /* we do not support proposals split up to two proposal substructures, as
304 * AH+ESP bundles are not supported in RFC4301 anymore.
305 * To handle such structures safely, we just skip proposals with multiple
306 * protocols.
307 */
308 substructs = linked_list_create();
309 enumerator = this->proposals->create_enumerator(this->proposals);
310 while (enumerator->enumerate(enumerator, &substruct))
311 {
312 /* check if a proposal has a single protocol */
313 if (substruct->get_proposal_number(substruct) == struct_number)
314 {
315 if (ignore_struct_number < struct_number)
316 { /* remove an already added, if first of series */
317 substructs->remove_last(substructs, (void**)&substruct);
318 ignore_struct_number = struct_number;
319 }
320 continue;
321 }
322 struct_number++;
323 substructs->insert_last(substructs, substruct);
324 }
325 enumerator->destroy(enumerator);
326
327 /* generate proposals from substructs */
328 list = linked_list_create();
329 enumerator = substructs->create_enumerator(substructs);
330 while (enumerator->enumerate(enumerator, &substruct))
331 {
332 substruct->get_proposals(substruct, list);
333 }
334 enumerator->destroy(enumerator);
335 substructs->destroy(substructs);
336 return list;
337 }
338
339 METHOD(sa_payload_t, get_ipcomp_proposals, linked_list_t*,
340 private_sa_payload_t *this, u_int16_t *cpi)
341 {
342 int current_proposal = -1, unsupported_proposal = -1;
343 enumerator_t *enumerator;
344 proposal_substructure_t *substruct, *espah = NULL, *ipcomp = NULL;
345 linked_list_t *list;
346
347 /* we currently only support the combination ESP|AH+IPComp, find the first */
348 enumerator = this->proposals->create_enumerator(this->proposals);
349 while (enumerator->enumerate(enumerator, &substruct))
350 {
351 u_int8_t proposal_number = substruct->get_proposal_number(substruct);
352 u_int8_t protocol_id = substruct->get_protocol_id(substruct);
353
354 if (proposal_number == unsupported_proposal)
355 {
356 continue;
357 }
358 if (protocol_id != PROTO_ESP && protocol_id != PROTO_AH &&
359 protocol_id != PROTO_IPCOMP)
360 { /* unsupported combination */
361 espah = ipcomp = NULL;
362 unsupported_proposal = current_proposal;
363 continue;
364 }
365 if (proposal_number != current_proposal)
366 { /* start of a new proposal */
367 if (espah && ipcomp)
368 { /* previous proposal is valid */
369 break;
370 }
371 espah = ipcomp = NULL;
372 current_proposal = proposal_number;
373 }
374 switch (protocol_id)
375 {
376 case PROTO_ESP:
377 case PROTO_AH:
378 espah = substruct;
379 break;
380 case PROTO_IPCOMP:
381 ipcomp = substruct;
382 break;
383 }
384 }
385 enumerator->destroy(enumerator);
386
387 list = linked_list_create();
388 if (espah && ipcomp && ipcomp->get_cpi(ipcomp, cpi))
389 {
390 espah->get_proposals(espah, list);
391 }
392 return list;
393 }
394
395 METHOD(sa_payload_t, create_substructure_enumerator, enumerator_t*,
396 private_sa_payload_t *this)
397 {
398 return this->proposals->create_enumerator(this->proposals);
399 }
400
401 METHOD(sa_payload_t, get_lifetime, u_int32_t,
402 private_sa_payload_t *this)
403 {
404 proposal_substructure_t *substruct;
405 enumerator_t *enumerator;
406 u_int32_t lifetime = 0;
407
408 enumerator = this->proposals->create_enumerator(this->proposals);
409 if (enumerator->enumerate(enumerator, &substruct))
410 {
411 lifetime = substruct->get_lifetime(substruct);
412 }
413 enumerator->destroy(enumerator);
414
415 return lifetime;
416 }
417
418 METHOD(sa_payload_t, get_lifebytes, u_int64_t,
419 private_sa_payload_t *this)
420 {
421 proposal_substructure_t *substruct;
422 enumerator_t *enumerator;
423 u_int64_t lifebytes = 0;
424
425 enumerator = this->proposals->create_enumerator(this->proposals);
426 if (enumerator->enumerate(enumerator, &substruct))
427 {
428 lifebytes = substruct->get_lifebytes(substruct);
429 }
430 enumerator->destroy(enumerator);
431
432 return lifebytes;
433 }
434
435 METHOD(sa_payload_t, get_auth_method, auth_method_t,
436 private_sa_payload_t *this)
437 {
438 proposal_substructure_t *substruct;
439 enumerator_t *enumerator;
440 auth_method_t method = AUTH_NONE;
441
442 enumerator = this->proposals->create_enumerator(this->proposals);
443 if (enumerator->enumerate(enumerator, &substruct))
444 {
445 method = substruct->get_auth_method(substruct);
446 }
447 enumerator->destroy(enumerator);
448
449 return method;
450 }
451
452 METHOD(sa_payload_t, get_encap_mode, ipsec_mode_t,
453 private_sa_payload_t *this, bool *udp)
454 {
455 proposal_substructure_t *substruct;
456 enumerator_t *enumerator;
457 ipsec_mode_t mode = MODE_NONE;
458
459 enumerator = this->proposals->create_enumerator(this->proposals);
460 if (enumerator->enumerate(enumerator, &substruct))
461 {
462 mode = substruct->get_encap_mode(substruct, udp);
463 }
464 enumerator->destroy(enumerator);
465
466 return mode;
467 }
468
469 METHOD2(payload_t, sa_payload_t, destroy, void,
470 private_sa_payload_t *this)
471 {
472 this->proposals->destroy_offset(this->proposals,
473 offsetof(payload_t, destroy));
474 free(this);
475 }
476
477 /*
478 * Described in header.
479 */
480 sa_payload_t *sa_payload_create(payload_type_t type)
481 {
482 private_sa_payload_t *this;
483
484 INIT(this,
485 .public = {
486 .payload_interface = {
487 .verify = _verify,
488 .get_encoding_rules = _get_encoding_rules,
489 .get_header_length = _get_header_length,
490 .get_length = _get_length,
491 .get_next_type = _get_next_type,
492 .set_next_type = _set_next_type,
493 .get_type = _get_type,
494 .destroy = _destroy,
495 },
496 .get_proposals = _get_proposals,
497 .get_ipcomp_proposals = _get_ipcomp_proposals,
498 .create_substructure_enumerator = _create_substructure_enumerator,
499 .get_lifetime = _get_lifetime,
500 .get_lifebytes = _get_lifebytes,
501 .get_auth_method = _get_auth_method,
502 .get_encap_mode = _get_encap_mode,
503 .destroy = _destroy,
504 },
505 .next_payload = PL_NONE,
506 .proposals = linked_list_create(),
507 .type = type,
508 /* for IKEv1 only */
509 .doi = IKEV1_DOI_IPSEC,
510 .situation = SIT_IDENTITY_ONLY,
511 );
512
513 compute_length(this);
514
515 return &this->public;
516 }
517
518 /*
519 * Described in header.
520 */
521 sa_payload_t *sa_payload_create_from_proposals_v2(linked_list_t *proposals)
522 {
523 private_sa_payload_t *this;
524 enumerator_t *enumerator;
525 proposal_t *proposal;
526
527 this = (private_sa_payload_t*)sa_payload_create(PLV2_SECURITY_ASSOCIATION);
528 enumerator = proposals->create_enumerator(proposals);
529 while (enumerator->enumerate(enumerator, &proposal))
530 {
531 add_proposal_v2(this, proposal);
532 }
533 enumerator->destroy(enumerator);
534
535 return &this->public;
536 }
537
538 /*
539 * Described in header.
540 */
541 sa_payload_t *sa_payload_create_from_proposal_v2(proposal_t *proposal)
542 {
543 private_sa_payload_t *this;
544
545 this = (private_sa_payload_t*)sa_payload_create(PLV2_SECURITY_ASSOCIATION);
546 add_proposal_v2(this, proposal);
547
548 return &this->public;
549
550 }
551
552 /*
553 * Described in header.
554 */
555 sa_payload_t *sa_payload_create_from_proposals_v1(linked_list_t *proposals,
556 u_int32_t lifetime, u_int64_t lifebytes,
557 auth_method_t auth, ipsec_mode_t mode,
558 encap_t udp, u_int16_t cpi)
559 {
560 proposal_substructure_t *substruct;
561 private_sa_payload_t *this;
562
563 this = (private_sa_payload_t*)sa_payload_create(PLV1_SECURITY_ASSOCIATION);
564
565 if (!proposals || !proposals->get_count(proposals))
566 {
567 return &this->public;
568 }
569
570 /* IKEv1 encodes multiple proposals in a single substructure
571 * TODO-IKEv1: Encode ESP+AH proposals in two substructs with same num */
572 substruct = proposal_substructure_create_from_proposals_v1(proposals,
573 lifetime, lifebytes, auth, mode, udp);
574 this->proposals->insert_last(this->proposals, substruct);
575 substruct->set_is_last_proposal(substruct, FALSE);
576 if (cpi)
577 {
578 u_int8_t proposal_number = substruct->get_proposal_number(substruct);
579
580 substruct = proposal_substructure_create_for_ipcomp_v1(lifetime,
581 lifebytes, cpi, mode, udp, proposal_number);
582 this->proposals->insert_last(this->proposals, substruct);
583 substruct->set_is_last_proposal(substruct, FALSE);
584 /* add the proposals again without IPComp */
585 substruct = proposal_substructure_create_from_proposals_v1(proposals,
586 lifetime, lifebytes, auth, mode, udp);
587 substruct->set_proposal_number(substruct, proposal_number + 1);
588 this->proposals->insert_last(this->proposals, substruct);
589 }
590 substruct->set_is_last_proposal(substruct, TRUE);
591 compute_length(this);
592
593 return &this->public;
594 }
595
596 /*
597 * Described in header.
598 */
599 sa_payload_t *sa_payload_create_from_proposal_v1(proposal_t *proposal,
600 u_int32_t lifetime, u_int64_t lifebytes,
601 auth_method_t auth, ipsec_mode_t mode,
602 encap_t udp, u_int16_t cpi)
603 {
604 private_sa_payload_t *this;
605 linked_list_t *proposals;
606
607 proposals = linked_list_create();
608 proposals->insert_last(proposals, proposal);
609 this = (private_sa_payload_t*)sa_payload_create_from_proposals_v1(proposals,
610 lifetime, lifebytes, auth, mode, udp, cpi);
611 proposals->destroy(proposals);
612 return &this->public;
613 }