]>
Commit | Line | Data |
---|---|---|
47eb8943 | 1 | /* |
24a8d125 | 2 | * Copyright (C) 2012-2013 Tobias Brunner |
47eb8943 TB |
3 | * Copyright (C) 2012 Giuliano Grassi |
4 | * Copyright (C) 2012 Ralf Sager | |
5 | * Hochschule fuer Technik Rapperswil | |
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 | */ | |
17 | ||
18 | ||
19 | #include "esp_packet.h" | |
20 | ||
21 | #include <library.h> | |
f05b4272 | 22 | #include <utils/debug.h> |
47eb8943 TB |
23 | #include <crypto/crypters/crypter.h> |
24 | #include <crypto/signers/signer.h> | |
25 | #include <bio/bio_reader.h> | |
26 | #include <bio/bio_writer.h> | |
27 | ||
1da56773 | 28 | #ifndef WIN32 |
47eb8943 | 29 | #include <netinet/in.h> |
1da56773 | 30 | #endif |
47eb8943 TB |
31 | |
32 | typedef struct private_esp_packet_t private_esp_packet_t; | |
33 | ||
34 | /** | |
35 | * Private additions to esp_packet_t. | |
36 | */ | |
37 | struct private_esp_packet_t { | |
38 | ||
39 | /** | |
40 | * Public members | |
41 | */ | |
42 | esp_packet_t public; | |
43 | ||
44 | /** | |
05a2a795 | 45 | * Raw ESP packet |
47eb8943 | 46 | */ |
05a2a795 | 47 | packet_t *packet; |
47eb8943 TB |
48 | |
49 | /** | |
50 | * Payload of this packet | |
51 | */ | |
b37758c4 | 52 | ip_packet_t *payload; |
47eb8943 TB |
53 | |
54 | /** | |
55 | * Next Header info (e.g. IPPROTO_IPIP) | |
56 | */ | |
b12c53ce | 57 | uint8_t next_header; |
47eb8943 | 58 | |
47eb8943 TB |
59 | }; |
60 | ||
05a2a795 TB |
61 | /** |
62 | * Forward declaration for clone() | |
63 | */ | |
b37758c4 | 64 | static private_esp_packet_t *esp_packet_create_internal(packet_t *packet); |
05a2a795 TB |
65 | |
66 | METHOD(packet_t, set_source, void, | |
67 | private_esp_packet_t *this, host_t *src) | |
68 | { | |
69 | return this->packet->set_source(this->packet, src); | |
70 | } | |
71 | ||
72 | METHOD2(esp_packet_t, packet_t, get_source, host_t*, | |
73 | private_esp_packet_t *this) | |
74 | { | |
75 | return this->packet->get_source(this->packet); | |
76 | } | |
77 | ||
78 | METHOD(packet_t, set_destination, void, | |
79 | private_esp_packet_t *this, host_t *dst) | |
80 | { | |
81 | return this->packet->set_destination(this->packet, dst); | |
82 | } | |
83 | ||
84 | METHOD2(esp_packet_t, packet_t, get_destination, host_t*, | |
85 | private_esp_packet_t *this) | |
86 | { | |
87 | return this->packet->get_destination(this->packet); | |
88 | } | |
89 | ||
90 | METHOD(packet_t, get_data, chunk_t, | |
91 | private_esp_packet_t *this) | |
92 | { | |
93 | return this->packet->get_data(this->packet); | |
94 | } | |
95 | ||
96 | METHOD(packet_t, set_data, void, | |
97 | private_esp_packet_t *this, chunk_t data) | |
98 | { | |
99 | return this->packet->set_data(this->packet, data); | |
100 | } | |
101 | ||
b12c53ce | 102 | METHOD(packet_t, get_dscp, uint8_t, |
11166899 MW |
103 | private_esp_packet_t *this) |
104 | { | |
105 | return this->packet->get_dscp(this->packet); | |
106 | } | |
107 | ||
108 | METHOD(packet_t, set_dscp, void, | |
b12c53ce | 109 | private_esp_packet_t *this, uint8_t value) |
11166899 MW |
110 | { |
111 | this->packet->set_dscp(this->packet, value); | |
112 | } | |
113 | ||
05a2a795 TB |
114 | METHOD(packet_t, skip_bytes, void, |
115 | private_esp_packet_t *this, size_t bytes) | |
116 | { | |
117 | return this->packet->skip_bytes(this->packet, bytes); | |
118 | } | |
119 | ||
5f35b733 | 120 | METHOD(packet_t, clone_, packet_t*, |
05a2a795 TB |
121 | private_esp_packet_t *this) |
122 | { | |
123 | private_esp_packet_t *pkt; | |
124 | ||
b37758c4 TB |
125 | pkt = esp_packet_create_internal(this->packet->clone(this->packet)); |
126 | pkt->payload = this->payload ? this->payload->clone(this->payload) : NULL; | |
05a2a795 TB |
127 | pkt->next_header = this->next_header; |
128 | return &pkt->public.packet; | |
129 | } | |
130 | ||
47eb8943 | 131 | METHOD(esp_packet_t, parse_header, bool, |
b12c53ce | 132 | private_esp_packet_t *this, uint32_t *spi) |
47eb8943 TB |
133 | { |
134 | bio_reader_t *reader; | |
b12c53ce | 135 | uint32_t seq; |
47eb8943 | 136 | |
05a2a795 | 137 | reader = bio_reader_create(this->packet->get_data(this->packet)); |
47eb8943 TB |
138 | if (!reader->read_uint32(reader, spi) || |
139 | !reader->read_uint32(reader, &seq)) | |
140 | { | |
141 | DBG1(DBG_ESP, "failed to parse ESP header: invalid length"); | |
142 | reader->destroy(reader); | |
143 | return FALSE; | |
144 | } | |
145 | reader->destroy(reader); | |
146 | ||
147 | DBG2(DBG_ESP, "parsed ESP header with SPI %.8x [seq %u]", *spi, seq); | |
148 | *spi = htonl(*spi); | |
149 | return TRUE; | |
150 | } | |
151 | ||
152 | /** | |
153 | * Check padding as specified in RFC 4303 | |
154 | */ | |
155 | static bool check_padding(chunk_t padding) | |
156 | { | |
157 | size_t i; | |
158 | ||
159 | for (i = 0; i < padding.len; ++i) | |
160 | { | |
b12c53ce | 161 | if (padding.ptr[i] != (uint8_t)(i + 1)) |
47eb8943 TB |
162 | { |
163 | return FALSE; | |
164 | } | |
165 | } | |
166 | return TRUE; | |
167 | } | |
168 | ||
169 | /** | |
170 | * Remove the padding from the payload and set the next header info | |
171 | */ | |
b37758c4 | 172 | static bool remove_padding(private_esp_packet_t *this, chunk_t plaintext) |
47eb8943 | 173 | { |
b12c53ce | 174 | uint8_t next_header, pad_length; |
b37758c4 | 175 | chunk_t padding, payload; |
47eb8943 TB |
176 | bio_reader_t *reader; |
177 | ||
b37758c4 | 178 | reader = bio_reader_create(plaintext); |
47eb8943 TB |
179 | if (!reader->read_uint8_end(reader, &next_header) || |
180 | !reader->read_uint8_end(reader, &pad_length)) | |
181 | { | |
182 | DBG1(DBG_ESP, "parsing ESP payload failed: invalid length"); | |
b37758c4 | 183 | goto failed; |
47eb8943 TB |
184 | } |
185 | if (!reader->read_data_end(reader, pad_length, &padding) || | |
186 | !check_padding(padding)) | |
187 | { | |
188 | DBG1(DBG_ESP, "parsing ESP payload failed: invalid padding"); | |
b37758c4 TB |
189 | goto failed; |
190 | } | |
191 | this->payload = ip_packet_create(reader->peek(reader)); | |
192 | reader->destroy(reader); | |
193 | if (!this->payload) | |
194 | { | |
195 | DBG1(DBG_ESP, "parsing ESP payload failed: unsupported payload"); | |
47eb8943 TB |
196 | return FALSE; |
197 | } | |
47eb8943 | 198 | this->next_header = next_header; |
b37758c4 | 199 | payload = this->payload->get_encoding(this->payload); |
47eb8943 TB |
200 | |
201 | DBG3(DBG_ESP, "ESP payload:\n payload %B\n padding %B\n " | |
b37758c4 TB |
202 | "padding length = %hhu, next header = %hhu", &payload, &padding, |
203 | pad_length, this->next_header); | |
47eb8943 | 204 | return TRUE; |
b37758c4 TB |
205 | |
206 | failed: | |
207 | reader->destroy(reader); | |
208 | chunk_free(&plaintext); | |
209 | return FALSE; | |
47eb8943 TB |
210 | } |
211 | ||
212 | METHOD(esp_packet_t, decrypt, status_t, | |
213 | private_esp_packet_t *this, esp_context_t *esp_context) | |
214 | { | |
215 | bio_reader_t *reader; | |
b12c53ce | 216 | uint32_t spi, seq; |
24a8d125 TB |
217 | chunk_t data, iv, icv, aad, ciphertext, plaintext; |
218 | aead_t *aead; | |
47eb8943 | 219 | |
b37758c4 TB |
220 | DESTROY_IF(this->payload); |
221 | this->payload = NULL; | |
47eb8943 | 222 | |
05a2a795 | 223 | data = this->packet->get_data(this->packet); |
24a8d125 | 224 | aead = esp_context->get_aead(esp_context); |
47eb8943 | 225 | |
05a2a795 | 226 | reader = bio_reader_create(data); |
47eb8943 TB |
227 | if (!reader->read_uint32(reader, &spi) || |
228 | !reader->read_uint32(reader, &seq) || | |
24a8d125 TB |
229 | !reader->read_data(reader, aead->get_iv_size(aead), &iv) || |
230 | !reader->read_data_end(reader, aead->get_icv_size(aead), &icv) || | |
231 | reader->remaining(reader) % aead->get_block_size(aead)) | |
47eb8943 TB |
232 | { |
233 | DBG1(DBG_ESP, "ESP decryption failed: invalid length"); | |
234 | return PARSE_ERROR; | |
235 | } | |
236 | ciphertext = reader->peek(reader); | |
237 | reader->destroy(reader); | |
238 | ||
239 | if (!esp_context->verify_seqno(esp_context, seq)) | |
240 | { | |
241 | DBG1(DBG_ESP, "ESP sequence number verification failed:\n " | |
242 | "src %H, dst %H, SPI %.8x [seq %u]", | |
05a2a795 | 243 | get_source(this), get_destination(this), spi, seq); |
47eb8943 TB |
244 | return VERIFY_ERROR; |
245 | } | |
246 | DBG3(DBG_ESP, "ESP decryption:\n SPI %.8x [seq %u]\n IV %B\n " | |
247 | "encrypted %B\n ICV %B", spi, seq, &iv, &ciphertext, &icv); | |
248 | ||
f6cadb7f TB |
249 | /* include ICV in ciphertext for decryption/verification */ |
250 | ciphertext.len += icv.len; | |
24a8d125 TB |
251 | /* aad = spi + seq */ |
252 | aad = chunk_create(data.ptr, 8); | |
47eb8943 | 253 | |
24a8d125 | 254 | if (!aead->decrypt(aead, ciphertext, aad, iv, &plaintext)) |
47eb8943 | 255 | { |
24a8d125 | 256 | DBG1(DBG_ESP, "ESP decryption or ICV verification failed"); |
47eb8943 TB |
257 | return FAILED; |
258 | } | |
24a8d125 | 259 | esp_context->set_authenticated_seqno(esp_context, seq); |
47eb8943 | 260 | |
b37758c4 | 261 | if (!remove_padding(this, plaintext)) |
47eb8943 | 262 | { |
47eb8943 TB |
263 | return PARSE_ERROR; |
264 | } | |
265 | return SUCCESS; | |
266 | } | |
267 | ||
268 | /** | |
269 | * Generate the padding as specified in RFC4303 | |
270 | */ | |
271 | static void generate_padding(chunk_t padding) | |
272 | { | |
273 | size_t i; | |
274 | ||
275 | for (i = 0; i < padding.len; ++i) | |
276 | { | |
b12c53ce | 277 | padding.ptr[i] = (uint8_t)(i + 1); |
47eb8943 TB |
278 | } |
279 | } | |
280 | ||
281 | METHOD(esp_packet_t, encrypt, status_t, | |
b12c53ce | 282 | private_esp_packet_t *this, esp_context_t *esp_context, uint32_t spi) |
47eb8943 | 283 | { |
24a8d125 | 284 | chunk_t iv, icv, aad, padding, payload, ciphertext; |
47eb8943 | 285 | bio_writer_t *writer; |
b12c53ce | 286 | uint32_t next_seqno; |
47eb8943 | 287 | size_t blocksize, plainlen; |
24a8d125 | 288 | aead_t *aead; |
d74c254d | 289 | iv_gen_t *iv_gen; |
47eb8943 | 290 | |
05a2a795 | 291 | this->packet->set_data(this->packet, chunk_empty); |
47eb8943 TB |
292 | |
293 | if (!esp_context->next_seqno(esp_context, &next_seqno)) | |
294 | { | |
295 | DBG1(DBG_ESP, "ESP encapsulation failed: sequence numbers cycled"); | |
296 | return FAILED; | |
297 | } | |
298 | ||
d74c254d TB |
299 | aead = esp_context->get_aead(esp_context); |
300 | iv_gen = aead->get_iv_gen(aead); | |
301 | if (!iv_gen) | |
47eb8943 | 302 | { |
d74c254d | 303 | DBG1(DBG_ESP, "ESP encryption failed: no IV generator"); |
47eb8943 TB |
304 | return NOT_FOUND; |
305 | } | |
47eb8943 | 306 | |
24a8d125 TB |
307 | blocksize = aead->get_block_size(aead); |
308 | iv.len = aead->get_iv_size(aead); | |
309 | icv.len = aead->get_icv_size(aead); | |
47eb8943 TB |
310 | |
311 | /* plaintext = payload, padding, pad_length, next_header */ | |
b37758c4 TB |
312 | payload = this->payload ? this->payload->get_encoding(this->payload) |
313 | : chunk_empty; | |
314 | plainlen = payload.len + 2; | |
f5c5fd6f TB |
315 | padding.len = pad_len(plainlen, blocksize); |
316 | /* ICV must be on a 4-byte boundary */ | |
317 | padding.len += pad_len(iv.len + plainlen + padding.len, 4); | |
47eb8943 TB |
318 | plainlen += padding.len; |
319 | ||
320 | /* len = spi, seq, IV, plaintext, ICV */ | |
b12c53ce | 321 | writer = bio_writer_create(2 * sizeof(uint32_t) + iv.len + plainlen + |
47eb8943 TB |
322 | icv.len); |
323 | writer->write_uint32(writer, ntohl(spi)); | |
324 | writer->write_uint32(writer, next_seqno); | |
325 | ||
326 | iv = writer->skip(writer, iv.len); | |
e8229ad5 | 327 | if (!iv_gen->get_iv(iv_gen, next_seqno, iv.len, iv.ptr)) |
47eb8943 TB |
328 | { |
329 | DBG1(DBG_ESP, "ESP encryption failed: could not generate IV"); | |
330 | writer->destroy(writer); | |
47eb8943 TB |
331 | return FAILED; |
332 | } | |
47eb8943 TB |
333 | |
334 | /* plain-/ciphertext will start here */ | |
335 | ciphertext = writer->get_buf(writer); | |
336 | ciphertext.ptr += ciphertext.len; | |
337 | ciphertext.len = plainlen; | |
338 | ||
b37758c4 | 339 | writer->write_data(writer, payload); |
47eb8943 TB |
340 | |
341 | padding = writer->skip(writer, padding.len); | |
342 | generate_padding(padding); | |
343 | ||
344 | writer->write_uint8(writer, padding.len); | |
345 | writer->write_uint8(writer, this->next_header); | |
346 | ||
24a8d125 TB |
347 | /* aad = spi + seq */ |
348 | aad = writer->get_buf(writer); | |
349 | aad.len = 8; | |
350 | icv = writer->skip(writer, icv.len); | |
351 | ||
47eb8943 | 352 | DBG3(DBG_ESP, "ESP before encryption:\n payload = %B\n padding = %B\n " |
b37758c4 | 353 | "padding length = %hhu, next header = %hhu", &payload, &padding, |
b12c53ce | 354 | (uint8_t)padding.len, this->next_header); |
47eb8943 | 355 | |
24a8d125 TB |
356 | /* encrypt/authenticate the content inline */ |
357 | if (!aead->encrypt(aead, ciphertext, aad, iv, NULL)) | |
47eb8943 | 358 | { |
24a8d125 | 359 | DBG1(DBG_ESP, "ESP encryption or ICV generation failed"); |
47eb8943 TB |
360 | writer->destroy(writer); |
361 | return FAILED; | |
362 | } | |
363 | ||
364 | DBG3(DBG_ESP, "ESP packet:\n SPI %.8x [seq %u]\n IV %B\n " | |
365 | "encrypted %B\n ICV %B", ntohl(spi), next_seqno, &iv, | |
366 | &ciphertext, &icv); | |
367 | ||
05a2a795 | 368 | this->packet->set_data(this->packet, writer->extract_buf(writer)); |
47eb8943 TB |
369 | writer->destroy(writer); |
370 | return SUCCESS; | |
371 | } | |
372 | ||
b12c53ce | 373 | METHOD(esp_packet_t, get_next_header, uint8_t, |
47eb8943 TB |
374 | private_esp_packet_t *this) |
375 | { | |
376 | return this->next_header; | |
377 | } | |
378 | ||
b37758c4 | 379 | METHOD(esp_packet_t, get_payload, ip_packet_t*, |
47eb8943 TB |
380 | private_esp_packet_t *this) |
381 | { | |
382 | return this->payload; | |
383 | } | |
384 | ||
b37758c4 TB |
385 | METHOD(esp_packet_t, extract_payload, ip_packet_t*, |
386 | private_esp_packet_t *this) | |
387 | { | |
388 | ip_packet_t *payload; | |
389 | ||
390 | payload = this->payload; | |
391 | this->payload = NULL; | |
392 | return payload; | |
393 | } | |
394 | ||
05a2a795 | 395 | METHOD2(esp_packet_t, packet_t, destroy, void, |
47eb8943 TB |
396 | private_esp_packet_t *this) |
397 | { | |
b37758c4 | 398 | DESTROY_IF(this->payload); |
05a2a795 | 399 | this->packet->destroy(this->packet); |
47eb8943 TB |
400 | free(this); |
401 | } | |
402 | ||
b37758c4 | 403 | static private_esp_packet_t *esp_packet_create_internal(packet_t *packet) |
47eb8943 TB |
404 | { |
405 | private_esp_packet_t *this; | |
406 | ||
407 | INIT(this, | |
408 | .public = { | |
05a2a795 TB |
409 | .packet = { |
410 | .set_source = _set_source, | |
411 | .get_source = _get_source, | |
412 | .set_destination = _set_destination, | |
413 | .get_destination = _get_destination, | |
414 | .get_data = _get_data, | |
415 | .set_data = _set_data, | |
11166899 MW |
416 | .get_dscp = _get_dscp, |
417 | .set_dscp = _set_dscp, | |
05a2a795 | 418 | .skip_bytes = _skip_bytes, |
5f35b733 | 419 | .clone = _clone_, |
05a2a795 TB |
420 | .destroy = _destroy, |
421 | }, | |
47eb8943 TB |
422 | .get_source = _get_source, |
423 | .get_destination = _get_destination, | |
47eb8943 TB |
424 | .get_next_header = _get_next_header, |
425 | .parse_header = _parse_header, | |
426 | .decrypt = _decrypt, | |
427 | .encrypt = _encrypt, | |
b37758c4 TB |
428 | .get_payload = _get_payload, |
429 | .extract_payload = _extract_payload, | |
47eb8943 TB |
430 | .destroy = _destroy, |
431 | }, | |
05a2a795 | 432 | .packet = packet, |
47eb8943 TB |
433 | .next_header = IPPROTO_NONE, |
434 | ); | |
435 | return this; | |
436 | } | |
437 | ||
438 | /** | |
439 | * Described in header. | |
440 | */ | |
05a2a795 | 441 | esp_packet_t *esp_packet_create_from_packet(packet_t *packet) |
47eb8943 TB |
442 | { |
443 | private_esp_packet_t *this; | |
444 | ||
b37758c4 | 445 | this = esp_packet_create_internal(packet); |
47eb8943 TB |
446 | |
447 | return &this->public; | |
448 | } | |
449 | ||
450 | /** | |
451 | * Described in header. | |
452 | */ | |
453 | esp_packet_t *esp_packet_create_from_payload(host_t *src, host_t *dst, | |
b37758c4 | 454 | ip_packet_t *payload) |
47eb8943 TB |
455 | { |
456 | private_esp_packet_t *this; | |
05a2a795 | 457 | packet_t *packet; |
47eb8943 | 458 | |
05a2a795 | 459 | packet = packet_create_from_data(src, dst, chunk_empty); |
b37758c4 | 460 | this = esp_packet_create_internal(packet); |
47eb8943 | 461 | this->payload = payload; |
b37758c4 TB |
462 | if (payload) |
463 | { | |
464 | this->next_header = payload->get_version(payload) == 4 ? IPPROTO_IPIP | |
465 | : IPPROTO_IPV6; | |
466 | } | |
467 | else | |
468 | { | |
469 | this->next_header = IPPROTO_NONE; | |
470 | } | |
47eb8943 TB |
471 | return &this->public; |
472 | } |