]> git.ipfire.org Git - thirdparty/strongswan.git/blame - src/libipsec/esp_packet.c
libipsec: Fix ip_packet_create_from_data() version field in IPv6 header
[thirdparty/strongswan.git] / src / libipsec / esp_packet.c
CommitLineData
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
32typedef struct private_esp_packet_t private_esp_packet_t;
33
34/**
35 * Private additions to esp_packet_t.
36 */
37struct 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 64static private_esp_packet_t *esp_packet_create_internal(packet_t *packet);
05a2a795
TB
65
66METHOD(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
72METHOD2(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
78METHOD(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
84METHOD2(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
90METHOD(packet_t, get_data, chunk_t,
91 private_esp_packet_t *this)
92{
93 return this->packet->get_data(this->packet);
94}
95
96METHOD(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 102METHOD(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
108METHOD(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
114METHOD(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 120METHOD(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 131METHOD(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 */
155static 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 172static 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
206failed:
207 reader->destroy(reader);
208 chunk_free(&plaintext);
209 return FALSE;
47eb8943
TB
210}
211
212METHOD(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 */
271static 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
281METHOD(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 373METHOD(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 379METHOD(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
385METHOD(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 395METHOD2(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 403static 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 441esp_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 */
453esp_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}