From 47eb8943b299900054beded5e21717989ff4bb8e Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Thu, 5 Jul 2012 13:56:24 +0200 Subject: ESP packet wrapper added, handles encryption/decryption/verification etc. --- src/libipsec/esp_packet.c | 402 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 402 insertions(+) create mode 100644 src/libipsec/esp_packet.c (limited to 'src/libipsec/esp_packet.c') diff --git a/src/libipsec/esp_packet.c b/src/libipsec/esp_packet.c new file mode 100644 index 000000000..193bc621d --- /dev/null +++ b/src/libipsec/esp_packet.c @@ -0,0 +1,402 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Copyright (C) 2012 Giuliano Grassi + * Copyright (C) 2012 Ralf Sager + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + + +#include "esp_packet.h" + +#include +#include +#include +#include +#include +#include + +#include + +typedef struct private_esp_packet_t private_esp_packet_t; + +/** + * Private additions to esp_packet_t. + */ +struct private_esp_packet_t { + + /** + * Public members + */ + esp_packet_t public; + + /** + * Source address + */ + host_t *src; + + /** + * Destination address + */ + host_t *dst; + + /** + * Payload of this packet + */ + chunk_t payload; + + /** + * Next Header info (e.g. IPPROTO_IPIP) + */ + u_int8_t next_header; + + /** + * Raw packet data + */ + chunk_t packet_data; +}; + +METHOD(esp_packet_t, parse_header, bool, + private_esp_packet_t *this, u_int32_t *spi) +{ + bio_reader_t *reader; + u_int32_t seq; + + reader = bio_reader_create(this->packet_data); + if (!reader->read_uint32(reader, spi) || + !reader->read_uint32(reader, &seq)) + { + DBG1(DBG_ESP, "failed to parse ESP header: invalid length"); + reader->destroy(reader); + return FALSE; + } + reader->destroy(reader); + + DBG2(DBG_ESP, "parsed ESP header with SPI %.8x [seq %u]", *spi, seq); + *spi = htonl(*spi); + return TRUE; +} + +/** + * Check padding as specified in RFC 4303 + */ +static bool check_padding(chunk_t padding) +{ + size_t i; + + for (i = 0; i < padding.len; ++i) + { + if (padding.ptr[i] != (u_int8_t)(i + 1)) + { + return FALSE; + } + } + return TRUE; +} + +/** + * Remove the padding from the payload and set the next header info + */ +static bool remove_padding(private_esp_packet_t *this) +{ + u_int8_t next_header, pad_length; + chunk_t padding; + bio_reader_t *reader; + + reader = bio_reader_create(this->payload); + if (!reader->read_uint8_end(reader, &next_header) || + !reader->read_uint8_end(reader, &pad_length)) + { + DBG1(DBG_ESP, "parsing ESP payload failed: invalid length"); + reader->destroy(reader); + return FALSE; + } + if (!reader->read_data_end(reader, pad_length, &padding) || + !check_padding(padding)) + { + DBG1(DBG_ESP, "parsing ESP payload failed: invalid padding"); + reader->destroy(reader); + return FALSE; + } + this->payload = reader->peek(reader); + this->next_header = next_header; + reader->destroy(reader); + + DBG3(DBG_ESP, "ESP payload:\n payload %B\n padding %B\n " + "padding length = %hhu, next header = %hhu", &this->payload, + &padding, pad_length, this->next_header); + return TRUE; +} + +METHOD(esp_packet_t, decrypt, status_t, + private_esp_packet_t *this, esp_context_t *esp_context) +{ + bio_reader_t *reader; + u_int32_t spi, seq; + chunk_t spi_seq, iv, icv, ciphertext; + crypter_t *crypter; + signer_t *signer; + + chunk_free(&this->payload); + + crypter = esp_context->get_crypter(esp_context); + signer = esp_context->get_signer(esp_context); + + reader = bio_reader_create(this->packet_data); + if (!reader->read_uint32(reader, &spi) || + !reader->read_uint32(reader, &seq) || + !reader->read_data(reader, crypter->get_iv_size(crypter), &iv) || + !reader->read_data_end(reader, signer->get_block_size(signer), &icv) || + reader->remaining(reader) % crypter->get_block_size(crypter)) + { + DBG1(DBG_ESP, "ESP decryption failed: invalid length"); + return PARSE_ERROR; + } + ciphertext = reader->peek(reader); + reader->destroy(reader); + + if (!esp_context->verify_seqno(esp_context, seq)) + { + DBG1(DBG_ESP, "ESP sequence number verification failed:\n " + "src %H, dst %H, SPI %.8x [seq %u]", + this->src, this->dst, spi, seq); + return VERIFY_ERROR; + } + DBG3(DBG_ESP, "ESP decryption:\n SPI %.8x [seq %u]\n IV %B\n " + "encrypted %B\n ICV %B", spi, seq, &iv, &ciphertext, &icv); + + spi_seq = chunk_create(this->packet_data.ptr, 8); + if (!signer->get_signature(signer, spi_seq, NULL) || + !signer->get_signature(signer, iv, NULL) || + !signer->verify_signature(signer, ciphertext, icv)) + { + DBG1(DBG_ESP, "ICV verification failed!"); + return FAILED; + } + esp_context->set_authenticated_seqno(esp_context, seq); + + if (!crypter->decrypt(crypter, ciphertext, iv, &this->payload)) + { + DBG1(DBG_ESP, "ESP decryption failed"); + return FAILED; + } + + if (!remove_padding(this)) + { + chunk_free(&this->payload); + return PARSE_ERROR; + } + return SUCCESS; +} + +/** + * Generate the padding as specified in RFC4303 + */ +static void generate_padding(chunk_t padding) +{ + size_t i; + + for (i = 0; i < padding.len; ++i) + { + padding.ptr[i] = (u_int8_t)(i + 1); + } +} + +METHOD(esp_packet_t, encrypt, status_t, + private_esp_packet_t *this, esp_context_t *esp_context, u_int32_t spi) +{ + chunk_t iv, icv, padding, ciphertext, auth_data; + bio_writer_t *writer; + u_int32_t next_seqno; + size_t blocksize, plainlen; + crypter_t *crypter; + signer_t *signer; + rng_t *rng; + + chunk_free(&this->packet_data); + + if (!esp_context->next_seqno(esp_context, &next_seqno)) + { + DBG1(DBG_ESP, "ESP encapsulation failed: sequence numbers cycled"); + return FAILED; + } + + rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); + if (!rng) + { + DBG1(DBG_ESP, "ESP encryption failed: could not find RNG"); + return NOT_FOUND; + } + crypter = esp_context->get_crypter(esp_context); + signer = esp_context->get_signer(esp_context); + + blocksize = crypter->get_block_size(crypter); + iv.len = crypter->get_iv_size(crypter); + icv.len = signer->get_block_size(signer); + + /* plaintext = payload, padding, pad_length, next_header */ + plainlen = this->payload.len + 2; + padding.len = blocksize - (plainlen % blocksize); + plainlen += padding.len; + + /* len = spi, seq, IV, plaintext, ICV */ + writer = bio_writer_create(2 * sizeof(u_int32_t) + iv.len + plainlen + + icv.len); + writer->write_uint32(writer, ntohl(spi)); + writer->write_uint32(writer, next_seqno); + + iv = writer->skip(writer, iv.len); + if (!rng->get_bytes(rng, iv.len, iv.ptr)) + { + DBG1(DBG_ESP, "ESP encryption failed: could not generate IV"); + writer->destroy(writer); + rng->destroy(rng); + return FAILED; + } + rng->destroy(rng); + + /* plain-/ciphertext will start here */ + ciphertext = writer->get_buf(writer); + ciphertext.ptr += ciphertext.len; + ciphertext.len = plainlen; + + writer->write_data(writer, this->payload); + + padding = writer->skip(writer, padding.len); + generate_padding(padding); + + writer->write_uint8(writer, padding.len); + writer->write_uint8(writer, this->next_header); + + DBG3(DBG_ESP, "ESP before encryption:\n payload = %B\n padding = %B\n " + "padding length = %hhu, next header = %hhu", &this->payload, &padding, + (u_int8_t)padding.len, this->next_header); + + /* encrypt the content inline */ + if (!crypter->encrypt(crypter, ciphertext, iv, NULL)) + { + DBG1(DBG_ESP, "ESP encryption failed"); + writer->destroy(writer); + return FAILED; + } + + /* calculate signature */ + auth_data = writer->get_buf(writer); + icv = writer->skip(writer, icv.len); + if (!signer->get_signature(signer, auth_data, icv.ptr)) + { + DBG1(DBG_ESP, "ESP encryption failed: signature generation failed"); + writer->destroy(writer); + return FAILED; + } + + DBG3(DBG_ESP, "ESP packet:\n SPI %.8x [seq %u]\n IV %B\n " + "encrypted %B\n ICV %B", ntohl(spi), next_seqno, &iv, + &ciphertext, &icv); + + this->packet_data = writer->extract_buf(writer); + writer->destroy(writer); + return SUCCESS; +} + +METHOD(esp_packet_t, get_next_header, u_int8_t, + private_esp_packet_t *this) +{ + return this->next_header; +} + +METHOD(esp_packet_t, get_payload, chunk_t, + private_esp_packet_t *this) +{ + return this->payload; +} + +METHOD(esp_packet_t, get_packet_data, chunk_t, + private_esp_packet_t *this) +{ + return this->packet_data; +} + +METHOD(esp_packet_t, get_source, host_t*, + private_esp_packet_t *this) +{ + return this->src; +} + +METHOD(esp_packet_t, get_destination, host_t*, + private_esp_packet_t *this) +{ + return this->dst; +} + +METHOD(esp_packet_t, destroy, void, + private_esp_packet_t *this) +{ + chunk_free(&this->payload); + chunk_free(&this->packet_data); + this->src->destroy(this->src); + this->dst->destroy(this->dst); + free(this); +} + +static private_esp_packet_t *esp_packet_create_empty(host_t *src, host_t *dst) +{ + private_esp_packet_t *this; + + INIT(this, + .public = { + .get_source = _get_source, + .get_destination = _get_destination, + .get_packet_data = _get_packet_data, + .get_payload = _get_payload, + .get_next_header = _get_next_header, + .parse_header = _parse_header, + .decrypt = _decrypt, + .encrypt = _encrypt, + .destroy = _destroy, + }, + .src = src, + .dst = dst, + .next_header = IPPROTO_NONE, + ); + return this; +} + +/** + * Described in header. + */ +esp_packet_t *esp_packet_create_from_packet(host_t *src, host_t *dst, + chunk_t packet_data) +{ + private_esp_packet_t *this; + + this = esp_packet_create_empty(src, dst); + this->packet_data = packet_data; + + return &this->public; +} + +/** + * Described in header. + */ +esp_packet_t *esp_packet_create_from_payload(host_t *src, host_t *dst, + chunk_t payload, u_int8_t next_header) +{ + private_esp_packet_t *this; + + this = esp_packet_create_empty(src, dst); + this->next_header = next_header; + this->payload = payload; + + return &this->public; +} + -- cgit v1.2.3 From 05a2a7950cb5ea440b41882da05f1eae280ba979 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Sat, 7 Jul 2012 13:31:07 +0200 Subject: esp_packet_t implements packet_t interface This should allow to avoid unnecessary cloning of packet data. --- src/libipsec/esp_packet.c | 142 +++++++++++++++++++++++++++++----------------- 1 file changed, 90 insertions(+), 52 deletions(-) (limited to 'src/libipsec/esp_packet.c') diff --git a/src/libipsec/esp_packet.c b/src/libipsec/esp_packet.c index 193bc621d..75d8a7a94 100644 --- a/src/libipsec/esp_packet.c +++ b/src/libipsec/esp_packet.c @@ -40,14 +40,9 @@ struct private_esp_packet_t { esp_packet_t public; /** - * Source address + * Raw ESP packet */ - host_t *src; - - /** - * Destination address - */ - host_t *dst; + packet_t *packet; /** * Payload of this packet @@ -59,19 +54,73 @@ struct private_esp_packet_t { */ u_int8_t next_header; - /** - * Raw packet data - */ - chunk_t packet_data; }; +/** + * Forward declaration for clone() + */ +static private_esp_packet_t *esp_packet_create_empty(packet_t *packet); + +METHOD(packet_t, set_source, void, + private_esp_packet_t *this, host_t *src) +{ + return this->packet->set_source(this->packet, src); +} + +METHOD2(esp_packet_t, packet_t, get_source, host_t*, + private_esp_packet_t *this) +{ + return this->packet->get_source(this->packet); +} + +METHOD(packet_t, set_destination, void, + private_esp_packet_t *this, host_t *dst) +{ + return this->packet->set_destination(this->packet, dst); +} + +METHOD2(esp_packet_t, packet_t, get_destination, host_t*, + private_esp_packet_t *this) +{ + return this->packet->get_destination(this->packet); +} + +METHOD(packet_t, get_data, chunk_t, + private_esp_packet_t *this) +{ + return this->packet->get_data(this->packet); +} + +METHOD(packet_t, set_data, void, + private_esp_packet_t *this, chunk_t data) +{ + return this->packet->set_data(this->packet, data); +} + +METHOD(packet_t, skip_bytes, void, + private_esp_packet_t *this, size_t bytes) +{ + return this->packet->skip_bytes(this->packet, bytes); +} + +METHOD(packet_t, clone, packet_t*, + private_esp_packet_t *this) +{ + private_esp_packet_t *pkt; + + pkt = esp_packet_create_empty(this->packet->clone(this->packet)); + pkt->payload = chunk_clone(this->payload); + pkt->next_header = this->next_header; + return &pkt->public.packet; +} + METHOD(esp_packet_t, parse_header, bool, private_esp_packet_t *this, u_int32_t *spi) { bio_reader_t *reader; u_int32_t seq; - reader = bio_reader_create(this->packet_data); + reader = bio_reader_create(this->packet->get_data(this->packet)); if (!reader->read_uint32(reader, spi) || !reader->read_uint32(reader, &seq)) { @@ -142,16 +191,17 @@ METHOD(esp_packet_t, decrypt, status_t, { bio_reader_t *reader; u_int32_t spi, seq; - chunk_t spi_seq, iv, icv, ciphertext; + chunk_t data, iv, icv, ciphertext; crypter_t *crypter; signer_t *signer; chunk_free(&this->payload); + data = this->packet->get_data(this->packet); crypter = esp_context->get_crypter(esp_context); signer = esp_context->get_signer(esp_context); - reader = bio_reader_create(this->packet_data); + reader = bio_reader_create(data); if (!reader->read_uint32(reader, &spi) || !reader->read_uint32(reader, &seq) || !reader->read_data(reader, crypter->get_iv_size(crypter), &iv) || @@ -168,14 +218,13 @@ METHOD(esp_packet_t, decrypt, status_t, { DBG1(DBG_ESP, "ESP sequence number verification failed:\n " "src %H, dst %H, SPI %.8x [seq %u]", - this->src, this->dst, spi, seq); + get_source(this), get_destination(this), spi, seq); return VERIFY_ERROR; } DBG3(DBG_ESP, "ESP decryption:\n SPI %.8x [seq %u]\n IV %B\n " "encrypted %B\n ICV %B", spi, seq, &iv, &ciphertext, &icv); - spi_seq = chunk_create(this->packet_data.ptr, 8); - if (!signer->get_signature(signer, spi_seq, NULL) || + if (!signer->get_signature(signer, chunk_create(data.ptr, 8), NULL) || !signer->get_signature(signer, iv, NULL) || !signer->verify_signature(signer, ciphertext, icv)) { @@ -222,7 +271,7 @@ METHOD(esp_packet_t, encrypt, status_t, signer_t *signer; rng_t *rng; - chunk_free(&this->packet_data); + this->packet->set_data(this->packet, chunk_empty); if (!esp_context->next_seqno(esp_context, &next_seqno)) { @@ -303,7 +352,7 @@ METHOD(esp_packet_t, encrypt, status_t, "encrypted %B\n ICV %B", ntohl(spi), next_seqno, &iv, &ciphertext, &icv); - this->packet_data = writer->extract_buf(writer); + this->packet->set_data(this->packet, writer->extract_buf(writer)); writer->destroy(writer); return SUCCESS; } @@ -320,43 +369,33 @@ METHOD(esp_packet_t, get_payload, chunk_t, return this->payload; } -METHOD(esp_packet_t, get_packet_data, chunk_t, - private_esp_packet_t *this) -{ - return this->packet_data; -} - -METHOD(esp_packet_t, get_source, host_t*, - private_esp_packet_t *this) -{ - return this->src; -} - -METHOD(esp_packet_t, get_destination, host_t*, - private_esp_packet_t *this) -{ - return this->dst; -} - -METHOD(esp_packet_t, destroy, void, +METHOD2(esp_packet_t, packet_t, destroy, void, private_esp_packet_t *this) { chunk_free(&this->payload); - chunk_free(&this->packet_data); - this->src->destroy(this->src); - this->dst->destroy(this->dst); + this->packet->destroy(this->packet); free(this); } -static private_esp_packet_t *esp_packet_create_empty(host_t *src, host_t *dst) +static private_esp_packet_t *esp_packet_create_empty(packet_t *packet) { private_esp_packet_t *this; INIT(this, .public = { + .packet = { + .set_source = _set_source, + .get_source = _get_source, + .set_destination = _set_destination, + .get_destination = _get_destination, + .get_data = _get_data, + .set_data = _set_data, + .skip_bytes = _skip_bytes, + .clone = _clone, + .destroy = _destroy, + }, .get_source = _get_source, .get_destination = _get_destination, - .get_packet_data = _get_packet_data, .get_payload = _get_payload, .get_next_header = _get_next_header, .parse_header = _parse_header, @@ -364,8 +403,7 @@ static private_esp_packet_t *esp_packet_create_empty(host_t *src, host_t *dst) .encrypt = _encrypt, .destroy = _destroy, }, - .src = src, - .dst = dst, + .packet = packet, .next_header = IPPROTO_NONE, ); return this; @@ -374,13 +412,11 @@ static private_esp_packet_t *esp_packet_create_empty(host_t *src, host_t *dst) /** * Described in header. */ -esp_packet_t *esp_packet_create_from_packet(host_t *src, host_t *dst, - chunk_t packet_data) +esp_packet_t *esp_packet_create_from_packet(packet_t *packet) { private_esp_packet_t *this; - this = esp_packet_create_empty(src, dst); - this->packet_data = packet_data; + this = esp_packet_create_empty(packet); return &this->public; } @@ -389,14 +425,16 @@ esp_packet_t *esp_packet_create_from_packet(host_t *src, host_t *dst, * Described in header. */ esp_packet_t *esp_packet_create_from_payload(host_t *src, host_t *dst, - chunk_t payload, u_int8_t next_header) + chunk_t payload, + u_int8_t next_header) { private_esp_packet_t *this; + packet_t *packet; - this = esp_packet_create_empty(src, dst); + packet = packet_create_from_data(src, dst, chunk_empty); + this = esp_packet_create_empty(packet); this->next_header = next_header; this->payload = payload; return &this->public; } - -- cgit v1.2.3 From b37758c41eb3137a4398847e729d6fa3d70617a6 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Fri, 13 Jul 2012 15:23:00 +0200 Subject: Represent the payload of an ESP packet as ip_packet_t instead of a chunk_t --- src/libipsec/esp_packet.c | 94 ++++++++++++++++++++++++++++++----------------- 1 file changed, 61 insertions(+), 33 deletions(-) (limited to 'src/libipsec/esp_packet.c') diff --git a/src/libipsec/esp_packet.c b/src/libipsec/esp_packet.c index 75d8a7a94..bfcab95eb 100644 --- a/src/libipsec/esp_packet.c +++ b/src/libipsec/esp_packet.c @@ -47,7 +47,7 @@ struct private_esp_packet_t { /** * Payload of this packet */ - chunk_t payload; + ip_packet_t *payload; /** * Next Header info (e.g. IPPROTO_IPIP) @@ -59,7 +59,7 @@ struct private_esp_packet_t { /** * Forward declaration for clone() */ -static private_esp_packet_t *esp_packet_create_empty(packet_t *packet); +static private_esp_packet_t *esp_packet_create_internal(packet_t *packet); METHOD(packet_t, set_source, void, private_esp_packet_t *this, host_t *src) @@ -108,8 +108,8 @@ METHOD(packet_t, clone, packet_t*, { private_esp_packet_t *pkt; - pkt = esp_packet_create_empty(this->packet->clone(this->packet)); - pkt->payload = chunk_clone(this->payload); + pkt = esp_packet_create_internal(this->packet->clone(this->packet)); + pkt->payload = this->payload ? this->payload->clone(this->payload) : NULL; pkt->next_header = this->next_header; return &pkt->public.packet; } @@ -155,35 +155,44 @@ static bool check_padding(chunk_t padding) /** * Remove the padding from the payload and set the next header info */ -static bool remove_padding(private_esp_packet_t *this) +static bool remove_padding(private_esp_packet_t *this, chunk_t plaintext) { u_int8_t next_header, pad_length; - chunk_t padding; + chunk_t padding, payload; bio_reader_t *reader; - reader = bio_reader_create(this->payload); + reader = bio_reader_create(plaintext); if (!reader->read_uint8_end(reader, &next_header) || !reader->read_uint8_end(reader, &pad_length)) { DBG1(DBG_ESP, "parsing ESP payload failed: invalid length"); - reader->destroy(reader); - return FALSE; + goto failed; } if (!reader->read_data_end(reader, pad_length, &padding) || !check_padding(padding)) { DBG1(DBG_ESP, "parsing ESP payload failed: invalid padding"); - reader->destroy(reader); + goto failed; + } + this->payload = ip_packet_create(reader->peek(reader)); + reader->destroy(reader); + if (!this->payload) + { + DBG1(DBG_ESP, "parsing ESP payload failed: unsupported payload"); return FALSE; } - this->payload = reader->peek(reader); this->next_header = next_header; - reader->destroy(reader); + payload = this->payload->get_encoding(this->payload); DBG3(DBG_ESP, "ESP payload:\n payload %B\n padding %B\n " - "padding length = %hhu, next header = %hhu", &this->payload, - &padding, pad_length, this->next_header); + "padding length = %hhu, next header = %hhu", &payload, &padding, + pad_length, this->next_header); return TRUE; + +failed: + reader->destroy(reader); + chunk_free(&plaintext); + return FALSE; } METHOD(esp_packet_t, decrypt, status_t, @@ -191,11 +200,12 @@ METHOD(esp_packet_t, decrypt, status_t, { bio_reader_t *reader; u_int32_t spi, seq; - chunk_t data, iv, icv, ciphertext; + chunk_t data, iv, icv, ciphertext, plaintext; crypter_t *crypter; signer_t *signer; - chunk_free(&this->payload); + DESTROY_IF(this->payload); + this->payload = NULL; data = this->packet->get_data(this->packet); crypter = esp_context->get_crypter(esp_context); @@ -233,15 +243,14 @@ METHOD(esp_packet_t, decrypt, status_t, } esp_context->set_authenticated_seqno(esp_context, seq); - if (!crypter->decrypt(crypter, ciphertext, iv, &this->payload)) + if (!crypter->decrypt(crypter, ciphertext, iv, &plaintext)) { DBG1(DBG_ESP, "ESP decryption failed"); return FAILED; } - if (!remove_padding(this)) + if (!remove_padding(this, plaintext)) { - chunk_free(&this->payload); return PARSE_ERROR; } return SUCCESS; @@ -263,7 +272,7 @@ static void generate_padding(chunk_t padding) METHOD(esp_packet_t, encrypt, status_t, private_esp_packet_t *this, esp_context_t *esp_context, u_int32_t spi) { - chunk_t iv, icv, padding, ciphertext, auth_data; + chunk_t iv, icv, padding, payload, ciphertext, auth_data; bio_writer_t *writer; u_int32_t next_seqno; size_t blocksize, plainlen; @@ -293,7 +302,9 @@ METHOD(esp_packet_t, encrypt, status_t, icv.len = signer->get_block_size(signer); /* plaintext = payload, padding, pad_length, next_header */ - plainlen = this->payload.len + 2; + payload = this->payload ? this->payload->get_encoding(this->payload) + : chunk_empty; + plainlen = payload.len + 2; padding.len = blocksize - (plainlen % blocksize); plainlen += padding.len; @@ -318,7 +329,7 @@ METHOD(esp_packet_t, encrypt, status_t, ciphertext.ptr += ciphertext.len; ciphertext.len = plainlen; - writer->write_data(writer, this->payload); + writer->write_data(writer, payload); padding = writer->skip(writer, padding.len); generate_padding(padding); @@ -327,7 +338,7 @@ METHOD(esp_packet_t, encrypt, status_t, writer->write_uint8(writer, this->next_header); DBG3(DBG_ESP, "ESP before encryption:\n payload = %B\n padding = %B\n " - "padding length = %hhu, next header = %hhu", &this->payload, &padding, + "padding length = %hhu, next header = %hhu", &payload, &padding, (u_int8_t)padding.len, this->next_header); /* encrypt the content inline */ @@ -363,21 +374,31 @@ METHOD(esp_packet_t, get_next_header, u_int8_t, return this->next_header; } -METHOD(esp_packet_t, get_payload, chunk_t, +METHOD(esp_packet_t, get_payload, ip_packet_t*, private_esp_packet_t *this) { return this->payload; } +METHOD(esp_packet_t, extract_payload, ip_packet_t*, + private_esp_packet_t *this) +{ + ip_packet_t *payload; + + payload = this->payload; + this->payload = NULL; + return payload; +} + METHOD2(esp_packet_t, packet_t, destroy, void, private_esp_packet_t *this) { - chunk_free(&this->payload); + DESTROY_IF(this->payload); this->packet->destroy(this->packet); free(this); } -static private_esp_packet_t *esp_packet_create_empty(packet_t *packet) +static private_esp_packet_t *esp_packet_create_internal(packet_t *packet) { private_esp_packet_t *this; @@ -396,11 +417,12 @@ static private_esp_packet_t *esp_packet_create_empty(packet_t *packet) }, .get_source = _get_source, .get_destination = _get_destination, - .get_payload = _get_payload, .get_next_header = _get_next_header, .parse_header = _parse_header, .decrypt = _decrypt, .encrypt = _encrypt, + .get_payload = _get_payload, + .extract_payload = _extract_payload, .destroy = _destroy, }, .packet = packet, @@ -416,7 +438,7 @@ esp_packet_t *esp_packet_create_from_packet(packet_t *packet) { private_esp_packet_t *this; - this = esp_packet_create_empty(packet); + this = esp_packet_create_internal(packet); return &this->public; } @@ -425,16 +447,22 @@ esp_packet_t *esp_packet_create_from_packet(packet_t *packet) * Described in header. */ esp_packet_t *esp_packet_create_from_payload(host_t *src, host_t *dst, - chunk_t payload, - u_int8_t next_header) + ip_packet_t *payload) { private_esp_packet_t *this; packet_t *packet; packet = packet_create_from_data(src, dst, chunk_empty); - this = esp_packet_create_empty(packet); - this->next_header = next_header; + this = esp_packet_create_internal(packet); this->payload = payload; - + if (payload) + { + this->next_header = payload->get_version(payload) == 4 ? IPPROTO_IPIP + : IPPROTO_IPV6; + } + else + { + this->next_header = IPPROTO_NONE; + } return &this->public; } -- cgit v1.2.3