Return to esp_packet.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / libipsec |
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: }