Annotation of embedaddon/strongswan/src/libcharon/encoding/payloads/encrypted_payload.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2011-2018 Tobias Brunner
! 3: * Copyright (C) 2005-2010 Martin Willi
! 4: * Copyright (C) 2010 revosec AG
! 5: * Copyright (C) 2005 Jan Hutter
! 6: * HSR Hochschule fuer Technik Rapperswil
! 7: *
! 8: * This program is free software; you can redistribute it and/or modify it
! 9: * under the terms of the GNU General Public License as published by the
! 10: * Free Software Foundation; either version 2 of the License, or (at your
! 11: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
! 12: *
! 13: * This program is distributed in the hope that it will be useful, but
! 14: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
! 15: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
! 16: * for more details.
! 17: */
! 18:
! 19: #include <stddef.h>
! 20: #include <string.h>
! 21:
! 22: #include "encrypted_payload.h"
! 23: #include "encrypted_fragment_payload.h"
! 24:
! 25: #include <daemon.h>
! 26: #include <encoding/payloads/encodings.h>
! 27: #include <collections/linked_list.h>
! 28: #include <encoding/parser.h>
! 29:
! 30: typedef struct private_encrypted_payload_t private_encrypted_payload_t;
! 31: typedef struct private_encrypted_fragment_payload_t private_encrypted_fragment_payload_t;
! 32:
! 33: struct private_encrypted_payload_t {
! 34:
! 35: /**
! 36: * Public encrypted_payload_t interface.
! 37: */
! 38: encrypted_payload_t public;
! 39:
! 40: /**
! 41: * There is no next payload for an encrypted payload,
! 42: * since encrypted payload MUST be the last one.
! 43: * next_payload means here the first payload of the
! 44: * contained, encrypted payload.
! 45: */
! 46: uint8_t next_payload;
! 47:
! 48: /**
! 49: * Flags, including reserved bits
! 50: */
! 51: uint8_t flags;
! 52:
! 53: /**
! 54: * Length of this payload
! 55: */
! 56: uint16_t payload_length;
! 57:
! 58: /**
! 59: * Chunk containing the IV, plain, padding and ICV.
! 60: */
! 61: chunk_t encrypted;
! 62:
! 63: /**
! 64: * AEAD transform to use
! 65: */
! 66: aead_t *aead;
! 67:
! 68: /**
! 69: * Contained payloads
! 70: */
! 71: linked_list_t *payloads;
! 72:
! 73: /**
! 74: * Type of payload, PLV2_ENCRYPTED or PLV1_ENCRYPTED
! 75: */
! 76: payload_type_t type;
! 77: };
! 78:
! 79: struct private_encrypted_fragment_payload_t {
! 80:
! 81: /**
! 82: * Public interface.
! 83: */
! 84: encrypted_fragment_payload_t public;
! 85:
! 86: /**
! 87: * The first fragment contains the type of the first payload contained in
! 88: * the original encrypted payload, for all other fragments it MUST be set
! 89: * to zero.
! 90: */
! 91: uint8_t next_payload;
! 92:
! 93: /**
! 94: * Flags, including reserved bits
! 95: */
! 96: uint8_t flags;
! 97:
! 98: /**
! 99: * Length of this payload
! 100: */
! 101: uint16_t payload_length;
! 102:
! 103: /**
! 104: * Chunk containing the IV, plain, padding and ICV.
! 105: */
! 106: chunk_t encrypted;
! 107:
! 108: /**
! 109: * Fragment number
! 110: */
! 111: uint16_t fragment_number;
! 112:
! 113: /**
! 114: * Total fragments
! 115: */
! 116: uint16_t total_fragments;
! 117:
! 118: /**
! 119: * AEAD transform to use
! 120: */
! 121: aead_t *aead;
! 122:
! 123: /**
! 124: * Chunk containing the plain packet data.
! 125: */
! 126: chunk_t plain;
! 127: };
! 128:
! 129: /**
! 130: * Encoding rules to parse or generate a IKEv2-Encrypted Payload.
! 131: *
! 132: * The defined offsets are the positions in a object of type
! 133: * private_encrypted_payload_t.
! 134: */
! 135: static encoding_rule_t encodings_v2[] = {
! 136: /* 1 Byte next payload type, stored in the field next_payload */
! 137: { U_INT_8, offsetof(private_encrypted_payload_t, next_payload) },
! 138: /* Critical and 7 reserved bits, all stored for reconstruction */
! 139: { U_INT_8, offsetof(private_encrypted_payload_t, flags) },
! 140: /* Length of the whole encrypted payload*/
! 141: { PAYLOAD_LENGTH, offsetof(private_encrypted_payload_t, payload_length) },
! 142: /* encrypted data, stored in a chunk. contains iv, data, padding */
! 143: { CHUNK_DATA, offsetof(private_encrypted_payload_t, encrypted) },
! 144: };
! 145:
! 146: /*
! 147: 1 2 3
! 148: 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
! 149: +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! 150: ! Next Payload !C! RESERVED ! Payload Length !
! 151: +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! 152: ! Initialization Vector !
! 153: ! (length is block size for encryption algorithm) !
! 154: +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! 155: ! Encrypted IKE Payloads !
! 156: + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! 157: ! ! Padding (0-255 octets) !
! 158: +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+
! 159: ! ! Pad Length !
! 160: +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! 161: ~ Integrity Checksum Data ~
! 162: +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! 163: */
! 164:
! 165: /**
! 166: * Encoding rules to parse or generate a complete encrypted IKEv1 message.
! 167: *
! 168: * The defined offsets are the positions in a object of type
! 169: * private_encrypted_payload_t.
! 170: */
! 171: static encoding_rule_t encodings_v1[] = {
! 172: /* encrypted data, stored in a chunk */
! 173: { ENCRYPTED_DATA, offsetof(private_encrypted_payload_t, encrypted) },
! 174: };
! 175:
! 176: /*
! 177: 1 2 3
! 178: 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
! 179: +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! 180: ! Encrypted IKE Payloads !
! 181: + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! 182: ! ! Padding (0-255 octets) !
! 183: +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! 184: */
! 185:
! 186: /**
! 187: * Encoding rules to parse or generate an IKEv2-Encrypted Fragment Payload.
! 188: *
! 189: * The defined offsets are the positions in a object of type
! 190: * private_encrypted_payload_t.
! 191: */
! 192: static encoding_rule_t encodings_fragment[] = {
! 193: /* 1 Byte next payload type, stored in the field next_payload */
! 194: { U_INT_8, offsetof(private_encrypted_fragment_payload_t, next_payload) },
! 195: /* Critical and 7 reserved bits, all stored for reconstruction */
! 196: { U_INT_8, offsetof(private_encrypted_fragment_payload_t, flags) },
! 197: /* Length of the whole encryption payload*/
! 198: { PAYLOAD_LENGTH, offsetof(private_encrypted_fragment_payload_t, payload_length) },
! 199: /* Fragment number */
! 200: { U_INT_16, offsetof(private_encrypted_fragment_payload_t, fragment_number) },
! 201: /* Total number of fragments */
! 202: { U_INT_16, offsetof(private_encrypted_fragment_payload_t, total_fragments) },
! 203: /* encrypted data, stored in a chunk. contains iv, data, padding */
! 204: { CHUNK_DATA, offsetof(private_encrypted_fragment_payload_t, encrypted) },
! 205: };
! 206:
! 207: /*
! 208: 1 2 3
! 209: 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
! 210: +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! 211: ! Next Payload !C! RESERVED ! Payload Length !
! 212: +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! 213: ! Fragment Number | Total Fragments !
! 214: +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! 215: ! Initialization Vector !
! 216: +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! 217: ! Encrypted IKE Payloads !
! 218: + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! 219: ! ! Padding (0-255 octets) !
! 220: +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+
! 221: ! ! Pad Length !
! 222: +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! 223: ~ Integrity Checksum Data ~
! 224: +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! 225: */
! 226:
! 227: METHOD(payload_t, verify, status_t,
! 228: private_encrypted_payload_t *this)
! 229: {
! 230: return SUCCESS;
! 231: }
! 232:
! 233: METHOD(payload_t, get_encoding_rules, int,
! 234: private_encrypted_payload_t *this, encoding_rule_t **rules)
! 235: {
! 236: if (this->type == PLV2_ENCRYPTED)
! 237: {
! 238: *rules = encodings_v2;
! 239: return countof(encodings_v2);
! 240: }
! 241: *rules = encodings_v1;
! 242: return countof(encodings_v1);
! 243: }
! 244:
! 245: METHOD(payload_t, get_header_length, int,
! 246: private_encrypted_payload_t *this)
! 247: {
! 248: if (this->type == PLV2_ENCRYPTED)
! 249: {
! 250: return 4;
! 251: }
! 252: return 0;
! 253: }
! 254:
! 255: METHOD(payload_t, get_type, payload_type_t,
! 256: private_encrypted_payload_t *this)
! 257: {
! 258: return this->type;
! 259: }
! 260:
! 261: METHOD(payload_t, get_next_type, payload_type_t,
! 262: private_encrypted_payload_t *this)
! 263: {
! 264: return this->next_payload;
! 265: }
! 266:
! 267: METHOD(payload_t, set_next_type, void,
! 268: private_encrypted_payload_t *this, payload_type_t type)
! 269: {
! 270: /* the next payload is set during add, still allow this for IKEv1 */
! 271: this->next_payload = type;
! 272: }
! 273:
! 274: /**
! 275: * Get length of encryption/integrity overhead for the given plaintext length
! 276: */
! 277: static size_t compute_overhead(aead_t *aead, size_t len)
! 278: {
! 279: size_t bs, overhead;
! 280:
! 281: /* padding */
! 282: bs = aead->get_block_size(aead);
! 283: overhead = bs - (len % bs);
! 284: /* add iv */
! 285: overhead += aead->get_iv_size(aead);
! 286: /* add icv */
! 287: overhead += aead->get_icv_size(aead);
! 288: return overhead;
! 289: }
! 290:
! 291: /**
! 292: * Compute the length of the whole payload
! 293: */
! 294: static void compute_length(private_encrypted_payload_t *this)
! 295: {
! 296: enumerator_t *enumerator;
! 297: payload_t *payload;
! 298: size_t length = 0;
! 299:
! 300: if (this->encrypted.len)
! 301: {
! 302: length = this->encrypted.len;
! 303: }
! 304: else
! 305: {
! 306: enumerator = this->payloads->create_enumerator(this->payloads);
! 307: while (enumerator->enumerate(enumerator, &payload))
! 308: {
! 309: length += payload->get_length(payload);
! 310: }
! 311: enumerator->destroy(enumerator);
! 312:
! 313: if (this->aead)
! 314: {
! 315: length += compute_overhead(this->aead, length);
! 316: }
! 317: }
! 318: length += get_header_length(this);
! 319: this->payload_length = length;
! 320: }
! 321:
! 322: METHOD2(payload_t, encrypted_payload_t, get_length, size_t,
! 323: private_encrypted_payload_t *this)
! 324: {
! 325: compute_length(this);
! 326: return this->payload_length;
! 327: }
! 328:
! 329: METHOD2(payload_t, encrypted_payload_t, get_length_plain, size_t,
! 330: private_encrypted_payload_t *this)
! 331: {
! 332: /* contains only the decrypted payload data, no IV, padding or ICV */
! 333: this->payload_length = this->encrypted.len;
! 334:
! 335: if (this->aead)
! 336: {
! 337: this->payload_length += compute_overhead(this->aead,
! 338: this->payload_length);
! 339: }
! 340: this->payload_length += get_header_length(this);
! 341: return this->payload_length;
! 342: }
! 343:
! 344: METHOD(encrypted_payload_t, add_payload, void,
! 345: private_encrypted_payload_t *this, payload_t *payload)
! 346: {
! 347: payload_t *last_payload;
! 348:
! 349: if (this->payloads->get_count(this->payloads) > 0)
! 350: {
! 351: this->payloads->get_last(this->payloads, (void **)&last_payload);
! 352: last_payload->set_next_type(last_payload, payload->get_type(payload));
! 353: }
! 354: else
! 355: {
! 356: this->next_payload = payload->get_type(payload);
! 357: }
! 358: payload->set_next_type(payload, PL_NONE);
! 359: this->payloads->insert_last(this->payloads, payload);
! 360: compute_length(this);
! 361: }
! 362:
! 363: METHOD(encrypted_payload_t, remove_payload, payload_t *,
! 364: private_encrypted_payload_t *this)
! 365: {
! 366: payload_t *payload;
! 367:
! 368: if (this->payloads->remove_first(this->payloads,
! 369: (void**)&payload) == SUCCESS)
! 370: {
! 371: return payload;
! 372: }
! 373: return NULL;
! 374: }
! 375:
! 376: /**
! 377: * Generate payload before encryption
! 378: */
! 379: static chunk_t generate(private_encrypted_payload_t *this,
! 380: generator_t *generator)
! 381: {
! 382: payload_t *current, *next;
! 383: enumerator_t *enumerator;
! 384: uint32_t *lenpos;
! 385: chunk_t chunk = chunk_empty;
! 386:
! 387: enumerator = this->payloads->create_enumerator(this->payloads);
! 388: if (enumerator->enumerate(enumerator, ¤t))
! 389: {
! 390: this->next_payload = current->get_type(current);
! 391:
! 392: while (enumerator->enumerate(enumerator, &next))
! 393: {
! 394: current->set_next_type(current, next->get_type(next));
! 395: generator->generate_payload(generator, current);
! 396: current = next;
! 397: }
! 398: current->set_next_type(current, PL_NONE);
! 399: generator->generate_payload(generator, current);
! 400:
! 401: chunk = generator->get_chunk(generator, &lenpos);
! 402: DBG2(DBG_ENC, "generated content in encrypted payload");
! 403: }
! 404: enumerator->destroy(enumerator);
! 405: return chunk;
! 406: }
! 407:
! 408: METHOD(encrypted_payload_t, generate_payloads, void,
! 409: private_encrypted_payload_t *this, generator_t *generator)
! 410: {
! 411: generate(this, generator);
! 412: }
! 413:
! 414: /**
! 415: * Append the encrypted payload header to the associated data
! 416: */
! 417: static chunk_t append_header(private_encrypted_payload_t *this, chunk_t assoc)
! 418: {
! 419: struct {
! 420: uint8_t next_payload;
! 421: uint8_t flags;
! 422: uint16_t length;
! 423: } __attribute__((packed)) header = {
! 424: .next_payload = this->next_payload,
! 425: .flags = this->flags,
! 426: .length = htons(get_length(this)),
! 427: };
! 428: return chunk_cat("cc", assoc, chunk_from_thing(header));
! 429: }
! 430:
! 431: /**
! 432: * Encrypts the data in plain and returns it in an allocated chunk.
! 433: */
! 434: static status_t encrypt_content(char *label, aead_t *aead, uint64_t mid,
! 435: chunk_t plain, chunk_t assoc, chunk_t *encrypted)
! 436: {
! 437: chunk_t iv, padding, icv, crypt;
! 438: iv_gen_t *iv_gen;
! 439: rng_t *rng;
! 440: size_t bs;
! 441:
! 442: rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
! 443: if (!rng)
! 444: {
! 445: DBG1(DBG_ENC, "encrypting %s failed, no RNG found", label);
! 446: return NOT_SUPPORTED;
! 447: }
! 448:
! 449: iv_gen = aead->get_iv_gen(aead);
! 450: if (!iv_gen)
! 451: {
! 452: DBG1(DBG_ENC, "encrypting %s failed, no IV generator", label);
! 453: return NOT_SUPPORTED;
! 454: }
! 455:
! 456: bs = aead->get_block_size(aead);
! 457: /* we need at least one byte padding to store the padding length */
! 458: padding.len = bs - (plain.len % bs);
! 459: iv.len = aead->get_iv_size(aead);
! 460: icv.len = aead->get_icv_size(aead);
! 461:
! 462: /* prepare data to authenticate-encrypt:
! 463: * | IV | plain | padding | ICV |
! 464: * \____crypt______/ ^
! 465: * | /
! 466: * v /
! 467: * assoc -> + ------->/
! 468: */
! 469: *encrypted = chunk_alloc(iv.len + plain.len + padding.len + icv.len);
! 470: iv.ptr = encrypted->ptr;
! 471: memcpy(iv.ptr + iv.len, plain.ptr, plain.len);
! 472: plain.ptr = iv.ptr + iv.len;
! 473: padding.ptr = plain.ptr + plain.len;
! 474: icv.ptr = padding.ptr + padding.len;
! 475: crypt = chunk_create(plain.ptr, plain.len + padding.len);
! 476:
! 477: if (!iv_gen->get_iv(iv_gen, mid, iv.len, iv.ptr) ||
! 478: !rng->get_bytes(rng, padding.len - 1, padding.ptr))
! 479: {
! 480: DBG1(DBG_ENC, "encrypting %s failed, no IV or padding", label);
! 481: rng->destroy(rng);
! 482:
! 483: return FAILED;
! 484: }
! 485: padding.ptr[padding.len - 1] = padding.len - 1;
! 486: rng->destroy(rng);
! 487:
! 488: DBG3(DBG_ENC, "%s encryption:", label);
! 489: DBG3(DBG_ENC, "IV %B", &iv);
! 490: DBG3(DBG_ENC, "plain %B", &plain);
! 491: DBG3(DBG_ENC, "padding %B", &padding);
! 492: DBG3(DBG_ENC, "assoc %B", &assoc);
! 493:
! 494: if (!aead->encrypt(aead, crypt, assoc, iv, NULL))
! 495: {
! 496: return FAILED;
! 497: }
! 498: DBG3(DBG_ENC, "encrypted %B", &crypt);
! 499: DBG3(DBG_ENC, "ICV %B", &icv);
! 500: return SUCCESS;
! 501: }
! 502:
! 503: METHOD(encrypted_payload_t, encrypt, status_t,
! 504: private_encrypted_payload_t *this, uint64_t mid, chunk_t assoc)
! 505: {
! 506: generator_t *generator;
! 507: chunk_t plain;
! 508: status_t status;
! 509:
! 510: if (this->aead == NULL)
! 511: {
! 512: DBG1(DBG_ENC, "encrypting encrypted payload failed, transform missing");
! 513: return INVALID_STATE;
! 514: }
! 515:
! 516: free(this->encrypted.ptr);
! 517: generator = generator_create();
! 518: plain = generate(this, generator);
! 519: assoc = append_header(this, assoc);
! 520: /* lower 32-bits are for fragment number, if used */
! 521: mid <<= 32;
! 522: status = encrypt_content("encrypted payload", this->aead, mid, plain, assoc,
! 523: &this->encrypted);
! 524: generator->destroy(generator);
! 525: free(assoc.ptr);
! 526: return status;
! 527: }
! 528:
! 529: METHOD(encrypted_payload_t, encrypt_v1, status_t,
! 530: private_encrypted_payload_t *this, uint64_t mid, chunk_t iv)
! 531: {
! 532: generator_t *generator;
! 533: chunk_t plain, padding;
! 534: size_t bs;
! 535:
! 536: if (this->aead == NULL)
! 537: {
! 538: DBG1(DBG_ENC, "encryption failed, transform missing");
! 539: return INVALID_STATE;
! 540: }
! 541:
! 542: generator = generator_create();
! 543: plain = generate(this, generator);
! 544: bs = this->aead->get_block_size(this->aead);
! 545: padding.len = bs - (plain.len % bs);
! 546:
! 547: /* prepare data to encrypt:
! 548: * | plain | padding | */
! 549: free(this->encrypted.ptr);
! 550: this->encrypted = chunk_alloc(plain.len + padding.len);
! 551: memcpy(this->encrypted.ptr, plain.ptr, plain.len);
! 552: plain.ptr = this->encrypted.ptr;
! 553: padding.ptr = plain.ptr + plain.len;
! 554: memset(padding.ptr, 0, padding.len);
! 555: generator->destroy(generator);
! 556:
! 557: DBG3(DBG_ENC, "encrypting payloads:");
! 558: DBG3(DBG_ENC, "IV %B", &iv);
! 559: DBG3(DBG_ENC, "plain %B", &plain);
! 560: DBG3(DBG_ENC, "padding %B", &padding);
! 561:
! 562: if (!this->aead->encrypt(this->aead, this->encrypted, chunk_empty, iv, NULL))
! 563: {
! 564: return FAILED;
! 565: }
! 566:
! 567: DBG3(DBG_ENC, "encrypted %B", &this->encrypted);
! 568:
! 569: return SUCCESS;
! 570: }
! 571:
! 572: /**
! 573: * Parse the payloads after decryption.
! 574: */
! 575: static status_t parse(private_encrypted_payload_t *this, chunk_t plain)
! 576: {
! 577: parser_t *parser;
! 578: payload_type_t type;
! 579:
! 580: parser = parser_create(plain);
! 581: parser->set_major_version(parser, this->type == PLV1_ENCRYPTED ? 1 : 2);
! 582: type = this->next_payload;
! 583: while (type != PL_NONE)
! 584: {
! 585: payload_t *payload;
! 586:
! 587: if (plain.len < 4 || untoh16(plain.ptr + 2) > plain.len)
! 588: {
! 589: DBG1(DBG_ENC, "invalid %N payload length, decryption failed?",
! 590: payload_type_names, type);
! 591: parser->destroy(parser);
! 592: return PARSE_ERROR;
! 593: }
! 594: if (parser->parse_payload(parser, type, &payload) != SUCCESS)
! 595: {
! 596: parser->destroy(parser);
! 597: return PARSE_ERROR;
! 598: }
! 599: if (payload->verify(payload) != SUCCESS)
! 600: {
! 601: DBG1(DBG_ENC, "%N verification failed",
! 602: payload_type_names, payload->get_type(payload));
! 603: payload->destroy(payload);
! 604: parser->destroy(parser);
! 605: return VERIFY_ERROR;
! 606: }
! 607: type = payload->get_next_type(payload);
! 608: this->payloads->insert_last(this->payloads, payload);
! 609: }
! 610: parser->destroy(parser);
! 611: DBG2(DBG_ENC, "parsed content of encrypted payload");
! 612: return SUCCESS;
! 613: }
! 614:
! 615: /**
! 616: * Decrypts the given data in-place and returns a chunk pointing to the
! 617: * resulting plaintext.
! 618: */
! 619: static status_t decrypt_content(char *label, aead_t *aead, chunk_t encrypted,
! 620: chunk_t assoc, chunk_t *plain)
! 621: {
! 622: chunk_t iv, padding, icv, crypt;
! 623: size_t bs;
! 624:
! 625: /* prepare data to authenticate-decrypt:
! 626: * | IV | plain | padding | ICV |
! 627: * \____crypt______/ ^
! 628: * | /
! 629: * v /
! 630: * assoc -> + ------->/
! 631: */
! 632: bs = aead->get_block_size(aead);
! 633: iv.len = aead->get_iv_size(aead);
! 634: iv.ptr = encrypted.ptr;
! 635: icv.len = aead->get_icv_size(aead);
! 636: icv.ptr = encrypted.ptr + encrypted.len - icv.len;
! 637: crypt.ptr = iv.ptr + iv.len;
! 638: crypt.len = encrypted.len - iv.len;
! 639:
! 640: if (iv.len + icv.len > encrypted.len ||
! 641: (crypt.len - icv.len) % bs)
! 642: {
! 643: DBG1(DBG_ENC, "decrypting %s payload failed, invalid length", label);
! 644: return FAILED;
! 645: }
! 646:
! 647: DBG3(DBG_ENC, "%s decryption:", label);
! 648: DBG3(DBG_ENC, "IV %B", &iv);
! 649: DBG3(DBG_ENC, "encrypted %B", &crypt);
! 650: DBG3(DBG_ENC, "ICV %B", &icv);
! 651: DBG3(DBG_ENC, "assoc %B", &assoc);
! 652:
! 653: if (!aead->decrypt(aead, crypt, assoc, iv, NULL))
! 654: {
! 655: DBG1(DBG_ENC, "verifying %s integrity failed", label);
! 656: return FAILED;
! 657: }
! 658:
! 659: *plain = chunk_create(crypt.ptr, crypt.len - icv.len);
! 660: padding.len = plain->ptr[plain->len - 1] + 1;
! 661: if (padding.len > plain->len)
! 662: {
! 663: DBG1(DBG_ENC, "decrypting %s failed, padding invalid %B", label,
! 664: &crypt);
! 665: return PARSE_ERROR;
! 666: }
! 667: plain->len -= padding.len;
! 668: padding.ptr = plain->ptr + plain->len;
! 669:
! 670: DBG3(DBG_ENC, "plain %B", plain);
! 671: DBG3(DBG_ENC, "padding %B", &padding);
! 672: return SUCCESS;
! 673: }
! 674:
! 675: METHOD(encrypted_payload_t, decrypt, status_t,
! 676: private_encrypted_payload_t *this, chunk_t assoc)
! 677: {
! 678: chunk_t plain;
! 679: status_t status;
! 680:
! 681: if (this->aead == NULL)
! 682: {
! 683: DBG1(DBG_ENC, "decrypting encrypted payload failed, transform missing");
! 684: return INVALID_STATE;
! 685: }
! 686:
! 687: assoc = append_header(this, assoc);
! 688: status = decrypt_content("encrypted payload", this->aead, this->encrypted,
! 689: assoc, &plain);
! 690: free(assoc.ptr);
! 691:
! 692: if (status != SUCCESS)
! 693: {
! 694: return status;
! 695: }
! 696: return parse(this, plain);
! 697: }
! 698:
! 699: METHOD(encrypted_payload_t, decrypt_plain, status_t,
! 700: private_encrypted_payload_t *this, chunk_t assoc)
! 701: {
! 702: if (!this->encrypted.ptr)
! 703: {
! 704: return FAILED;
! 705: }
! 706: return parse(this, this->encrypted);
! 707: }
! 708:
! 709: METHOD(encrypted_payload_t, decrypt_v1, status_t,
! 710: private_encrypted_payload_t *this, chunk_t iv)
! 711: {
! 712: if (this->aead == NULL)
! 713: {
! 714: DBG1(DBG_ENC, "decryption failed, transform missing");
! 715: return INVALID_STATE;
! 716: }
! 717:
! 718: /* data must be a multiple of block size */
! 719: if (iv.len != this->aead->get_block_size(this->aead) ||
! 720: this->encrypted.len < iv.len || this->encrypted.len % iv.len)
! 721: {
! 722: DBG1(DBG_ENC, "decryption failed, invalid length");
! 723: return FAILED;
! 724: }
! 725:
! 726: DBG3(DBG_ENC, "decrypting payloads:");
! 727: DBG3(DBG_ENC, "encrypted %B", &this->encrypted);
! 728:
! 729: if (!this->aead->decrypt(this->aead, this->encrypted, chunk_empty, iv, NULL))
! 730: {
! 731: return FAILED;
! 732: }
! 733:
! 734: DBG3(DBG_ENC, "plain %B", &this->encrypted);
! 735:
! 736: return parse(this, this->encrypted);
! 737: }
! 738:
! 739: METHOD(encrypted_payload_t, set_transform, void,
! 740: private_encrypted_payload_t *this, aead_t* aead)
! 741: {
! 742: this->aead = aead;
! 743: }
! 744:
! 745: METHOD(encrypted_payload_t, get_transform, aead_t*,
! 746: private_encrypted_payload_t *this)
! 747: {
! 748: return this->aead;
! 749: }
! 750:
! 751: METHOD2(payload_t, encrypted_payload_t, destroy, void,
! 752: private_encrypted_payload_t *this)
! 753: {
! 754: this->payloads->destroy_offset(this->payloads, offsetof(payload_t, destroy));
! 755: free(this->encrypted.ptr);
! 756: free(this);
! 757: }
! 758:
! 759: /*
! 760: * Described in header
! 761: */
! 762: encrypted_payload_t *encrypted_payload_create(payload_type_t type)
! 763: {
! 764: private_encrypted_payload_t *this;
! 765:
! 766: INIT(this,
! 767: .public = {
! 768: .payload_interface = {
! 769: .verify = _verify,
! 770: .get_encoding_rules = _get_encoding_rules,
! 771: .get_header_length = _get_header_length,
! 772: .get_length = _get_length,
! 773: .get_next_type = _get_next_type,
! 774: .set_next_type = _set_next_type,
! 775: .get_type = _get_type,
! 776: .destroy = _destroy,
! 777: },
! 778: .get_length = _get_length,
! 779: .add_payload = _add_payload,
! 780: .remove_payload = _remove_payload,
! 781: .generate_payloads = _generate_payloads,
! 782: .set_transform = _set_transform,
! 783: .get_transform = _get_transform,
! 784: .encrypt = _encrypt,
! 785: .decrypt = _decrypt,
! 786: .destroy = _destroy,
! 787: },
! 788: .next_payload = PL_NONE,
! 789: .payloads = linked_list_create(),
! 790: .type = type,
! 791: );
! 792: this->payload_length = get_header_length(this);
! 793:
! 794: if (type == PLV1_ENCRYPTED)
! 795: {
! 796: this->public.encrypt = _encrypt_v1;
! 797: this->public.decrypt = _decrypt_v1;
! 798: }
! 799:
! 800: return &this->public;
! 801: }
! 802:
! 803: /*
! 804: * Described in header
! 805: */
! 806: encrypted_payload_t *encrypted_payload_create_from_plain(payload_type_t next,
! 807: chunk_t plain)
! 808: {
! 809: private_encrypted_payload_t *this;
! 810:
! 811: this = (private_encrypted_payload_t*)encrypted_payload_create(PLV2_ENCRYPTED);
! 812: this->public.payload_interface.get_length = _get_length_plain;
! 813: this->public.get_length = _get_length_plain;
! 814: this->public.decrypt = _decrypt_plain;
! 815: this->next_payload = next;
! 816: this->encrypted = plain;
! 817:
! 818: return &this->public;
! 819: }
! 820:
! 821: METHOD(payload_t, frag_verify, status_t,
! 822: private_encrypted_fragment_payload_t *this)
! 823: {
! 824: if (!this->fragment_number || !this->total_fragments ||
! 825: this->fragment_number > this->total_fragments)
! 826: {
! 827: DBG1(DBG_ENC, "invalid fragment number (%u) or total fragments (%u)",
! 828: this->fragment_number, this->total_fragments);
! 829: return FAILED;
! 830: }
! 831: if (this->fragment_number > 1 && this->next_payload != 0)
! 832: {
! 833: DBG1(DBG_ENC, "invalid next payload (%u) for fragment %u, ignored",
! 834: this->next_payload, this->fragment_number);
! 835: this->next_payload = 0;
! 836: }
! 837: return SUCCESS;
! 838: }
! 839:
! 840: METHOD(payload_t, frag_get_encoding_rules, int,
! 841: private_encrypted_fragment_payload_t *this, encoding_rule_t **rules)
! 842: {
! 843: *rules = encodings_fragment;
! 844: return countof(encodings_fragment);
! 845: }
! 846:
! 847: METHOD(payload_t, frag_get_header_length, int,
! 848: private_encrypted_fragment_payload_t *this)
! 849: {
! 850: return 8;
! 851: }
! 852:
! 853: METHOD(payload_t, frag_get_type, payload_type_t,
! 854: private_encrypted_fragment_payload_t *this)
! 855: {
! 856: return PLV2_FRAGMENT;
! 857: }
! 858:
! 859: METHOD(payload_t, frag_get_next_type, payload_type_t,
! 860: private_encrypted_fragment_payload_t *this)
! 861: {
! 862: return this->next_payload;
! 863: }
! 864:
! 865: METHOD(payload_t, frag_set_next_type, void,
! 866: private_encrypted_fragment_payload_t *this, payload_type_t type)
! 867: {
! 868: if (this->fragment_number == 1 && this->next_payload == PL_NONE)
! 869: {
! 870: this->next_payload = type;
! 871: }
! 872: }
! 873:
! 874: METHOD2(payload_t, encrypted_payload_t, frag_get_length, size_t,
! 875: private_encrypted_fragment_payload_t *this)
! 876: {
! 877: if (this->encrypted.len)
! 878: {
! 879: this->payload_length = this->encrypted.len;
! 880: }
! 881: else
! 882: {
! 883: this->payload_length = this->plain.len;
! 884:
! 885: if (this->aead)
! 886: {
! 887: this->payload_length += compute_overhead(this->aead,
! 888: this->payload_length);
! 889: }
! 890: }
! 891: this->payload_length += frag_get_header_length(this);
! 892: return this->payload_length;
! 893: }
! 894:
! 895: METHOD(encrypted_fragment_payload_t, get_fragment_number, uint16_t,
! 896: private_encrypted_fragment_payload_t *this)
! 897: {
! 898: return this->fragment_number;
! 899: }
! 900:
! 901: METHOD(encrypted_fragment_payload_t, get_total_fragments, uint16_t,
! 902: private_encrypted_fragment_payload_t *this)
! 903: {
! 904: return this->total_fragments;
! 905: }
! 906:
! 907: METHOD(encrypted_fragment_payload_t, frag_get_content, chunk_t,
! 908: private_encrypted_fragment_payload_t *this)
! 909: {
! 910: return this->plain;
! 911: }
! 912:
! 913: METHOD(encrypted_payload_t, frag_add_payload, void,
! 914: private_encrypted_fragment_payload_t *this, payload_t* payload)
! 915: {
! 916: payload->destroy(payload);
! 917: }
! 918:
! 919: METHOD(encrypted_payload_t, frag_set_transform, void,
! 920: private_encrypted_fragment_payload_t *this, aead_t* aead)
! 921: {
! 922: this->aead = aead;
! 923: }
! 924:
! 925: METHOD(encrypted_payload_t, frag_get_transform, aead_t*,
! 926: private_encrypted_fragment_payload_t *this)
! 927: {
! 928: return this->aead;
! 929: }
! 930:
! 931: /**
! 932: * Append the encrypted fragment payload header to the associated data
! 933: */
! 934: static chunk_t append_header_frag(private_encrypted_fragment_payload_t *this,
! 935: chunk_t assoc)
! 936: {
! 937: struct {
! 938: uint8_t next_payload;
! 939: uint8_t flags;
! 940: uint16_t length;
! 941: uint16_t fragment_number;
! 942: uint16_t total_fragments;
! 943: } __attribute__((packed)) header = {
! 944: .next_payload = this->next_payload,
! 945: .flags = this->flags,
! 946: .length = htons(frag_get_length(this)),
! 947: .fragment_number = htons(this->fragment_number),
! 948: .total_fragments = htons(this->total_fragments),
! 949: };
! 950: return chunk_cat("cc", assoc, chunk_from_thing(header));
! 951: }
! 952:
! 953: METHOD(encrypted_payload_t, frag_encrypt, status_t,
! 954: private_encrypted_fragment_payload_t *this, uint64_t mid, chunk_t assoc)
! 955: {
! 956: status_t status;
! 957:
! 958: if (!this->aead)
! 959: {
! 960: DBG1(DBG_ENC, "encrypting encrypted fragment payload failed, "
! 961: "transform missing");
! 962: return INVALID_STATE;
! 963: }
! 964: free(this->encrypted.ptr);
! 965: assoc = append_header_frag(this, assoc);
! 966: /* IKEv2 message IDs are not unique if fragmentation is used, hence include
! 967: * the fragment number to make it unique */
! 968: mid = mid << 32 | this->fragment_number;
! 969: status = encrypt_content("encrypted fragment payload", this->aead, mid,
! 970: this->plain, assoc, &this->encrypted);
! 971: free(assoc.ptr);
! 972: return status;
! 973: }
! 974:
! 975: METHOD(encrypted_payload_t, frag_decrypt, status_t,
! 976: private_encrypted_fragment_payload_t *this, chunk_t assoc)
! 977: {
! 978: status_t status;
! 979:
! 980: if (!this->aead)
! 981: {
! 982: DBG1(DBG_ENC, "decrypting encrypted fragment payload failed, "
! 983: "transform missing");
! 984: return INVALID_STATE;
! 985: }
! 986: free(this->plain.ptr);
! 987: assoc = append_header_frag(this, assoc);
! 988: status = decrypt_content("encrypted fragment payload", this->aead,
! 989: this->encrypted, assoc, &this->plain);
! 990: this->plain = chunk_clone(this->plain);
! 991: free(assoc.ptr);
! 992: return status;
! 993: }
! 994:
! 995: METHOD2(payload_t, encrypted_payload_t, frag_destroy, void,
! 996: private_encrypted_fragment_payload_t *this)
! 997: {
! 998: free(this->encrypted.ptr);
! 999: free(this->plain.ptr);
! 1000: free(this);
! 1001: }
! 1002:
! 1003: /*
! 1004: * Described in header
! 1005: */
! 1006: encrypted_fragment_payload_t *encrypted_fragment_payload_create()
! 1007: {
! 1008: private_encrypted_fragment_payload_t *this;
! 1009:
! 1010: INIT(this,
! 1011: .public = {
! 1012: .encrypted = {
! 1013: .payload_interface = {
! 1014: .verify = _frag_verify,
! 1015: .get_encoding_rules = _frag_get_encoding_rules,
! 1016: .get_header_length = _frag_get_header_length,
! 1017: .get_length = _frag_get_length,
! 1018: .get_next_type = _frag_get_next_type,
! 1019: .set_next_type = _frag_set_next_type,
! 1020: .get_type = _frag_get_type,
! 1021: .destroy = _frag_destroy,
! 1022: },
! 1023: .get_length = _frag_get_length,
! 1024: .add_payload = _frag_add_payload,
! 1025: .remove_payload = (void*)return_null,
! 1026: .generate_payloads = nop,
! 1027: .set_transform = _frag_set_transform,
! 1028: .get_transform = _frag_get_transform,
! 1029: .encrypt = _frag_encrypt,
! 1030: .decrypt = _frag_decrypt,
! 1031: .destroy = _frag_destroy,
! 1032: },
! 1033: .get_fragment_number = _get_fragment_number,
! 1034: .get_total_fragments = _get_total_fragments,
! 1035: .get_content = _frag_get_content,
! 1036: },
! 1037: .next_payload = PL_NONE,
! 1038: );
! 1039: this->payload_length = frag_get_header_length(this);
! 1040:
! 1041: return &this->public;
! 1042: }
! 1043:
! 1044: /*
! 1045: * Described in header
! 1046: */
! 1047: encrypted_fragment_payload_t *encrypted_fragment_payload_create_from_data(
! 1048: uint16_t num, uint16_t total, chunk_t plain)
! 1049: {
! 1050: private_encrypted_fragment_payload_t *this;
! 1051:
! 1052: this = (private_encrypted_fragment_payload_t*)encrypted_fragment_payload_create();
! 1053: this->fragment_number = num;
! 1054: this->total_fragments = total;
! 1055: this->plain = chunk_clone(plain);
! 1056:
! 1057: return &this->public;
! 1058: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>