2 * Copyright (C) 2005-2010 Martin Willi
3 * Copyright (C) 2005 Jan Hutter
4 * Hochschule fuer Technik Rapperswil
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19 #include "proposal_substructure.h"
21 #include <encoding/payloads/encodings.h>
22 #include <encoding/payloads/transform_substructure.h>
24 #include <utils/linked_list.h>
28 * IKEv1 Value for a proposal payload.
30 #define PROPOSAL_TYPE_VALUE 2
32 typedef struct private_proposal_substructure_t private_proposal_substructure_t
;
35 * Private data of an proposal_substructure_t object.
37 struct private_proposal_substructure_t
{
40 * Public proposal_substructure_t interface.
42 proposal_substructure_t
public;
47 u_int8_t next_payload
;
55 * Length of this payload.
57 u_int16_t proposal_length
;
62 u_int8_t proposal_number
;
70 * SPI size of the following SPI.
75 * Number of transforms.
77 u_int8_t transforms_count
;
80 * SPI is stored as chunk.
85 * Transforms are stored in a linked_list_t.
87 linked_list_t
* transforms
;
91 * Encoding rules to parse or generate a Proposal substructure.
93 * The defined offsets are the positions in a object of type
94 * private_proposal_substructure_t.
96 encoding_rule_t proposal_substructure_encodings
[] = {
97 /* 1 Byte next payload type, stored in the field next_payload */
98 { U_INT_8
, offsetof(private_proposal_substructure_t
, next_payload
) },
100 { RESERVED_BYTE
, offsetof(private_proposal_substructure_t
, reserved
) },
101 /* Length of the whole proposal substructure payload*/
102 { PAYLOAD_LENGTH
, offsetof(private_proposal_substructure_t
, proposal_length
) },
103 /* proposal number is a number of 8 bit */
104 { U_INT_8
, offsetof(private_proposal_substructure_t
, proposal_number
) },
105 /* protocol ID is a number of 8 bit */
106 { U_INT_8
, offsetof(private_proposal_substructure_t
, protocol_id
) },
107 /* SPI Size has its own type */
108 { SPI_SIZE
, offsetof(private_proposal_substructure_t
, spi_size
) },
109 /* Number of transforms is a number of 8 bit */
110 { U_INT_8
, offsetof(private_proposal_substructure_t
, transforms_count
) },
111 /* SPI is a chunk of variable size*/
112 { SPI
, offsetof(private_proposal_substructure_t
, spi
) },
113 /* Transforms are stored in a transform substructure,
114 offset points to a linked_list_t pointer */
115 { TRANSFORMS
, offsetof(private_proposal_substructure_t
, transforms
) }
120 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
121 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
122 ! 0 (last) or 2 ! RESERVED ! Proposal Length !
123 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
124 ! Proposal # ! Protocol ID ! SPI Size !# of Transforms!
125 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
127 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
131 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
134 METHOD(payload_t
, verify
, status_t
,
135 private_proposal_substructure_t
*this)
137 status_t status
= SUCCESS
;
138 enumerator_t
*enumerator
;
141 if (this->next_payload
!= NO_PAYLOAD
&& this->next_payload
!= 2)
144 DBG1(DBG_ENC
, "inconsistent next payload");
147 if (this->transforms_count
!= this->transforms
->get_count(this->transforms
))
149 /* must be the same! */
150 DBG1(DBG_ENC
, "transform count invalid");
154 switch (this->protocol_id
)
158 if (this->spi
.len
!= 4)
160 DBG1(DBG_ENC
, "invalid SPI length in %N proposal",
161 protocol_id_names
, this->protocol_id
);
166 if (this->spi
.len
!= 0 && this->spi
.len
!= 8)
168 DBG1(DBG_ENC
, "invalid SPI length in IKE proposal");
175 enumerator
= this->transforms
->create_enumerator(this->transforms
);
176 while (enumerator
->enumerate(enumerator
, ¤t
))
178 status
= current
->verify(current
);
179 if (status
!= SUCCESS
)
181 DBG1(DBG_ENC
, "TRANSFORM_SUBSTRUCTURE verification failed");
185 enumerator
->destroy(enumerator
);
187 /* proposal number is checked in SA payload */
191 METHOD(payload_t
, get_encoding_rules
, void,
192 private_proposal_substructure_t
*this, encoding_rule_t
**rules
,
195 *rules
= proposal_substructure_encodings
;
196 *rule_count
= countof(proposal_substructure_encodings
);
199 METHOD(payload_t
, get_type
, payload_type_t
,
200 private_proposal_substructure_t
*this)
202 return PROPOSAL_SUBSTRUCTURE
;
205 METHOD(payload_t
, get_next_type
, payload_type_t
,
206 private_proposal_substructure_t
*this)
208 return this->next_payload
;
211 METHOD(payload_t
, set_next_type
, void,
212 private_proposal_substructure_t
*this, payload_type_t type
)
217 * (re-)compute the length of the payload.
219 static void compute_length(private_proposal_substructure_t
*this)
221 enumerator_t
*enumerator
;
222 payload_t
*transform
;
224 this->transforms_count
= 0;
225 this->proposal_length
= PROPOSAL_SUBSTRUCTURE_HEADER_LENGTH
+ this->spi
.len
;
226 enumerator
= this->transforms
->create_enumerator(this->transforms
);
227 while (enumerator
->enumerate(enumerator
, &transform
))
229 this->proposal_length
+= transform
->get_length(transform
);
230 this->transforms_count
++;
232 enumerator
->destroy(enumerator
);
235 METHOD(payload_t
, get_length
, size_t,
236 private_proposal_substructure_t
*this)
238 return this->proposal_length
;
242 * Add a transform substructure to the proposal
244 static void add_transform_substructure(private_proposal_substructure_t
*this,
245 transform_substructure_t
*transform
)
247 if (this->transforms
->get_count(this->transforms
) > 0)
249 transform_substructure_t
*last
;
251 this->transforms
->get_last(this->transforms
, (void **)&last
);
252 last
->set_is_last_transform(last
, FALSE
);
254 transform
->set_is_last_transform(transform
,TRUE
);
255 this->transforms
->insert_last(this->transforms
, transform
);
256 compute_length(this);
259 METHOD(proposal_substructure_t
, set_is_last_proposal
, void,
260 private_proposal_substructure_t
*this, bool is_last
)
262 this->next_payload
= is_last ?
0 : PROPOSAL_TYPE_VALUE
;
265 METHOD(proposal_substructure_t
, set_proposal_number
, void,
266 private_proposal_substructure_t
*this,u_int8_t proposal_number
)
268 this->proposal_number
= proposal_number
;
271 METHOD(proposal_substructure_t
, get_proposal_number
, u_int8_t
,
272 private_proposal_substructure_t
*this)
274 return this->proposal_number
;
277 METHOD(proposal_substructure_t
, set_protocol_id
, void,
278 private_proposal_substructure_t
*this,u_int8_t protocol_id
)
280 this->protocol_id
= protocol_id
;
283 METHOD(proposal_substructure_t
, get_protocol_id
, u_int8_t
,
284 private_proposal_substructure_t
*this)
286 return this->protocol_id
;
289 METHOD(proposal_substructure_t
, set_spi
, void,
290 private_proposal_substructure_t
*this, chunk_t spi
)
293 this->spi
= chunk_clone(spi
);
294 this->spi_size
= spi
.len
;
295 compute_length(this);
298 METHOD(proposal_substructure_t
, get_spi
, chunk_t
,
299 private_proposal_substructure_t
*this)
304 METHOD(proposal_substructure_t
, get_proposal
, proposal_t
*,
305 private_proposal_substructure_t
*this)
307 enumerator_t
*enumerator
;
308 transform_substructure_t
*transform
;
309 proposal_t
*proposal
;
312 proposal
= proposal_create(this->protocol_id
, this->proposal_number
);
314 enumerator
= this->transforms
->create_enumerator(this->transforms
);
315 while (enumerator
->enumerate(enumerator
, &transform
))
317 transform_type_t transform_type
;
318 u_int16_t transform_id
;
319 u_int16_t key_length
= 0;
321 transform_type
= transform
->get_transform_type(transform
);
322 transform_id
= transform
->get_transform_id(transform
);
323 transform
->get_key_length(transform
, &key_length
);
325 proposal
->add_algorithm(proposal
, transform_type
, transform_id
, key_length
);
327 enumerator
->destroy(enumerator
);
329 switch (this->spi
.len
)
332 spi
= *((u_int32_t
*)this->spi
.ptr
);
335 spi
= *((u_int64_t
*)this->spi
.ptr
);
340 proposal
->set_spi(proposal
, spi
);
345 METHOD(proposal_substructure_t
, create_substructure_enumerator
, enumerator_t
*,
346 private_proposal_substructure_t
*this)
348 return this->transforms
->create_enumerator(this->transforms
);
351 METHOD2(payload_t
, proposal_substructure_t
, destroy
, void,
352 private_proposal_substructure_t
*this)
354 this->transforms
->destroy_offset(this->transforms
,
355 offsetof(transform_substructure_t
, destroy
));
356 chunk_free(&this->spi
);
361 * Described in header.
363 proposal_substructure_t
*proposal_substructure_create()
365 private_proposal_substructure_t
*this;
369 .payload_interface
= {
371 .get_encoding_rules
= _get_encoding_rules
,
372 .get_length
= _get_length
,
373 .get_next_type
= _get_next_type
,
374 .set_next_type
= _set_next_type
,
375 .get_type
= _get_type
,
378 .set_proposal_number
= _set_proposal_number
,
379 .get_proposal_number
= _get_proposal_number
,
380 .set_protocol_id
= _set_protocol_id
,
381 .get_protocol_id
= _get_protocol_id
,
382 .set_is_last_proposal
= _set_is_last_proposal
,
383 .get_proposal
= _get_proposal
,
384 .create_substructure_enumerator
= _create_substructure_enumerator
,
389 .next_payload
= NO_PAYLOAD
,
390 .proposal_length
= PROPOSAL_SUBSTRUCTURE_HEADER_LENGTH
,
391 .transforms
= linked_list_create(),
394 return &this->public;
398 * Described in header.
400 proposal_substructure_t
*proposal_substructure_create_from_proposal(
401 proposal_t
*proposal
)
403 transform_substructure_t
*transform
;
404 private_proposal_substructure_t
*this;
405 u_int16_t alg
, key_size
;
406 enumerator_t
*enumerator
;
408 this = (private_proposal_substructure_t
*)proposal_substructure_create();
410 /* encryption algorithm is only available in ESP */
411 enumerator
= proposal
->create_enumerator(proposal
, ENCRYPTION_ALGORITHM
);
412 while (enumerator
->enumerate(enumerator
, &alg
, &key_size
))
414 transform
= transform_substructure_create_type(ENCRYPTION_ALGORITHM
,
416 add_transform_substructure(this, transform
);
418 enumerator
->destroy(enumerator
);
420 /* integrity algorithms */
421 enumerator
= proposal
->create_enumerator(proposal
, INTEGRITY_ALGORITHM
);
422 while (enumerator
->enumerate(enumerator
, &alg
, &key_size
))
424 transform
= transform_substructure_create_type(INTEGRITY_ALGORITHM
,
426 add_transform_substructure(this, transform
);
428 enumerator
->destroy(enumerator
);
431 enumerator
= proposal
->create_enumerator(proposal
, PSEUDO_RANDOM_FUNCTION
);
432 while (enumerator
->enumerate(enumerator
, &alg
, &key_size
))
434 transform
= transform_substructure_create_type(PSEUDO_RANDOM_FUNCTION
,
436 add_transform_substructure(this, transform
);
438 enumerator
->destroy(enumerator
);
441 enumerator
= proposal
->create_enumerator(proposal
, DIFFIE_HELLMAN_GROUP
);
442 while (enumerator
->enumerate(enumerator
, &alg
, NULL
))
444 transform
= transform_substructure_create_type(DIFFIE_HELLMAN_GROUP
,
446 add_transform_substructure(this, transform
);
448 enumerator
->destroy(enumerator
);
450 /* extended sequence numbers */
451 enumerator
= proposal
->create_enumerator(proposal
, EXTENDED_SEQUENCE_NUMBERS
);
452 while (enumerator
->enumerate(enumerator
, &alg
, NULL
))
454 transform
= transform_substructure_create_type(EXTENDED_SEQUENCE_NUMBERS
,
456 add_transform_substructure(this, transform
);
458 enumerator
->destroy(enumerator
);
460 /* add SPI, if necessary */
461 switch (proposal
->get_protocol(proposal
))
465 this->spi_size
= this->spi
.len
= 4;
466 this->spi
.ptr
= malloc(this->spi_size
);
467 *((u_int32_t
*)this->spi
.ptr
) = proposal
->get_spi(proposal
);
470 if (proposal
->get_spi(proposal
))
471 { /* IKE only uses SPIS when rekeying, but on initial setup */
472 this->spi_size
= this->spi
.len
= 8;
473 this->spi
.ptr
= malloc(this->spi_size
);
474 *((u_int64_t
*)this->spi
.ptr
) = proposal
->get_spi(proposal
);
480 this->proposal_number
= proposal
->get_number(proposal
);
481 this->protocol_id
= proposal
->get_protocol(proposal
);
482 compute_length(this);
484 return &this->public;