]>
Commit | Line | Data |
---|---|---|
0c7cfb18 MW |
1 | /** |
2 | * @file encryption_payload.c | |
3 | * | |
4 | * @brief Implementation of encryption_payload_t. | |
5 | * | |
6 | */ | |
7 | ||
8 | /* | |
9 | * Copyright (C) 2005 Jan Hutter, Martin Willi | |
10 | * Hochschule fuer Technik Rapperswil | |
11 | * | |
12 | * This program is free software; you can redistribute it and/or modify it | |
13 | * under the terms of the GNU General Public License as published by the | |
14 | * Free Software Foundation; either version 2 of the License, or (at your | |
15 | * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. | |
16 | * | |
17 | * This program is distributed in the hope that it will be useful, but | |
18 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
19 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
20 | * for more details. | |
21 | */ | |
5113680f | 22 | |
0c7cfb18 | 23 | #include <stddef.h> |
5113680f | 24 | #include <string.h> |
0c7cfb18 MW |
25 | |
26 | #include "encryption_payload.h" | |
27 | ||
ccf783d2 | 28 | #include <daemon.h> |
0c7cfb18 | 29 | #include <encoding/payloads/encodings.h> |
0c7cfb18 | 30 | #include <utils/linked_list.h> |
ccf783d2 | 31 | #include <utils/logger.h> |
0c7cfb18 MW |
32 | #include <encoding/generator.h> |
33 | #include <encoding/parser.h> | |
34 | #include <utils/iterator.h> | |
35 | #include <utils/randomizer.h> | |
68621281 | 36 | #include <crypto/signers/signer.h> |
0c7cfb18 MW |
37 | |
38 | ||
39 | ||
40 | ||
41 | typedef struct private_encryption_payload_t private_encryption_payload_t; | |
42 | ||
43 | /** | |
3fe05870 | 44 | * Private data of an encryption_payload_t' Object. |
0c7cfb18 MW |
45 | * |
46 | */ | |
47 | struct private_encryption_payload_t { | |
c3dc864e | 48 | |
0c7cfb18 | 49 | /** |
3fe05870 | 50 | * Public encryption_payload_t interface. |
0c7cfb18 MW |
51 | */ |
52 | encryption_payload_t public; | |
53 | ||
54 | /** | |
55 | * There is no next payload for an encryption payload, | |
56 | * since encryption payload MUST be the last one. | |
57 | * next_payload means here the first payload of the | |
58 | * contained, encrypted payload. | |
59 | */ | |
60 | u_int8_t next_payload; | |
61 | ||
62 | /** | |
3fe05870 | 63 | * Critical flag. |
0c7cfb18 MW |
64 | */ |
65 | bool critical; | |
66 | ||
67 | /** | |
68 | * Length of this payload | |
69 | */ | |
70 | u_int16_t payload_length; | |
71 | ||
0c7cfb18 | 72 | /** |
3fe05870 JH |
73 | * Chunk containing the iv, data, padding, |
74 | * and (an eventually not calculated) signature. | |
0c7cfb18 MW |
75 | */ |
76 | chunk_t encrypted; | |
77 | ||
78 | /** | |
3fe05870 | 79 | * Chunk containing the data in decrypted (unpadded) form. |
0c7cfb18 MW |
80 | */ |
81 | chunk_t decrypted; | |
82 | ||
83 | /** | |
3fe05870 | 84 | * Signer set by set_signer. |
0c7cfb18 MW |
85 | */ |
86 | signer_t *signer; | |
87 | ||
0f803b47 MW |
88 | /** |
89 | * Crypter, supplied by encrypt/decrypt | |
90 | */ | |
91 | crypter_t *crypter; | |
92 | ||
0c7cfb18 | 93 | /** |
3fe05870 | 94 | * Contained payloads of this encrpytion_payload. |
0c7cfb18 MW |
95 | */ |
96 | linked_list_t *payloads; | |
97 | ||
ccf783d2 MW |
98 | /** |
99 | * logger for this payload, uses MESSAGE context | |
100 | */ | |
101 | logger_t *logger; | |
102 | ||
0c7cfb18 MW |
103 | /** |
104 | * @brief Computes the length of this payload. | |
105 | * | |
106 | * @param this calling private_encryption_payload_t object | |
0c7cfb18 | 107 | */ |
3fe05870 | 108 | void (*compute_length) (private_encryption_payload_t *this); |
0c7cfb18 MW |
109 | |
110 | /** | |
111 | * @brief Generate payloads (unencrypted) in chunk decrypted. | |
112 | * | |
113 | * @param this calling private_encryption_payload_t object | |
0c7cfb18 | 114 | */ |
3fe05870 | 115 | void (*generate) (private_encryption_payload_t *this); |
ccf783d2 MW |
116 | |
117 | /** | |
118 | * @brief Parse payloads from a (unencrypted) chunk. | |
119 | * | |
120 | * @param this calling private_encryption_payload_t object | |
121 | */ | |
0c7cfb18 MW |
122 | status_t (*parse) (private_encryption_payload_t *this); |
123 | }; | |
124 | ||
125 | /** | |
3fe05870 | 126 | * Encoding rules to parse or generate a IKEv2-Encryption Payload. |
0c7cfb18 MW |
127 | * |
128 | * The defined offsets are the positions in a object of type | |
129 | * private_encryption_payload_t. | |
130 | * | |
131 | */ | |
132 | encoding_rule_t encryption_payload_encodings[] = { | |
133 | /* 1 Byte next payload type, stored in the field next_payload */ | |
134 | { U_INT_8, offsetof(private_encryption_payload_t, next_payload) }, | |
135 | /* the critical bit */ | |
136 | { FLAG, offsetof(private_encryption_payload_t, critical) }, | |
137 | /* 7 Bit reserved bits, nowhere stored */ | |
138 | { RESERVED_BIT, 0 }, | |
139 | { RESERVED_BIT, 0 }, | |
140 | { RESERVED_BIT, 0 }, | |
141 | { RESERVED_BIT, 0 }, | |
142 | { RESERVED_BIT, 0 }, | |
143 | { RESERVED_BIT, 0 }, | |
144 | { RESERVED_BIT, 0 }, | |
145 | /* Length of the whole encryption payload*/ | |
146 | { PAYLOAD_LENGTH, offsetof(private_encryption_payload_t, payload_length) }, | |
147 | /* encrypted data, stored in a chunk. contains iv, data, padding */ | |
148 | { ENCRYPTED_DATA, offsetof(private_encryption_payload_t, encrypted) }, | |
149 | }; | |
150 | ||
151 | /* | |
152 | 1 2 3 | |
153 | 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 | |
154 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
155 | ! Next Payload !C! RESERVED ! Payload Length ! | |
156 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
157 | ! Initialization Vector ! | |
158 | ! (length is block size for encryption algorithm) ! | |
159 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
160 | ! Encrypted IKE Payloads ! | |
161 | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
162 | ! ! Padding (0-255 octets) ! | |
163 | +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+ | |
164 | ! ! Pad Length ! | |
165 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
166 | ~ Integrity Checksum Data ~ | |
167 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
168 | */ | |
169 | ||
170 | /** | |
3fe05870 | 171 | * Implementation of payload_t.verify. |
0c7cfb18 MW |
172 | */ |
173 | static status_t verify(private_encryption_payload_t *this) | |
174 | { | |
ee29afd4 | 175 | return SUCCESS; |
0c7cfb18 MW |
176 | } |
177 | ||
0c7cfb18 | 178 | /** |
3fe05870 | 179 | * Implementation of payload_t.get_encoding_rules. |
0c7cfb18 | 180 | */ |
3fe05870 | 181 | static void get_encoding_rules(private_encryption_payload_t *this, encoding_rule_t **rules, size_t *rule_count) |
0c7cfb18 MW |
182 | { |
183 | *rules = encryption_payload_encodings; | |
184 | *rule_count = sizeof(encryption_payload_encodings) / sizeof(encoding_rule_t); | |
0c7cfb18 MW |
185 | } |
186 | ||
187 | /** | |
3fe05870 | 188 | * Implementation of payload_t.get_type. |
0c7cfb18 MW |
189 | */ |
190 | static payload_type_t get_type(private_encryption_payload_t *this) | |
191 | { | |
192 | return ENCRYPTED; | |
193 | } | |
194 | ||
195 | /** | |
3fe05870 | 196 | * Implementation of payload_t.get_next_type. |
0c7cfb18 MW |
197 | */ |
198 | static payload_type_t get_next_type(private_encryption_payload_t *this) | |
199 | { | |
200 | /* returns first contained payload here */ | |
201 | return (this->next_payload); | |
202 | } | |
203 | ||
204 | /** | |
3fe05870 | 205 | * Implementation of payload_t.set_next_type. |
0c7cfb18 | 206 | */ |
3fe05870 | 207 | static void set_next_type(private_encryption_payload_t *this, payload_type_t type) |
0c7cfb18 | 208 | { |
3fe05870 JH |
209 | /* set next type is not allowed, since this payload MUST be the last one |
210 | * and so nothing is done in here*/ | |
0c7cfb18 MW |
211 | } |
212 | ||
213 | /** | |
3fe05870 | 214 | * Implementation of payload_t.get_length. |
0c7cfb18 MW |
215 | */ |
216 | static size_t get_length(private_encryption_payload_t *this) | |
217 | { | |
218 | this->compute_length(this); | |
219 | return this->payload_length; | |
220 | } | |
221 | ||
222 | /** | |
3fe05870 | 223 | * Implementation of payload_t.create_payload_iterator. |
0c7cfb18 | 224 | */ |
a0753941 | 225 | static iterator_t *create_payload_iterator (private_encryption_payload_t *this, bool forward) |
0c7cfb18 | 226 | { |
a0753941 | 227 | return (this->payloads->create_iterator(this->payloads, forward)); |
0c7cfb18 MW |
228 | } |
229 | ||
230 | /** | |
3fe05870 | 231 | * Implementation of payload_t.add_payload. |
0c7cfb18 | 232 | */ |
3fe05870 | 233 | static void add_payload(private_encryption_payload_t *this, payload_t *payload) |
0c7cfb18 MW |
234 | { |
235 | payload_t *last_payload; | |
3fe05870 | 236 | if (this->payloads->get_count(this->payloads) > 0) |
0c7cfb18 | 237 | { |
3fe05870 | 238 | this->payloads->get_last(this->payloads,(void **) &last_payload); |
0f803b47 | 239 | last_payload->set_next_type(last_payload, payload->get_type(payload)); |
0c7cfb18 MW |
240 | } |
241 | else | |
242 | { | |
0f803b47 | 243 | this->next_payload = payload->get_type(payload); |
0c7cfb18 MW |
244 | } |
245 | payload->set_next_type(payload, NO_PAYLOAD); | |
0f803b47 | 246 | this->payloads->insert_last(this->payloads, (void*)payload); |
0c7cfb18 | 247 | this->compute_length(this); |
0c7cfb18 MW |
248 | } |
249 | ||
bc788302 MW |
250 | /** |
251 | * Implementation of encryption_payload_t.remove_first_payload. | |
252 | */ | |
253 | static status_t remove_first_payload(private_encryption_payload_t *this, payload_t **payload) | |
254 | { | |
255 | return this->payloads->remove_first(this->payloads, (void**)payload); | |
256 | } | |
257 | ||
258 | /** | |
259 | * Implementation of encryption_payload_t.get_payload_count. | |
260 | */ | |
261 | static size_t get_payload_count(private_encryption_payload_t *this) | |
262 | { | |
263 | return this->payloads->get_count(this->payloads); | |
264 | } | |
265 | ||
266 | ||
0c7cfb18 | 267 | /** |
3fe05870 | 268 | * Implementation of encryption_payload_t.encrypt. |
0c7cfb18 | 269 | */ |
0f803b47 | 270 | static status_t encrypt(private_encryption_payload_t *this) |
0c7cfb18 | 271 | { |
0f803b47 | 272 | chunk_t iv, padding, to_crypt, result; |
0c7cfb18 MW |
273 | randomizer_t *randomizer; |
274 | status_t status; | |
0f803b47 | 275 | size_t block_size; |
0c7cfb18 | 276 | |
0f803b47 | 277 | if (this->signer == NULL || this->crypter == NULL) |
0c7cfb18 | 278 | { |
ccf783d2 | 279 | this->logger->log(this->logger, ERROR, "could not encrypt, signer/crypter not set"); |
0c7cfb18 MW |
280 | return INVALID_STATE; |
281 | } | |
282 | ||
283 | /* for random data in iv and padding */ | |
284 | randomizer = randomizer_create(); | |
0c7cfb18 | 285 | |
ccf783d2 | 286 | |
0c7cfb18 | 287 | /* build payload chunk */ |
3fe05870 | 288 | this->generate(this); |
0c7cfb18 | 289 | |
aee3eb52 | 290 | this->logger->log(this->logger, CONTROL|LEVEL2, "encrypting payloads"); |
16b9a73c | 291 | this->logger->log_chunk(this->logger, RAW|LEVEL2, "data to encrypt", this->decrypted); |
ccf783d2 | 292 | |
0c7cfb18 | 293 | /* build padding */ |
0f803b47 MW |
294 | block_size = this->crypter->get_block_size(this->crypter); |
295 | padding.len = block_size - ((this->decrypted.len + 1) % block_size); | |
68621281 MW |
296 | status = randomizer->allocate_pseudo_random_bytes(randomizer, padding.len, &padding); |
297 | if (status != SUCCESS) | |
298 | { | |
299 | randomizer->destroy(randomizer); | |
300 | return status; | |
301 | } | |
0c7cfb18 MW |
302 | |
303 | /* concatenate payload data, padding, padding len */ | |
0f803b47 | 304 | to_crypt.len = this->decrypted.len + padding.len + 1; |
5113680f | 305 | to_crypt.ptr = malloc(to_crypt.len); |
0c7cfb18 | 306 | |
0f803b47 MW |
307 | memcpy(to_crypt.ptr, this->decrypted.ptr, this->decrypted.len); |
308 | memcpy(to_crypt.ptr + this->decrypted.len, padding.ptr, padding.len); | |
309 | *(to_crypt.ptr + to_crypt.len - 1) = padding.len; | |
0c7cfb18 MW |
310 | |
311 | /* build iv */ | |
0f803b47 | 312 | iv.len = block_size; |
68621281 | 313 | status = randomizer->allocate_pseudo_random_bytes(randomizer, iv.len, &iv); |
0c7cfb18 | 314 | randomizer->destroy(randomizer); |
68621281 MW |
315 | if (status != SUCCESS) |
316 | { | |
5113680f MW |
317 | chunk_free(&to_crypt); |
318 | chunk_free(&padding); | |
68621281 MW |
319 | return status; |
320 | } | |
30b5b412 | 321 | |
16b9a73c | 322 | this->logger->log_chunk(this->logger, RAW|LEVEL2, "data before encryption with padding", to_crypt); |
0c7cfb18 | 323 | |
0f803b47 | 324 | /* encrypt to_crypt chunk */ |
5113680f | 325 | free(this->encrypted.ptr); |
0f803b47 | 326 | status = this->crypter->encrypt(this->crypter, to_crypt, iv, &result); |
5113680f MW |
327 | free(padding.ptr); |
328 | free(to_crypt.ptr); | |
0c7cfb18 MW |
329 | if (status != SUCCESS) |
330 | { | |
aee3eb52 | 331 | this->logger->log(this->logger, ERROR|LEVEL1, "encryption failed"); |
5113680f | 332 | free(iv.ptr); |
0c7cfb18 MW |
333 | return status; |
334 | } | |
16b9a73c | 335 | this->logger->log_chunk(this->logger, RAW|LEVEL2, "data after encryption", result); |
30b5b412 | 336 | |
0c7cfb18 | 337 | |
0f803b47 MW |
338 | /* build encrypted result with iv and signature */ |
339 | this->encrypted.len = iv.len + result.len + this->signer->get_block_size(this->signer); | |
5113680f MW |
340 | free(this->encrypted.ptr); |
341 | this->encrypted.ptr = malloc(this->encrypted.len); | |
0f803b47 MW |
342 | |
343 | /* fill in result, signature is left out */ | |
344 | memcpy(this->encrypted.ptr, iv.ptr, iv.len); | |
345 | memcpy(this->encrypted.ptr + iv.len, result.ptr, result.len); | |
346 | ||
5113680f MW |
347 | free(result.ptr); |
348 | free(iv.ptr); | |
16b9a73c | 349 | this->logger->log_chunk(this->logger, RAW|LEVEL2, "data after encryption with IV and (invalid) signature", this->encrypted); |
30b5b412 | 350 | |
0c7cfb18 MW |
351 | return SUCCESS; |
352 | } | |
353 | ||
354 | /** | |
3fe05870 | 355 | * Implementation of encryption_payload_t.encrypt. |
0c7cfb18 | 356 | */ |
0f803b47 | 357 | static status_t decrypt(private_encryption_payload_t *this) |
0c7cfb18 MW |
358 | { |
359 | chunk_t iv, concatenated; | |
360 | u_int8_t padding_length; | |
361 | status_t status; | |
362 | ||
ccf783d2 | 363 | |
aee3eb52 | 364 | this->logger->log(this->logger, CONTROL|LEVEL2, "decrypting encryption payload"); |
16b9a73c | 365 | this->logger->log_chunk(this->logger, RAW|LEVEL2, "data before decryption with IV and (invalid) signature", this->encrypted); |
30b5b412 | 366 | |
ccf783d2 | 367 | |
0f803b47 | 368 | if (this->signer == NULL || this->crypter == NULL) |
0c7cfb18 | 369 | { |
ccf783d2 | 370 | this->logger->log(this->logger, ERROR, "could not decrypt, no crypter/signer set"); |
0c7cfb18 MW |
371 | return INVALID_STATE; |
372 | } | |
bc788302 | 373 | |
0c7cfb18 | 374 | /* get IV */ |
0f803b47 | 375 | iv.len = this->crypter->get_block_size(this->crypter); |
01de2f3c | 376 | |
0c7cfb18 MW |
377 | iv.ptr = this->encrypted.ptr; |
378 | ||
379 | /* point concatenated to data + padding + padding_length*/ | |
380 | concatenated.ptr = this->encrypted.ptr + iv.len; | |
381 | concatenated.len = this->encrypted.len - iv.len - this->signer->get_block_size(this->signer); | |
0f803b47 | 382 | |
0c7cfb18 MW |
383 | /* check the size of input: |
384 | * concatenated must be at least on block_size of crypter | |
385 | */ | |
386 | if (concatenated.len < iv.len) | |
387 | { | |
aee3eb52 | 388 | this->logger->log(this->logger, ERROR|LEVEL1, "could not decrypt, invalid input"); |
0c7cfb18 MW |
389 | return FAILED; |
390 | } | |
391 | ||
392 | /* free previus data, if any */ | |
5113680f | 393 | free(this->decrypted.ptr); |
0c7cfb18 | 394 | |
16b9a73c | 395 | this->logger->log_chunk(this->logger, RAW|LEVEL2, "data before decryption", concatenated); |
30b5b412 | 396 | |
0f803b47 | 397 | status = this->crypter->decrypt(this->crypter, concatenated, iv, &(this->decrypted)); |
0c7cfb18 MW |
398 | if (status != SUCCESS) |
399 | { | |
aee3eb52 | 400 | this->logger->log(this->logger, ERROR|LEVEL1, "could not decrypt, decryption failed"); |
0c7cfb18 MW |
401 | return FAILED; |
402 | } | |
16b9a73c | 403 | this->logger->log_chunk(this->logger, RAW|LEVEL2, "data after decryption with padding", this->decrypted); |
30b5b412 | 404 | |
0c7cfb18 MW |
405 | |
406 | /* get padding length, sits just bevore signature */ | |
407 | padding_length = *(this->decrypted.ptr + this->decrypted.len - 1); | |
0f803b47 MW |
408 | /* add one byte to the padding length, since the padding_length field is not included */ |
409 | padding_length++; | |
0c7cfb18 MW |
410 | this->decrypted.len -= padding_length; |
411 | ||
412 | /* check size again */ | |
413 | if (padding_length > concatenated.len || this->decrypted.len < 0) | |
414 | { | |
aee3eb52 | 415 | this->logger->log(this->logger, ERROR|LEVEL1, "decryption failed, invalid padding length found. Invalid key?"); |
0c7cfb18 MW |
416 | /* decryption failed :-/ */ |
417 | return FAILED; | |
418 | } | |
419 | ||
420 | /* free padding */ | |
5113680f | 421 | this->decrypted.ptr = realloc(this->decrypted.ptr, this->decrypted.len); |
16b9a73c | 422 | this->logger->log_chunk(this->logger, RAW|LEVEL2, "data after decryption without padding", this->decrypted); |
aee3eb52 | 423 | this->logger->log(this->logger, CONTROL|LEVEL2, "decryption successful, trying to parse content"); |
1b3f92d2 | 424 | return (this->parse(this)); |
0c7cfb18 MW |
425 | } |
426 | ||
427 | /** | |
0f803b47 | 428 | * Implementation of encryption_payload_t.set_transforms. |
0c7cfb18 | 429 | */ |
0f803b47 | 430 | static void set_transforms(private_encryption_payload_t *this, crypter_t* crypter, signer_t* signer) |
0c7cfb18 MW |
431 | { |
432 | this->signer = signer; | |
0f803b47 | 433 | this->crypter = crypter; |
0c7cfb18 MW |
434 | } |
435 | ||
436 | /** | |
3fe05870 | 437 | * Implementation of encryption_payload_t.build_signature. |
0c7cfb18 MW |
438 | */ |
439 | static status_t build_signature(private_encryption_payload_t *this, chunk_t data) | |
440 | { | |
441 | chunk_t data_without_sig = data; | |
442 | chunk_t sig; | |
443 | ||
444 | if (this->signer == NULL) | |
445 | { | |
ccf783d2 | 446 | this->logger->log(this->logger, ERROR, "unable to build signature, no signer set"); |
0c7cfb18 MW |
447 | return INVALID_STATE; |
448 | } | |
449 | ||
450 | sig.len = this->signer->get_block_size(this->signer); | |
451 | data_without_sig.len -= sig.len; | |
452 | sig.ptr = data.ptr + data_without_sig.len; | |
aee3eb52 | 453 | this->logger->log(this->logger, CONTROL|LEVEL2, "building signature"); |
0c7cfb18 MW |
454 | this->signer->get_signature(this->signer, data_without_sig, sig.ptr); |
455 | return SUCCESS; | |
456 | } | |
457 | ||
458 | /** | |
3fe05870 | 459 | * Implementation of encryption_payload_t.verify_signature. |
0c7cfb18 MW |
460 | */ |
461 | static status_t verify_signature(private_encryption_payload_t *this, chunk_t data) | |
462 | { | |
463 | chunk_t sig, data_without_sig; | |
464 | bool valid; | |
465 | ||
466 | if (this->signer == NULL) | |
467 | { | |
ccf783d2 | 468 | this->logger->log(this->logger, ERROR, "unable to verify signature, no signer set"); |
0c7cfb18 MW |
469 | return INVALID_STATE; |
470 | } | |
471 | /* find signature in data chunk */ | |
472 | sig.len = this->signer->get_block_size(this->signer); | |
473 | if (data.len <= sig.len) | |
474 | { | |
aee3eb52 | 475 | this->logger->log(this->logger, ERROR|LEVEL1, "unable to verify signature, invalid input"); |
0c7cfb18 MW |
476 | return FAILED; |
477 | } | |
478 | sig.ptr = data.ptr + data.len - sig.len; | |
479 | ||
480 | /* verify it */ | |
481 | data_without_sig.len = data.len - sig.len; | |
482 | data_without_sig.ptr = data.ptr; | |
f1046648 | 483 | valid = this->signer->verify_signature(this->signer, data_without_sig, sig); |
0c7cfb18 MW |
484 | |
485 | if (!valid) | |
486 | { | |
aee3eb52 | 487 | this->logger->log(this->logger, ERROR|LEVEL1, "signature verification failed"); |
0c7cfb18 MW |
488 | return FAILED; |
489 | } | |
490 | ||
aee3eb52 | 491 | this->logger->log(this->logger, CONTROL|LEVEL2, "signature verification successful"); |
0c7cfb18 MW |
492 | return SUCCESS; |
493 | } | |
494 | ||
495 | /** | |
3fe05870 | 496 | * Implementation of private_encryption_payload_t.generate. |
0c7cfb18 | 497 | */ |
3fe05870 | 498 | static void generate(private_encryption_payload_t *this) |
0c7cfb18 | 499 | { |
0c7cfb18 MW |
500 | payload_t *current_payload, *next_payload; |
501 | generator_t *generator; | |
502 | iterator_t *iterator; | |
503 | ||
0f803b47 MW |
504 | /* recalculate length before generating */ |
505 | this->compute_length(this); | |
506 | ||
0c7cfb18 | 507 | /* create iterator */ |
a0753941 | 508 | iterator = this->payloads->create_iterator(this->payloads, TRUE); |
0c7cfb18 MW |
509 | |
510 | /* get first payload */ | |
511 | if (iterator->has_next(iterator)) | |
512 | { | |
513 | iterator->current(iterator, (void**)¤t_payload); | |
514 | this->next_payload = current_payload->get_type(current_payload); | |
515 | } | |
516 | else | |
517 | { | |
518 | /* no paylads? */ | |
aee3eb52 | 519 | this->logger->log(this->logger, CONTROL|LEVEL1, "generating contained payloads, but no available"); |
5113680f | 520 | free(this->decrypted.ptr); |
0c7cfb18 MW |
521 | this->decrypted = CHUNK_INITIALIZER; |
522 | iterator->destroy(iterator); | |
3fe05870 | 523 | return; |
0c7cfb18 MW |
524 | } |
525 | ||
526 | generator = generator_create(); | |
0c7cfb18 MW |
527 | |
528 | /* build all payload, except last */ | |
529 | while(iterator->has_next(iterator)) | |
530 | { | |
531 | iterator->current(iterator, (void**)&next_payload); | |
532 | current_payload->set_next_type(current_payload, next_payload->get_type(next_payload)); | |
0f30f568 | 533 | generator->generate_payload(generator, current_payload); |
0c7cfb18 MW |
534 | current_payload = next_payload; |
535 | } | |
536 | iterator->destroy(iterator); | |
537 | ||
538 | /* build last payload */ | |
539 | current_payload->set_next_type(current_payload, NO_PAYLOAD); | |
0f30f568 | 540 | generator->generate_payload(generator, current_payload); |
0c7cfb18 MW |
541 | |
542 | /* free already generated data */ | |
5113680f | 543 | free(this->decrypted.ptr); |
0c7cfb18 | 544 | |
0f30f568 | 545 | generator->write_to_chunk(generator, &(this->decrypted)); |
0c7cfb18 | 546 | generator->destroy(generator); |
aee3eb52 | 547 | this->logger->log(this->logger, CONTROL|LEVEL1, "successfully generated content in encrpytion payload"); |
0c7cfb18 MW |
548 | } |
549 | ||
3fe05870 JH |
550 | /** |
551 | * Implementation of private_encryption_payload_t.parse. | |
552 | */ | |
0c7cfb18 MW |
553 | static status_t parse(private_encryption_payload_t *this) |
554 | { | |
555 | parser_t *parser; | |
556 | status_t status; | |
557 | payload_type_t current_payload_type; | |
558 | ||
559 | /* check if there is decrypted data */ | |
560 | if (this->decrypted.ptr == NULL) | |
561 | { | |
ccf783d2 | 562 | this->logger->log(this->logger, ERROR, "unable to parse, no input!"); |
0c7cfb18 MW |
563 | return INVALID_STATE; |
564 | } | |
565 | ||
566 | /* build a parser on the decrypted data */ | |
567 | parser = parser_create(this->decrypted); | |
0c7cfb18 MW |
568 | |
569 | current_payload_type = this->next_payload; | |
570 | /* parse all payloads */ | |
571 | while (current_payload_type != NO_PAYLOAD) | |
572 | { | |
573 | payload_t *current_payload; | |
574 | ||
575 | status = parser->parse_payload(parser, current_payload_type, (payload_t**)¤t_payload); | |
576 | if (status != SUCCESS) | |
577 | { | |
0f803b47 | 578 | parser->destroy(parser); |
0c7cfb18 MW |
579 | return PARSE_ERROR; |
580 | } | |
1b3f92d2 | 581 | |
0c7cfb18 MW |
582 | status = current_payload->verify(current_payload); |
583 | if (status != SUCCESS) | |
584 | { | |
aee3eb52 | 585 | this->logger->log(this->logger, ERROR|LEVEL1, "%s verification failed: %s", |
ccf783d2 MW |
586 | mapping_find(payload_type_m,current_payload->get_type(current_payload)), |
587 | mapping_find(status_m, status)); | |
1b3f92d2 | 588 | current_payload->destroy(current_payload); |
0f803b47 | 589 | parser->destroy(parser); |
0c7cfb18 MW |
590 | return VERIFY_ERROR; |
591 | } | |
592 | ||
593 | /* get next payload type */ | |
594 | current_payload_type = current_payload->get_next_type(current_payload); | |
595 | ||
3fe05870 | 596 | this->payloads->insert_last(this->payloads,current_payload); |
0c7cfb18 | 597 | } |
0f803b47 | 598 | parser->destroy(parser); |
aee3eb52 | 599 | this->logger->log(this->logger, CONTROL|LEVEL1, "succesfully parsed content of encryption payload"); |
0c7cfb18 MW |
600 | return SUCCESS; |
601 | } | |
602 | ||
603 | /** | |
3fe05870 | 604 | * Implementation of private_encryption_payload_t.compute_length. |
0c7cfb18 | 605 | */ |
3fe05870 | 606 | static void compute_length(private_encryption_payload_t *this) |
0c7cfb18 MW |
607 | { |
608 | iterator_t *iterator; | |
0f803b47 | 609 | size_t block_size, length = 0; |
a0753941 | 610 | iterator = this->payloads->create_iterator(this->payloads, TRUE); |
3fe05870 | 611 | |
0f803b47 | 612 | /* count payload length */ |
0c7cfb18 MW |
613 | while (iterator->has_next(iterator)) |
614 | { | |
615 | payload_t *current_payload; | |
616 | iterator->current(iterator, (void **) ¤t_payload); | |
617 | length += current_payload->get_length(current_payload); | |
618 | } | |
619 | iterator->destroy(iterator); | |
620 | ||
0f803b47 MW |
621 | if (this->crypter && this->signer) |
622 | { | |
623 | /* append one byte for padding length */ | |
624 | length++; | |
625 | /* append padding */ | |
626 | block_size = this->crypter->get_block_size(this->crypter); | |
627 | length += block_size - length % block_size; | |
628 | /* add iv */ | |
629 | length += block_size; | |
630 | /* add signature */ | |
631 | length += this->signer->get_block_size(this->signer); | |
632 | } | |
633 | length += ENCRYPTION_PAYLOAD_HEADER_LENGTH; | |
0c7cfb18 | 634 | this->payload_length = length; |
0c7cfb18 MW |
635 | } |
636 | ||
ccf783d2 MW |
637 | |
638 | /** | |
639 | * Implementation of payload_t.destroy. | |
640 | */ | |
641 | static void destroy(private_encryption_payload_t *this) | |
642 | { | |
643 | /* all proposals are getting destroyed */ | |
644 | while (this->payloads->get_count(this->payloads) > 0) | |
645 | { | |
646 | payload_t *current_payload; | |
647 | this->payloads->remove_last(this->payloads,(void **)¤t_payload); | |
648 | current_payload->destroy(current_payload); | |
649 | } | |
650 | this->payloads->destroy(this->payloads); | |
5113680f MW |
651 | free(this->encrypted.ptr); |
652 | free(this->decrypted.ptr); | |
653 | free(this); | |
ccf783d2 MW |
654 | } |
655 | ||
0c7cfb18 MW |
656 | /* |
657 | * Described in header | |
658 | */ | |
659 | encryption_payload_t *encryption_payload_create() | |
660 | { | |
5113680f | 661 | private_encryption_payload_t *this = malloc_thing(private_encryption_payload_t); |
0c7cfb18 MW |
662 | |
663 | /* payload_t interface functions */ | |
664 | this->public.payload_interface.verify = (status_t (*) (payload_t *))verify; | |
3fe05870 | 665 | this->public.payload_interface.get_encoding_rules = (void (*) (payload_t *, encoding_rule_t **, size_t *) ) get_encoding_rules; |
0c7cfb18 MW |
666 | this->public.payload_interface.get_length = (size_t (*) (payload_t *)) get_length; |
667 | this->public.payload_interface.get_next_type = (payload_type_t (*) (payload_t *)) get_next_type; | |
3fe05870 | 668 | this->public.payload_interface.set_next_type = (void (*) (payload_t *,payload_type_t)) set_next_type; |
0c7cfb18 | 669 | this->public.payload_interface.get_type = (payload_type_t (*) (payload_t *)) get_type; |
3fe05870 | 670 | this->public.payload_interface.destroy = (void (*) (payload_t *))destroy; |
0c7cfb18 MW |
671 | |
672 | /* public functions */ | |
a0753941 | 673 | this->public.create_payload_iterator = (iterator_t * (*) (encryption_payload_t *,bool)) create_payload_iterator; |
3fe05870 | 674 | this->public.add_payload = (void (*) (encryption_payload_t *,payload_t *)) add_payload; |
bc788302 MW |
675 | this->public.remove_first_payload = (status_t (*)(encryption_payload_t*, payload_t **)) remove_first_payload; |
676 | this->public.get_payload_count = (size_t (*)(encryption_payload_t*)) get_payload_count; | |
677 | ||
0f803b47 MW |
678 | this->public.encrypt = (status_t (*) (encryption_payload_t *)) encrypt; |
679 | this->public.decrypt = (status_t (*) (encryption_payload_t *)) decrypt; | |
680 | this->public.set_transforms = (void (*) (encryption_payload_t*,crypter_t*,signer_t*)) set_transforms; | |
0c7cfb18 MW |
681 | this->public.build_signature = (status_t (*) (encryption_payload_t*, chunk_t)) build_signature; |
682 | this->public.verify_signature = (status_t (*) (encryption_payload_t*, chunk_t)) verify_signature; | |
3fe05870 | 683 | this->public.destroy = (void (*) (encryption_payload_t *)) destroy; |
0c7cfb18 MW |
684 | |
685 | /* private functions */ | |
686 | this->compute_length = compute_length; | |
687 | this->generate = generate; | |
688 | this->parse = parse; | |
5113680f | 689 | this->logger = logger_manager->get_logger(logger_manager, ENCRYPTION_PAYLOAD); |
0c7cfb18 MW |
690 | |
691 | /* set default values of the fields */ | |
dec59822 | 692 | this->critical = FALSE; |
0c7cfb18 MW |
693 | this->next_payload = NO_PAYLOAD; |
694 | this->payload_length = ENCRYPTION_PAYLOAD_HEADER_LENGTH; | |
0c7cfb18 MW |
695 | this->encrypted = CHUNK_INITIALIZER; |
696 | this->decrypted = CHUNK_INITIALIZER; | |
0c7cfb18 | 697 | this->signer = NULL; |
0f803b47 | 698 | this->crypter = NULL; |
0c7cfb18 MW |
699 | this->payloads = linked_list_create(); |
700 | ||
0c7cfb18 MW |
701 | return (&(this->public)); |
702 | } |