]>
Commit | Line | Data |
---|---|---|
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 |
30 | typedef 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 | 35 | struct 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 |
86 | static 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 | */ | |
128 | static 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 |
160 | METHOD(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 |
197 | METHOD(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 |
209 | METHOD(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 |
219 | METHOD(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 |
225 | METHOD(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 |
231 | METHOD(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 | 240 | static 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 **)¤t)) | |
60356f33 | 249 | { |
38fb67fb | 250 | this->payload_length += current->get_length(current); |
60356f33 | 251 | } |
80f93f20 | 252 | enumerator->destroy(enumerator); |
60356f33 MW |
253 | } |
254 | ||
80f93f20 MW |
255 | METHOD(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 | 264 | static 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 |
290 | METHOD(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 | 345 | METHOD(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 |
401 | METHOD(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 | 407 | METHOD(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 | 430 | METHOD(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 | ||
453 | METHOD(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 | ||
470 | METHOD(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 |
487 | METHOD2(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 | 498 | sa_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 | */ | |
539 | sa_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 | */ | |
559 | sa_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 | */ | |
573 | sa_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 | */ | |
617 | sa_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 | } |