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, &current, 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>