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