Annotation of embedaddon/strongswan/src/libipsec/esp_packet.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2012-2013 Tobias Brunner
! 3: * Copyright (C) 2012 Giuliano Grassi
! 4: * Copyright (C) 2012 Ralf Sager
! 5: * HSR 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: #ifndef WIN32
! 29: #include <netinet/in.h>
! 30: #endif
! 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: /**
! 45: * Raw ESP packet
! 46: */
! 47: packet_t *packet;
! 48:
! 49: /**
! 50: * Payload of this packet
! 51: */
! 52: ip_packet_t *payload;
! 53:
! 54: /**
! 55: * Next Header info (e.g. IPPROTO_IPIP)
! 56: */
! 57: uint8_t next_header;
! 58:
! 59: };
! 60:
! 61: /**
! 62: * Forward declaration for clone()
! 63: */
! 64: static private_esp_packet_t *esp_packet_create_internal(packet_t *packet);
! 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:
! 102: METHOD(packet_t, get_dscp, uint8_t,
! 103: private_esp_packet_t *this)
! 104: {
! 105: return this->packet->get_dscp(this->packet);
! 106: }
! 107:
! 108: METHOD(packet_t, set_dscp, void,
! 109: private_esp_packet_t *this, uint8_t value)
! 110: {
! 111: this->packet->set_dscp(this->packet, value);
! 112: }
! 113:
! 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:
! 120: METHOD(packet_t, clone_, packet_t*,
! 121: private_esp_packet_t *this)
! 122: {
! 123: private_esp_packet_t *pkt;
! 124:
! 125: pkt = esp_packet_create_internal(this->packet->clone(this->packet));
! 126: pkt->payload = this->payload ? this->payload->clone(this->payload) : NULL;
! 127: pkt->next_header = this->next_header;
! 128: return &pkt->public.packet;
! 129: }
! 130:
! 131: METHOD(esp_packet_t, parse_header, bool,
! 132: private_esp_packet_t *this, uint32_t *spi)
! 133: {
! 134: bio_reader_t *reader;
! 135: uint32_t seq;
! 136:
! 137: reader = bio_reader_create(this->packet->get_data(this->packet));
! 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: {
! 161: if (padding.ptr[i] != (uint8_t)(i + 1))
! 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: */
! 172: static bool remove_padding(private_esp_packet_t *this, chunk_t plaintext)
! 173: {
! 174: uint8_t next_header, pad_length;
! 175: chunk_t padding, payload;
! 176: bio_reader_t *reader;
! 177:
! 178: reader = bio_reader_create(plaintext);
! 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");
! 183: goto failed;
! 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");
! 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");
! 196: return FALSE;
! 197: }
! 198: this->next_header = next_header;
! 199: payload = this->payload->get_encoding(this->payload);
! 200:
! 201: DBG3(DBG_ESP, "ESP payload:\n payload %B\n padding %B\n "
! 202: "padding length = %hhu, next header = %hhu", &payload, &padding,
! 203: pad_length, this->next_header);
! 204: return TRUE;
! 205:
! 206: failed:
! 207: reader->destroy(reader);
! 208: chunk_free(&plaintext);
! 209: return FALSE;
! 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;
! 216: uint32_t spi, seq;
! 217: chunk_t data, iv, icv, aad, ciphertext, plaintext;
! 218: aead_t *aead;
! 219:
! 220: DESTROY_IF(this->payload);
! 221: this->payload = NULL;
! 222:
! 223: data = this->packet->get_data(this->packet);
! 224: aead = esp_context->get_aead(esp_context);
! 225:
! 226: reader = bio_reader_create(data);
! 227: if (!reader->read_uint32(reader, &spi) ||
! 228: !reader->read_uint32(reader, &seq) ||
! 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))
! 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]",
! 243: get_source(this), get_destination(this), spi, seq);
! 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:
! 249: /* include ICV in ciphertext for decryption/verification */
! 250: ciphertext.len += icv.len;
! 251: /* aad = spi + seq */
! 252: aad = chunk_create(data.ptr, 8);
! 253:
! 254: if (!aead->decrypt(aead, ciphertext, aad, iv, &plaintext))
! 255: {
! 256: DBG1(DBG_ESP, "ESP decryption or ICV verification failed");
! 257: return FAILED;
! 258: }
! 259: esp_context->set_authenticated_seqno(esp_context, seq);
! 260:
! 261: if (!remove_padding(this, plaintext))
! 262: {
! 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: {
! 277: padding.ptr[i] = (uint8_t)(i + 1);
! 278: }
! 279: }
! 280:
! 281: METHOD(esp_packet_t, encrypt, status_t,
! 282: private_esp_packet_t *this, esp_context_t *esp_context, uint32_t spi)
! 283: {
! 284: chunk_t iv, icv, aad, padding, payload, ciphertext;
! 285: bio_writer_t *writer;
! 286: uint32_t next_seqno;
! 287: size_t blocksize, plainlen;
! 288: aead_t *aead;
! 289: iv_gen_t *iv_gen;
! 290:
! 291: this->packet->set_data(this->packet, chunk_empty);
! 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:
! 299: aead = esp_context->get_aead(esp_context);
! 300: iv_gen = aead->get_iv_gen(aead);
! 301: if (!iv_gen)
! 302: {
! 303: DBG1(DBG_ESP, "ESP encryption failed: no IV generator");
! 304: return NOT_FOUND;
! 305: }
! 306:
! 307: blocksize = aead->get_block_size(aead);
! 308: iv.len = aead->get_iv_size(aead);
! 309: icv.len = aead->get_icv_size(aead);
! 310:
! 311: /* plaintext = payload, padding, pad_length, next_header */
! 312: payload = this->payload ? this->payload->get_encoding(this->payload)
! 313: : chunk_empty;
! 314: plainlen = payload.len + 2;
! 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);
! 318: plainlen += padding.len;
! 319:
! 320: /* len = spi, seq, IV, plaintext, ICV */
! 321: writer = bio_writer_create(2 * sizeof(uint32_t) + iv.len + plainlen +
! 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);
! 327: if (!iv_gen->get_iv(iv_gen, next_seqno, iv.len, iv.ptr))
! 328: {
! 329: DBG1(DBG_ESP, "ESP encryption failed: could not generate IV");
! 330: writer->destroy(writer);
! 331: return FAILED;
! 332: }
! 333:
! 334: /* plain-/ciphertext will start here */
! 335: ciphertext = writer->get_buf(writer);
! 336: ciphertext.ptr += ciphertext.len;
! 337: ciphertext.len = plainlen;
! 338:
! 339: writer->write_data(writer, payload);
! 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:
! 347: /* aad = spi + seq */
! 348: aad = writer->get_buf(writer);
! 349: aad.len = 8;
! 350: icv = writer->skip(writer, icv.len);
! 351:
! 352: DBG3(DBG_ESP, "ESP before encryption:\n payload = %B\n padding = %B\n "
! 353: "padding length = %hhu, next header = %hhu", &payload, &padding,
! 354: (uint8_t)padding.len, this->next_header);
! 355:
! 356: /* encrypt/authenticate the content inline */
! 357: if (!aead->encrypt(aead, ciphertext, aad, iv, NULL))
! 358: {
! 359: DBG1(DBG_ESP, "ESP encryption or ICV generation failed");
! 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:
! 368: this->packet->set_data(this->packet, writer->extract_buf(writer));
! 369: writer->destroy(writer);
! 370: return SUCCESS;
! 371: }
! 372:
! 373: METHOD(esp_packet_t, get_next_header, uint8_t,
! 374: private_esp_packet_t *this)
! 375: {
! 376: return this->next_header;
! 377: }
! 378:
! 379: METHOD(esp_packet_t, get_payload, ip_packet_t*,
! 380: private_esp_packet_t *this)
! 381: {
! 382: return this->payload;
! 383: }
! 384:
! 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:
! 395: METHOD2(esp_packet_t, packet_t, destroy, void,
! 396: private_esp_packet_t *this)
! 397: {
! 398: DESTROY_IF(this->payload);
! 399: this->packet->destroy(this->packet);
! 400: free(this);
! 401: }
! 402:
! 403: static private_esp_packet_t *esp_packet_create_internal(packet_t *packet)
! 404: {
! 405: private_esp_packet_t *this;
! 406:
! 407: INIT(this,
! 408: .public = {
! 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,
! 416: .get_dscp = _get_dscp,
! 417: .set_dscp = _set_dscp,
! 418: .skip_bytes = _skip_bytes,
! 419: .clone = _clone_,
! 420: .destroy = _destroy,
! 421: },
! 422: .get_source = _get_source,
! 423: .get_destination = _get_destination,
! 424: .get_next_header = _get_next_header,
! 425: .parse_header = _parse_header,
! 426: .decrypt = _decrypt,
! 427: .encrypt = _encrypt,
! 428: .get_payload = _get_payload,
! 429: .extract_payload = _extract_payload,
! 430: .destroy = _destroy,
! 431: },
! 432: .packet = packet,
! 433: .next_header = IPPROTO_NONE,
! 434: );
! 435: return this;
! 436: }
! 437:
! 438: /**
! 439: * Described in header.
! 440: */
! 441: esp_packet_t *esp_packet_create_from_packet(packet_t *packet)
! 442: {
! 443: private_esp_packet_t *this;
! 444:
! 445: this = esp_packet_create_internal(packet);
! 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,
! 454: ip_packet_t *payload)
! 455: {
! 456: private_esp_packet_t *this;
! 457: packet_t *packet;
! 458:
! 459: packet = packet_create_from_data(src, dst, chunk_empty);
! 460: this = esp_packet_create_internal(packet);
! 461: this->payload = payload;
! 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: }
! 471: return &this->public;
! 472: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>