]>
Commit | Line | Data |
---|---|---|
da42afc5 | 1 | /* |
7da3143a | 2 | * Copyright (C) 2012-2020 Tobias Brunner |
806b69a4 | 3 | * Copyright (C) 2005-2010 Martin Willi |
c71d53ba | 4 | * Copyright (C) 2005 Jan Hutter |
1b671669 | 5 | * HSR Hochschule fuer Technik Rapperswil |
da42afc5 JH |
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 | */ | |
5113680f | 17 | |
da42afc5 JH |
18 | #include <stddef.h> |
19 | ||
20 | #include "proposal_substructure.h" | |
21 | ||
4a962238 MW |
22 | #include <encoding/payloads/encodings.h> |
23 | #include <encoding/payloads/transform_substructure.h> | |
db7ef624 | 24 | #include <library.h> |
12642a68 | 25 | #include <collections/linked_list.h> |
60356f33 | 26 | #include <daemon.h> |
da42afc5 | 27 | |
c3dc864e | 28 | /** |
1bf2971f | 29 | * IKEv2 Value for a proposal payload. |
c3dc864e MW |
30 | */ |
31 | #define PROPOSAL_TYPE_VALUE 2 | |
32 | ||
95c61cb9 JH |
33 | typedef struct private_proposal_substructure_t private_proposal_substructure_t; |
34 | ||
da42afc5 | 35 | /** |
3fe05870 | 36 | * Private data of an proposal_substructure_t object. |
da42afc5 | 37 | */ |
95c61cb9 | 38 | struct private_proposal_substructure_t { |
806b69a4 | 39 | |
da42afc5 | 40 | /** |
3fe05870 | 41 | * Public proposal_substructure_t interface. |
da42afc5 JH |
42 | */ |
43 | proposal_substructure_t public; | |
7daf5226 | 44 | |
da42afc5 | 45 | /** |
3fe05870 | 46 | * Next payload type. |
da42afc5 | 47 | */ |
b12c53ce | 48 | uint8_t next_payload; |
da42afc5 | 49 | |
c93c7a75 MW |
50 | /** |
51 | * reserved byte | |
52 | */ | |
b12c53ce | 53 | uint8_t reserved; |
c93c7a75 | 54 | |
da42afc5 | 55 | /** |
3fe05870 | 56 | * Length of this payload. |
da42afc5 | 57 | */ |
b12c53ce | 58 | uint16_t proposal_length; |
7daf5226 | 59 | |
da42afc5 | 60 | /** |
3fe05870 | 61 | * Proposal number. |
da42afc5 | 62 | */ |
b12c53ce | 63 | uint8_t proposal_number; |
7daf5226 | 64 | |
da42afc5 | 65 | /** |
3fe05870 | 66 | * Protocol ID. |
da42afc5 | 67 | */ |
b12c53ce | 68 | uint8_t protocol_id; |
da42afc5 JH |
69 | |
70 | /** | |
3fe05870 | 71 | * SPI size of the following SPI. |
da42afc5 | 72 | */ |
b12c53ce | 73 | uint8_t spi_size; |
da42afc5 JH |
74 | |
75 | /** | |
3fe05870 | 76 | * Number of transforms. |
da42afc5 | 77 | */ |
b12c53ce | 78 | uint8_t transforms_count; |
7daf5226 | 79 | |
7b3814f7 MW |
80 | /** |
81 | * SPI is stored as chunk. | |
82 | */ | |
83 | chunk_t spi; | |
7daf5226 | 84 | |
7b3814f7 MW |
85 | /** |
86 | * Transforms are stored in a linked_list_t. | |
87 | */ | |
1bf2971f MW |
88 | linked_list_t *transforms; |
89 | ||
90 | /** | |
3ecfc83c | 91 | * Type of this payload, PLV2_PROPOSAL_SUBSTRUCTURE or PLV1_PROPOSAL_SUBSTRUCTURE |
1bf2971f MW |
92 | */ |
93 | payload_type_t type; | |
da42afc5 JH |
94 | }; |
95 | ||
96 | /** | |
1bf2971f | 97 | * Encoding rules for a IKEv1 Proposal substructure. |
da42afc5 | 98 | */ |
1bf2971f MW |
99 | static encoding_rule_t encodings_v1[] = { |
100 | /* 1 Byte next payload type, stored in the field next_payload */ | |
101 | { U_INT_8, offsetof(private_proposal_substructure_t, next_payload) }, | |
102 | /* 1 Reserved Byte */ | |
103 | { RESERVED_BYTE, offsetof(private_proposal_substructure_t, reserved) }, | |
104 | /* Length of the whole proposal substructure payload*/ | |
105 | { PAYLOAD_LENGTH, offsetof(private_proposal_substructure_t, proposal_length) }, | |
106 | /* proposal number is a number of 8 bit */ | |
107 | { U_INT_8, offsetof(private_proposal_substructure_t, proposal_number) }, | |
108 | /* protocol ID is a number of 8 bit */ | |
109 | { U_INT_8, offsetof(private_proposal_substructure_t, protocol_id) }, | |
110 | /* SPI Size has its own type */ | |
111 | { SPI_SIZE, offsetof(private_proposal_substructure_t, spi_size) }, | |
112 | /* Number of transforms is a number of 8 bit */ | |
113 | { U_INT_8, offsetof(private_proposal_substructure_t, transforms_count) }, | |
114 | /* SPI is a chunk of variable size*/ | |
115 | { SPI, offsetof(private_proposal_substructure_t, spi) }, | |
f62a7c7c | 116 | /* Transforms are stored in a transform substructure list */ |
3ecfc83c | 117 | { PAYLOAD_LIST + PLV1_TRANSFORM_SUBSTRUCTURE, |
f62a7c7c | 118 | offsetof(private_proposal_substructure_t, transforms) }, |
1bf2971f MW |
119 | }; |
120 | ||
121 | /** | |
122 | * Encoding rules for a IKEv2 Proposal substructure. | |
123 | */ | |
124 | static encoding_rule_t encodings_v2[] = { | |
7b3814f7 | 125 | /* 1 Byte next payload type, stored in the field next_payload */ |
806b69a4 | 126 | { U_INT_8, offsetof(private_proposal_substructure_t, next_payload) }, |
c93c7a75 MW |
127 | /* 1 Reserved Byte */ |
128 | { RESERVED_BYTE, offsetof(private_proposal_substructure_t, reserved) }, | |
b860cffd | 129 | /* Length of the whole proposal substructure payload*/ |
806b69a4 | 130 | { PAYLOAD_LENGTH, offsetof(private_proposal_substructure_t, proposal_length) }, |
da42afc5 | 131 | /* proposal number is a number of 8 bit */ |
806b69a4 | 132 | { U_INT_8, offsetof(private_proposal_substructure_t, proposal_number) }, |
da42afc5 | 133 | /* protocol ID is a number of 8 bit */ |
806b69a4 | 134 | { U_INT_8, offsetof(private_proposal_substructure_t, protocol_id) }, |
da42afc5 | 135 | /* SPI Size has its own type */ |
806b69a4 | 136 | { SPI_SIZE, offsetof(private_proposal_substructure_t, spi_size) }, |
da42afc5 | 137 | /* Number of transforms is a number of 8 bit */ |
806b69a4 | 138 | { U_INT_8, offsetof(private_proposal_substructure_t, transforms_count) }, |
da42afc5 | 139 | /* SPI is a chunk of variable size*/ |
806b69a4 | 140 | { SPI, offsetof(private_proposal_substructure_t, spi) }, |
f62a7c7c | 141 | /* Transforms are stored in a transform substructure list */ |
3ecfc83c | 142 | { PAYLOAD_LIST + PLV2_TRANSFORM_SUBSTRUCTURE, |
f62a7c7c | 143 | offsetof(private_proposal_substructure_t, transforms) }, |
da42afc5 JH |
144 | }; |
145 | ||
e31eb71e JH |
146 | /* |
147 | 1 2 3 | |
148 | 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 | |
149 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
150 | ! 0 (last) or 2 ! RESERVED ! Proposal Length ! | |
151 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
152 | ! Proposal # ! Protocol ID ! SPI Size !# of Transforms! | |
153 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
154 | ~ SPI (variable) ~ | |
155 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
156 | ! ! | |
157 | ~ <Transforms> ~ | |
158 | ! ! | |
159 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
160 | */ | |
161 | ||
1bf2971f MW |
162 | /** |
163 | * Encryption. | |
164 | */ | |
165 | typedef enum { | |
166 | IKEV1_ENCR_DES_CBC = 1, | |
167 | IKEV1_ENCR_IDEA_CBC = 2, | |
168 | IKEV1_ENCR_BLOWFISH_CBC = 3, | |
169 | IKEV1_ENCR_RC5_R16_B64_CBC = 4, | |
170 | IKEV1_ENCR_3DES_CBC = 5, | |
171 | IKEV1_ENCR_CAST_CBC = 6, | |
172 | IKEV1_ENCR_AES_CBC = 7, | |
173 | IKEV1_ENCR_CAMELLIA_CBC = 8, | |
4b797f46 AS |
174 | /* FreeS/WAN proprietary */ |
175 | IKEV1_ENCR_SERPENT_CBC = 65004, | |
176 | IKEV1_ENCR_TWOFISH_CBC = 65005, | |
1bf2971f MW |
177 | } ikev1_encryption_t; |
178 | ||
179 | /** | |
180 | * IKEv1 hash. | |
181 | */ | |
182 | typedef enum { | |
183 | IKEV1_HASH_MD5 = 1, | |
184 | IKEV1_HASH_SHA1 = 2, | |
185 | IKEV1_HASH_TIGER = 3, | |
186 | IKEV1_HASH_SHA2_256 = 4, | |
187 | IKEV1_HASH_SHA2_384 = 5, | |
188 | IKEV1_HASH_SHA2_512 = 6, | |
189 | } ikev1_hash_t; | |
190 | ||
191 | /** | |
192 | * IKEv1 Transform ID IKE. | |
193 | */ | |
194 | typedef enum { | |
195 | IKEV1_TRANSID_KEY_IKE = 1, | |
196 | } ikev1_ike_transid_t; | |
197 | ||
198 | /** | |
4b797f46 | 199 | * IKEv1 Transform ID ESP encryption algorithm. |
1bf2971f MW |
200 | */ |
201 | typedef enum { | |
4b797f46 AS |
202 | IKEV1_ESP_ENCR_DES_IV64 = 1, |
203 | IKEV1_ESP_ENCR_DES = 2, | |
204 | IKEV1_ESP_ENCR_3DES = 3, | |
205 | IKEV1_ESP_ENCR_RC5 = 4, | |
206 | IKEV1_ESP_ENCR_IDEA = 5, | |
207 | IKEV1_ESP_ENCR_CAST = 6, | |
208 | IKEV1_ESP_ENCR_BLOWFISH = 7, | |
209 | IKEV1_ESP_ENCR_3IDEA = 8, | |
210 | IKEV1_ESP_ENCR_DES_IV32 = 9, | |
211 | IKEV1_ESP_ENCR_RC4 = 10, | |
212 | IKEV1_ESP_ENCR_NULL = 11, | |
213 | IKEV1_ESP_ENCR_AES_CBC = 12, | |
214 | IKEV1_ESP_ENCR_AES_CTR = 13, | |
215 | IKEV1_ESP_ENCR_AES_CCM_8 = 14, | |
216 | IKEV1_ESP_ENCR_AES_CCM_12 = 15, | |
217 | IKEV1_ESP_ENCR_AES_CCM_16 = 16, | |
218 | IKEV1_ESP_ENCR_AES_GCM_8 = 18, | |
219 | IKEV1_ESP_ENCR_AES_GCM_12 = 19, | |
220 | IKEV1_ESP_ENCR_AES_GCM_16 = 20, | |
221 | IKEV1_ESP_ENCR_SEED_CBC = 21, | |
222 | IKEV1_ESP_ENCR_CAMELLIA = 22, | |
223 | IKEV1_ESP_ENCR_NULL_AUTH_AES_GMAC = 23, | |
224 | /* FreeS/WAN proprietary */ | |
225 | IKEV1_ESP_ENCR_SERPENT = 252, | |
226 | IKEV1_ESP_ENCR_TWOFISH = 253, | |
728f529c | 227 | } ikev1_esp_transid_t; |
1bf2971f | 228 | |
3771b858 MW |
229 | /** |
230 | * IKEv1 Transform ID AH authentication algorithm. | |
231 | */ | |
232 | typedef enum { | |
233 | IKEV1_AH_HMAC_MD5 = 2, | |
234 | IKEV1_AH_HMAC_SHA = 3, | |
235 | IKEV1_AH_DES_MAC = 4, | |
236 | IKEV1_AH_HMAC_SHA2_256 = 5, | |
237 | IKEV1_AH_HMAC_SHA2_384 = 6, | |
238 | IKEV1_AH_HMAC_SHA2_512 = 7, | |
239 | IKEV1_AH_RIPEMD = 8, | |
240 | IKEV1_AH_AES_XCBC_MAC = 9, | |
241 | IKEV1_AH_RSA = 10, | |
242 | IKEV1_AH_AES_128_GMAC = 11, | |
243 | IKEV1_AH_AES_192_GMAC = 12, | |
244 | IKEV1_AH_AES_256_GMAC = 13, | |
245 | } ikev1_ah_transid_t; | |
246 | ||
728f529c TB |
247 | /** |
248 | * IKEv1 authentication algorithm. | |
249 | */ | |
250 | typedef enum { | |
251 | IKEV1_AUTH_HMAC_MD5 = 1, | |
252 | IKEV1_AUTH_HMAC_SHA = 2, | |
253 | IKEV1_AUTH_DES_MAC = 3, | |
254 | IKEV1_AUTH_KPDK = 4, | |
255 | IKEV1_AUTH_HMAC_SHA2_256 = 5, | |
256 | IKEV1_AUTH_HMAC_SHA2_384 = 6, | |
257 | IKEV1_AUTH_HMAC_SHA2_512 = 7, | |
258 | IKEV1_AUTH_HMAC_RIPEMD = 8, | |
259 | IKEV1_AUTH_AES_XCBC_MAC = 9, | |
260 | IKEV1_AUTH_SIG_RSA = 10, | |
261 | IKEV1_AUTH_AES_128_GMAC = 11, | |
262 | IKEV1_AUTH_AES_192_GMAC = 12, | |
263 | IKEV1_AUTH_AES_256_GMAC = 13, | |
264 | } ikev1_auth_algo_t; | |
265 | ||
1bf2971f MW |
266 | /** |
267 | * IKEv1 ESP Encapsulation mode. | |
268 | */ | |
269 | typedef enum { | |
270 | IKEV1_ENCAP_TUNNEL = 1, | |
271 | IKEV1_ENCAP_TRANSPORT = 2, | |
272 | IKEV1_ENCAP_UDP_TUNNEL = 3, | |
273 | IKEV1_ENCAP_UDP_TRANSPORT = 4, | |
0ff8d20a VR |
274 | IKEV1_ENCAP_UDP_TUNNEL_DRAFT_00_03 = 61443, |
275 | IKEV1_ENCAP_UDP_TRANSPORT_DRAFT_00_03 = 61444, | |
1bf2971f MW |
276 | } ikev1_esp_encap_t; |
277 | ||
278 | /** | |
279 | * IKEv1 Life duration types. | |
280 | */ | |
281 | typedef enum { | |
282 | IKEV1_LIFE_TYPE_SECONDS = 1, | |
283 | IKEV1_LIFE_TYPE_KILOBYTES = 2, | |
284 | } ikev1_life_type_t; | |
285 | ||
717333da | 286 | /** |
4b797f46 | 287 | * IKEv1 authentication methods |
717333da MW |
288 | */ |
289 | typedef enum { | |
290 | IKEV1_AUTH_PSK = 1, | |
291 | IKEV1_AUTH_DSS_SIG = 2, | |
292 | IKEV1_AUTH_RSA_SIG = 3, | |
293 | IKEV1_AUTH_RSA_ENC = 4, | |
294 | IKEV1_AUTH_RSA_ENC_REV = 5, | |
6261c0c3 MW |
295 | IKEV1_AUTH_ECDSA_256 = 9, |
296 | IKEV1_AUTH_ECDSA_384 = 10, | |
297 | IKEV1_AUTH_ECDSA_521 = 11, | |
4b797f46 | 298 | /* XAuth Modes */ |
8b30286f CO |
299 | IKEV1_AUTH_XAUTH_INIT_PSK = 65001, |
300 | IKEV1_AUTH_XAUTH_RESP_PSK = 65002, | |
301 | IKEV1_AUTH_XAUTH_INIT_DSS = 65003, | |
302 | IKEV1_AUTH_XAUTH_RESP_DSS = 65004, | |
303 | IKEV1_AUTH_XAUTH_INIT_RSA = 65005, | |
304 | IKEV1_AUTH_XAUTH_RESP_RSA = 65006, | |
305 | IKEV1_AUTH_XAUTH_INIT_RSA_ENC = 65007, | |
306 | IKEV1_AUTH_XAUTH_RESP_RSA_ENC = 65008, | |
307 | IKEV1_AUTH_XAUTH_INIT_RSA_ENC_REV = 65009, | |
308 | IKEV1_AUTH_XAUTH_RESP_RSA_ENC_REV = 65010, | |
4b797f46 | 309 | /* Hybrid Modes */ |
51da01a7 MW |
310 | IKEV1_AUTH_HYBRID_INIT_RSA = 64221, |
311 | IKEV1_AUTH_HYBRID_RESP_RSA = 64222, | |
312 | IKEV1_AUTH_HYBRID_INIT_DSS = 64223, | |
313 | IKEV1_AUTH_HYBRID_RESP_DSS = 64224, | |
717333da MW |
314 | } ikev1_auth_method_t; |
315 | ||
7a75cae8 TB |
316 | /** |
317 | * IKEv1 IPComp transform IDs | |
318 | */ | |
319 | typedef enum { | |
320 | IKEV1_IPCOMP_OUI = 1, | |
321 | IKEV1_IPCOMP_DEFLATE = 2, | |
322 | IKEV1_IPCOMP_LZS = 3, | |
323 | } ikev1_ipcomp_transform_t; | |
324 | ||
806b69a4 MW |
325 | METHOD(payload_t, verify, status_t, |
326 | private_proposal_substructure_t *this) | |
e31eb71e | 327 | { |
346af6f3 | 328 | status_t status = SUCCESS; |
806b69a4 MW |
329 | enumerator_t *enumerator; |
330 | payload_t *current; | |
7daf5226 | 331 | |
3ecfc83c | 332 | if (this->next_payload != PL_NONE && this->next_payload != 2) |
e31eb71e JH |
333 | { |
334 | /* must be 0 or 2 */ | |
b83806d8 | 335 | DBG1(DBG_ENC, "inconsistent next payload"); |
e31eb71e JH |
336 | return FAILED; |
337 | } | |
338 | if (this->transforms_count != this->transforms->get_count(this->transforms)) | |
339 | { | |
340 | /* must be the same! */ | |
b83806d8 | 341 | DBG1(DBG_ENC, "transform count invalid"); |
e31eb71e JH |
342 | return FAILED; |
343 | } | |
344 | ||
fe04e93a MW |
345 | switch (this->protocol_id) |
346 | { | |
7a75cae8 | 347 | case PROTO_IPCOMP: |
4141f016 | 348 | if (this->spi.len != 2 && this->spi.len != 4) |
7a75cae8 TB |
349 | { |
350 | DBG1(DBG_ENC, "invalid CPI length in IPCOMP proposal"); | |
351 | return FAILED; | |
352 | } | |
353 | break; | |
fe04e93a MW |
354 | case PROTO_AH: |
355 | case PROTO_ESP: | |
356 | if (this->spi.len != 4) | |
357 | { | |
b83806d8 | 358 | DBG1(DBG_ENC, "invalid SPI length in %N proposal", |
7a75cae8 | 359 | protocol_id_names, this->protocol_id); |
fe04e93a MW |
360 | return FAILED; |
361 | } | |
362 | break; | |
363 | case PROTO_IKE: | |
3ecfc83c | 364 | if (this->type == PLV1_PROPOSAL_SUBSTRUCTURE) |
fe04e93a | 365 | { |
a30e0001 TB |
366 | if (this->spi.len <= 16) |
367 | { /* according to RFC 2409, section 3.5 anything between | |
368 | * 0 and 16 is fine */ | |
369 | break; | |
370 | } | |
fe04e93a | 371 | } |
a30e0001 TB |
372 | else if (this->spi.len == 0 || this->spi.len == 8) |
373 | { | |
374 | break; | |
375 | } | |
376 | DBG1(DBG_ENC, "invalid SPI length in IKE proposal"); | |
377 | return FAILED; | |
fe04e93a | 378 | default: |
806b69a4 | 379 | break; |
e31eb71e | 380 | } |
806b69a4 MW |
381 | enumerator = this->transforms->create_enumerator(this->transforms); |
382 | while (enumerator->enumerate(enumerator, ¤t)) | |
346af6f3 | 383 | { |
806b69a4 | 384 | status = current->verify(current); |
346af6f3 JH |
385 | if (status != SUCCESS) |
386 | { | |
b83806d8 | 387 | DBG1(DBG_ENC, "TRANSFORM_SUBSTRUCTURE verification failed"); |
346af6f3 JH |
388 | break; |
389 | } | |
390 | } | |
806b69a4 | 391 | enumerator->destroy(enumerator); |
7daf5226 MW |
392 | |
393 | /* proposal number is checked in SA payload */ | |
346af6f3 | 394 | return status; |
e31eb71e JH |
395 | } |
396 | ||
e9b55b83 MW |
397 | METHOD(payload_t, get_encoding_rules, int, |
398 | private_proposal_substructure_t *this, encoding_rule_t **rules) | |
da42afc5 | 399 | { |
3ecfc83c | 400 | if (this->type == PLV2_PROPOSAL_SUBSTRUCTURE) |
1bf2971f MW |
401 | { |
402 | *rules = encodings_v2; | |
e9b55b83 | 403 | return countof(encodings_v2); |
1bf2971f | 404 | } |
e9b55b83 MW |
405 | *rules = encodings_v1; |
406 | return countof(encodings_v1); | |
da42afc5 JH |
407 | } |
408 | ||
38fb67fb MW |
409 | METHOD(payload_t, get_header_length, int, |
410 | private_proposal_substructure_t *this) | |
411 | { | |
412 | return 8 + this->spi_size; | |
413 | } | |
414 | ||
806b69a4 MW |
415 | METHOD(payload_t, get_type, payload_type_t, |
416 | private_proposal_substructure_t *this) | |
da42afc5 | 417 | { |
1bf2971f | 418 | return this->type; |
da42afc5 JH |
419 | } |
420 | ||
806b69a4 MW |
421 | METHOD(payload_t, get_next_type, payload_type_t, |
422 | private_proposal_substructure_t *this) | |
da42afc5 | 423 | { |
806b69a4 | 424 | return this->next_payload; |
da42afc5 JH |
425 | } |
426 | ||
806b69a4 MW |
427 | METHOD(payload_t, set_next_type, void, |
428 | private_proposal_substructure_t *this, payload_type_t type) | |
32cbc7bc | 429 | { |
32cbc7bc JH |
430 | } |
431 | ||
60356f33 MW |
432 | /** |
433 | * (re-)compute the length of the payload. | |
434 | */ | |
435 | static void compute_length(private_proposal_substructure_t *this) | |
436 | { | |
1f5b2bec MW |
437 | enumerator_t *enumerator; |
438 | payload_t *transform; | |
7daf5226 | 439 | |
1f5b2bec | 440 | this->transforms_count = 0; |
38fb67fb | 441 | this->proposal_length = get_header_length(this); |
1f5b2bec MW |
442 | enumerator = this->transforms->create_enumerator(this->transforms); |
443 | while (enumerator->enumerate(enumerator, &transform)) | |
60356f33 | 444 | { |
1f5b2bec MW |
445 | this->proposal_length += transform->get_length(transform); |
446 | this->transforms_count++; | |
60356f33 | 447 | } |
1f5b2bec | 448 | enumerator->destroy(enumerator); |
60356f33 MW |
449 | } |
450 | ||
806b69a4 MW |
451 | METHOD(payload_t, get_length, size_t, |
452 | private_proposal_substructure_t *this) | |
da42afc5 JH |
453 | { |
454 | return this->proposal_length; | |
455 | } | |
456 | ||
b860cffd | 457 | /** |
806b69a4 | 458 | * Add a transform substructure to the proposal |
b860cffd | 459 | */ |
806b69a4 MW |
460 | static void add_transform_substructure(private_proposal_substructure_t *this, |
461 | transform_substructure_t *transform) | |
b860cffd | 462 | { |
a14dffd1 JH |
463 | if (this->transforms->get_count(this->transforms) > 0) |
464 | { | |
806b69a4 | 465 | transform_substructure_t *last; |
a14dffd1 | 466 | |
806b69a4 MW |
467 | this->transforms->get_last(this->transforms, (void **)&last); |
468 | last->set_is_last_transform(last, FALSE); | |
a14dffd1 JH |
469 | } |
470 | transform->set_is_last_transform(transform,TRUE); | |
806b69a4 | 471 | this->transforms->insert_last(this->transforms, transform); |
60356f33 | 472 | compute_length(this); |
67978e0b JH |
473 | } |
474 | ||
806b69a4 MW |
475 | METHOD(proposal_substructure_t, set_is_last_proposal, void, |
476 | private_proposal_substructure_t *this, bool is_last) | |
b737e9d9 | 477 | { |
806b69a4 | 478 | this->next_payload = is_last ? 0 : PROPOSAL_TYPE_VALUE; |
b737e9d9 JH |
479 | } |
480 | ||
806b69a4 | 481 | METHOD(proposal_substructure_t, set_proposal_number, void, |
b12c53ce | 482 | private_proposal_substructure_t *this,uint8_t proposal_number) |
67978e0b JH |
483 | { |
484 | this->proposal_number = proposal_number; | |
67978e0b JH |
485 | } |
486 | ||
b12c53ce | 487 | METHOD(proposal_substructure_t, get_proposal_number, uint8_t, |
806b69a4 | 488 | private_proposal_substructure_t *this) |
67978e0b | 489 | { |
806b69a4 | 490 | return this->proposal_number; |
67978e0b JH |
491 | } |
492 | ||
806b69a4 | 493 | METHOD(proposal_substructure_t, set_protocol_id, void, |
b12c53ce | 494 | private_proposal_substructure_t *this,uint8_t protocol_id) |
67978e0b JH |
495 | { |
496 | this->protocol_id = protocol_id; | |
67978e0b JH |
497 | } |
498 | ||
b12c53ce | 499 | METHOD(proposal_substructure_t, get_protocol_id, uint8_t, |
806b69a4 | 500 | private_proposal_substructure_t *this) |
67978e0b | 501 | { |
806b69a4 | 502 | return this->protocol_id; |
b860cffd JH |
503 | } |
504 | ||
806b69a4 MW |
505 | METHOD(proposal_substructure_t, set_spi, void, |
506 | private_proposal_substructure_t *this, chunk_t spi) | |
67978e0b | 507 | { |
806b69a4 MW |
508 | free(this->spi.ptr); |
509 | this->spi = chunk_clone(spi); | |
67978e0b | 510 | this->spi_size = spi.len; |
60356f33 | 511 | compute_length(this); |
67978e0b JH |
512 | } |
513 | ||
806b69a4 MW |
514 | METHOD(proposal_substructure_t, get_spi, chunk_t, |
515 | private_proposal_substructure_t *this) | |
67978e0b | 516 | { |
806b69a4 | 517 | return this->spi; |
67978e0b JH |
518 | } |
519 | ||
7a75cae8 | 520 | METHOD(proposal_substructure_t, get_cpi, bool, |
b12c53ce | 521 | private_proposal_substructure_t *this, uint16_t *cpi) |
7a75cae8 TB |
522 | { |
523 | ||
524 | transform_substructure_t *transform; | |
525 | enumerator_t *enumerator; | |
526 | ||
527 | if (this->protocol_id != PROTO_IPCOMP) | |
528 | { | |
529 | return FALSE; | |
530 | } | |
531 | ||
532 | enumerator = this->transforms->create_enumerator(this->transforms); | |
533 | while (enumerator->enumerate(enumerator, &transform)) | |
534 | { | |
535 | if (transform->get_transform_id(transform) == IKEV1_IPCOMP_DEFLATE) | |
536 | { | |
537 | if (cpi) | |
538 | { | |
4141f016 | 539 | *cpi = htons(untoh16(this->spi.ptr + this->spi.len - 2)); |
7a75cae8 TB |
540 | } |
541 | enumerator->destroy(enumerator); | |
542 | return TRUE; | |
543 | } | |
544 | } | |
545 | enumerator->destroy(enumerator); | |
546 | return FALSE; | |
547 | } | |
548 | ||
1bf2971f MW |
549 | /** |
550 | * Add a transform to a proposal for IKEv2 | |
551 | */ | |
552 | static void add_to_proposal_v2(proposal_t *proposal, | |
553 | transform_substructure_t *transform) | |
554 | { | |
555 | transform_attribute_t *tattr; | |
556 | enumerator_t *enumerator; | |
b12c53ce | 557 | uint16_t key_length = 0; |
1bf2971f MW |
558 | |
559 | enumerator = transform->create_attribute_enumerator(transform); | |
560 | while (enumerator->enumerate(enumerator, &tattr)) | |
561 | { | |
562 | if (tattr->get_attribute_type(tattr) == TATTR_IKEV2_KEY_LENGTH) | |
563 | { | |
564 | key_length = tattr->get_value(tattr); | |
565 | break; | |
566 | } | |
567 | } | |
568 | enumerator->destroy(enumerator); | |
569 | ||
570 | proposal->add_algorithm(proposal, | |
571 | transform->get_transform_type_or_number(transform), | |
572 | transform->get_transform_id(transform), key_length); | |
573 | } | |
574 | ||
3a470f30 MW |
575 | /** |
576 | * Map IKEv1 to IKEv2 algorithms | |
577 | */ | |
578 | typedef struct { | |
b12c53ce AS |
579 | uint16_t ikev1; |
580 | uint16_t ikev2; | |
3a470f30 MW |
581 | } algo_map_t; |
582 | ||
583 | /** | |
584 | * Encryption algorithm mapping | |
585 | */ | |
586 | static algo_map_t map_encr[] = { | |
587 | { IKEV1_ENCR_DES_CBC, ENCR_DES }, | |
588 | { IKEV1_ENCR_IDEA_CBC, ENCR_IDEA }, | |
589 | { IKEV1_ENCR_BLOWFISH_CBC, ENCR_BLOWFISH }, | |
590 | { IKEV1_ENCR_3DES_CBC, ENCR_3DES }, | |
591 | { IKEV1_ENCR_CAST_CBC, ENCR_CAST }, | |
592 | { IKEV1_ENCR_AES_CBC, ENCR_AES_CBC }, | |
593 | { IKEV1_ENCR_CAMELLIA_CBC, ENCR_CAMELLIA_CBC }, | |
4b797f46 AS |
594 | { IKEV1_ENCR_SERPENT_CBC, ENCR_SERPENT_CBC }, |
595 | { IKEV1_ENCR_TWOFISH_CBC, ENCR_TWOFISH_CBC }, | |
3a470f30 MW |
596 | }; |
597 | ||
598 | /** | |
599 | * Integrity algorithm mapping | |
600 | */ | |
601 | static algo_map_t map_integ[] = { | |
602 | { IKEV1_HASH_MD5, AUTH_HMAC_MD5_96 }, | |
603 | { IKEV1_HASH_SHA1, AUTH_HMAC_SHA1_96 }, | |
604 | { IKEV1_HASH_SHA2_256, AUTH_HMAC_SHA2_256_128 }, | |
605 | { IKEV1_HASH_SHA2_384, AUTH_HMAC_SHA2_384_192 }, | |
606 | { IKEV1_HASH_SHA2_512, AUTH_HMAC_SHA2_512_256 }, | |
607 | }; | |
608 | ||
609 | /** | |
610 | * PRF algorithm mapping | |
611 | */ | |
612 | static algo_map_t map_prf[] = { | |
613 | { IKEV1_HASH_MD5, PRF_HMAC_MD5 }, | |
614 | { IKEV1_HASH_SHA1, PRF_HMAC_SHA1 }, | |
615 | { IKEV1_HASH_SHA2_256, PRF_HMAC_SHA2_256 }, | |
616 | { IKEV1_HASH_SHA2_384, PRF_HMAC_SHA2_384 }, | |
617 | { IKEV1_HASH_SHA2_512, PRF_HMAC_SHA2_512 }, | |
618 | }; | |
619 | ||
4b797f46 AS |
620 | /** |
621 | * ESP encryption algorithm mapping | |
622 | */ | |
728f529c | 623 | static algo_map_t map_esp[] = { |
4b797f46 AS |
624 | { IKEV1_ESP_ENCR_DES_IV64, ENCR_DES_IV64 }, |
625 | { IKEV1_ESP_ENCR_DES, ENCR_DES }, | |
626 | { IKEV1_ESP_ENCR_3DES, ENCR_3DES }, | |
627 | { IKEV1_ESP_ENCR_RC5, ENCR_RC5 }, | |
628 | { IKEV1_ESP_ENCR_IDEA, ENCR_IDEA }, | |
629 | { IKEV1_ESP_ENCR_CAST, ENCR_CAST }, | |
630 | { IKEV1_ESP_ENCR_BLOWFISH, ENCR_BLOWFISH }, | |
631 | { IKEV1_ESP_ENCR_3IDEA, ENCR_3IDEA }, | |
632 | { IKEV1_ESP_ENCR_DES_IV32, ENCR_DES_IV32 }, | |
633 | { IKEV1_ESP_ENCR_NULL, ENCR_NULL }, | |
634 | { IKEV1_ESP_ENCR_AES_CBC, ENCR_AES_CBC }, | |
635 | { IKEV1_ESP_ENCR_AES_CTR, ENCR_AES_CTR }, | |
636 | { IKEV1_ESP_ENCR_AES_CCM_8, ENCR_AES_CCM_ICV8 }, | |
637 | { IKEV1_ESP_ENCR_AES_CCM_12, ENCR_AES_CCM_ICV12 }, | |
638 | { IKEV1_ESP_ENCR_AES_CCM_16, ENCR_AES_CCM_ICV16 }, | |
639 | { IKEV1_ESP_ENCR_AES_GCM_8, ENCR_AES_GCM_ICV8 }, | |
640 | { IKEV1_ESP_ENCR_AES_GCM_12, ENCR_AES_GCM_ICV12 }, | |
641 | { IKEV1_ESP_ENCR_AES_GCM_16, ENCR_AES_GCM_ICV16 }, | |
642 | { IKEV1_ESP_ENCR_CAMELLIA, ENCR_CAMELLIA_CBC }, | |
643 | { IKEV1_ESP_ENCR_NULL_AUTH_AES_GMAC, ENCR_NULL_AUTH_AES_GMAC }, | |
644 | { IKEV1_ESP_ENCR_SERPENT, ENCR_SERPENT_CBC }, | |
645 | { IKEV1_ESP_ENCR_TWOFISH, ENCR_TWOFISH_CBC }, | |
646 | }; | |
647 | ||
3771b858 MW |
648 | /** |
649 | * AH authentication algorithm mapping | |
650 | */ | |
651 | static algo_map_t map_ah[] = { | |
652 | { IKEV1_AH_HMAC_MD5, AUTH_HMAC_MD5_96 }, | |
653 | { IKEV1_AH_HMAC_SHA, AUTH_HMAC_SHA1_96 }, | |
654 | { IKEV1_AH_DES_MAC, AUTH_DES_MAC }, | |
655 | { IKEV1_AH_HMAC_SHA2_256, AUTH_HMAC_SHA2_256_128 }, | |
656 | { IKEV1_AH_HMAC_SHA2_384, AUTH_HMAC_SHA2_384_192 }, | |
657 | { IKEV1_AH_HMAC_SHA2_512, AUTH_HMAC_SHA2_512_256 }, | |
658 | { IKEV1_AH_AES_XCBC_MAC, AUTH_AES_XCBC_96 }, | |
659 | { IKEV1_AH_AES_128_GMAC, AUTH_AES_128_GMAC }, | |
660 | { IKEV1_AH_AES_192_GMAC, AUTH_AES_192_GMAC }, | |
661 | { IKEV1_AH_AES_256_GMAC, AUTH_AES_256_GMAC }, | |
662 | }; | |
663 | ||
1bf2971f | 664 | /** |
728f529c | 665 | * ESP/AH authentication algorithm mapping |
1bf2971f | 666 | */ |
728f529c TB |
667 | static algo_map_t map_auth[] = { |
668 | { IKEV1_AUTH_HMAC_MD5, AUTH_HMAC_MD5_96 }, | |
669 | { IKEV1_AUTH_HMAC_SHA, AUTH_HMAC_SHA1_96 }, | |
670 | { IKEV1_AUTH_DES_MAC, AUTH_DES_MAC }, | |
671 | { IKEV1_AUTH_KPDK, AUTH_KPDK_MD5 }, | |
672 | { IKEV1_AUTH_HMAC_SHA2_256, AUTH_HMAC_SHA2_256_128 }, | |
673 | { IKEV1_AUTH_HMAC_SHA2_384, AUTH_HMAC_SHA2_384_192 }, | |
674 | { IKEV1_AUTH_HMAC_SHA2_512, AUTH_HMAC_SHA2_512_256 }, | |
675 | { IKEV1_AUTH_AES_XCBC_MAC, AUTH_AES_XCBC_96 }, | |
676 | { IKEV1_AUTH_AES_128_GMAC, AUTH_AES_128_GMAC }, | |
677 | { IKEV1_AUTH_AES_192_GMAC, AUTH_AES_192_GMAC }, | |
678 | { IKEV1_AUTH_AES_256_GMAC, AUTH_AES_256_GMAC }, | |
679 | }; | |
680 | ||
681 | /** | |
682 | * Map an IKEv1 to an IKEv2 identifier | |
683 | */ | |
b12c53ce AS |
684 | static uint16_t ikev2_from_ikev1(algo_map_t *map, int count, uint16_t def, |
685 | uint16_t value) | |
1bf2971f | 686 | { |
728f529c | 687 | int i; |
1bf2971f | 688 | |
1bf2971f MW |
689 | for (i = 0; i < count; i++) |
690 | { | |
691 | if (map[i].ikev1 == value) | |
692 | { | |
693 | return map[i].ikev2; | |
694 | } | |
695 | } | |
696 | return def; | |
697 | } | |
698 | ||
3a470f30 | 699 | /** |
728f529c | 700 | * Map an IKEv2 to an IKEv1 identifier |
3a470f30 | 701 | */ |
b12c53ce | 702 | static uint16_t ikev1_from_ikev2(algo_map_t *map, int count, uint16_t value) |
3a470f30 | 703 | { |
728f529c | 704 | int i; |
3a470f30 | 705 | |
3a470f30 MW |
706 | for (i = 0; i < count; i++) |
707 | { | |
708 | if (map[i].ikev2 == value) | |
709 | { | |
710 | return map[i].ikev1; | |
711 | } | |
712 | } | |
713 | return 0; | |
714 | } | |
715 | ||
4b797f46 | 716 | /** |
728f529c | 717 | * Get IKEv2 algorithm from IKEv1 identifier |
4b797f46 | 718 | */ |
b12c53ce | 719 | static uint16_t get_alg_from_ikev1(transform_type_t type, uint16_t value) |
4b797f46 | 720 | { |
4b797f46 AS |
721 | switch (type) |
722 | { | |
723 | case ENCRYPTION_ALGORITHM: | |
728f529c TB |
724 | return ikev2_from_ikev1(map_encr, countof(map_encr), |
725 | ENCR_UNDEFINED, value); | |
4b797f46 | 726 | case INTEGRITY_ALGORITHM: |
728f529c TB |
727 | return ikev2_from_ikev1(map_integ, countof(map_integ), |
728 | AUTH_UNDEFINED, value); | |
729 | case PSEUDO_RANDOM_FUNCTION: | |
730 | return ikev2_from_ikev1(map_prf, countof(map_prf), | |
731 | PRF_UNDEFINED, value); | |
4b797f46 AS |
732 | default: |
733 | return 0; | |
734 | } | |
728f529c TB |
735 | } |
736 | ||
737 | /** | |
738 | * Get IKEv1 algorithm from IKEv2 identifier | |
739 | */ | |
b12c53ce | 740 | static uint16_t get_ikev1_from_alg(transform_type_t type, uint16_t value) |
728f529c TB |
741 | { |
742 | switch (type) | |
4b797f46 | 743 | { |
728f529c TB |
744 | case ENCRYPTION_ALGORITHM: |
745 | return ikev1_from_ikev2(map_encr, countof(map_encr), value); | |
746 | case INTEGRITY_ALGORITHM: | |
747 | return ikev1_from_ikev2(map_integ, countof(map_integ), value); | |
748 | case PSEUDO_RANDOM_FUNCTION: | |
749 | return ikev1_from_ikev2(map_prf, countof(map_prf), value); | |
750 | default: | |
751 | return 0; | |
4b797f46 | 752 | } |
4b797f46 AS |
753 | } |
754 | ||
755 | /** | |
728f529c | 756 | * Get IKEv2 algorithm from IKEv1 ESP/AH transform ID |
4b797f46 | 757 | */ |
b12c53ce AS |
758 | static uint16_t get_alg_from_ikev1_transid(transform_type_t type, |
759 | uint16_t value) | |
4b797f46 | 760 | { |
4b797f46 AS |
761 | switch (type) |
762 | { | |
763 | case ENCRYPTION_ALGORITHM: | |
728f529c TB |
764 | return ikev2_from_ikev1(map_esp, countof(map_esp), |
765 | ENCR_UNDEFINED, value); | |
4b797f46 | 766 | case INTEGRITY_ALGORITHM: |
728f529c TB |
767 | return ikev2_from_ikev1(map_ah, countof(map_ah), |
768 | AUTH_UNDEFINED, value); | |
4b797f46 AS |
769 | default: |
770 | return 0; | |
771 | } | |
728f529c TB |
772 | } |
773 | ||
774 | /** | |
775 | * Get IKEv1 ESP/AH transform ID from IKEv2 identifier | |
776 | */ | |
b12c53ce AS |
777 | static uint16_t get_ikev1_transid_from_alg(transform_type_t type, |
778 | uint16_t value) | |
728f529c TB |
779 | { |
780 | switch (type) | |
4b797f46 | 781 | { |
728f529c TB |
782 | case ENCRYPTION_ALGORITHM: |
783 | return ikev1_from_ikev2(map_esp, countof(map_esp), value); | |
784 | case INTEGRITY_ALGORITHM: | |
785 | return ikev1_from_ikev2(map_ah, countof(map_ah), value); | |
786 | default: | |
787 | return 0; | |
4b797f46 | 788 | } |
4b797f46 | 789 | } |
728f529c TB |
790 | |
791 | /** | |
792 | * Get IKEv1 authentication algorithm from IKEv2 identifier | |
793 | */ | |
b12c53ce | 794 | static uint16_t get_alg_from_ikev1_auth(uint16_t value) |
728f529c TB |
795 | { |
796 | return ikev2_from_ikev1(map_auth, countof(map_auth), AUTH_UNDEFINED, value); | |
797 | } | |
798 | ||
799 | /** | |
800 | * Get IKEv1 authentication algorithm from IKEv2 identifier | |
801 | */ | |
b12c53ce | 802 | static uint16_t get_ikev1_auth_from_alg(uint16_t value) |
728f529c TB |
803 | { |
804 | return ikev1_from_ikev2(map_auth, countof(map_auth), value); | |
805 | } | |
806 | ||
fbebc2a0 MW |
807 | /** |
808 | * Get IKEv1 authentication attribute from auth_method_t | |
809 | */ | |
b12c53ce | 810 | static uint16_t get_ikev1_auth(auth_method_t method) |
fbebc2a0 MW |
811 | { |
812 | switch (method) | |
813 | { | |
814 | case AUTH_RSA: | |
815 | return IKEV1_AUTH_RSA_SIG; | |
816 | case AUTH_DSS: | |
817 | return IKEV1_AUTH_DSS_SIG; | |
b4e81535 MW |
818 | case AUTH_XAUTH_INIT_PSK: |
819 | return IKEV1_AUTH_XAUTH_INIT_PSK; | |
a9aa75b9 MW |
820 | case AUTH_XAUTH_RESP_PSK: |
821 | return IKEV1_AUTH_XAUTH_RESP_PSK; | |
b4e81535 MW |
822 | case AUTH_XAUTH_INIT_RSA: |
823 | return IKEV1_AUTH_XAUTH_INIT_RSA; | |
a9aa75b9 MW |
824 | case AUTH_XAUTH_RESP_RSA: |
825 | return IKEV1_AUTH_XAUTH_RESP_RSA; | |
51da01a7 MW |
826 | case AUTH_HYBRID_INIT_RSA: |
827 | return IKEV1_AUTH_HYBRID_INIT_RSA; | |
a9aa75b9 MW |
828 | case AUTH_HYBRID_RESP_RSA: |
829 | return IKEV1_AUTH_HYBRID_RESP_RSA; | |
6261c0c3 MW |
830 | case AUTH_ECDSA_256: |
831 | return IKEV1_AUTH_ECDSA_256; | |
832 | case AUTH_ECDSA_384: | |
833 | return IKEV1_AUTH_ECDSA_384; | |
834 | case AUTH_ECDSA_521: | |
835 | return IKEV1_AUTH_ECDSA_521; | |
fbebc2a0 | 836 | case AUTH_PSK: |
6261c0c3 | 837 | default: |
fbebc2a0 MW |
838 | return IKEV1_AUTH_PSK; |
839 | } | |
840 | } | |
841 | ||
842 | /** | |
843 | * Get IKEv1 encapsulation mode | |
844 | */ | |
b12c53ce | 845 | static uint16_t get_ikev1_mode(ipsec_mode_t mode, encap_t udp) |
fbebc2a0 MW |
846 | { |
847 | switch (mode) | |
848 | { | |
849 | case MODE_TUNNEL: | |
0ff8d20a VR |
850 | switch (udp) |
851 | { | |
852 | case ENCAP_UDP: | |
853 | return IKEV1_ENCAP_UDP_TUNNEL; | |
854 | case ENCAP_UDP_DRAFT_00_03: | |
855 | return IKEV1_ENCAP_UDP_TUNNEL_DRAFT_00_03; | |
856 | default: | |
857 | return IKEV1_ENCAP_TUNNEL; | |
858 | } | |
fbebc2a0 | 859 | case MODE_TRANSPORT: |
0ff8d20a VR |
860 | switch (udp) |
861 | { | |
862 | case ENCAP_UDP: | |
863 | return IKEV1_ENCAP_UDP_TRANSPORT; | |
864 | case ENCAP_UDP_DRAFT_00_03: | |
865 | return IKEV1_ENCAP_UDP_TRANSPORT_DRAFT_00_03; | |
866 | default: | |
867 | return IKEV1_ENCAP_TRANSPORT; | |
868 | } | |
fbebc2a0 MW |
869 | default: |
870 | return IKEV1_ENCAP_TUNNEL; | |
871 | } | |
872 | } | |
873 | ||
1bf2971f MW |
874 | /** |
875 | * Add an IKE transform to a proposal for IKEv1 | |
876 | */ | |
877 | static void add_to_proposal_v1_ike(proposal_t *proposal, | |
878 | transform_substructure_t *transform) | |
879 | { | |
880 | transform_attribute_type_t type; | |
881 | transform_attribute_t *tattr; | |
882 | enumerator_t *enumerator; | |
b12c53ce AS |
883 | uint16_t value, key_length = 0; |
884 | uint16_t encr = ENCR_UNDEFINED; | |
1bf2971f MW |
885 | |
886 | enumerator = transform->create_attribute_enumerator(transform); | |
887 | while (enumerator->enumerate(enumerator, &tattr)) | |
888 | { | |
889 | type = tattr->get_attribute_type(tattr); | |
890 | value = tattr->get_value(tattr); | |
891 | switch (type) | |
892 | { | |
893 | case TATTR_PH1_ENCRYPTION_ALGORITHM: | |
894 | encr = get_alg_from_ikev1(ENCRYPTION_ALGORITHM, value); | |
895 | break; | |
896 | case TATTR_PH1_KEY_LENGTH: | |
897 | key_length = value; | |
898 | break; | |
899 | case TATTR_PH1_HASH_ALGORITHM: | |
900 | proposal->add_algorithm(proposal, INTEGRITY_ALGORITHM, | |
901 | get_alg_from_ikev1(INTEGRITY_ALGORITHM, value), 0); | |
902 | proposal->add_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, | |
903 | get_alg_from_ikev1(PSEUDO_RANDOM_FUNCTION, value), 0); | |
904 | break; | |
905 | case TATTR_PH1_GROUP: | |
906 | proposal->add_algorithm(proposal, DIFFIE_HELLMAN_GROUP, | |
907 | value, 0); | |
908 | break; | |
909 | default: | |
1bf2971f MW |
910 | break; |
911 | } | |
912 | } | |
913 | enumerator->destroy(enumerator); | |
914 | ||
915 | if (encr != ENCR_UNDEFINED) | |
916 | { | |
636b2e9b TB |
917 | if (encr == ENCR_AES_CBC && !key_length) |
918 | { /* some implementations don't send a Key Length attribute for | |
919 | * AES-128, early drafts of RFC 3602 allowed that */ | |
920 | key_length = 128; | |
921 | } | |
1bf2971f MW |
922 | proposal->add_algorithm(proposal, ENCRYPTION_ALGORITHM, encr, key_length); |
923 | } | |
924 | } | |
925 | ||
926 | /** | |
3771b858 | 927 | * Add an ESP/AH transform to a proposal for IKEv1 |
1bf2971f | 928 | */ |
3771b858 MW |
929 | static void add_to_proposal_v1(proposal_t *proposal, |
930 | transform_substructure_t *transform, protocol_id_t proto) | |
1bf2971f | 931 | { |
cc9629d8 MW |
932 | transform_attribute_type_t type; |
933 | transform_attribute_t *tattr; | |
934 | enumerator_t *enumerator; | |
b12c53ce | 935 | uint16_t encr, value, key_length = 0; |
40bb4677 | 936 | extended_sequence_numbers_t esn = NO_EXT_SEQ_NUMBERS; |
cc9629d8 MW |
937 | |
938 | enumerator = transform->create_attribute_enumerator(transform); | |
939 | while (enumerator->enumerate(enumerator, &tattr)) | |
940 | { | |
941 | type = tattr->get_attribute_type(tattr); | |
942 | value = tattr->get_value(tattr); | |
943 | switch (type) | |
944 | { | |
945 | case TATTR_PH2_KEY_LENGTH: | |
946 | key_length = value; | |
947 | break; | |
948 | case TATTR_PH2_AUTH_ALGORITHM: | |
949 | proposal->add_algorithm(proposal, INTEGRITY_ALGORITHM, | |
728f529c | 950 | get_alg_from_ikev1_auth(value), 0); |
cc9629d8 | 951 | break; |
9bb4de1d MW |
952 | case TATTR_PH2_GROUP: |
953 | proposal->add_algorithm(proposal, DIFFIE_HELLMAN_GROUP, | |
954 | value, 0); | |
955 | break; | |
40bb4677 TE |
956 | case TATTR_PH2_EXT_SEQ_NUMBER: |
957 | esn = EXT_SEQ_NUMBERS; | |
958 | break; | |
cc9629d8 | 959 | default: |
cc9629d8 MW |
960 | break; |
961 | } | |
962 | } | |
963 | enumerator->destroy(enumerator); | |
964 | ||
40bb4677 | 965 | proposal->add_algorithm(proposal, EXTENDED_SEQUENCE_NUMBERS, esn, 0); |
3771b858 | 966 | if (proto == PROTO_ESP) |
4b797f46 | 967 | { |
728f529c | 968 | encr = get_alg_from_ikev1_transid(ENCRYPTION_ALGORITHM, |
3771b858 MW |
969 | transform->get_transform_id(transform)); |
970 | if (encr) | |
971 | { | |
636b2e9b TB |
972 | if (encr == ENCR_AES_CBC && !key_length) |
973 | { /* some implementations don't send a Key Length attribute for | |
974 | * AES-128, early drafts of RFC 3602 allowed that for IKE, some | |
975 | * also seem to do it for ESP */ | |
976 | key_length = 128; | |
977 | } | |
3771b858 MW |
978 | proposal->add_algorithm(proposal, ENCRYPTION_ALGORITHM, encr, |
979 | key_length); | |
980 | } | |
4b797f46 | 981 | } |
1bf2971f MW |
982 | } |
983 | ||
d50152a7 MW |
984 | METHOD(proposal_substructure_t, get_proposals, void, |
985 | private_proposal_substructure_t *this, linked_list_t *proposals) | |
b737e9d9 | 986 | { |
191a26a6 | 987 | transform_substructure_t *transform; |
1bf2971f | 988 | enumerator_t *enumerator; |
d50152a7 | 989 | proposal_t *proposal = NULL; |
b12c53ce | 990 | uint64_t spi = 0; |
7daf5226 | 991 | |
d50152a7 MW |
992 | switch (this->spi.len) |
993 | { | |
994 | case 4: | |
b12c53ce | 995 | spi = *((uint32_t*)this->spi.ptr); |
d50152a7 MW |
996 | break; |
997 | case 8: | |
b12c53ce | 998 | spi = *((uint64_t*)this->spi.ptr); |
d50152a7 MW |
999 | break; |
1000 | default: | |
1001 | break; | |
1002 | } | |
7daf5226 | 1003 | |
806b69a4 MW |
1004 | enumerator = this->transforms->create_enumerator(this->transforms); |
1005 | while (enumerator->enumerate(enumerator, &transform)) | |
c06dbbab | 1006 | { |
3ecfc83c | 1007 | if (this->type == PLV2_PROPOSAL_SUBSTRUCTURE) |
1bf2971f | 1008 | { |
7da3143a TB |
1009 | if (!proposal) |
1010 | { | |
1011 | proposal = proposal_create(this->protocol_id, | |
1012 | this->proposal_number); | |
1013 | proposal->set_spi(proposal, spi); | |
1014 | proposals->insert_last(proposals, proposal); | |
1015 | } | |
1bf2971f MW |
1016 | add_to_proposal_v2(proposal, transform); |
1017 | } | |
1018 | else | |
1019 | { | |
7da3143a TB |
1020 | /* create a new proposal for each transform in IKEv1 */ |
1021 | proposal = proposal_create_v1( | |
1022 | this->protocol_id, this->proposal_number, | |
1023 | transform->get_transform_type_or_number(transform)); | |
1024 | proposal->set_spi(proposal, spi); | |
1025 | proposals->insert_last(proposals, proposal); | |
1bf2971f MW |
1026 | switch (this->protocol_id) |
1027 | { | |
1028 | case PROTO_IKE: | |
1029 | add_to_proposal_v1_ike(proposal, transform); | |
1030 | break; | |
1031 | case PROTO_ESP: | |
3771b858 MW |
1032 | case PROTO_AH: |
1033 | add_to_proposal_v1(proposal, transform, this->protocol_id); | |
1bf2971f MW |
1034 | break; |
1035 | default: | |
1036 | break; | |
1037 | } | |
1bf2971f | 1038 | } |
c06dbbab | 1039 | } |
806b69a4 | 1040 | enumerator->destroy(enumerator); |
c06dbbab MW |
1041 | } |
1042 | ||
54f2bdd6 MW |
1043 | METHOD(proposal_substructure_t, create_substructure_enumerator, enumerator_t*, |
1044 | private_proposal_substructure_t *this) | |
1045 | { | |
1046 | return this->transforms->create_enumerator(this->transforms); | |
1047 | } | |
1048 | ||
914ec2db | 1049 | /** |
927c1dd9 | 1050 | * Get an attribute from any transform, 0 if not found |
914ec2db | 1051 | */ |
b12c53ce | 1052 | static uint64_t get_attr(private_proposal_substructure_t *this, |
927c1dd9 | 1053 | transform_attribute_type_t type) |
914ec2db | 1054 | { |
927c1dd9 MW |
1055 | enumerator_t *transforms, *attributes; |
1056 | transform_substructure_t *transform; | |
914ec2db | 1057 | transform_attribute_t *attr; |
914ec2db | 1058 | |
927c1dd9 MW |
1059 | transforms = this->transforms->create_enumerator(this->transforms); |
1060 | while (transforms->enumerate(transforms, &transform)) | |
914ec2db | 1061 | { |
927c1dd9 MW |
1062 | attributes = transform->create_attribute_enumerator(transform); |
1063 | while (attributes->enumerate(attributes, &attr)) | |
914ec2db | 1064 | { |
927c1dd9 MW |
1065 | if (attr->get_attribute_type(attr) == type) |
1066 | { | |
1067 | attributes->destroy(attributes); | |
1068 | transforms->destroy(transforms); | |
1069 | return attr->get_value(attr); | |
1070 | } | |
914ec2db | 1071 | } |
927c1dd9 | 1072 | attributes->destroy(attributes); |
914ec2db | 1073 | } |
927c1dd9 MW |
1074 | transforms->destroy(transforms); |
1075 | return 0; | |
914ec2db MW |
1076 | } |
1077 | ||
914ec2db | 1078 | /** |
927c1dd9 | 1079 | * Look up a lifetime duration of a given kind in all transforms |
914ec2db | 1080 | */ |
b12c53ce | 1081 | static uint64_t get_life_duration(private_proposal_substructure_t *this, |
e0dd36c9 TB |
1082 | uint8_t number, transform_attribute_type_t type_attr, |
1083 | ikev1_life_type_t type, transform_attribute_type_t dur_attr) | |
914ec2db | 1084 | { |
927c1dd9 | 1085 | enumerator_t *transforms, *attributes; |
914ec2db | 1086 | transform_substructure_t *transform; |
927c1dd9 | 1087 | transform_attribute_t *attr; |
914ec2db | 1088 | |
927c1dd9 MW |
1089 | transforms = this->transforms->create_enumerator(this->transforms); |
1090 | while (transforms->enumerate(transforms, &transform)) | |
914ec2db | 1091 | { |
e0dd36c9 TB |
1092 | if (transform->get_transform_type_or_number(transform) != number) |
1093 | { | |
1094 | continue; | |
1095 | } | |
927c1dd9 MW |
1096 | attributes = transform->create_attribute_enumerator(transform); |
1097 | while (attributes->enumerate(attributes, &attr)) | |
914ec2db | 1098 | { |
927c1dd9 MW |
1099 | if (attr->get_attribute_type(attr) == type_attr && |
1100 | attr->get_value(attr) == type) | |
1101 | { /* got type attribute, look for duration following next */ | |
1102 | while (attributes->enumerate(attributes, &attr)) | |
1103 | { | |
1104 | if (attr->get_attribute_type(attr) == dur_attr) | |
1105 | { | |
1106 | attributes->destroy(attributes); | |
1107 | transforms->destroy(transforms); | |
1108 | return attr->get_value(attr); | |
1109 | } | |
1110 | } | |
914ec2db | 1111 | } |
914ec2db | 1112 | } |
927c1dd9 | 1113 | attributes->destroy(attributes); |
914ec2db | 1114 | } |
927c1dd9 MW |
1115 | transforms->destroy(transforms); |
1116 | return 0; | |
914ec2db MW |
1117 | } |
1118 | ||
b12c53ce | 1119 | METHOD(proposal_substructure_t, get_lifetime, uint32_t, |
e0dd36c9 | 1120 | private_proposal_substructure_t *this, uint8_t transform) |
914ec2db | 1121 | { |
b12c53ce | 1122 | uint32_t duration; |
914ec2db MW |
1123 | |
1124 | switch (this->protocol_id) | |
1125 | { | |
1126 | case PROTO_IKE: | |
e0dd36c9 TB |
1127 | return get_life_duration(this, transform, TATTR_PH1_LIFE_TYPE, |
1128 | IKEV1_LIFE_TYPE_SECONDS, TATTR_PH1_LIFE_DURATION); | |
914ec2db | 1129 | case PROTO_ESP: |
3771b858 | 1130 | case PROTO_AH: |
e0dd36c9 TB |
1131 | duration = get_life_duration(this, transform, |
1132 | TATTR_PH2_SA_LIFE_TYPE, IKEV1_LIFE_TYPE_SECONDS, | |
1133 | TATTR_PH2_SA_LIFE_DURATION); | |
927c1dd9 | 1134 | if (!duration) |
914ec2db MW |
1135 | { /* default to 8 hours, RFC 2407 */ |
1136 | return 28800; | |
1137 | } | |
927c1dd9 | 1138 | return duration; |
914ec2db | 1139 | default: |
927c1dd9 | 1140 | return 0; |
914ec2db | 1141 | } |
914ec2db MW |
1142 | } |
1143 | ||
b12c53ce | 1144 | METHOD(proposal_substructure_t, get_lifebytes, uint64_t, |
e0dd36c9 | 1145 | private_proposal_substructure_t *this, uint8_t transform) |
914ec2db | 1146 | { |
914ec2db MW |
1147 | switch (this->protocol_id) |
1148 | { | |
914ec2db | 1149 | case PROTO_ESP: |
3771b858 | 1150 | case PROTO_AH: |
e0dd36c9 TB |
1151 | return 1000 * get_life_duration(this, transform, |
1152 | TATTR_PH2_SA_LIFE_TYPE, IKEV1_LIFE_TYPE_KILOBYTES, | |
1153 | TATTR_PH2_SA_LIFE_DURATION); | |
927c1dd9 | 1154 | case PROTO_IKE: |
914ec2db | 1155 | default: |
927c1dd9 | 1156 | return 0; |
914ec2db | 1157 | } |
914ec2db MW |
1158 | } |
1159 | ||
1160 | METHOD(proposal_substructure_t, get_auth_method, auth_method_t, | |
1161 | private_proposal_substructure_t *this) | |
1162 | { | |
927c1dd9 | 1163 | switch (get_attr(this, TATTR_PH1_AUTH_METHOD)) |
914ec2db MW |
1164 | { |
1165 | case IKEV1_AUTH_PSK: | |
1166 | return AUTH_PSK; | |
1167 | case IKEV1_AUTH_RSA_SIG: | |
1168 | return AUTH_RSA; | |
1169 | case IKEV1_AUTH_DSS_SIG: | |
1170 | return AUTH_DSS; | |
b4e81535 MW |
1171 | case IKEV1_AUTH_XAUTH_INIT_PSK: |
1172 | return AUTH_XAUTH_INIT_PSK; | |
a9aa75b9 MW |
1173 | case IKEV1_AUTH_XAUTH_RESP_PSK: |
1174 | return AUTH_XAUTH_RESP_PSK; | |
b4e81535 MW |
1175 | case IKEV1_AUTH_XAUTH_INIT_RSA: |
1176 | return AUTH_XAUTH_INIT_RSA; | |
a9aa75b9 MW |
1177 | case IKEV1_AUTH_XAUTH_RESP_RSA: |
1178 | return AUTH_XAUTH_RESP_RSA; | |
51da01a7 MW |
1179 | case IKEV1_AUTH_HYBRID_INIT_RSA: |
1180 | return AUTH_HYBRID_INIT_RSA; | |
a9aa75b9 MW |
1181 | case IKEV1_AUTH_HYBRID_RESP_RSA: |
1182 | return AUTH_HYBRID_RESP_RSA; | |
6261c0c3 MW |
1183 | case IKEV1_AUTH_ECDSA_256: |
1184 | return AUTH_ECDSA_256; | |
1185 | case IKEV1_AUTH_ECDSA_384: | |
1186 | return AUTH_ECDSA_384; | |
1187 | case IKEV1_AUTH_ECDSA_521: | |
1188 | return AUTH_ECDSA_521; | |
914ec2db | 1189 | default: |
914ec2db MW |
1190 | return AUTH_NONE; |
1191 | } | |
1192 | } | |
1193 | ||
1194 | METHOD(proposal_substructure_t, get_encap_mode, ipsec_mode_t, | |
1195 | private_proposal_substructure_t *this, bool *udp) | |
1196 | { | |
1197 | *udp = FALSE; | |
927c1dd9 | 1198 | switch (get_attr(this, TATTR_PH2_ENCAP_MODE)) |
914ec2db MW |
1199 | { |
1200 | case IKEV1_ENCAP_TRANSPORT: | |
1201 | return MODE_TRANSPORT; | |
1202 | case IKEV1_ENCAP_TUNNEL: | |
5ed4b727 | 1203 | return MODE_TUNNEL; |
914ec2db | 1204 | case IKEV1_ENCAP_UDP_TRANSPORT: |
0ff8d20a | 1205 | case IKEV1_ENCAP_UDP_TRANSPORT_DRAFT_00_03: |
914ec2db MW |
1206 | *udp = TRUE; |
1207 | return MODE_TRANSPORT; | |
1208 | case IKEV1_ENCAP_UDP_TUNNEL: | |
0ff8d20a | 1209 | case IKEV1_ENCAP_UDP_TUNNEL_DRAFT_00_03: |
914ec2db MW |
1210 | *udp = TRUE; |
1211 | return MODE_TUNNEL; | |
1212 | default: | |
1213 | /* default to TUNNEL, RFC 2407 says implementation specific */ | |
1214 | return MODE_TUNNEL; | |
1215 | } | |
1216 | } | |
1217 | ||
806b69a4 MW |
1218 | METHOD2(payload_t, proposal_substructure_t, destroy, void, |
1219 | private_proposal_substructure_t *this) | |
b9459040 | 1220 | { |
55bbff11 | 1221 | this->transforms->destroy_offset(this->transforms, |
1bf2971f | 1222 | offsetof(payload_t, destroy)); |
55bbff11 | 1223 | chunk_free(&this->spi); |
5113680f | 1224 | free(this); |
b9459040 | 1225 | } |
67978e0b | 1226 | |
da42afc5 | 1227 | /* |
3fe05870 | 1228 | * Described in header. |
da42afc5 | 1229 | */ |
1bf2971f | 1230 | proposal_substructure_t *proposal_substructure_create(payload_type_t type) |
da42afc5 | 1231 | { |
806b69a4 MW |
1232 | private_proposal_substructure_t *this; |
1233 | ||
1234 | INIT(this, | |
1235 | .public = { | |
1236 | .payload_interface = { | |
1237 | .verify = _verify, | |
1238 | .get_encoding_rules = _get_encoding_rules, | |
38fb67fb | 1239 | .get_header_length = _get_header_length, |
806b69a4 MW |
1240 | .get_length = _get_length, |
1241 | .get_next_type = _get_next_type, | |
1242 | .set_next_type = _set_next_type, | |
1243 | .get_type = _get_type, | |
1244 | .destroy = _destroy, | |
1245 | }, | |
1246 | .set_proposal_number = _set_proposal_number, | |
1247 | .get_proposal_number = _get_proposal_number, | |
1248 | .set_protocol_id = _set_protocol_id, | |
1249 | .get_protocol_id = _get_protocol_id, | |
1250 | .set_is_last_proposal = _set_is_last_proposal, | |
d50152a7 | 1251 | .get_proposals = _get_proposals, |
54f2bdd6 | 1252 | .create_substructure_enumerator = _create_substructure_enumerator, |
806b69a4 MW |
1253 | .set_spi = _set_spi, |
1254 | .get_spi = _get_spi, | |
7a75cae8 | 1255 | .get_cpi = _get_cpi, |
914ec2db MW |
1256 | .get_lifetime = _get_lifetime, |
1257 | .get_lifebytes = _get_lifebytes, | |
1258 | .get_auth_method = _get_auth_method, | |
1259 | .get_encap_mode = _get_encap_mode, | |
806b69a4 MW |
1260 | .destroy = _destroy, |
1261 | }, | |
3ecfc83c | 1262 | .next_payload = PL_NONE, |
806b69a4 | 1263 | .transforms = linked_list_create(), |
1bf2971f | 1264 | .type = type, |
806b69a4 | 1265 | ); |
38fb67fb | 1266 | compute_length(this); |
806b69a4 MW |
1267 | |
1268 | return &this->public; | |
da42afc5 | 1269 | } |
384efc76 | 1270 | |
3a470f30 MW |
1271 | /** |
1272 | * Add an IKEv1 IKE proposal to the substructure | |
384efc76 | 1273 | */ |
3a470f30 | 1274 | static void set_from_proposal_v1_ike(private_proposal_substructure_t *this, |
b12c53ce | 1275 | proposal_t *proposal, uint32_t lifetime, |
fbebc2a0 | 1276 | auth_method_t method, int number) |
384efc76 | 1277 | { |
384efc76 | 1278 | transform_substructure_t *transform; |
b12c53ce | 1279 | uint16_t alg, key_size; |
3c7e72f5 | 1280 | enumerator_t *enumerator; |
1bf2971f | 1281 | |
3ecfc83c | 1282 | transform = transform_substructure_create_type(PLV1_TRANSFORM_SUBSTRUCTURE, |
62a27ba3 | 1283 | number, IKEV1_TRANSID_KEY_IKE); |
3a470f30 MW |
1284 | |
1285 | enumerator = proposal->create_enumerator(proposal, ENCRYPTION_ALGORITHM); | |
a0f6f393 | 1286 | while (enumerator->enumerate(enumerator, &alg, &key_size)) |
3a470f30 MW |
1287 | { |
1288 | alg = get_ikev1_from_alg(ENCRYPTION_ALGORITHM, alg); | |
1289 | if (alg) | |
1290 | { | |
1291 | transform->add_transform_attribute(transform, | |
3ecfc83c | 1292 | transform_attribute_create_value(PLV1_TRANSFORM_ATTRIBUTE, |
3a470f30 MW |
1293 | TATTR_PH1_ENCRYPTION_ALGORITHM, alg)); |
1294 | if (key_size) | |
1295 | { | |
1296 | transform->add_transform_attribute(transform, | |
3ecfc83c | 1297 | transform_attribute_create_value(PLV1_TRANSFORM_ATTRIBUTE, |
3a470f30 MW |
1298 | TATTR_PH1_KEY_LENGTH, key_size)); |
1299 | } | |
a0f6f393 | 1300 | break; |
3a470f30 MW |
1301 | } |
1302 | } | |
1303 | enumerator->destroy(enumerator); | |
1304 | ||
1305 | /* encode the integrity algorithm as hash and assume use the same PRF */ | |
1306 | enumerator = proposal->create_enumerator(proposal, INTEGRITY_ALGORITHM); | |
a0f6f393 | 1307 | while (enumerator->enumerate(enumerator, &alg, &key_size)) |
1bf2971f | 1308 | { |
3a470f30 MW |
1309 | alg = get_ikev1_from_alg(INTEGRITY_ALGORITHM, alg); |
1310 | if (alg) | |
1311 | { | |
1312 | transform->add_transform_attribute(transform, | |
3ecfc83c | 1313 | transform_attribute_create_value(PLV1_TRANSFORM_ATTRIBUTE, |
3a470f30 | 1314 | TATTR_PH1_HASH_ALGORITHM, alg)); |
a0f6f393 | 1315 | break; |
3a470f30 | 1316 | } |
1bf2971f | 1317 | } |
3a470f30 | 1318 | enumerator->destroy(enumerator); |
7daf5226 | 1319 | |
3a470f30 | 1320 | enumerator = proposal->create_enumerator(proposal, DIFFIE_HELLMAN_GROUP); |
cd89f1a0 | 1321 | if (enumerator->enumerate(enumerator, &alg, &key_size)) |
3a470f30 MW |
1322 | { |
1323 | transform->add_transform_attribute(transform, | |
3ecfc83c | 1324 | transform_attribute_create_value(PLV1_TRANSFORM_ATTRIBUTE, |
3a470f30 MW |
1325 | TATTR_PH1_GROUP, alg)); |
1326 | } | |
1327 | enumerator->destroy(enumerator); | |
1328 | ||
717333da | 1329 | transform->add_transform_attribute(transform, |
3ecfc83c | 1330 | transform_attribute_create_value(PLV1_TRANSFORM_ATTRIBUTE, |
fbebc2a0 | 1331 | TATTR_PH1_AUTH_METHOD, get_ikev1_auth(method))); |
f5c00960 | 1332 | transform->add_transform_attribute(transform, |
3ecfc83c | 1333 | transform_attribute_create_value(PLV1_TRANSFORM_ATTRIBUTE, |
f5c00960 MW |
1334 | TATTR_PH1_LIFE_TYPE, IKEV1_LIFE_TYPE_SECONDS)); |
1335 | transform->add_transform_attribute(transform, | |
3ecfc83c | 1336 | transform_attribute_create_value(PLV1_TRANSFORM_ATTRIBUTE, |
fbebc2a0 | 1337 | TATTR_PH1_LIFE_DURATION, lifetime)); |
3a470f30 MW |
1338 | |
1339 | add_transform_substructure(this, transform); | |
1340 | } | |
1341 | ||
1342 | /** | |
3771b858 | 1343 | * Add an IKEv1 ESP/AH proposal to the substructure |
3a470f30 | 1344 | */ |
3771b858 | 1345 | static void set_from_proposal_v1(private_proposal_substructure_t *this, |
b12c53ce | 1346 | proposal_t *proposal, uint32_t lifetime, uint64_t lifebytes, |
0ff8d20a | 1347 | ipsec_mode_t mode, encap_t udp, int number) |
3a470f30 | 1348 | { |
cc9629d8 | 1349 | transform_substructure_t *transform = NULL; |
b12c53ce | 1350 | uint16_t alg, transid, key_size; |
cc9629d8 MW |
1351 | enumerator_t *enumerator; |
1352 | ||
1353 | enumerator = proposal->create_enumerator(proposal, ENCRYPTION_ALGORITHM); | |
1354 | if (enumerator->enumerate(enumerator, &alg, &key_size)) | |
1355 | { | |
728f529c TB |
1356 | transid = get_ikev1_transid_from_alg(ENCRYPTION_ALGORITHM, alg); |
1357 | if (transid) | |
cc9629d8 | 1358 | { |
3771b858 | 1359 | transform = transform_substructure_create_type( |
728f529c | 1360 | PLV1_TRANSFORM_SUBSTRUCTURE, number, transid); |
4b797f46 AS |
1361 | if (key_size) |
1362 | { | |
1363 | transform->add_transform_attribute(transform, | |
3ecfc83c | 1364 | transform_attribute_create_value(PLV1_TRANSFORM_ATTRIBUTE, |
4b797f46 AS |
1365 | TATTR_PH2_KEY_LENGTH, key_size)); |
1366 | } | |
cc9629d8 MW |
1367 | } |
1368 | } | |
1369 | enumerator->destroy(enumerator); | |
cc9629d8 MW |
1370 | |
1371 | enumerator = proposal->create_enumerator(proposal, INTEGRITY_ALGORITHM); | |
cd89f1a0 | 1372 | if (enumerator->enumerate(enumerator, &alg, &key_size)) |
cc9629d8 | 1373 | { |
5d580ae0 | 1374 | transid = get_ikev1_transid_from_alg(INTEGRITY_ALGORITHM, alg); |
728f529c | 1375 | alg = get_ikev1_auth_from_alg(alg); |
8456d6f5 | 1376 | if (alg) |
cc9629d8 | 1377 | { |
8456d6f5 | 1378 | if (!transform && transid) |
3771b858 MW |
1379 | { |
1380 | transform = transform_substructure_create_type( | |
728f529c | 1381 | PLV1_TRANSFORM_SUBSTRUCTURE, number, transid); |
3771b858 | 1382 | } |
8456d6f5 TE |
1383 | if (transform) |
1384 | { | |
1385 | transform->add_transform_attribute(transform, | |
1386 | transform_attribute_create_value(PLV1_TRANSFORM_ATTRIBUTE, | |
1387 | TATTR_PH2_AUTH_ALGORITHM, alg)); | |
1388 | } | |
cc9629d8 MW |
1389 | } |
1390 | } | |
1391 | enumerator->destroy(enumerator); | |
1392 | ||
3771b858 MW |
1393 | if (!transform) |
1394 | { | |
1395 | return; | |
1396 | } | |
1397 | ||
9bb4de1d MW |
1398 | enumerator = proposal->create_enumerator(proposal, DIFFIE_HELLMAN_GROUP); |
1399 | if (enumerator->enumerate(enumerator, &alg, &key_size)) | |
1400 | { | |
1401 | transform->add_transform_attribute(transform, | |
3ecfc83c | 1402 | transform_attribute_create_value(PLV1_TRANSFORM_ATTRIBUTE, |
9bb4de1d MW |
1403 | TATTR_PH2_GROUP, alg)); |
1404 | } | |
1405 | enumerator->destroy(enumerator); | |
1406 | ||
f5c00960 | 1407 | transform->add_transform_attribute(transform, |
3ecfc83c | 1408 | transform_attribute_create_value(PLV1_TRANSFORM_ATTRIBUTE, |
fbebc2a0 MW |
1409 | TATTR_PH2_ENCAP_MODE, get_ikev1_mode(mode, udp))); |
1410 | if (lifetime) | |
1411 | { | |
1412 | transform->add_transform_attribute(transform, | |
3ecfc83c | 1413 | transform_attribute_create_value(PLV1_TRANSFORM_ATTRIBUTE, |
f5c00960 | 1414 | TATTR_PH2_SA_LIFE_TYPE, IKEV1_LIFE_TYPE_SECONDS)); |
fbebc2a0 | 1415 | transform->add_transform_attribute(transform, |
3ecfc83c | 1416 | transform_attribute_create_value(PLV1_TRANSFORM_ATTRIBUTE, |
fbebc2a0 MW |
1417 | TATTR_PH2_SA_LIFE_DURATION, lifetime)); |
1418 | } | |
927c1dd9 | 1419 | if (lifebytes) |
fbebc2a0 MW |
1420 | { |
1421 | transform->add_transform_attribute(transform, | |
3ecfc83c | 1422 | transform_attribute_create_value(PLV1_TRANSFORM_ATTRIBUTE, |
fbebc2a0 MW |
1423 | TATTR_PH2_SA_LIFE_TYPE, IKEV1_LIFE_TYPE_KILOBYTES)); |
1424 | transform->add_transform_attribute(transform, | |
3ecfc83c | 1425 | transform_attribute_create_value(PLV1_TRANSFORM_ATTRIBUTE, |
fbebc2a0 MW |
1426 | TATTR_PH2_SA_LIFE_DURATION, lifebytes / 1000)); |
1427 | } | |
cc9629d8 | 1428 | |
40bb4677 TE |
1429 | enumerator = proposal->create_enumerator(proposal, |
1430 | EXTENDED_SEQUENCE_NUMBERS); | |
1431 | while (enumerator->enumerate(enumerator, &alg, NULL)) | |
1432 | { | |
1433 | if (alg == EXT_SEQ_NUMBERS) | |
1434 | { | |
1435 | transform->add_transform_attribute(transform, | |
1436 | transform_attribute_create_value(PLV1_TRANSFORM_ATTRIBUTE, | |
1437 | TATTR_PH2_EXT_SEQ_NUMBER, alg)); | |
1438 | } | |
1439 | } | |
1440 | enumerator->destroy(enumerator); | |
cc9629d8 | 1441 | add_transform_substructure(this, transform); |
3a470f30 MW |
1442 | } |
1443 | ||
1444 | /** | |
1445 | * Add an IKEv2 proposal to the substructure | |
1446 | */ | |
1447 | static void set_from_proposal_v2(private_proposal_substructure_t *this, | |
1448 | proposal_t *proposal) | |
1449 | { | |
1450 | transform_substructure_t *transform; | |
b12c53ce | 1451 | uint16_t alg, key_size; |
3a470f30 | 1452 | enumerator_t *enumerator; |
7daf5226 | 1453 | |
f3bb1bd0 | 1454 | /* encryption algorithm is only available in ESP */ |
3c7e72f5 MW |
1455 | enumerator = proposal->create_enumerator(proposal, ENCRYPTION_ALGORITHM); |
1456 | while (enumerator->enumerate(enumerator, &alg, &key_size)) | |
384efc76 | 1457 | { |
3ecfc83c | 1458 | transform = transform_substructure_create_type(PLV2_TRANSFORM_SUBSTRUCTURE, |
3a470f30 MW |
1459 | ENCRYPTION_ALGORITHM, alg); |
1460 | if (key_size) | |
1461 | { | |
1462 | transform->add_transform_attribute(transform, | |
3ecfc83c | 1463 | transform_attribute_create_value(PLV2_TRANSFORM_ATTRIBUTE, |
3a470f30 MW |
1464 | TATTR_IKEV2_KEY_LENGTH, key_size)); |
1465 | } | |
3c7e72f5 | 1466 | add_transform_substructure(this, transform); |
384efc76 | 1467 | } |
3c7e72f5 | 1468 | enumerator->destroy(enumerator); |
7daf5226 | 1469 | |
384efc76 | 1470 | /* integrity algorithms */ |
3c7e72f5 MW |
1471 | enumerator = proposal->create_enumerator(proposal, INTEGRITY_ALGORITHM); |
1472 | while (enumerator->enumerate(enumerator, &alg, &key_size)) | |
384efc76 | 1473 | { |
3ecfc83c | 1474 | transform = transform_substructure_create_type(PLV2_TRANSFORM_SUBSTRUCTURE, |
3a470f30 | 1475 | INTEGRITY_ALGORITHM, alg); |
3c7e72f5 | 1476 | add_transform_substructure(this, transform); |
384efc76 | 1477 | } |
3c7e72f5 | 1478 | enumerator->destroy(enumerator); |
7daf5226 | 1479 | |
c06dbbab | 1480 | /* prf algorithms */ |
3c7e72f5 MW |
1481 | enumerator = proposal->create_enumerator(proposal, PSEUDO_RANDOM_FUNCTION); |
1482 | while (enumerator->enumerate(enumerator, &alg, &key_size)) | |
c06dbbab | 1483 | { |
3ecfc83c | 1484 | transform = transform_substructure_create_type(PLV2_TRANSFORM_SUBSTRUCTURE, |
3a470f30 | 1485 | PSEUDO_RANDOM_FUNCTION, alg); |
3c7e72f5 | 1486 | add_transform_substructure(this, transform); |
c06dbbab | 1487 | } |
3c7e72f5 | 1488 | enumerator->destroy(enumerator); |
7daf5226 | 1489 | |
384efc76 | 1490 | /* dh groups */ |
3c7e72f5 MW |
1491 | enumerator = proposal->create_enumerator(proposal, DIFFIE_HELLMAN_GROUP); |
1492 | while (enumerator->enumerate(enumerator, &alg, NULL)) | |
384efc76 | 1493 | { |
3ecfc83c | 1494 | transform = transform_substructure_create_type(PLV2_TRANSFORM_SUBSTRUCTURE, |
3a470f30 | 1495 | DIFFIE_HELLMAN_GROUP, alg); |
3c7e72f5 | 1496 | add_transform_substructure(this, transform); |
384efc76 | 1497 | } |
3c7e72f5 | 1498 | enumerator->destroy(enumerator); |
7daf5226 | 1499 | |
384efc76 | 1500 | /* extended sequence numbers */ |
3c7e72f5 MW |
1501 | enumerator = proposal->create_enumerator(proposal, EXTENDED_SEQUENCE_NUMBERS); |
1502 | while (enumerator->enumerate(enumerator, &alg, NULL)) | |
384efc76 | 1503 | { |
3ecfc83c | 1504 | transform = transform_substructure_create_type(PLV2_TRANSFORM_SUBSTRUCTURE, |
3a470f30 | 1505 | EXTENDED_SEQUENCE_NUMBERS, alg); |
3c7e72f5 | 1506 | add_transform_substructure(this, transform); |
384efc76 | 1507 | } |
3c7e72f5 | 1508 | enumerator->destroy(enumerator); |
3a470f30 MW |
1509 | } |
1510 | ||
fbebc2a0 MW |
1511 | /** |
1512 | * Set SPI and other data from proposal, compute length | |
3a470f30 | 1513 | */ |
fbebc2a0 | 1514 | static void set_data(private_proposal_substructure_t *this, proposal_t *proposal) |
3a470f30 | 1515 | { |
b12c53ce AS |
1516 | uint64_t spi64; |
1517 | uint32_t spi32; | |
3a470f30 | 1518 | |
fe04e93a MW |
1519 | /* add SPI, if necessary */ |
1520 | switch (proposal->get_protocol(proposal)) | |
8d77edde | 1521 | { |
fe04e93a MW |
1522 | case PROTO_AH: |
1523 | case PROTO_ESP: | |
3a470f30 MW |
1524 | spi32 = proposal->get_spi(proposal); |
1525 | this->spi = chunk_clone(chunk_from_thing(spi32)); | |
1526 | this->spi_size = this->spi.len; | |
fe04e93a MW |
1527 | break; |
1528 | case PROTO_IKE: | |
3a470f30 MW |
1529 | spi64 = proposal->get_spi(proposal); |
1530 | if (spi64) | |
fe04e93a | 1531 | { /* IKE only uses SPIS when rekeying, but on initial setup */ |
3a470f30 MW |
1532 | this->spi = chunk_clone(chunk_from_thing(spi64)); |
1533 | this->spi_size = this->spi.len; | |
fe04e93a MW |
1534 | } |
1535 | break; | |
4c23a8c9 MW |
1536 | default: |
1537 | break; | |
8d77edde | 1538 | } |
1c6b43b8 TB |
1539 | /* default to 1 if no number is set (mainly for IKEv1, for IKEv2 the numbers |
1540 | * are explicitly set when proposals are added to the SA payload) */ | |
1541 | this->proposal_number = proposal->get_number(proposal) ?: 1; | |
8d77edde | 1542 | this->protocol_id = proposal->get_protocol(proposal); |
2ecbd618 | 1543 | compute_length(this); |
fbebc2a0 MW |
1544 | } |
1545 | ||
1546 | /* | |
1547 | * Described in header. | |
1548 | */ | |
1549 | proposal_substructure_t *proposal_substructure_create_from_proposal_v2( | |
1550 | proposal_t *proposal) | |
1551 | { | |
1552 | private_proposal_substructure_t *this; | |
1553 | ||
1554 | this = (private_proposal_substructure_t*) | |
de77957e | 1555 | proposal_substructure_create(PLV2_PROPOSAL_SUBSTRUCTURE); |
fbebc2a0 MW |
1556 | set_from_proposal_v2(this, proposal); |
1557 | set_data(this, proposal); | |
1558 | ||
1559 | return &this->public; | |
1560 | } | |
1561 | ||
1562 | /** | |
859f9c8c | 1563 | * Creates an IKEv1 proposal_substructure_t from a proposal_t. |
fbebc2a0 | 1564 | */ |
859f9c8c | 1565 | static proposal_substructure_t *proposal_substructure_create_from_proposal_v1( |
b12c53ce | 1566 | proposal_t *proposal, uint32_t lifetime, uint64_t lifebytes, |
859f9c8c | 1567 | auth_method_t auth, ipsec_mode_t mode, encap_t udp, uint8_t number) |
fbebc2a0 MW |
1568 | { |
1569 | private_proposal_substructure_t *this; | |
1570 | ||
1571 | this = (private_proposal_substructure_t*) | |
3ecfc83c | 1572 | proposal_substructure_create(PLV1_PROPOSAL_SUBSTRUCTURE); |
fbebc2a0 MW |
1573 | switch (proposal->get_protocol(proposal)) |
1574 | { | |
1575 | case PROTO_IKE: | |
859f9c8c | 1576 | set_from_proposal_v1_ike(this, proposal, lifetime, auth, number); |
fbebc2a0 MW |
1577 | break; |
1578 | case PROTO_ESP: | |
3771b858 MW |
1579 | case PROTO_AH: |
1580 | set_from_proposal_v1(this, proposal, lifetime, | |
859f9c8c | 1581 | lifebytes, mode, udp, number); |
fbebc2a0 MW |
1582 | break; |
1583 | default: | |
1584 | break; | |
1585 | } | |
1586 | set_data(this, proposal); | |
7daf5226 | 1587 | |
fe04e93a | 1588 | return &this->public; |
384efc76 | 1589 | } |
62a27ba3 MW |
1590 | |
1591 | /** | |
1592 | * See header. | |
1593 | */ | |
fbebc2a0 | 1594 | proposal_substructure_t *proposal_substructure_create_from_proposals_v1( |
b12c53ce | 1595 | linked_list_t *proposals, uint32_t lifetime, uint64_t lifebytes, |
0ff8d20a | 1596 | auth_method_t auth, ipsec_mode_t mode, encap_t udp) |
62a27ba3 MW |
1597 | { |
1598 | private_proposal_substructure_t *this = NULL; | |
1599 | enumerator_t *enumerator; | |
1600 | proposal_t *proposal; | |
859f9c8c | 1601 | int number = 1; |
62a27ba3 MW |
1602 | |
1603 | enumerator = proposals->create_enumerator(proposals); | |
1604 | while (enumerator->enumerate(enumerator, &proposal)) | |
1605 | { | |
1606 | if (!this) | |
859f9c8c TB |
1607 | { /* as responder the transform number is set and we only have a |
1608 | * single proposal, start with 1 otherwise */ | |
62a27ba3 | 1609 | this = (private_proposal_substructure_t*) |
fbebc2a0 | 1610 | proposal_substructure_create_from_proposal_v1( |
859f9c8c TB |
1611 | proposal, lifetime, lifebytes, auth, mode, udp, |
1612 | proposal->get_transform_number(proposal) ?: number); | |
62a27ba3 MW |
1613 | } |
1614 | else | |
1615 | { | |
1616 | switch (proposal->get_protocol(proposal)) | |
1617 | { | |
1618 | case PROTO_IKE: | |
fbebc2a0 MW |
1619 | set_from_proposal_v1_ike(this, proposal, lifetime, |
1620 | auth, ++number); | |
62a27ba3 MW |
1621 | break; |
1622 | case PROTO_ESP: | |
3771b858 MW |
1623 | case PROTO_AH: |
1624 | set_from_proposal_v1(this, proposal, lifetime, | |
1625 | lifebytes, mode, udp, ++number); | |
62a27ba3 MW |
1626 | break; |
1627 | default: | |
1628 | break; | |
1629 | } | |
1630 | } | |
1631 | } | |
1632 | enumerator->destroy(enumerator); | |
1633 | ||
1634 | return &this->public; | |
1635 | } | |
7a75cae8 TB |
1636 | |
1637 | /** | |
1638 | * See header. | |
1639 | */ | |
1640 | proposal_substructure_t *proposal_substructure_create_for_ipcomp_v1( | |
b12c53ce AS |
1641 | uint32_t lifetime, uint64_t lifebytes, uint16_t cpi, |
1642 | ipsec_mode_t mode, encap_t udp, uint8_t proposal_number) | |
7a75cae8 TB |
1643 | { |
1644 | private_proposal_substructure_t *this; | |
1645 | transform_substructure_t *transform; | |
1646 | ||
1647 | ||
1648 | this = (private_proposal_substructure_t*) | |
3ecfc83c | 1649 | proposal_substructure_create(PLV1_PROPOSAL_SUBSTRUCTURE); |
7a75cae8 TB |
1650 | |
1651 | /* we currently support DEFLATE only */ | |
3ecfc83c | 1652 | transform = transform_substructure_create_type(PLV1_TRANSFORM_SUBSTRUCTURE, |
7a75cae8 TB |
1653 | 1, IKEV1_IPCOMP_DEFLATE); |
1654 | ||
daab61e5 | 1655 | transform->add_transform_attribute(transform, |
3ecfc83c | 1656 | transform_attribute_create_value(PLV1_TRANSFORM_ATTRIBUTE, |
daab61e5 | 1657 | TATTR_PH2_ENCAP_MODE, get_ikev1_mode(mode, udp))); |
7a75cae8 TB |
1658 | if (lifetime) |
1659 | { | |
1660 | transform->add_transform_attribute(transform, | |
3ecfc83c | 1661 | transform_attribute_create_value(PLV1_TRANSFORM_ATTRIBUTE, |
7a75cae8 TB |
1662 | TATTR_PH2_SA_LIFE_TYPE, IKEV1_LIFE_TYPE_SECONDS)); |
1663 | transform->add_transform_attribute(transform, | |
3ecfc83c | 1664 | transform_attribute_create_value(PLV1_TRANSFORM_ATTRIBUTE, |
7a75cae8 TB |
1665 | TATTR_PH2_SA_LIFE_DURATION, lifetime)); |
1666 | } | |
1667 | if (lifebytes) | |
1668 | { | |
1669 | transform->add_transform_attribute(transform, | |
3ecfc83c | 1670 | transform_attribute_create_value(PLV1_TRANSFORM_ATTRIBUTE, |
7a75cae8 TB |
1671 | TATTR_PH2_SA_LIFE_TYPE, IKEV1_LIFE_TYPE_KILOBYTES)); |
1672 | transform->add_transform_attribute(transform, | |
3ecfc83c | 1673 | transform_attribute_create_value(PLV1_TRANSFORM_ATTRIBUTE, |
7a75cae8 TB |
1674 | TATTR_PH2_SA_LIFE_DURATION, lifebytes / 1000)); |
1675 | } | |
1676 | ||
1677 | add_transform_substructure(this, transform); | |
1678 | ||
1679 | this->spi = chunk_clone(chunk_from_thing(cpi)); | |
1680 | this->spi_size = this->spi.len; | |
1681 | this->protocol_id = PROTO_IPCOMP; | |
1682 | this->proposal_number = proposal_number; | |
1683 | ||
1684 | compute_length(this); | |
1685 | ||
1686 | return &this->public; | |
a9aa75b9 | 1687 | } |