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