Annotation of embedaddon/strongswan/src/libstrongswan/crypto/proposal/proposal.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2008-2020 Tobias Brunner
! 3: * Copyright (C) 2006-2010 Martin Willi
! 4: * Copyright (C) 2013-2015 Andreas Steffen
! 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 <string.h>
! 19:
! 20: #include "proposal.h"
! 21:
! 22: #include <collections/array.h>
! 23: #include <utils/identification.h>
! 24:
! 25: #include <crypto/transform.h>
! 26: #include <crypto/prfs/prf.h>
! 27: #include <crypto/crypters/crypter.h>
! 28: #include <crypto/signers/signer.h>
! 29:
! 30: ENUM(protocol_id_names, PROTO_NONE, PROTO_IPCOMP,
! 31: "PROTO_NONE",
! 32: "IKE",
! 33: "AH",
! 34: "ESP",
! 35: "IPCOMP",
! 36: );
! 37:
! 38: typedef struct private_proposal_t private_proposal_t;
! 39:
! 40: /**
! 41: * Private data of an proposal_t object
! 42: */
! 43: struct private_proposal_t {
! 44:
! 45: /**
! 46: * Public part
! 47: */
! 48: proposal_t public;
! 49:
! 50: /**
! 51: * protocol (ESP or AH)
! 52: */
! 53: protocol_id_t protocol;
! 54:
! 55: /**
! 56: * Priority ordered list of transforms, as entry_t
! 57: */
! 58: array_t *transforms;
! 59:
! 60: /**
! 61: * Types of transforms contained, as transform_type_t
! 62: */
! 63: array_t *types;
! 64:
! 65: /**
! 66: * senders SPI
! 67: */
! 68: uint64_t spi;
! 69:
! 70: /**
! 71: * Proposal number
! 72: */
! 73: uint8_t number;
! 74:
! 75: /**
! 76: * Transform number (IKEv1 only)
! 77: */
! 78: uint8_t transform_number;
! 79: };
! 80:
! 81: /**
! 82: * This is a hack to not change the previous order when printing proposals
! 83: */
! 84: static transform_type_t type_for_sort(const void *type)
! 85: {
! 86: const transform_type_t *t = type;
! 87:
! 88: switch (*t)
! 89: {
! 90: case PSEUDO_RANDOM_FUNCTION:
! 91: return INTEGRITY_ALGORITHM;
! 92: case INTEGRITY_ALGORITHM:
! 93: return PSEUDO_RANDOM_FUNCTION;
! 94: default:
! 95: return *t;
! 96: }
! 97: }
! 98:
! 99: /**
! 100: * Sort transform types
! 101: */
! 102: static int type_sort(const void *a, const void *b, void *user)
! 103: {
! 104: transform_type_t ta = type_for_sort(a), tb = type_for_sort(b);
! 105: return ta - tb;
! 106: }
! 107:
! 108: /**
! 109: * Find a transform type
! 110: */
! 111: static int type_find(const void *a, const void *b)
! 112: {
! 113: return type_sort(a, b, NULL);
! 114: }
! 115:
! 116: /**
! 117: * Check if the given transform type is already in the set
! 118: */
! 119: static bool contains_type(array_t *types, transform_type_t type)
! 120: {
! 121: return array_bsearch(types, &type, type_find, NULL) != -1;
! 122: }
! 123:
! 124: /**
! 125: * Add the given transform type to the set
! 126: */
! 127: static void add_type(array_t *types, transform_type_t type)
! 128: {
! 129: if (!contains_type(types, type))
! 130: {
! 131: array_insert(types, ARRAY_TAIL, &type);
! 132: array_sort(types, type_sort, NULL);
! 133: }
! 134: }
! 135:
! 136: /**
! 137: * Merge two sets of transform types into a new array
! 138: */
! 139: static array_t *merge_types(private_proposal_t *this, private_proposal_t *other)
! 140: {
! 141: array_t *types;
! 142: transform_type_t type;
! 143: int i, count;
! 144:
! 145: count = max(array_count(this->types), array_count(other->types));
! 146: types = array_create(sizeof(transform_type_t), count);
! 147:
! 148: for (i = 0; i < count; i++)
! 149: {
! 150: if (array_get(this->types, i, &type))
! 151: {
! 152: add_type(types, type);
! 153: }
! 154: if (array_get(other->types, i, &type))
! 155: {
! 156: add_type(types, type);
! 157: }
! 158: }
! 159: return types;
! 160: }
! 161:
! 162: /**
! 163: * Remove the given transform type from the set
! 164: */
! 165: static void remove_type(private_proposal_t *this, transform_type_t type)
! 166: {
! 167: int i;
! 168:
! 169: i = array_bsearch(this->types, &type, type_find, NULL);
! 170: if (i >= 0)
! 171: {
! 172: array_remove(this->types, i, NULL);
! 173: }
! 174: }
! 175:
! 176: /**
! 177: * Struct used to store different kinds of algorithms.
! 178: */
! 179: typedef struct {
! 180: /** Type of the transform */
! 181: transform_type_t type;
! 182: /** algorithm identifier */
! 183: uint16_t alg;
! 184: /** key size in bits, or zero if not needed */
! 185: uint16_t key_size;
! 186: } entry_t;
! 187:
! 188: METHOD(proposal_t, add_algorithm, void,
! 189: private_proposal_t *this, transform_type_t type,
! 190: uint16_t alg, uint16_t key_size)
! 191: {
! 192: entry_t entry = {
! 193: .type = type,
! 194: .alg = alg,
! 195: .key_size = key_size,
! 196: };
! 197:
! 198: array_insert(this->transforms, ARRAY_TAIL, &entry);
! 199: add_type(this->types, type);
! 200: }
! 201:
! 202: CALLBACK(alg_filter, bool,
! 203: uintptr_t type, enumerator_t *orig, va_list args)
! 204: {
! 205: entry_t *entry;
! 206: uint16_t *alg, *key_size;
! 207:
! 208: VA_ARGS_VGET(args, alg, key_size);
! 209:
! 210: while (orig->enumerate(orig, &entry))
! 211: {
! 212: if (entry->type != type)
! 213: {
! 214: continue;
! 215: }
! 216: if (alg)
! 217: {
! 218: *alg = entry->alg;
! 219: }
! 220: if (key_size)
! 221: {
! 222: *key_size = entry->key_size;
! 223: }
! 224: return TRUE;
! 225: }
! 226: return FALSE;
! 227: }
! 228:
! 229: METHOD(proposal_t, create_enumerator, enumerator_t*,
! 230: private_proposal_t *this, transform_type_t type)
! 231: {
! 232: return enumerator_create_filter(
! 233: array_create_enumerator(this->transforms),
! 234: alg_filter, (void*)(uintptr_t)type, NULL);
! 235: }
! 236:
! 237: METHOD(proposal_t, get_algorithm, bool,
! 238: private_proposal_t *this, transform_type_t type,
! 239: uint16_t *alg, uint16_t *key_size)
! 240: {
! 241: enumerator_t *enumerator;
! 242: bool found = FALSE;
! 243:
! 244: enumerator = create_enumerator(this, type);
! 245: if (enumerator->enumerate(enumerator, alg, key_size))
! 246: {
! 247: found = TRUE;
! 248: }
! 249: enumerator->destroy(enumerator);
! 250:
! 251: return found;
! 252: }
! 253:
! 254: METHOD(proposal_t, has_dh_group, bool,
! 255: private_proposal_t *this, diffie_hellman_group_t group)
! 256: {
! 257: bool found = FALSE, any = FALSE;
! 258: enumerator_t *enumerator;
! 259: uint16_t current;
! 260:
! 261: enumerator = create_enumerator(this, DIFFIE_HELLMAN_GROUP);
! 262: while (enumerator->enumerate(enumerator, ¤t, NULL))
! 263: {
! 264: any = TRUE;
! 265: if (current == group)
! 266: {
! 267: found = TRUE;
! 268: break;
! 269: }
! 270: }
! 271: enumerator->destroy(enumerator);
! 272:
! 273: if (!any && group == MODP_NONE)
! 274: {
! 275: found = TRUE;
! 276: }
! 277: return found;
! 278: }
! 279:
! 280: METHOD(proposal_t, promote_dh_group, bool,
! 281: private_proposal_t *this, diffie_hellman_group_t group)
! 282: {
! 283: enumerator_t *enumerator;
! 284: entry_t *entry;
! 285: bool found = FALSE;
! 286:
! 287: enumerator = array_create_enumerator(this->transforms);
! 288: while (enumerator->enumerate(enumerator, &entry))
! 289: {
! 290: if (entry->type == DIFFIE_HELLMAN_GROUP &&
! 291: entry->alg == group)
! 292: {
! 293: array_remove_at(this->transforms, enumerator);
! 294: found = TRUE;
! 295: }
! 296: }
! 297: enumerator->destroy(enumerator);
! 298:
! 299: if (found)
! 300: {
! 301: entry_t entry = {
! 302: .type = DIFFIE_HELLMAN_GROUP,
! 303: .alg = group,
! 304: };
! 305: array_insert(this->transforms, ARRAY_HEAD, &entry);
! 306: }
! 307: return found;
! 308: }
! 309:
! 310: /**
! 311: * Select a matching proposal from this and other.
! 312: */
! 313: static bool select_algo(private_proposal_t *this, proposal_t *other,
! 314: transform_type_t type, proposal_selection_flag_t flags,
! 315: bool log, uint16_t *alg, uint16_t *ks)
! 316: {
! 317: enumerator_t *e1, *e2;
! 318: uint16_t alg1, alg2, ks1, ks2;
! 319: bool found = FALSE, optional = FALSE;
! 320:
! 321: if (type == DIFFIE_HELLMAN_GROUP)
! 322: {
! 323: optional = this->protocol == PROTO_ESP || this->protocol == PROTO_AH;
! 324: }
! 325:
! 326: e1 = create_enumerator(this, type);
! 327: e2 = other->create_enumerator(other, type);
! 328: if (!e1->enumerate(e1, &alg1, NULL))
! 329: {
! 330: if (!e2->enumerate(e2, &alg2, NULL))
! 331: {
! 332: found = TRUE;
! 333: }
! 334: else if (optional)
! 335: {
! 336: do
! 337: { /* if NONE is proposed, we accept the proposal */
! 338: found = !alg2;
! 339: }
! 340: while (!found && e2->enumerate(e2, &alg2, NULL));
! 341: }
! 342: }
! 343: else if (!e2->enumerate(e2, NULL, NULL))
! 344: {
! 345: if (optional)
! 346: {
! 347: do
! 348: { /* if NONE is proposed, we accept the proposal */
! 349: found = !alg1;
! 350: }
! 351: while (!found && e1->enumerate(e1, &alg1, NULL));
! 352: }
! 353: }
! 354:
! 355: e1->destroy(e1);
! 356: e1 = create_enumerator(this, type);
! 357: /* compare algs, order of algs in "first" is preferred */
! 358: while (!found && e1->enumerate(e1, &alg1, &ks1))
! 359: {
! 360: e2->destroy(e2);
! 361: e2 = other->create_enumerator(other, type);
! 362: while (e2->enumerate(e2, &alg2, &ks2))
! 363: {
! 364: if (alg1 == alg2 && ks1 == ks2)
! 365: {
! 366: if ((flags & PROPOSAL_SKIP_PRIVATE) && alg1 >= 1024)
! 367: {
! 368: if (log)
! 369: {
! 370: DBG1(DBG_CFG, "an algorithm from private space would "
! 371: "match, but peer implementation is unknown, "
! 372: "skipped");
! 373: }
! 374: continue;
! 375: }
! 376: *alg = alg1;
! 377: *ks = ks1;
! 378: found = TRUE;
! 379: break;
! 380: }
! 381: }
! 382: }
! 383: e1->destroy(e1);
! 384: e2->destroy(e2);
! 385: return found;
! 386: }
! 387:
! 388: /**
! 389: * Select algorithms from the given proposals, if selected is given, the result
! 390: * is stored there and errors are logged.
! 391: */
! 392: static bool select_algos(private_proposal_t *this, proposal_t *other,
! 393: proposal_t *selected, proposal_selection_flag_t flags)
! 394: {
! 395: transform_type_t type;
! 396: array_t *types;
! 397: bool skip_integrity = FALSE;
! 398: int i;
! 399:
! 400: types = merge_types(this, (private_proposal_t*)other);
! 401: for (i = 0; i < array_count(types); i++)
! 402: {
! 403: uint16_t alg = 0, ks = 0;
! 404:
! 405: array_get(types, i, &type);
! 406: if (type == INTEGRITY_ALGORITHM && skip_integrity)
! 407: {
! 408: continue;
! 409: }
! 410: if (type == DIFFIE_HELLMAN_GROUP && (flags & PROPOSAL_SKIP_DH))
! 411: {
! 412: continue;
! 413: }
! 414: if (select_algo(this, other, type, flags, selected != NULL, &alg, &ks))
! 415: {
! 416: if (alg == 0 && type != EXTENDED_SEQUENCE_NUMBERS)
! 417: { /* 0 is "valid" for extended sequence numbers, for other
! 418: * transforms it either means NONE or is reserved */
! 419: continue;
! 420: }
! 421: if (selected)
! 422: {
! 423: selected->add_algorithm(selected, type, alg, ks);
! 424: }
! 425: if (type == ENCRYPTION_ALGORITHM &&
! 426: encryption_algorithm_is_aead(alg))
! 427: {
! 428: /* no integrity algorithm required, we have an AEAD */
! 429: skip_integrity = TRUE;
! 430: }
! 431: }
! 432: else
! 433: {
! 434: if (selected)
! 435: {
! 436: DBG2(DBG_CFG, " no acceptable %N found", transform_type_names,
! 437: type);
! 438: }
! 439: array_destroy(types);
! 440: return FALSE;
! 441: }
! 442: }
! 443: array_destroy(types);
! 444: return TRUE;
! 445: }
! 446:
! 447: METHOD(proposal_t, select_proposal, proposal_t*,
! 448: private_proposal_t *this, proposal_t *other,
! 449: proposal_selection_flag_t flags)
! 450: {
! 451: proposal_t *selected;
! 452:
! 453: DBG2(DBG_CFG, "selecting proposal:");
! 454:
! 455: if (this->protocol != other->get_protocol(other))
! 456: {
! 457: DBG2(DBG_CFG, " protocol mismatch, skipping");
! 458: return NULL;
! 459: }
! 460:
! 461: if (flags & PROPOSAL_PREFER_SUPPLIED)
! 462: {
! 463: selected = proposal_create_v1(this->protocol, this->number,
! 464: this->transform_number);
! 465: selected->set_spi(selected, this->spi);
! 466: }
! 467: else
! 468: {
! 469: selected = proposal_create_v1(this->protocol, other->get_number(other),
! 470: other->get_transform_number(other));
! 471: selected->set_spi(selected, other->get_spi(other));
! 472: }
! 473:
! 474: if (!select_algos(this, other, selected, flags))
! 475: {
! 476: selected->destroy(selected);
! 477: return NULL;
! 478: }
! 479: DBG2(DBG_CFG, " proposal matches");
! 480: return selected;
! 481: }
! 482:
! 483: METHOD(proposal_t, matches, bool,
! 484: private_proposal_t *this, proposal_t *other,
! 485: proposal_selection_flag_t flags)
! 486: {
! 487: if (this->protocol != other->get_protocol(other))
! 488: {
! 489: return FALSE;
! 490: }
! 491: return select_algos(this, other, NULL, flags);
! 492: }
! 493:
! 494: METHOD(proposal_t, get_protocol, protocol_id_t,
! 495: private_proposal_t *this)
! 496: {
! 497: return this->protocol;
! 498: }
! 499:
! 500: METHOD(proposal_t, set_spi, void,
! 501: private_proposal_t *this, uint64_t spi)
! 502: {
! 503: this->spi = spi;
! 504: }
! 505:
! 506: METHOD(proposal_t, get_spi, uint64_t,
! 507: private_proposal_t *this)
! 508: {
! 509: return this->spi;
! 510: }
! 511:
! 512: /**
! 513: * Check if two proposals have the same algorithms for a given transform type
! 514: */
! 515: static bool algo_list_equals(private_proposal_t *this, proposal_t *other,
! 516: transform_type_t type)
! 517: {
! 518: enumerator_t *e1, *e2;
! 519: uint16_t alg1, alg2, ks1, ks2;
! 520: bool equals = TRUE;
! 521:
! 522: e1 = create_enumerator(this, type);
! 523: e2 = other->create_enumerator(other, type);
! 524: while (e1->enumerate(e1, &alg1, &ks1))
! 525: {
! 526: if (!e2->enumerate(e2, &alg2, &ks2))
! 527: {
! 528: /* this has more algs */
! 529: equals = FALSE;
! 530: break;
! 531: }
! 532: if (alg1 != alg2 || ks1 != ks2)
! 533: {
! 534: equals = FALSE;
! 535: break;
! 536: }
! 537: }
! 538: if (e2->enumerate(e2, &alg2, &ks2))
! 539: {
! 540: /* other has more algs */
! 541: equals = FALSE;
! 542: }
! 543: e1->destroy(e1);
! 544: e2->destroy(e2);
! 545:
! 546: return equals;
! 547: }
! 548:
! 549: METHOD(proposal_t, get_number, uint8_t,
! 550: private_proposal_t *this)
! 551: {
! 552: return this->number;
! 553: }
! 554:
! 555: METHOD(proposal_t, get_transform_number, uint8_t,
! 556: private_proposal_t *this)
! 557: {
! 558: return this->transform_number;
! 559: }
! 560:
! 561: METHOD(proposal_t, equals, bool,
! 562: private_proposal_t *this, proposal_t *other)
! 563: {
! 564: transform_type_t type;
! 565: array_t *types;
! 566: int i;
! 567:
! 568: if (&this->public == other)
! 569: {
! 570: return TRUE;
! 571: }
! 572:
! 573: types = merge_types(this, (private_proposal_t*)other);
! 574: for (i = 0; i < array_count(types); i++)
! 575: {
! 576: array_get(types, i, &type);
! 577: if (!algo_list_equals(this, other, type))
! 578: {
! 579: array_destroy(types);
! 580: return FALSE;
! 581: }
! 582: }
! 583: array_destroy(types);
! 584: return TRUE;
! 585: }
! 586:
! 587: METHOD(proposal_t, clone_, proposal_t*,
! 588: private_proposal_t *this, proposal_selection_flag_t flags)
! 589: {
! 590: private_proposal_t *clone;
! 591: enumerator_t *enumerator;
! 592: entry_t *entry;
! 593:
! 594: clone = (private_proposal_t*)proposal_create(this->protocol, 0);
! 595:
! 596: enumerator = array_create_enumerator(this->transforms);
! 597: while (enumerator->enumerate(enumerator, &entry))
! 598: {
! 599: if (entry->alg >= 1024 && (flags & PROPOSAL_SKIP_PRIVATE))
! 600: {
! 601: continue;
! 602: }
! 603: if (entry->type == DIFFIE_HELLMAN_GROUP && (flags & PROPOSAL_SKIP_DH))
! 604: {
! 605: continue;
! 606: }
! 607: array_insert(clone->transforms, ARRAY_TAIL, entry);
! 608: add_type(clone->types, entry->type);
! 609: }
! 610: enumerator->destroy(enumerator);
! 611:
! 612: clone->spi = this->spi;
! 613: clone->number = this->number;
! 614: clone->transform_number = this->transform_number;
! 615:
! 616: return &clone->public;
! 617: }
! 618:
! 619: /**
! 620: * Map integrity algorithms to the PRF functions using the same algorithm.
! 621: */
! 622: static const struct {
! 623: integrity_algorithm_t integ;
! 624: pseudo_random_function_t prf;
! 625: } integ_prf_map[] = {
! 626: {AUTH_HMAC_SHA1_96, PRF_HMAC_SHA1 },
! 627: {AUTH_HMAC_SHA1_160, PRF_HMAC_SHA1 },
! 628: {AUTH_HMAC_SHA2_256_128, PRF_HMAC_SHA2_256 },
! 629: {AUTH_HMAC_SHA2_384_192, PRF_HMAC_SHA2_384 },
! 630: {AUTH_HMAC_SHA2_512_256, PRF_HMAC_SHA2_512 },
! 631: {AUTH_HMAC_MD5_96, PRF_HMAC_MD5 },
! 632: {AUTH_HMAC_MD5_128, PRF_HMAC_MD5 },
! 633: {AUTH_AES_XCBC_96, PRF_AES128_XCBC },
! 634: {AUTH_CAMELLIA_XCBC_96, PRF_CAMELLIA128_XCBC },
! 635: {AUTH_AES_CMAC_96, PRF_AES128_CMAC },
! 636: };
! 637:
! 638: /**
! 639: * Remove all entries of the given transform type
! 640: */
! 641: static void remove_transform(private_proposal_t *this, transform_type_t type)
! 642: {
! 643: enumerator_t *e;
! 644: entry_t *entry;
! 645:
! 646: e = array_create_enumerator(this->transforms);
! 647: while (e->enumerate(e, &entry))
! 648: {
! 649: if (entry->type == type)
! 650: {
! 651: array_remove_at(this->transforms, e);
! 652: }
! 653: }
! 654: e->destroy(e);
! 655: remove_type(this, type);
! 656: }
! 657:
! 658: /**
! 659: * Checks the proposal read from a string.
! 660: */
! 661: static bool check_proposal(private_proposal_t *this)
! 662: {
! 663: enumerator_t *e;
! 664: entry_t *entry;
! 665: uint16_t alg, ks;
! 666: bool all_aead = TRUE, any_aead = FALSE, any_enc = FALSE;
! 667: int i;
! 668:
! 669: if (this->protocol == PROTO_IKE)
! 670: {
! 671: if (!get_algorithm(this, PSEUDO_RANDOM_FUNCTION, NULL, NULL))
! 672: { /* No explicit PRF found. We assume the same algorithm as used
! 673: * for integrity checking. */
! 674: e = create_enumerator(this, INTEGRITY_ALGORITHM);
! 675: while (e->enumerate(e, &alg, &ks))
! 676: {
! 677: for (i = 0; i < countof(integ_prf_map); i++)
! 678: {
! 679: if (alg == integ_prf_map[i].integ)
! 680: {
! 681: add_algorithm(this, PSEUDO_RANDOM_FUNCTION,
! 682: integ_prf_map[i].prf, 0);
! 683: break;
! 684: }
! 685: }
! 686: }
! 687: e->destroy(e);
! 688: }
! 689: if (!get_algorithm(this, PSEUDO_RANDOM_FUNCTION, NULL, NULL))
! 690: {
! 691: DBG1(DBG_CFG, "a PRF algorithm is mandatory in IKE proposals");
! 692: return FALSE;
! 693: }
! 694: /* remove MODP_NONE from IKE proposal */
! 695: e = array_create_enumerator(this->transforms);
! 696: while (e->enumerate(e, &entry))
! 697: {
! 698: if (entry->type == DIFFIE_HELLMAN_GROUP && !entry->alg)
! 699: {
! 700: array_remove_at(this->transforms, e);
! 701: }
! 702: }
! 703: e->destroy(e);
! 704: if (!get_algorithm(this, DIFFIE_HELLMAN_GROUP, NULL, NULL))
! 705: {
! 706: DBG1(DBG_CFG, "a DH group is mandatory in IKE proposals");
! 707: return FALSE;
! 708: }
! 709: }
! 710: else
! 711: { /* remove PRFs from ESP/AH proposals */
! 712: remove_transform(this, PSEUDO_RANDOM_FUNCTION);
! 713: }
! 714:
! 715: if (this->protocol == PROTO_IKE || this->protocol == PROTO_ESP)
! 716: {
! 717: e = create_enumerator(this, ENCRYPTION_ALGORITHM);
! 718: while (e->enumerate(e, &alg, &ks))
! 719: {
! 720: any_enc = TRUE;
! 721: if (encryption_algorithm_is_aead(alg))
! 722: {
! 723: any_aead = TRUE;
! 724: continue;
! 725: }
! 726: all_aead = FALSE;
! 727: }
! 728: e->destroy(e);
! 729:
! 730: if (!any_enc)
! 731: {
! 732: DBG1(DBG_CFG, "an encryption algorithm is mandatory in %N proposals",
! 733: protocol_id_names, this->protocol);
! 734: return FALSE;
! 735: }
! 736: else if (any_aead && !all_aead)
! 737: {
! 738: DBG1(DBG_CFG, "classic and combined-mode (AEAD) encryption "
! 739: "algorithms can't be contained in the same %N proposal",
! 740: protocol_id_names, this->protocol);
! 741: return FALSE;
! 742: }
! 743: else if (all_aead)
! 744: { /* if all encryption algorithms in the proposal are AEADs,
! 745: * we MUST NOT propose any integrity algorithms */
! 746: remove_transform(this, INTEGRITY_ALGORITHM);
! 747: }
! 748: else if (this->protocol == PROTO_IKE &&
! 749: !get_algorithm(this, INTEGRITY_ALGORITHM, NULL, NULL))
! 750: {
! 751: DBG1(DBG_CFG, "an integrity algorithm is mandatory in %N proposals "
! 752: "with classic (non-AEAD) encryption algorithms",
! 753: protocol_id_names, this->protocol);
! 754: return FALSE;
! 755: }
! 756: }
! 757: else
! 758: { /* AES-GMAC is parsed as encryption algorithm, so we map that to the
! 759: * proper integrity algorithm */
! 760: e = array_create_enumerator(this->transforms);
! 761: while (e->enumerate(e, &entry))
! 762: {
! 763: if (entry->type == ENCRYPTION_ALGORITHM)
! 764: {
! 765: if (entry->alg == ENCR_NULL_AUTH_AES_GMAC)
! 766: {
! 767: entry->type = INTEGRITY_ALGORITHM;
! 768: ks = entry->key_size;
! 769: entry->key_size = 0;
! 770: switch (ks)
! 771: {
! 772: case 128:
! 773: entry->alg = AUTH_AES_128_GMAC;
! 774: continue;
! 775: case 192:
! 776: entry->alg = AUTH_AES_192_GMAC;
! 777: continue;
! 778: case 256:
! 779: entry->alg = AUTH_AES_256_GMAC;
! 780: continue;
! 781: default:
! 782: break;
! 783: }
! 784: }
! 785: /* remove all other encryption algorithms */
! 786: array_remove_at(this->transforms, e);
! 787: }
! 788: }
! 789: e->destroy(e);
! 790: remove_type(this, ENCRYPTION_ALGORITHM);
! 791:
! 792: if (!get_algorithm(this, INTEGRITY_ALGORITHM, NULL, NULL))
! 793: {
! 794: DBG1(DBG_CFG, "an integrity algorithm is mandatory in AH "
! 795: "proposals");
! 796: return FALSE;
! 797: }
! 798: }
! 799:
! 800: if (this->protocol == PROTO_AH || this->protocol == PROTO_ESP)
! 801: {
! 802: if (!get_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NULL, NULL))
! 803: { /* ESN not specified, assume not supported */
! 804: add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0);
! 805: }
! 806: }
! 807:
! 808: array_compress(this->transforms);
! 809: array_compress(this->types);
! 810: return TRUE;
! 811: }
! 812:
! 813: /**
! 814: * add a algorithm identified by a string to the proposal.
! 815: */
! 816: static bool add_string_algo(private_proposal_t *this, const char *alg)
! 817: {
! 818: const proposal_token_t *token;
! 819:
! 820: token = lib->proposal->get_token(lib->proposal, alg);
! 821: if (token == NULL)
! 822: {
! 823: DBG1(DBG_CFG, "algorithm '%s' not recognized", alg);
! 824: return FALSE;
! 825: }
! 826:
! 827: add_algorithm(this, token->type, token->algorithm, token->keysize);
! 828:
! 829: return TRUE;
! 830: }
! 831:
! 832: /**
! 833: * Print all algorithms of the given type
! 834: */
! 835: static int print_alg(private_proposal_t *this, printf_hook_data_t *data,
! 836: transform_type_t type, bool *first)
! 837: {
! 838: enumerator_t *enumerator;
! 839: size_t written = 0;
! 840: entry_t *entry;
! 841: enum_name_t *names;
! 842:
! 843: names = transform_get_enum_names(type);
! 844:
! 845: enumerator = array_create_enumerator(this->transforms);
! 846: while (enumerator->enumerate(enumerator, &entry))
! 847: {
! 848: char *prefix = "/";
! 849:
! 850: if (type != entry->type)
! 851: {
! 852: continue;
! 853: }
! 854: if (*first)
! 855: {
! 856: prefix = "";
! 857: *first = FALSE;
! 858: }
! 859: if (names)
! 860: {
! 861: written += print_in_hook(data, "%s%N", prefix, names, entry->alg);
! 862: }
! 863: else
! 864: {
! 865: written += print_in_hook(data, "%sUNKNOWN_%u_%u", prefix,
! 866: entry->type, entry->alg);
! 867: }
! 868: if (entry->key_size)
! 869: {
! 870: written += print_in_hook(data, "_%u", entry->key_size);
! 871: }
! 872: }
! 873: enumerator->destroy(enumerator);
! 874: return written;
! 875: }
! 876:
! 877: /**
! 878: * Described in header.
! 879: */
! 880: int proposal_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec,
! 881: const void *const *args)
! 882: {
! 883: private_proposal_t *this = *((private_proposal_t**)(args[0]));
! 884: linked_list_t *list = *((linked_list_t**)(args[0]));
! 885: enumerator_t *enumerator;
! 886: transform_type_t *type;
! 887: size_t written = 0;
! 888: bool first = TRUE;
! 889:
! 890: if (this == NULL)
! 891: {
! 892: return print_in_hook(data, "(null)");
! 893: }
! 894:
! 895: if (spec->hash)
! 896: {
! 897: enumerator = list->create_enumerator(list);
! 898: while (enumerator->enumerate(enumerator, &this))
! 899: { /* call recursively */
! 900: if (first)
! 901: {
! 902: written += print_in_hook(data, "%P", this);
! 903: first = FALSE;
! 904: }
! 905: else
! 906: {
! 907: written += print_in_hook(data, ", %P", this);
! 908: }
! 909: }
! 910: enumerator->destroy(enumerator);
! 911: return written;
! 912: }
! 913:
! 914: written = print_in_hook(data, "%N:", protocol_id_names, this->protocol);
! 915: enumerator = array_create_enumerator(this->types);
! 916: while (enumerator->enumerate(enumerator, &type))
! 917: {
! 918: written += print_alg(this, data, *type, &first);
! 919: }
! 920: enumerator->destroy(enumerator);
! 921: return written;
! 922: }
! 923:
! 924: METHOD(proposal_t, destroy, void,
! 925: private_proposal_t *this)
! 926: {
! 927: array_destroy(this->transforms);
! 928: array_destroy(this->types);
! 929: free(this);
! 930: }
! 931:
! 932: /*
! 933: * Described in header
! 934: */
! 935: proposal_t *proposal_create_v1(protocol_id_t protocol, uint8_t number,
! 936: uint8_t transform)
! 937: {
! 938: private_proposal_t *this;
! 939:
! 940: INIT(this,
! 941: .public = {
! 942: .add_algorithm = _add_algorithm,
! 943: .create_enumerator = _create_enumerator,
! 944: .get_algorithm = _get_algorithm,
! 945: .has_dh_group = _has_dh_group,
! 946: .promote_dh_group = _promote_dh_group,
! 947: .select = _select_proposal,
! 948: .matches = _matches,
! 949: .get_protocol = _get_protocol,
! 950: .set_spi = _set_spi,
! 951: .get_spi = _get_spi,
! 952: .get_number = _get_number,
! 953: .get_transform_number = _get_transform_number,
! 954: .equals = _equals,
! 955: .clone = _clone_,
! 956: .destroy = _destroy,
! 957: },
! 958: .protocol = protocol,
! 959: .number = number,
! 960: .transform_number = transform,
! 961: .transforms = array_create(sizeof(entry_t), 0),
! 962: .types = array_create(sizeof(transform_type_t), 0),
! 963: );
! 964:
! 965: return &this->public;
! 966: }
! 967:
! 968: /*
! 969: * Described in header
! 970: */
! 971: proposal_t *proposal_create(protocol_id_t protocol, uint8_t number)
! 972: {
! 973: return proposal_create_v1(protocol, number, 0);
! 974: }
! 975:
! 976: /**
! 977: * Add supported IKE algorithms to proposal
! 978: */
! 979: static bool proposal_add_supported_ike(private_proposal_t *this, bool aead)
! 980: {
! 981: enumerator_t *enumerator;
! 982: encryption_algorithm_t encryption;
! 983: integrity_algorithm_t integrity;
! 984: pseudo_random_function_t prf;
! 985: diffie_hellman_group_t group;
! 986: const char *plugin_name;
! 987:
! 988: if (aead)
! 989: {
! 990: /* Round 1 adds algorithms with at least 128 bit security strength */
! 991: enumerator = lib->crypto->create_aead_enumerator(lib->crypto);
! 992: while (enumerator->enumerate(enumerator, &encryption, &plugin_name))
! 993: {
! 994: switch (encryption)
! 995: {
! 996: case ENCR_AES_GCM_ICV16:
! 997: case ENCR_AES_CCM_ICV16:
! 998: case ENCR_CAMELLIA_CCM_ICV16:
! 999: /* we assume that we support all AES/Camellia sizes */
! 1000: add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 128);
! 1001: add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 192);
! 1002: add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 256);
! 1003: break;
! 1004: case ENCR_CHACHA20_POLY1305:
! 1005: add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 0);
! 1006: break;
! 1007: default:
! 1008: break;
! 1009: }
! 1010: }
! 1011: enumerator->destroy(enumerator);
! 1012:
! 1013: /* Round 2 adds algorithms with less than 128 bit security strength */
! 1014: enumerator = lib->crypto->create_aead_enumerator(lib->crypto);
! 1015: while (enumerator->enumerate(enumerator, &encryption, &plugin_name))
! 1016: {
! 1017: switch (encryption)
! 1018: {
! 1019: case ENCR_AES_GCM_ICV12:
! 1020: case ENCR_AES_GCM_ICV8:
! 1021: case ENCR_AES_CCM_ICV12:
! 1022: case ENCR_AES_CCM_ICV8:
! 1023: case ENCR_CAMELLIA_CCM_ICV12:
! 1024: case ENCR_CAMELLIA_CCM_ICV8:
! 1025: /* we assume that we support all AES/Camellia sizes */
! 1026: add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 128);
! 1027: add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 192);
! 1028: add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 256);
! 1029: break;
! 1030: default:
! 1031: break;
! 1032: }
! 1033: }
! 1034: enumerator->destroy(enumerator);
! 1035:
! 1036: if (!array_count(this->transforms))
! 1037: {
! 1038: return FALSE;
! 1039: }
! 1040: }
! 1041: else
! 1042: {
! 1043: /* Round 1 adds algorithms with at least 128 bit security strength */
! 1044: enumerator = lib->crypto->create_crypter_enumerator(lib->crypto);
! 1045: while (enumerator->enumerate(enumerator, &encryption, &plugin_name))
! 1046: {
! 1047: switch (encryption)
! 1048: {
! 1049: case ENCR_AES_CBC:
! 1050: case ENCR_AES_CTR:
! 1051: case ENCR_CAMELLIA_CBC:
! 1052: case ENCR_CAMELLIA_CTR:
! 1053: /* we assume that we support all AES/Camellia sizes */
! 1054: add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 128);
! 1055: add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 192);
! 1056: add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 256);
! 1057: break;
! 1058: default:
! 1059: break;
! 1060: }
! 1061: }
! 1062: enumerator->destroy(enumerator);
! 1063:
! 1064: /* Round 2 adds algorithms with less than 128 bit security strength */
! 1065: enumerator = lib->crypto->create_crypter_enumerator(lib->crypto);
! 1066: while (enumerator->enumerate(enumerator, &encryption, &plugin_name))
! 1067: {
! 1068: switch (encryption)
! 1069: {
! 1070: case ENCR_3DES:
! 1071: add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 0);
! 1072: break;
! 1073: case ENCR_DES:
! 1074: /* no, thanks */
! 1075: break;
! 1076: default:
! 1077: break;
! 1078: }
! 1079: }
! 1080: enumerator->destroy(enumerator);
! 1081:
! 1082: if (!array_count(this->transforms))
! 1083: {
! 1084: return FALSE;
! 1085: }
! 1086:
! 1087: /* Round 1 adds algorithms with at least 128 bit security strength */
! 1088: enumerator = lib->crypto->create_signer_enumerator(lib->crypto);
! 1089: while (enumerator->enumerate(enumerator, &integrity, &plugin_name))
! 1090: {
! 1091: switch (integrity)
! 1092: {
! 1093: case AUTH_HMAC_SHA2_256_128:
! 1094: case AUTH_HMAC_SHA2_384_192:
! 1095: case AUTH_HMAC_SHA2_512_256:
! 1096: add_algorithm(this, INTEGRITY_ALGORITHM, integrity, 0);
! 1097: break;
! 1098: default:
! 1099: break;
! 1100: }
! 1101: }
! 1102: enumerator->destroy(enumerator);
! 1103:
! 1104: /* Round 2 adds algorithms with less than 128 bit security strength */
! 1105: enumerator = lib->crypto->create_signer_enumerator(lib->crypto);
! 1106: while (enumerator->enumerate(enumerator, &integrity, &plugin_name))
! 1107: {
! 1108: switch (integrity)
! 1109: {
! 1110: case AUTH_AES_XCBC_96:
! 1111: case AUTH_AES_CMAC_96:
! 1112: case AUTH_HMAC_SHA1_96:
! 1113: add_algorithm(this, INTEGRITY_ALGORITHM, integrity, 0);
! 1114: break;
! 1115: case AUTH_HMAC_MD5_96:
! 1116: /* no, thanks */
! 1117: default:
! 1118: break;
! 1119: }
! 1120: }
! 1121: enumerator->destroy(enumerator);
! 1122: }
! 1123:
! 1124: /* Round 1 adds algorithms with at least 128 bit security strength */
! 1125: enumerator = lib->crypto->create_prf_enumerator(lib->crypto);
! 1126: while (enumerator->enumerate(enumerator, &prf, &plugin_name))
! 1127: {
! 1128: switch (prf)
! 1129: {
! 1130: case PRF_HMAC_SHA2_256:
! 1131: case PRF_HMAC_SHA2_384:
! 1132: case PRF_HMAC_SHA2_512:
! 1133: case PRF_AES128_XCBC:
! 1134: case PRF_AES128_CMAC:
! 1135: add_algorithm(this, PSEUDO_RANDOM_FUNCTION, prf, 0);
! 1136: break;
! 1137: default:
! 1138: break;
! 1139: }
! 1140: }
! 1141: enumerator->destroy(enumerator);
! 1142:
! 1143: /* Round 2 adds algorithms with less than 128 bit security strength */
! 1144: enumerator = lib->crypto->create_prf_enumerator(lib->crypto);
! 1145: while (enumerator->enumerate(enumerator, &prf, &plugin_name))
! 1146: {
! 1147: switch (prf)
! 1148: {
! 1149: case PRF_HMAC_SHA1:
! 1150: add_algorithm(this, PSEUDO_RANDOM_FUNCTION, prf, 0);
! 1151: break;
! 1152: case PRF_HMAC_MD5:
! 1153: /* no, thanks */
! 1154: break;
! 1155: default:
! 1156: break;
! 1157: }
! 1158: }
! 1159: enumerator->destroy(enumerator);
! 1160:
! 1161: /* Round 1 adds ECC and NTRU algorithms with at least 128 bit security strength */
! 1162: enumerator = lib->crypto->create_dh_enumerator(lib->crypto);
! 1163: while (enumerator->enumerate(enumerator, &group, &plugin_name))
! 1164: {
! 1165: switch (group)
! 1166: {
! 1167: case ECP_256_BIT:
! 1168: case ECP_384_BIT:
! 1169: case ECP_521_BIT:
! 1170: case ECP_256_BP:
! 1171: case ECP_384_BP:
! 1172: case ECP_512_BP:
! 1173: case CURVE_25519:
! 1174: case CURVE_448:
! 1175: case NTRU_128_BIT:
! 1176: case NTRU_192_BIT:
! 1177: case NTRU_256_BIT:
! 1178: case NH_128_BIT:
! 1179: add_algorithm(this, DIFFIE_HELLMAN_GROUP, group, 0);
! 1180: break;
! 1181: default:
! 1182: break;
! 1183: }
! 1184: }
! 1185: enumerator->destroy(enumerator);
! 1186:
! 1187: /* Round 2 adds other algorithms with at least 128 bit security strength */
! 1188: enumerator = lib->crypto->create_dh_enumerator(lib->crypto);
! 1189: while (enumerator->enumerate(enumerator, &group, &plugin_name))
! 1190: {
! 1191: switch (group)
! 1192: {
! 1193: case MODP_3072_BIT:
! 1194: case MODP_4096_BIT:
! 1195: case MODP_6144_BIT:
! 1196: case MODP_8192_BIT:
! 1197: add_algorithm(this, DIFFIE_HELLMAN_GROUP, group, 0);
! 1198: break;
! 1199: default:
! 1200: break;
! 1201: }
! 1202: }
! 1203: enumerator->destroy(enumerator);
! 1204:
! 1205: /* Round 3 adds algorithms with less than 128 bit security strength */
! 1206: enumerator = lib->crypto->create_dh_enumerator(lib->crypto);
! 1207: while (enumerator->enumerate(enumerator, &group, &plugin_name))
! 1208: {
! 1209: switch (group)
! 1210: {
! 1211: case MODP_NULL:
! 1212: /* only for testing purposes */
! 1213: break;
! 1214: case MODP_768_BIT:
! 1215: case MODP_1024_BIT:
! 1216: case MODP_1536_BIT:
! 1217: /* weak */
! 1218: break;
! 1219: case MODP_1024_160:
! 1220: case MODP_2048_224:
! 1221: case MODP_2048_256:
! 1222: /* RFC 5114 primes are of questionable source */
! 1223: break;
! 1224: case ECP_224_BIT:
! 1225: case ECP_224_BP:
! 1226: case ECP_192_BIT:
! 1227: case NTRU_112_BIT:
! 1228: /* rarely used */
! 1229: break;
! 1230: case MODP_2048_BIT:
! 1231: add_algorithm(this, DIFFIE_HELLMAN_GROUP, group, 0);
! 1232: break;
! 1233: default:
! 1234: break;
! 1235: }
! 1236: }
! 1237: enumerator->destroy(enumerator);
! 1238:
! 1239: return TRUE;
! 1240: }
! 1241:
! 1242: /*
! 1243: * Described in header
! 1244: */
! 1245: proposal_t *proposal_create_default(protocol_id_t protocol)
! 1246: {
! 1247: private_proposal_t *this = (private_proposal_t*)proposal_create(protocol, 0);
! 1248:
! 1249: switch (protocol)
! 1250: {
! 1251: case PROTO_IKE:
! 1252: if (!proposal_add_supported_ike(this, FALSE))
! 1253: {
! 1254: destroy(this);
! 1255: return NULL;
! 1256: }
! 1257: break;
! 1258: case PROTO_ESP:
! 1259: add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 128);
! 1260: add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 192);
! 1261: add_algorithm(this, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 256);
! 1262: add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_256_128, 0);
! 1263: add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_384_192, 0);
! 1264: add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_512_256, 0);
! 1265: add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0);
! 1266: add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_AES_XCBC_96, 0);
! 1267: add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0);
! 1268: break;
! 1269: case PROTO_AH:
! 1270: add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_256_128, 0);
! 1271: add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_384_192, 0);
! 1272: add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_512_256, 0);
! 1273: add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0);
! 1274: add_algorithm(this, INTEGRITY_ALGORITHM, AUTH_AES_XCBC_96, 0);
! 1275: add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0);
! 1276: break;
! 1277: default:
! 1278: break;
! 1279: }
! 1280: return &this->public;
! 1281: }
! 1282:
! 1283: /*
! 1284: * Described in header
! 1285: */
! 1286: proposal_t *proposal_create_default_aead(protocol_id_t protocol)
! 1287: {
! 1288: private_proposal_t *this;
! 1289:
! 1290: switch (protocol)
! 1291: {
! 1292: case PROTO_IKE:
! 1293: this = (private_proposal_t*)proposal_create(protocol, 0);
! 1294: if (!proposal_add_supported_ike(this, TRUE))
! 1295: {
! 1296: destroy(this);
! 1297: return NULL;
! 1298: }
! 1299: return &this->public;
! 1300: case PROTO_ESP:
! 1301: /* we currently don't include any AEAD proposal for ESP, as we
! 1302: * don't know if our kernel backend actually supports it. */
! 1303: return NULL;
! 1304: case PROTO_AH:
! 1305: default:
! 1306: return NULL;
! 1307: }
! 1308: }
! 1309:
! 1310: /*
! 1311: * Described in header
! 1312: */
! 1313: proposal_t *proposal_create_from_string(protocol_id_t protocol, const char *algs)
! 1314: {
! 1315: private_proposal_t *this;
! 1316: enumerator_t *enumerator;
! 1317: bool failed = TRUE;
! 1318: char *alg;
! 1319:
! 1320: this = (private_proposal_t*)proposal_create(protocol, 0);
! 1321:
! 1322: /* get all tokens, separated by '-' */
! 1323: enumerator = enumerator_create_token(algs, "-", " ");
! 1324: while (enumerator->enumerate(enumerator, &alg))
! 1325: {
! 1326: if (!add_string_algo(this, alg))
! 1327: {
! 1328: failed = TRUE;
! 1329: break;
! 1330: }
! 1331: failed = FALSE;
! 1332: }
! 1333: enumerator->destroy(enumerator);
! 1334:
! 1335: if (failed || !check_proposal(this))
! 1336: {
! 1337: destroy(this);
! 1338: return NULL;
! 1339: }
! 1340:
! 1341: return &this->public;
! 1342: }
! 1343:
! 1344: /*
! 1345: * Described in header
! 1346: */
! 1347: proposal_t *proposal_select(linked_list_t *configured, linked_list_t *supplied,
! 1348: proposal_selection_flag_t flags)
! 1349: {
! 1350: enumerator_t *prefer_enum, *match_enum;
! 1351: proposal_t *proposal, *match, *selected = NULL;
! 1352:
! 1353: if (flags & PROPOSAL_PREFER_SUPPLIED)
! 1354: {
! 1355: prefer_enum = supplied->create_enumerator(supplied);
! 1356: match_enum = configured->create_enumerator(configured);
! 1357: }
! 1358: else
! 1359: {
! 1360: prefer_enum = configured->create_enumerator(configured);
! 1361: match_enum = supplied->create_enumerator(supplied);
! 1362: }
! 1363:
! 1364: while (prefer_enum->enumerate(prefer_enum, &proposal))
! 1365: {
! 1366: if (flags & PROPOSAL_PREFER_SUPPLIED)
! 1367: {
! 1368: configured->reset_enumerator(configured, match_enum);
! 1369: }
! 1370: else
! 1371: {
! 1372: supplied->reset_enumerator(supplied, match_enum);
! 1373: }
! 1374: while (match_enum->enumerate(match_enum, &match))
! 1375: {
! 1376: selected = proposal->select(proposal, match, flags);
! 1377: if (selected)
! 1378: {
! 1379: DBG2(DBG_CFG, "received proposals: %#P", supplied);
! 1380: DBG2(DBG_CFG, "configured proposals: %#P", configured);
! 1381: DBG1(DBG_CFG, "selected proposal: %P", selected);
! 1382: break;
! 1383: }
! 1384: }
! 1385: if (selected)
! 1386: {
! 1387: break;
! 1388: }
! 1389: }
! 1390: prefer_enum->destroy(prefer_enum);
! 1391: match_enum->destroy(match_enum);
! 1392: if (!selected)
! 1393: {
! 1394: DBG1(DBG_CFG, "received proposals: %#P", supplied);
! 1395: DBG1(DBG_CFG, "configured proposals: %#P", configured);
! 1396: }
! 1397: return selected;
! 1398: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>