Annotation of embedaddon/strongswan/src/libcharon/encoding/payloads/sa_payload.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (C) 2012-2020 Tobias Brunner
3: * Copyright (C) 2005-2010 Martin Willi
4: * Copyright (C) 2005 Jan Hutter
5: * HSR 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: uint8_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: uint16_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: uint32_t doi;
75:
76: /**
77: * IKEv1 situation
78: */
79: uint32_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 **)¤t))
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 may start with 0 or 1 (or any other number really) */
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: int current_number = substruct->get_proposal_number(substruct);
313:
314: /* check if a proposal has a single protocol */
315: if (current_number == struct_number)
316: {
317: if (ignore_struct_number < struct_number)
318: { /* remove an already added substruct, if first of series */
319: substructs->remove_last(substructs, (void**)&substruct);
320: ignore_struct_number = struct_number;
321: }
322: continue;
323: }
324: /* for IKEv1 the numbers don't have to be consecutive, for IKEv2 they do
325: * but since we don't really care for the actual number we accept them
326: * anyway. we already verified that they increase monotonically. */
327: struct_number = current_number;
328: substructs->insert_last(substructs, substruct);
329: }
330: enumerator->destroy(enumerator);
331:
332: /* generate proposals from substructs */
333: list = linked_list_create();
334: enumerator = substructs->create_enumerator(substructs);
335: while (enumerator->enumerate(enumerator, &substruct))
336: {
337: substruct->get_proposals(substruct, list);
338: }
339: enumerator->destroy(enumerator);
340: substructs->destroy(substructs);
341: return list;
342: }
343:
344: METHOD(sa_payload_t, get_ipcomp_proposals, linked_list_t*,
345: private_sa_payload_t *this, uint16_t *cpi)
346: {
347: int current_proposal = -1, unsupported_proposal = -1;
348: enumerator_t *enumerator;
349: proposal_substructure_t *substruct, *espah = NULL, *ipcomp = NULL;
350: linked_list_t *list;
351:
352: /* we currently only support the combination ESP|AH+IPComp, find the first */
353: enumerator = this->proposals->create_enumerator(this->proposals);
354: while (enumerator->enumerate(enumerator, &substruct))
355: {
356: uint8_t proposal_number = substruct->get_proposal_number(substruct);
357: uint8_t protocol_id = substruct->get_protocol_id(substruct);
358:
359: if (proposal_number == unsupported_proposal)
360: {
361: continue;
362: }
363: if (protocol_id != PROTO_ESP && protocol_id != PROTO_AH &&
364: protocol_id != PROTO_IPCOMP)
365: { /* unsupported combination */
366: espah = ipcomp = NULL;
367: unsupported_proposal = current_proposal;
368: continue;
369: }
370: if (proposal_number != current_proposal)
371: { /* start of a new proposal */
372: if (espah && ipcomp && ipcomp->get_cpi(ipcomp, NULL))
373: { /* previous proposal is valid */
374: break;
375: }
376: espah = ipcomp = NULL;
377: current_proposal = proposal_number;
378: }
379: switch (protocol_id)
380: {
381: case PROTO_ESP:
382: case PROTO_AH:
383: espah = substruct;
384: break;
385: case PROTO_IPCOMP:
386: ipcomp = substruct;
387: break;
388: }
389: }
390: enumerator->destroy(enumerator);
391:
392: list = linked_list_create();
393: if (espah && ipcomp && ipcomp->get_cpi(ipcomp, cpi))
394: {
395: espah->get_proposals(espah, list);
396: }
397: return list;
398: }
399:
400: METHOD(sa_payload_t, create_substructure_enumerator, enumerator_t*,
401: private_sa_payload_t *this)
402: {
403: return this->proposals->create_enumerator(this->proposals);
404: }
405:
406: METHOD(sa_payload_t, get_lifetime, uint32_t,
407: private_sa_payload_t *this, proposal_t *proposal)
408: {
409: proposal_substructure_t *substruct;
410: enumerator_t *enumerator;
411: uint8_t number = proposal->get_number(proposal);
412: uint32_t lifetime = 0;
413:
414: enumerator = this->proposals->create_enumerator(this->proposals);
415: while (enumerator->enumerate(enumerator, &substruct))
416: {
417: if (substruct->get_proposal_number(substruct) == number)
418: {
419: lifetime = substruct->get_lifetime(substruct,
420: proposal->get_transform_number(proposal));
421: break;
422: }
423: }
424: enumerator->destroy(enumerator);
425:
426: return lifetime;
427: }
428:
429: METHOD(sa_payload_t, get_lifebytes, uint64_t,
430: private_sa_payload_t *this, proposal_t *proposal)
431: {
432: proposal_substructure_t *substruct;
433: enumerator_t *enumerator;
434: uint8_t number = proposal->get_number(proposal);
435: uint64_t lifebytes = 0;
436:
437: enumerator = this->proposals->create_enumerator(this->proposals);
438: while (enumerator->enumerate(enumerator, &substruct))
439: {
440: if (substruct->get_proposal_number(substruct) == number)
441: {
442: lifebytes = substruct->get_lifebytes(substruct,
443: proposal->get_transform_number(proposal));
444: break;
445: }
446: }
447: enumerator->destroy(enumerator);
448:
449: return lifebytes;
450: }
451:
452: METHOD(sa_payload_t, get_auth_method, auth_method_t,
453: private_sa_payload_t *this)
454: {
455: proposal_substructure_t *substruct;
456: enumerator_t *enumerator;
457: auth_method_t method = AUTH_NONE;
458:
459: enumerator = this->proposals->create_enumerator(this->proposals);
460: if (enumerator->enumerate(enumerator, &substruct))
461: {
462: method = substruct->get_auth_method(substruct);
463: }
464: enumerator->destroy(enumerator);
465:
466: return method;
467: }
468:
469: METHOD(sa_payload_t, get_encap_mode, ipsec_mode_t,
470: private_sa_payload_t *this, bool *udp)
471: {
472: proposal_substructure_t *substruct;
473: enumerator_t *enumerator;
474: ipsec_mode_t mode = MODE_NONE;
475:
476: enumerator = this->proposals->create_enumerator(this->proposals);
477: if (enumerator->enumerate(enumerator, &substruct))
478: {
479: mode = substruct->get_encap_mode(substruct, udp);
480: }
481: enumerator->destroy(enumerator);
482:
483: return mode;
484: }
485:
486: METHOD2(payload_t, sa_payload_t, destroy, void,
487: private_sa_payload_t *this)
488: {
489: this->proposals->destroy_offset(this->proposals,
490: offsetof(payload_t, destroy));
491: free(this);
492: }
493:
494: /*
495: * Described in header.
496: */
497: sa_payload_t *sa_payload_create(payload_type_t type)
498: {
499: private_sa_payload_t *this;
500:
501: INIT(this,
502: .public = {
503: .payload_interface = {
504: .verify = _verify,
505: .get_encoding_rules = _get_encoding_rules,
506: .get_header_length = _get_header_length,
507: .get_length = _get_length,
508: .get_next_type = _get_next_type,
509: .set_next_type = _set_next_type,
510: .get_type = _get_type,
511: .destroy = _destroy,
512: },
513: .get_proposals = _get_proposals,
514: .get_ipcomp_proposals = _get_ipcomp_proposals,
515: .create_substructure_enumerator = _create_substructure_enumerator,
516: .get_lifetime = _get_lifetime,
517: .get_lifebytes = _get_lifebytes,
518: .get_auth_method = _get_auth_method,
519: .get_encap_mode = _get_encap_mode,
520: .destroy = _destroy,
521: },
522: .next_payload = PL_NONE,
523: .proposals = linked_list_create(),
524: .type = type,
525: /* for IKEv1 only */
526: .doi = IKEV1_DOI_IPSEC,
527: .situation = SIT_IDENTITY_ONLY,
528: );
529:
530: compute_length(this);
531:
532: return &this->public;
533: }
534:
535: /*
536: * Described in header.
537: */
538: sa_payload_t *sa_payload_create_from_proposals_v2(linked_list_t *proposals)
539: {
540: private_sa_payload_t *this;
541: enumerator_t *enumerator;
542: proposal_t *proposal;
543:
544: this = (private_sa_payload_t*)sa_payload_create(PLV2_SECURITY_ASSOCIATION);
545: enumerator = proposals->create_enumerator(proposals);
546: while (enumerator->enumerate(enumerator, &proposal))
547: {
548: add_proposal_v2(this, proposal);
549: }
550: enumerator->destroy(enumerator);
551:
552: return &this->public;
553: }
554:
555: /*
556: * Described in header.
557: */
558: sa_payload_t *sa_payload_create_from_proposal_v2(proposal_t *proposal)
559: {
560: private_sa_payload_t *this;
561:
562: this = (private_sa_payload_t*)sa_payload_create(PLV2_SECURITY_ASSOCIATION);
563: add_proposal_v2(this, proposal);
564:
565: return &this->public;
566:
567: }
568:
569: /*
570: * Described in header.
571: */
572: sa_payload_t *sa_payload_create_from_proposals_v1(linked_list_t *proposals,
573: uint32_t lifetime, uint64_t lifebytes,
574: auth_method_t auth, ipsec_mode_t mode,
575: encap_t udp, uint16_t cpi)
576: {
577: proposal_substructure_t *substruct;
578: private_sa_payload_t *this;
579:
580: this = (private_sa_payload_t*)sa_payload_create(PLV1_SECURITY_ASSOCIATION);
581:
582: if (!proposals || !proposals->get_count(proposals))
583: {
584: return &this->public;
585: }
586:
587: /* IKEv1 encodes multiple proposals in a single substructure
588: * TODO-IKEv1: Encode ESP+AH proposals in two substructs with same num */
589: substruct = proposal_substructure_create_from_proposals_v1(proposals,
590: lifetime, lifebytes, auth, mode, udp);
591: this->proposals->insert_last(this->proposals, substruct);
592: substruct->set_is_last_proposal(substruct, FALSE);
593: if (cpi)
594: {
595: uint8_t proposal_number = substruct->get_proposal_number(substruct);
596:
597: substruct = proposal_substructure_create_for_ipcomp_v1(lifetime,
598: lifebytes, cpi, mode, udp, proposal_number);
599: this->proposals->insert_last(this->proposals, substruct);
600: substruct->set_is_last_proposal(substruct, FALSE);
601: /* add the proposals again without IPComp */
602: substruct = proposal_substructure_create_from_proposals_v1(proposals,
603: lifetime, lifebytes, auth, mode, udp);
604: substruct->set_proposal_number(substruct, proposal_number + 1);
605: this->proposals->insert_last(this->proposals, substruct);
606: }
607: substruct->set_is_last_proposal(substruct, TRUE);
608: compute_length(this);
609:
610: return &this->public;
611: }
612:
613: /*
614: * Described in header.
615: */
616: sa_payload_t *sa_payload_create_from_proposal_v1(proposal_t *proposal,
617: uint32_t lifetime, uint64_t lifebytes,
618: auth_method_t auth, ipsec_mode_t mode,
619: encap_t udp, uint16_t cpi)
620: {
621: private_sa_payload_t *this;
622: linked_list_t *proposals;
623:
624: proposals = linked_list_create();
625: proposals->insert_last(proposals, proposal);
626: this = (private_sa_payload_t*)sa_payload_create_from_proposals_v1(proposals,
627: lifetime, lifebytes, auth, mode, udp, cpi);
628: proposals->destroy(proposals);
629: return &this->public;
630: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>