Return to sa_payload.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / libcharon / encoding / payloads |
1.1 misho 1: /* 2: * Copyright (C) 2012-2020 Tobias Brunner 3: * Copyright (C) 2005-2010 Martin Willi 4: * Copyright (C) 2005 Jan Hutter 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: #include <stddef.h> 19: 20: #include "sa_payload.h" 21: 22: #include <encoding/payloads/encodings.h> 23: #include <collections/linked_list.h> 24: #include <daemon.h> 25: 26: /* IKEv1 situation */ 27: #define SIT_IDENTITY_ONLY 1 28: 29: typedef struct private_sa_payload_t private_sa_payload_t; 30: 31: /** 32: * Private data of an sa_payload_t object. 33: */ 34: struct private_sa_payload_t { 35: 36: /** 37: * Public sa_payload_t interface. 38: */ 39: sa_payload_t public; 40: 41: /** 42: * Next payload type. 43: */ 44: uint8_t next_payload; 45: 46: /** 47: * Critical flag. 48: */ 49: bool critical; 50: 51: /** 52: * Reserved bits 53: */ 54: bool reserved[8]; 55: 56: /** 57: * Length of this payload. 58: */ 59: uint16_t payload_length; 60: 61: /** 62: * Proposals in this payload are stored in a linked_list_t. 63: */ 64: linked_list_t *proposals; 65: 66: /** 67: * Type of this payload, V1 or V2 68: */ 69: payload_type_t type; 70: 71: /** 72: * IKEv1 DOI 73: */ 74: uint32_t doi; 75: 76: /** 77: * IKEv1 situation 78: */ 79: uint32_t situation; 80: }; 81: 82: /** 83: * Encoding rules for IKEv1 SA payload 84: */ 85: static encoding_rule_t encodings_v1[] = { 86: /* 1 Byte next payload type, stored in the field next_payload */ 87: { U_INT_8, offsetof(private_sa_payload_t, next_payload) }, 88: /* 8 reserved bits */ 89: { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[0]) }, 90: { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[1]) }, 91: { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[2]) }, 92: { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[3]) }, 93: { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[4]) }, 94: { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[5]) }, 95: { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[6]) }, 96: { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[7]) }, 97: /* Length of the whole SA payload*/ 98: { PAYLOAD_LENGTH, offsetof(private_sa_payload_t, payload_length) }, 99: /* DOI*/ 100: { U_INT_32, offsetof(private_sa_payload_t, doi) }, 101: /* Situation*/ 102: { U_INT_32, offsetof(private_sa_payload_t, situation) }, 103: /* Proposals are stored in a proposal substructure list */ 104: { PAYLOAD_LIST + PLV1_PROPOSAL_SUBSTRUCTURE, 105: offsetof(private_sa_payload_t, proposals) }, 106: }; 107: 108: /* 109: 1 2 3 110: 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 111: +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 112: ! Next Payload ! RESERVED ! Payload Length ! 113: +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 114: ! DOI ! 115: +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 116: ! Situation ! 117: +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 118: ! ! 119: ~ <Proposals> ~ 120: ! ! 121: +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 122: */ 123: 124: /** 125: * Encoding rules for IKEv2 SA payload 126: */ 127: static encoding_rule_t encodings_v2[] = { 128: /* 1 Byte next payload type, stored in the field next_payload */ 129: { U_INT_8, offsetof(private_sa_payload_t, next_payload) }, 130: /* the critical bit */ 131: { FLAG, offsetof(private_sa_payload_t, critical) }, 132: /* 7 Bit reserved bits */ 133: { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[0]) }, 134: { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[1]) }, 135: { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[2]) }, 136: { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[3]) }, 137: { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[4]) }, 138: { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[5]) }, 139: { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[6]) }, 140: /* Length of the whole SA payload*/ 141: { PAYLOAD_LENGTH, offsetof(private_sa_payload_t, payload_length) }, 142: /* Proposals are stored in a proposal substructure list */ 143: { PAYLOAD_LIST + PLV2_PROPOSAL_SUBSTRUCTURE, 144: offsetof(private_sa_payload_t, proposals) }, 145: }; 146: 147: /* 148: 1 2 3 149: 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 150: +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 151: ! Next Payload !C! RESERVED ! Payload Length ! 152: +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 153: ! ! 154: ~ <Proposals> ~ 155: ! ! 156: +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 157: */ 158: 159: METHOD(payload_t, verify, status_t, 160: private_sa_payload_t *this) 161: { 162: int expected_number = 0, current_number; 163: status_t status = SUCCESS; 164: enumerator_t *enumerator; 165: proposal_substructure_t *substruct; 166: 167: if (this->type == PLV2_SECURITY_ASSOCIATION) 168: { 169: expected_number = 1; 170: } 171: 172: /* check proposal numbering */ 173: enumerator = this->proposals->create_enumerator(this->proposals); 174: while (enumerator->enumerate(enumerator, (void**)&substruct)) 175: { 176: current_number = substruct->get_proposal_number(substruct); 177: if (current_number < expected_number) 178: { 179: DBG1(DBG_ENC, "proposal number smaller than previous"); 180: status = FAILED; 181: break; 182: } 183: 184: status = substruct->payload_interface.verify(&substruct->payload_interface); 185: if (status != SUCCESS) 186: { 187: DBG1(DBG_ENC, "PROPOSAL_SUBSTRUCTURE verification failed"); 188: break; 189: } 190: expected_number = current_number; 191: } 192: enumerator->destroy(enumerator); 193: return status; 194: } 195: 196: METHOD(payload_t, get_encoding_rules, int, 197: private_sa_payload_t *this, encoding_rule_t **rules) 198: { 199: if (this->type == PLV1_SECURITY_ASSOCIATION) 200: { 201: *rules = encodings_v1; 202: return countof(encodings_v1); 203: } 204: *rules = encodings_v2; 205: return countof(encodings_v2); 206: } 207: 208: METHOD(payload_t, get_header_length, int, 209: private_sa_payload_t *this) 210: { 211: if (this->type == PLV1_SECURITY_ASSOCIATION) 212: { 213: return 12; 214: } 215: return 4; 216: } 217: 218: METHOD(payload_t, get_type, payload_type_t, 219: private_sa_payload_t *this) 220: { 221: return this->type; 222: } 223: 224: METHOD(payload_t, get_next_type, payload_type_t, 225: private_sa_payload_t *this) 226: { 227: return this->next_payload; 228: } 229: 230: METHOD(payload_t, set_next_type, void, 231: private_sa_payload_t *this,payload_type_t type) 232: { 233: this->next_payload = type; 234: } 235: 236: /** 237: * recompute length of the payload. 238: */ 239: static void compute_length(private_sa_payload_t *this) 240: { 241: enumerator_t *enumerator; 242: payload_t *current; 243: 244: this->payload_length = get_header_length(this); 245: 246: enumerator = this->proposals->create_enumerator(this->proposals); 247: while (enumerator->enumerate(enumerator, (void **)¤t)) 248: { 249: this->payload_length += current->get_length(current); 250: } 251: enumerator->destroy(enumerator); 252: } 253: 254: METHOD(payload_t, get_length, size_t, 255: private_sa_payload_t *this) 256: { 257: return this->payload_length; 258: } 259: 260: /** 261: * Create a transform substructure from a proposal, add to payload 262: */ 263: static void add_proposal_v2(private_sa_payload_t *this, proposal_t *proposal) 264: { 265: proposal_substructure_t *substruct, *last; 266: u_int count; 267: 268: substruct = proposal_substructure_create_from_proposal_v2(proposal); 269: count = this->proposals->get_count(this->proposals); 270: if (count > 0) 271: { 272: this->proposals->get_last(this->proposals, (void**)&last); 273: /* last transform is now not anymore last one */ 274: last->set_is_last_proposal(last, FALSE); 275: } 276: substruct->set_is_last_proposal(substruct, TRUE); 277: if (proposal->get_number(proposal)) 278: { /* use the selected proposals number, if any */ 279: substruct->set_proposal_number(substruct, proposal->get_number(proposal)); 280: } 281: else 282: { 283: substruct->set_proposal_number(substruct, count + 1); 284: } 285: this->proposals->insert_last(this->proposals, substruct); 286: compute_length(this); 287: } 288: 289: METHOD(sa_payload_t, get_proposals, linked_list_t*, 290: private_sa_payload_t *this) 291: { 292: int struct_number = 0; 293: int ignore_struct_number = 0; 294: enumerator_t *enumerator; 295: proposal_substructure_t *substruct; 296: linked_list_t *substructs, *list; 297: 298: if (this->type == PLV1_SECURITY_ASSOCIATION) 299: { /* IKEv1 proposals may start with 0 or 1 (or any other number really) */ 300: struct_number = ignore_struct_number = -1; 301: } 302: 303: /* we do not support proposals split up to two proposal substructures, as 304: * AH+ESP bundles are not supported in RFC4301 anymore. 305: * To handle such structures safely, we just skip proposals with multiple 306: * protocols. 307: */ 308: substructs = linked_list_create(); 309: enumerator = this->proposals->create_enumerator(this->proposals); 310: while (enumerator->enumerate(enumerator, &substruct)) 311: { 312: int current_number = substruct->get_proposal_number(substruct); 313: 314: /* check if a proposal has a single protocol */ 315: if (current_number == struct_number) 316: { 317: if (ignore_struct_number < struct_number) 318: { /* remove an already added substruct, if first of series */ 319: substructs->remove_last(substructs, (void**)&substruct); 320: ignore_struct_number = struct_number; 321: } 322: continue; 323: } 324: /* for IKEv1 the numbers don't have to be consecutive, for IKEv2 they do 325: * but since we don't really care for the actual number we accept them 326: * anyway. we already verified that they increase monotonically. */ 327: struct_number = current_number; 328: substructs->insert_last(substructs, substruct); 329: } 330: enumerator->destroy(enumerator); 331: 332: /* generate proposals from substructs */ 333: list = linked_list_create(); 334: enumerator = substructs->create_enumerator(substructs); 335: while (enumerator->enumerate(enumerator, &substruct)) 336: { 337: substruct->get_proposals(substruct, list); 338: } 339: enumerator->destroy(enumerator); 340: substructs->destroy(substructs); 341: return list; 342: } 343: 344: METHOD(sa_payload_t, get_ipcomp_proposals, linked_list_t*, 345: private_sa_payload_t *this, uint16_t *cpi) 346: { 347: int current_proposal = -1, unsupported_proposal = -1; 348: enumerator_t *enumerator; 349: proposal_substructure_t *substruct, *espah = NULL, *ipcomp = NULL; 350: linked_list_t *list; 351: 352: /* we currently only support the combination ESP|AH+IPComp, find the first */ 353: enumerator = this->proposals->create_enumerator(this->proposals); 354: while (enumerator->enumerate(enumerator, &substruct)) 355: { 356: uint8_t proposal_number = substruct->get_proposal_number(substruct); 357: uint8_t protocol_id = substruct->get_protocol_id(substruct); 358: 359: if (proposal_number == unsupported_proposal) 360: { 361: continue; 362: } 363: if (protocol_id != PROTO_ESP && protocol_id != PROTO_AH && 364: protocol_id != PROTO_IPCOMP) 365: { /* unsupported combination */ 366: espah = ipcomp = NULL; 367: unsupported_proposal = current_proposal; 368: continue; 369: } 370: if (proposal_number != current_proposal) 371: { /* start of a new proposal */ 372: if (espah && ipcomp && ipcomp->get_cpi(ipcomp, NULL)) 373: { /* previous proposal is valid */ 374: break; 375: } 376: espah = ipcomp = NULL; 377: current_proposal = proposal_number; 378: } 379: switch (protocol_id) 380: { 381: case PROTO_ESP: 382: case PROTO_AH: 383: espah = substruct; 384: break; 385: case PROTO_IPCOMP: 386: ipcomp = substruct; 387: break; 388: } 389: } 390: enumerator->destroy(enumerator); 391: 392: list = linked_list_create(); 393: if (espah && ipcomp && ipcomp->get_cpi(ipcomp, cpi)) 394: { 395: espah->get_proposals(espah, list); 396: } 397: return list; 398: } 399: 400: METHOD(sa_payload_t, create_substructure_enumerator, enumerator_t*, 401: private_sa_payload_t *this) 402: { 403: return this->proposals->create_enumerator(this->proposals); 404: } 405: 406: METHOD(sa_payload_t, get_lifetime, uint32_t, 407: private_sa_payload_t *this, proposal_t *proposal) 408: { 409: proposal_substructure_t *substruct; 410: enumerator_t *enumerator; 411: uint8_t number = proposal->get_number(proposal); 412: uint32_t lifetime = 0; 413: 414: enumerator = this->proposals->create_enumerator(this->proposals); 415: while (enumerator->enumerate(enumerator, &substruct)) 416: { 417: if (substruct->get_proposal_number(substruct) == number) 418: { 419: lifetime = substruct->get_lifetime(substruct, 420: proposal->get_transform_number(proposal)); 421: break; 422: } 423: } 424: enumerator->destroy(enumerator); 425: 426: return lifetime; 427: } 428: 429: METHOD(sa_payload_t, get_lifebytes, uint64_t, 430: private_sa_payload_t *this, proposal_t *proposal) 431: { 432: proposal_substructure_t *substruct; 433: enumerator_t *enumerator; 434: uint8_t number = proposal->get_number(proposal); 435: uint64_t lifebytes = 0; 436: 437: enumerator = this->proposals->create_enumerator(this->proposals); 438: while (enumerator->enumerate(enumerator, &substruct)) 439: { 440: if (substruct->get_proposal_number(substruct) == number) 441: { 442: lifebytes = substruct->get_lifebytes(substruct, 443: proposal->get_transform_number(proposal)); 444: break; 445: } 446: } 447: enumerator->destroy(enumerator); 448: 449: return lifebytes; 450: } 451: 452: METHOD(sa_payload_t, get_auth_method, auth_method_t, 453: private_sa_payload_t *this) 454: { 455: proposal_substructure_t *substruct; 456: enumerator_t *enumerator; 457: auth_method_t method = AUTH_NONE; 458: 459: enumerator = this->proposals->create_enumerator(this->proposals); 460: if (enumerator->enumerate(enumerator, &substruct)) 461: { 462: method = substruct->get_auth_method(substruct); 463: } 464: enumerator->destroy(enumerator); 465: 466: return method; 467: } 468: 469: METHOD(sa_payload_t, get_encap_mode, ipsec_mode_t, 470: private_sa_payload_t *this, bool *udp) 471: { 472: proposal_substructure_t *substruct; 473: enumerator_t *enumerator; 474: ipsec_mode_t mode = MODE_NONE; 475: 476: enumerator = this->proposals->create_enumerator(this->proposals); 477: if (enumerator->enumerate(enumerator, &substruct)) 478: { 479: mode = substruct->get_encap_mode(substruct, udp); 480: } 481: enumerator->destroy(enumerator); 482: 483: return mode; 484: } 485: 486: METHOD2(payload_t, sa_payload_t, destroy, void, 487: private_sa_payload_t *this) 488: { 489: this->proposals->destroy_offset(this->proposals, 490: offsetof(payload_t, destroy)); 491: free(this); 492: } 493: 494: /* 495: * Described in header. 496: */ 497: sa_payload_t *sa_payload_create(payload_type_t type) 498: { 499: private_sa_payload_t *this; 500: 501: INIT(this, 502: .public = { 503: .payload_interface = { 504: .verify = _verify, 505: .get_encoding_rules = _get_encoding_rules, 506: .get_header_length = _get_header_length, 507: .get_length = _get_length, 508: .get_next_type = _get_next_type, 509: .set_next_type = _set_next_type, 510: .get_type = _get_type, 511: .destroy = _destroy, 512: }, 513: .get_proposals = _get_proposals, 514: .get_ipcomp_proposals = _get_ipcomp_proposals, 515: .create_substructure_enumerator = _create_substructure_enumerator, 516: .get_lifetime = _get_lifetime, 517: .get_lifebytes = _get_lifebytes, 518: .get_auth_method = _get_auth_method, 519: .get_encap_mode = _get_encap_mode, 520: .destroy = _destroy, 521: }, 522: .next_payload = PL_NONE, 523: .proposals = linked_list_create(), 524: .type = type, 525: /* for IKEv1 only */ 526: .doi = IKEV1_DOI_IPSEC, 527: .situation = SIT_IDENTITY_ONLY, 528: ); 529: 530: compute_length(this); 531: 532: return &this->public; 533: } 534: 535: /* 536: * Described in header. 537: */ 538: sa_payload_t *sa_payload_create_from_proposals_v2(linked_list_t *proposals) 539: { 540: private_sa_payload_t *this; 541: enumerator_t *enumerator; 542: proposal_t *proposal; 543: 544: this = (private_sa_payload_t*)sa_payload_create(PLV2_SECURITY_ASSOCIATION); 545: enumerator = proposals->create_enumerator(proposals); 546: while (enumerator->enumerate(enumerator, &proposal)) 547: { 548: add_proposal_v2(this, proposal); 549: } 550: enumerator->destroy(enumerator); 551: 552: return &this->public; 553: } 554: 555: /* 556: * Described in header. 557: */ 558: sa_payload_t *sa_payload_create_from_proposal_v2(proposal_t *proposal) 559: { 560: private_sa_payload_t *this; 561: 562: this = (private_sa_payload_t*)sa_payload_create(PLV2_SECURITY_ASSOCIATION); 563: add_proposal_v2(this, proposal); 564: 565: return &this->public; 566: 567: } 568: 569: /* 570: * Described in header. 571: */ 572: sa_payload_t *sa_payload_create_from_proposals_v1(linked_list_t *proposals, 573: uint32_t lifetime, uint64_t lifebytes, 574: auth_method_t auth, ipsec_mode_t mode, 575: encap_t udp, uint16_t cpi) 576: { 577: proposal_substructure_t *substruct; 578: private_sa_payload_t *this; 579: 580: this = (private_sa_payload_t*)sa_payload_create(PLV1_SECURITY_ASSOCIATION); 581: 582: if (!proposals || !proposals->get_count(proposals)) 583: { 584: return &this->public; 585: } 586: 587: /* IKEv1 encodes multiple proposals in a single substructure 588: * TODO-IKEv1: Encode ESP+AH proposals in two substructs with same num */ 589: substruct = proposal_substructure_create_from_proposals_v1(proposals, 590: lifetime, lifebytes, auth, mode, udp); 591: this->proposals->insert_last(this->proposals, substruct); 592: substruct->set_is_last_proposal(substruct, FALSE); 593: if (cpi) 594: { 595: uint8_t proposal_number = substruct->get_proposal_number(substruct); 596: 597: substruct = proposal_substructure_create_for_ipcomp_v1(lifetime, 598: lifebytes, cpi, mode, udp, proposal_number); 599: this->proposals->insert_last(this->proposals, substruct); 600: substruct->set_is_last_proposal(substruct, FALSE); 601: /* add the proposals again without IPComp */ 602: substruct = proposal_substructure_create_from_proposals_v1(proposals, 603: lifetime, lifebytes, auth, mode, udp); 604: substruct->set_proposal_number(substruct, proposal_number + 1); 605: this->proposals->insert_last(this->proposals, substruct); 606: } 607: substruct->set_is_last_proposal(substruct, TRUE); 608: compute_length(this); 609: 610: return &this->public; 611: } 612: 613: /* 614: * Described in header. 615: */ 616: sa_payload_t *sa_payload_create_from_proposal_v1(proposal_t *proposal, 617: uint32_t lifetime, uint64_t lifebytes, 618: auth_method_t auth, ipsec_mode_t mode, 619: encap_t udp, uint16_t cpi) 620: { 621: private_sa_payload_t *this; 622: linked_list_t *proposals; 623: 624: proposals = linked_list_create(); 625: proposals->insert_last(proposals, proposal); 626: this = (private_sa_payload_t*)sa_payload_create_from_proposals_v1(proposals, 627: lifetime, lifebytes, auth, mode, udp, cpi); 628: proposals->destroy(proposals); 629: return &this->public; 630: }