Annotation of embedaddon/strongswan/src/libcharon/sa/ikev2/keymat_v2.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (C) 2015 Tobias Brunner
        !             3:  * Copyright (C) 2008 Martin Willi
        !             4:  * HSR Hochschule fuer Technik Rapperswil
        !             5:  *
        !             6:  * This program is free software; you can redistribute it and/or modify it
        !             7:  * under the terms of the GNU General Public License as published by the
        !             8:  * Free Software Foundation; either version 2 of the License, or (at your
        !             9:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
        !            10:  *
        !            11:  * This program is distributed in the hope that it will be useful, but
        !            12:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
        !            13:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
        !            14:  * for more details.
        !            15:  */
        !            16: 
        !            17: #include "keymat_v2.h"
        !            18: 
        !            19: #include <daemon.h>
        !            20: #include <crypto/prf_plus.h>
        !            21: #include <crypto/hashers/hash_algorithm_set.h>
        !            22: 
        !            23: typedef struct private_keymat_v2_t private_keymat_v2_t;
        !            24: 
        !            25: /**
        !            26:  * Private data of an keymat_t object.
        !            27:  */
        !            28: struct private_keymat_v2_t {
        !            29: 
        !            30:        /**
        !            31:         * Public keymat_v2_t interface.
        !            32:         */
        !            33:        keymat_v2_t public;
        !            34: 
        !            35:        /**
        !            36:         * IKE_SA Role, initiator or responder
        !            37:         */
        !            38:        bool initiator;
        !            39: 
        !            40:        /**
        !            41:         * inbound AEAD
        !            42:         */
        !            43:        aead_t *aead_in;
        !            44: 
        !            45:        /**
        !            46:         * outbound AEAD
        !            47:         */
        !            48:        aead_t *aead_out;
        !            49: 
        !            50:        /**
        !            51:         * General purpose PRF
        !            52:         */
        !            53:        prf_t *prf;
        !            54: 
        !            55:        /**
        !            56:         * Negotiated PRF algorithm
        !            57:         */
        !            58:        pseudo_random_function_t prf_alg;
        !            59: 
        !            60:        /**
        !            61:         * Key to derive key material from for CHILD_SAs, rekeying
        !            62:         */
        !            63:        chunk_t skd;
        !            64: 
        !            65:        /**
        !            66:         * Key to build outgoing authentication data (SKp)
        !            67:         */
        !            68:        chunk_t skp_build;
        !            69: 
        !            70:        /**
        !            71:         * Key to verify incoming authentication data (SKp)
        !            72:         */
        !            73:        chunk_t skp_verify;
        !            74: 
        !            75:        /**
        !            76:         * Set of hash algorithms supported by peer for signature authentication
        !            77:         */
        !            78:        hash_algorithm_set_t *hash_algorithms;
        !            79: };
        !            80: 
        !            81: METHOD(keymat_t, get_version, ike_version_t,
        !            82:        private_keymat_v2_t *this)
        !            83: {
        !            84:        return IKEV2;
        !            85: }
        !            86: 
        !            87: METHOD(keymat_t, create_dh, diffie_hellman_t*,
        !            88:        private_keymat_v2_t *this, diffie_hellman_group_t group)
        !            89: {
        !            90:        return lib->crypto->create_dh(lib->crypto, group);
        !            91: }
        !            92: 
        !            93: METHOD(keymat_t, create_nonce_gen, nonce_gen_t*,
        !            94:        private_keymat_v2_t *this)
        !            95: {
        !            96:        return lib->crypto->create_nonce_gen(lib->crypto);
        !            97: }
        !            98: 
        !            99: /**
        !           100:  * Derive IKE keys for a combined AEAD algorithm
        !           101:  */
        !           102: static bool derive_ike_aead(private_keymat_v2_t *this, uint16_t alg,
        !           103:                                                        uint16_t key_size, prf_plus_t *prf_plus)
        !           104: {
        !           105:        aead_t *aead_i, *aead_r;
        !           106:        chunk_t sk_ei = chunk_empty, sk_er = chunk_empty;
        !           107:        u_int salt_size;
        !           108: 
        !           109:        switch (alg)
        !           110:        {
        !           111:                case ENCR_AES_GCM_ICV8:
        !           112:                case ENCR_AES_GCM_ICV12:
        !           113:                case ENCR_AES_GCM_ICV16:
        !           114:                        /* RFC 4106 */
        !           115:                case ENCR_CHACHA20_POLY1305:
        !           116:                        salt_size = 4;
        !           117:                        break;
        !           118:                case ENCR_AES_CCM_ICV8:
        !           119:                case ENCR_AES_CCM_ICV12:
        !           120:                case ENCR_AES_CCM_ICV16:
        !           121:                        /* RFC 4309 */
        !           122:                case ENCR_CAMELLIA_CCM_ICV8:
        !           123:                case ENCR_CAMELLIA_CCM_ICV12:
        !           124:                case ENCR_CAMELLIA_CCM_ICV16:
        !           125:                        /* RFC 5529 */
        !           126:                        salt_size = 3;
        !           127:                        break;
        !           128:                default:
        !           129:                        DBG1(DBG_IKE, "nonce size for %N unknown!",
        !           130:                                 encryption_algorithm_names, alg);
        !           131:                        return FALSE;
        !           132:        }
        !           133: 
        !           134:        /* SK_ei/SK_er used for encryption */
        !           135:        aead_i = lib->crypto->create_aead(lib->crypto, alg, key_size / 8, salt_size);
        !           136:        aead_r = lib->crypto->create_aead(lib->crypto, alg, key_size / 8, salt_size);
        !           137:        if (aead_i == NULL || aead_r == NULL)
        !           138:        {
        !           139:                DBG1(DBG_IKE, "%N %N (key size %d) not supported!",
        !           140:                         transform_type_names, ENCRYPTION_ALGORITHM,
        !           141:                         encryption_algorithm_names, alg, key_size);
        !           142:                goto failure;
        !           143:        }
        !           144:        key_size = aead_i->get_key_size(aead_i);
        !           145:        if (key_size != aead_r->get_key_size(aead_r))
        !           146:        {
        !           147:                goto failure;
        !           148:        }
        !           149:        if (!prf_plus->allocate_bytes(prf_plus, key_size, &sk_ei))
        !           150:        {
        !           151:                goto failure;
        !           152:        }
        !           153:        DBG4(DBG_IKE, "Sk_ei secret %B", &sk_ei);
        !           154:        if (!aead_i->set_key(aead_i, sk_ei))
        !           155:        {
        !           156:                goto failure;
        !           157:        }
        !           158: 
        !           159:        if (!prf_plus->allocate_bytes(prf_plus, key_size, &sk_er))
        !           160:        {
        !           161:                goto failure;
        !           162:        }
        !           163:        DBG4(DBG_IKE, "Sk_er secret %B", &sk_er);
        !           164:        if (!aead_r->set_key(aead_r, sk_er))
        !           165:        {
        !           166:                goto failure;
        !           167:        }
        !           168: 
        !           169:        if (this->initiator)
        !           170:        {
        !           171:                this->aead_in = aead_r;
        !           172:                this->aead_out = aead_i;
        !           173:        }
        !           174:        else
        !           175:        {
        !           176:                this->aead_in = aead_i;
        !           177:                this->aead_out = aead_r;
        !           178:        }
        !           179:        aead_i = aead_r = NULL;
        !           180:        charon->bus->ike_derived_keys(charon->bus, sk_ei, sk_er, chunk_empty,
        !           181:                                                                  chunk_empty);
        !           182: 
        !           183: failure:
        !           184:        DESTROY_IF(aead_i);
        !           185:        DESTROY_IF(aead_r);
        !           186:        chunk_clear(&sk_ei);
        !           187:        chunk_clear(&sk_er);
        !           188:        return this->aead_in && this->aead_out;
        !           189: }
        !           190: 
        !           191: /**
        !           192:  * Derive IKE keys for traditional encryption and MAC algorithms
        !           193:  */
        !           194: static bool derive_ike_traditional(private_keymat_v2_t *this, uint16_t enc_alg,
        !           195:                                        uint16_t enc_size, uint16_t int_alg, prf_plus_t *prf_plus)
        !           196: {
        !           197:        crypter_t *crypter_i = NULL, *crypter_r = NULL;
        !           198:        signer_t *signer_i, *signer_r;
        !           199:        iv_gen_t *ivg_i, *ivg_r;
        !           200:        size_t key_size;
        !           201:        chunk_t sk_ei = chunk_empty, sk_er = chunk_empty,
        !           202:                        sk_ai = chunk_empty, sk_ar = chunk_empty;
        !           203: 
        !           204:        signer_i = lib->crypto->create_signer(lib->crypto, int_alg);
        !           205:        signer_r = lib->crypto->create_signer(lib->crypto, int_alg);
        !           206:        crypter_i = lib->crypto->create_crypter(lib->crypto, enc_alg, enc_size / 8);
        !           207:        crypter_r = lib->crypto->create_crypter(lib->crypto, enc_alg, enc_size / 8);
        !           208:        if (signer_i == NULL || signer_r == NULL)
        !           209:        {
        !           210:                DBG1(DBG_IKE, "%N %N not supported!",
        !           211:                         transform_type_names, INTEGRITY_ALGORITHM,
        !           212:                         integrity_algorithm_names, int_alg);
        !           213:                goto failure;
        !           214:        }
        !           215:        if (crypter_i == NULL || crypter_r == NULL)
        !           216:        {
        !           217:                DBG1(DBG_IKE, "%N %N (key size %d) not supported!",
        !           218:                         transform_type_names, ENCRYPTION_ALGORITHM,
        !           219:                         encryption_algorithm_names, enc_alg, enc_size);
        !           220:                goto failure;
        !           221:        }
        !           222: 
        !           223:        /* SK_ai/SK_ar used for integrity protection */
        !           224:        key_size = signer_i->get_key_size(signer_i);
        !           225: 
        !           226:        if (!prf_plus->allocate_bytes(prf_plus, key_size, &sk_ai))
        !           227:        {
        !           228:                goto failure;
        !           229:        }
        !           230:        DBG4(DBG_IKE, "Sk_ai secret %B", &sk_ai);
        !           231:        if (!signer_i->set_key(signer_i, sk_ai))
        !           232:        {
        !           233:                goto failure;
        !           234:        }
        !           235: 
        !           236:        if (!prf_plus->allocate_bytes(prf_plus, key_size, &sk_ar))
        !           237:        {
        !           238:                goto failure;
        !           239:        }
        !           240:        DBG4(DBG_IKE, "Sk_ar secret %B", &sk_ar);
        !           241:        if (!signer_r->set_key(signer_r, sk_ar))
        !           242:        {
        !           243:                goto failure;
        !           244:        }
        !           245: 
        !           246:        /* SK_ei/SK_er used for encryption */
        !           247:        key_size = crypter_i->get_key_size(crypter_i);
        !           248: 
        !           249:        if (!prf_plus->allocate_bytes(prf_plus, key_size, &sk_ei))
        !           250:        {
        !           251:                goto failure;
        !           252:        }
        !           253:        DBG4(DBG_IKE, "Sk_ei secret %B", &sk_ei);
        !           254:        if (!crypter_i->set_key(crypter_i, sk_ei))
        !           255:        {
        !           256:                goto failure;
        !           257:        }
        !           258: 
        !           259:        if (!prf_plus->allocate_bytes(prf_plus, key_size, &sk_er))
        !           260:        {
        !           261:                goto failure;
        !           262:        }
        !           263:        DBG4(DBG_IKE, "Sk_er secret %B", &sk_er);
        !           264:        if (!crypter_r->set_key(crypter_r, sk_er))
        !           265:        {
        !           266:                goto failure;
        !           267:        }
        !           268: 
        !           269:        ivg_i = iv_gen_create_for_alg(enc_alg);
        !           270:        ivg_r = iv_gen_create_for_alg(enc_alg);
        !           271:        if (!ivg_i || !ivg_r)
        !           272:        {
        !           273:                goto failure;
        !           274:        }
        !           275:        if (this->initiator)
        !           276:        {
        !           277:                this->aead_in = aead_create(crypter_r, signer_r, ivg_r);
        !           278:                this->aead_out = aead_create(crypter_i, signer_i, ivg_i);
        !           279:        }
        !           280:        else
        !           281:        {
        !           282:                this->aead_in = aead_create(crypter_i, signer_i, ivg_i);
        !           283:                this->aead_out = aead_create(crypter_r, signer_r, ivg_r);
        !           284:        }
        !           285:        signer_i = signer_r = NULL;
        !           286:        crypter_i = crypter_r = NULL;
        !           287:        charon->bus->ike_derived_keys(charon->bus, sk_ei, sk_er, sk_ai, sk_ar);
        !           288: 
        !           289: failure:
        !           290:        chunk_clear(&sk_ai);
        !           291:        chunk_clear(&sk_ar);
        !           292:        chunk_clear(&sk_ei);
        !           293:        chunk_clear(&sk_er);
        !           294:        DESTROY_IF(signer_i);
        !           295:        DESTROY_IF(signer_r);
        !           296:        DESTROY_IF(crypter_i);
        !           297:        DESTROY_IF(crypter_r);
        !           298:        return this->aead_in && this->aead_out;
        !           299: }
        !           300: 
        !           301: METHOD(keymat_v2_t, derive_ike_keys, bool,
        !           302:        private_keymat_v2_t *this, proposal_t *proposal, diffie_hellman_t *dh,
        !           303:        chunk_t nonce_i, chunk_t nonce_r, ike_sa_id_t *id,
        !           304:        pseudo_random_function_t rekey_function, chunk_t rekey_skd)
        !           305: {
        !           306:        chunk_t skeyseed = chunk_empty, key, secret, full_nonce, fixed_nonce;
        !           307:        chunk_t prf_plus_seed, spi_i, spi_r;
        !           308:        prf_plus_t *prf_plus = NULL;
        !           309:        uint16_t alg, key_size, int_alg;
        !           310:        prf_t *rekey_prf = NULL;
        !           311: 
        !           312:        spi_i = chunk_alloca(sizeof(uint64_t));
        !           313:        spi_r = chunk_alloca(sizeof(uint64_t));
        !           314: 
        !           315:        if (!dh->get_shared_secret(dh, &secret))
        !           316:        {
        !           317:                return FALSE;
        !           318:        }
        !           319: 
        !           320:        /* Create SAs general purpose PRF first, we may use it here */
        !           321:        if (!proposal->get_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, &alg, NULL))
        !           322:        {
        !           323:                DBG1(DBG_IKE, "no %N selected",
        !           324:                         transform_type_names, PSEUDO_RANDOM_FUNCTION);
        !           325:                chunk_clear(&secret);
        !           326:                return FALSE;
        !           327:        }
        !           328:        this->prf_alg = alg;
        !           329:        this->prf = lib->crypto->create_prf(lib->crypto, alg);
        !           330:        if (this->prf == NULL)
        !           331:        {
        !           332:                DBG1(DBG_IKE, "%N %N not supported!",
        !           333:                         transform_type_names, PSEUDO_RANDOM_FUNCTION,
        !           334:                         pseudo_random_function_names, alg);
        !           335:                chunk_clear(&secret);
        !           336:                return FALSE;
        !           337:        }
        !           338:        DBG4(DBG_IKE, "shared Diffie Hellman secret %B", &secret);
        !           339:        /* full nonce is used as seed for PRF+ ... */
        !           340:        full_nonce = chunk_cat("cc", nonce_i, nonce_r);
        !           341:        /* but the PRF may need a fixed key which only uses the first bytes of
        !           342:         * the nonces. */
        !           343:        switch (alg)
        !           344:        {
        !           345:                case PRF_AES128_CMAC:
        !           346:                        /* while variable keys may be used according to RFC 4615, RFC 7296
        !           347:                         * explicitly limits the key size to 128 bit for this application */
        !           348:                case PRF_AES128_XCBC:
        !           349:                        /* while RFC 4434 defines variable keys for AES-XCBC, RFC 3664 does
        !           350:                         * not and therefore fixed key semantics apply to XCBC for key
        !           351:                         * derivation, which is also reinforced by RFC 7296 */
        !           352:                case PRF_CAMELLIA128_XCBC:
        !           353:                        /* draft-kanno-ipsecme-camellia-xcbc refers to rfc 4434, we
        !           354:                         * assume fixed key length. */
        !           355:                        key_size = this->prf->get_key_size(this->prf)/2;
        !           356:                        nonce_i.len = min(nonce_i.len, key_size);
        !           357:                        nonce_r.len = min(nonce_r.len, key_size);
        !           358:                        break;
        !           359:                default:
        !           360:                        /* all other algorithms use variable key length, full nonce */
        !           361:                        break;
        !           362:        }
        !           363:        fixed_nonce = chunk_cat("cc", nonce_i, nonce_r);
        !           364:        *((uint64_t*)spi_i.ptr) = id->get_initiator_spi(id);
        !           365:        *((uint64_t*)spi_r.ptr) = id->get_responder_spi(id);
        !           366:        prf_plus_seed = chunk_cat("ccc", full_nonce, spi_i, spi_r);
        !           367: 
        !           368:        /* KEYMAT = prf+ (SKEYSEED, Ni | Nr | SPIi | SPIr)
        !           369:         *
        !           370:         * if we are rekeying, SKEYSEED is built on another way
        !           371:         */
        !           372:        if (rekey_function == PRF_UNDEFINED) /* not rekeying */
        !           373:        {
        !           374:                /* SKEYSEED = prf(Ni | Nr, g^ir) */
        !           375:                if (this->prf->set_key(this->prf, fixed_nonce) &&
        !           376:                        this->prf->allocate_bytes(this->prf, secret, &skeyseed) &&
        !           377:                        this->prf->set_key(this->prf, skeyseed))
        !           378:                {
        !           379:                        prf_plus = prf_plus_create(this->prf, TRUE, prf_plus_seed);
        !           380:                }
        !           381:        }
        !           382:        else
        !           383:        {
        !           384:                /* SKEYSEED = prf(SK_d (old), [g^ir (new)] | Ni | Nr)
        !           385:                 * use OLD SAs PRF functions for both prf_plus and prf */
        !           386:                rekey_prf = lib->crypto->create_prf(lib->crypto, rekey_function);
        !           387:                if (!rekey_prf)
        !           388:                {
        !           389:                        DBG1(DBG_IKE, "PRF of old SA %N not supported!",
        !           390:                                 pseudo_random_function_names, rekey_function);
        !           391:                        chunk_clear(&secret);
        !           392:                        chunk_free(&full_nonce);
        !           393:                        chunk_free(&fixed_nonce);
        !           394:                        chunk_clear(&prf_plus_seed);
        !           395:                        return FALSE;
        !           396:                }
        !           397:                secret = chunk_cat("mc", secret, full_nonce);
        !           398:                if (rekey_prf->set_key(rekey_prf, rekey_skd) &&
        !           399:                        rekey_prf->allocate_bytes(rekey_prf, secret, &skeyseed) &&
        !           400:                        rekey_prf->set_key(rekey_prf, skeyseed))
        !           401:                {
        !           402:                        prf_plus = prf_plus_create(rekey_prf, TRUE, prf_plus_seed);
        !           403:                }
        !           404:        }
        !           405:        DBG4(DBG_IKE, "SKEYSEED %B", &skeyseed);
        !           406: 
        !           407:        chunk_clear(&skeyseed);
        !           408:        chunk_clear(&secret);
        !           409:        chunk_free(&full_nonce);
        !           410:        chunk_free(&fixed_nonce);
        !           411:        chunk_clear(&prf_plus_seed);
        !           412: 
        !           413:        if (!prf_plus)
        !           414:        {
        !           415:                goto failure;
        !           416:        }
        !           417: 
        !           418:        /* KEYMAT = SK_d | SK_ai | SK_ar | SK_ei | SK_er | SK_pi | SK_pr */
        !           419: 
        !           420:        /* SK_d is used for generating CHILD_SA key mat => store for later use */
        !           421:        key_size = this->prf->get_key_size(this->prf);
        !           422:        if (!prf_plus->allocate_bytes(prf_plus, key_size, &this->skd))
        !           423:        {
        !           424:                goto failure;
        !           425:        }
        !           426:        DBG4(DBG_IKE, "Sk_d secret %B", &this->skd);
        !           427: 
        !           428:        if (!proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &alg, &key_size))
        !           429:        {
        !           430:                DBG1(DBG_IKE, "no %N selected",
        !           431:                         transform_type_names, ENCRYPTION_ALGORITHM);
        !           432:                goto failure;
        !           433:        }
        !           434: 
        !           435:        if (encryption_algorithm_is_aead(alg))
        !           436:        {
        !           437:                if (!derive_ike_aead(this, alg, key_size, prf_plus))
        !           438:                {
        !           439:                        goto failure;
        !           440:                }
        !           441:        }
        !           442:        else
        !           443:        {
        !           444:                if (!proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM,
        !           445:                                                                         &int_alg, NULL))
        !           446:                {
        !           447:                        DBG1(DBG_IKE, "no %N selected",
        !           448:                                 transform_type_names, INTEGRITY_ALGORITHM);
        !           449:                        goto failure;
        !           450:                }
        !           451:                if (!derive_ike_traditional(this, alg, key_size, int_alg, prf_plus))
        !           452:                {
        !           453:                        goto failure;
        !           454:                }
        !           455:        }
        !           456: 
        !           457:        /* SK_pi/SK_pr used for authentication => stored for later */
        !           458:        key_size = this->prf->get_key_size(this->prf);
        !           459:        if (!prf_plus->allocate_bytes(prf_plus, key_size, &key))
        !           460:        {
        !           461:                goto failure;
        !           462:        }
        !           463:        DBG4(DBG_IKE, "Sk_pi secret %B", &key);
        !           464:        if (this->initiator)
        !           465:        {
        !           466:                this->skp_build = key;
        !           467:        }
        !           468:        else
        !           469:        {
        !           470:                this->skp_verify = key;
        !           471:        }
        !           472:        if (!prf_plus->allocate_bytes(prf_plus, key_size, &key))
        !           473:        {
        !           474:                goto failure;
        !           475:        }
        !           476:        DBG4(DBG_IKE, "Sk_pr secret %B", &key);
        !           477:        if (this->initiator)
        !           478:        {
        !           479:                this->skp_verify = key;
        !           480:        }
        !           481:        else
        !           482:        {
        !           483:                this->skp_build = key;
        !           484:        }
        !           485: 
        !           486:        /* all done, prf_plus not needed anymore */
        !           487: failure:
        !           488:        DESTROY_IF(prf_plus);
        !           489:        DESTROY_IF(rekey_prf);
        !           490: 
        !           491:        return this->skp_build.len && this->skp_verify.len;
        !           492: }
        !           493: 
        !           494: /**
        !           495:  * Derives a key from the given key and a PRF that was initialized with a PPK
        !           496:  */
        !           497: static bool derive_ppk_key(prf_t *prf, char *name, chunk_t key,
        !           498:                                                   chunk_t *new_key)
        !           499: {
        !           500:        prf_plus_t *prf_plus;
        !           501: 
        !           502:        prf_plus = prf_plus_create(prf, TRUE, key);
        !           503:        if (!prf_plus ||
        !           504:                !prf_plus->allocate_bytes(prf_plus, key.len, new_key))
        !           505:        {
        !           506:                DBG1(DBG_IKE, "unable to derive %s with PPK", name);
        !           507:                DESTROY_IF(prf_plus);
        !           508:                return FALSE;
        !           509:        }
        !           510:        prf_plus->destroy(prf_plus);
        !           511:        return TRUE;
        !           512: }
        !           513: 
        !           514: /**
        !           515:  * Use the given PPK to derive a new SK_pi/r
        !           516:  */
        !           517: static bool derive_skp_ppk(private_keymat_v2_t *this, chunk_t ppk, chunk_t skp,
        !           518:                                                   chunk_t *new_skp)
        !           519: {
        !           520:        if (!this->prf->set_key(this->prf, ppk))
        !           521:        {
        !           522:                DBG1(DBG_IKE, "unable to set PPK in PRF");
        !           523:                return FALSE;
        !           524:        }
        !           525:        return derive_ppk_key(this->prf, "SK_p", skp, new_skp);
        !           526: }
        !           527: 
        !           528: METHOD(keymat_v2_t, derive_ike_keys_ppk, bool,
        !           529:        private_keymat_v2_t *this, chunk_t ppk)
        !           530: {
        !           531:        chunk_t skd = chunk_empty, new_skpi = chunk_empty, new_skpr = chunk_empty;
        !           532:        chunk_t *skpi, *skpr;
        !           533: 
        !           534:        if (!this->skd.ptr)
        !           535:        {
        !           536:                return FALSE;
        !           537:        }
        !           538: 
        !           539:        if (this->initiator)
        !           540:        {
        !           541:                skpi = &this->skp_build;
        !           542:                skpr = &this->skp_verify;
        !           543:        }
        !           544:        else
        !           545:        {
        !           546:                skpi = &this->skp_verify;
        !           547:                skpr = &this->skp_build;
        !           548:        }
        !           549: 
        !           550:        DBG4(DBG_IKE, "derive keys using PPK %B", &ppk);
        !           551: 
        !           552:        if (!this->prf->set_key(this->prf, ppk))
        !           553:        {
        !           554:                DBG1(DBG_IKE, "unable to set PPK in PRF");
        !           555:                return FALSE;
        !           556:        }
        !           557:        if (!derive_ppk_key(this->prf, "Sk_d", this->skd, &skd) ||
        !           558:                !derive_ppk_key(this->prf, "Sk_pi", *skpi, &new_skpi) ||
        !           559:                !derive_ppk_key(this->prf, "Sk_pr", *skpr, &new_skpr))
        !           560:        {
        !           561:                chunk_clear(&skd);
        !           562:                chunk_clear(&new_skpi);
        !           563:                chunk_clear(&new_skpr);
        !           564:                return FALSE;
        !           565:        }
        !           566: 
        !           567:        DBG4(DBG_IKE, "Sk_d secret %B", &skd);
        !           568:        chunk_clear(&this->skd);
        !           569:        this->skd = skd;
        !           570: 
        !           571:        DBG4(DBG_IKE, "Sk_pi secret %B", &new_skpi);
        !           572:        chunk_clear(skpi);
        !           573:        *skpi = new_skpi;
        !           574: 
        !           575:        DBG4(DBG_IKE, "Sk_pr secret %B", &new_skpr);
        !           576:        chunk_clear(skpr);
        !           577:        *skpr = new_skpr;
        !           578:        return TRUE;
        !           579: }
        !           580: 
        !           581: METHOD(keymat_v2_t, derive_child_keys, bool,
        !           582:        private_keymat_v2_t *this, proposal_t *proposal, diffie_hellman_t *dh,
        !           583:        chunk_t nonce_i, chunk_t nonce_r, chunk_t *encr_i, chunk_t *integ_i,
        !           584:        chunk_t *encr_r, chunk_t *integ_r)
        !           585: {
        !           586:        uint16_t enc_alg, int_alg, enc_size = 0, int_size = 0;
        !           587:        chunk_t seed, secret = chunk_empty;
        !           588:        prf_plus_t *prf_plus;
        !           589: 
        !           590:        if (proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM,
        !           591:                                                                &enc_alg, &enc_size))
        !           592:        {
        !           593:                DBG2(DBG_CHD, "  using %N for encryption",
        !           594:                         encryption_algorithm_names, enc_alg);
        !           595: 
        !           596:                if (!enc_size)
        !           597:                {
        !           598:                        enc_size = keymat_get_keylen_encr(enc_alg);
        !           599:                }
        !           600:                if (enc_alg != ENCR_NULL && !enc_size)
        !           601:                {
        !           602:                        DBG1(DBG_CHD, "no keylength defined for %N",
        !           603:                                 encryption_algorithm_names, enc_alg);
        !           604:                        return FALSE;
        !           605:                }
        !           606:                /* to bytes */
        !           607:                enc_size /= 8;
        !           608: 
        !           609:                /* CCM/GCM/CTR/GMAC needs additional bytes */
        !           610:                switch (enc_alg)
        !           611:                {
        !           612:                        case ENCR_AES_CCM_ICV8:
        !           613:                        case ENCR_AES_CCM_ICV12:
        !           614:                        case ENCR_AES_CCM_ICV16:
        !           615:                        case ENCR_CAMELLIA_CCM_ICV8:
        !           616:                        case ENCR_CAMELLIA_CCM_ICV12:
        !           617:                        case ENCR_CAMELLIA_CCM_ICV16:
        !           618:                                enc_size += 3;
        !           619:                                break;
        !           620:                        case ENCR_AES_GCM_ICV8:
        !           621:                        case ENCR_AES_GCM_ICV12:
        !           622:                        case ENCR_AES_GCM_ICV16:
        !           623:                        case ENCR_AES_CTR:
        !           624:                        case ENCR_CAMELLIA_CTR:
        !           625:                        case ENCR_NULL_AUTH_AES_GMAC:
        !           626:                        case ENCR_CHACHA20_POLY1305:
        !           627:                                enc_size += 4;
        !           628:                                break;
        !           629:                        default:
        !           630:                                break;
        !           631:                }
        !           632:        }
        !           633: 
        !           634:        if (proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM,
        !           635:                                                                &int_alg, &int_size))
        !           636:        {
        !           637:                DBG2(DBG_CHD, "  using %N for integrity",
        !           638:                         integrity_algorithm_names, int_alg);
        !           639: 
        !           640:                if (!int_size)
        !           641:                {
        !           642:                        int_size = keymat_get_keylen_integ(int_alg);
        !           643:                }
        !           644:                if (!int_size)
        !           645:                {
        !           646:                        DBG1(DBG_CHD, "no keylength defined for %N",
        !           647:                                 integrity_algorithm_names, int_alg);
        !           648:                        return FALSE;
        !           649:                }
        !           650:                /* to bytes */
        !           651:                int_size /= 8;
        !           652:        }
        !           653: 
        !           654:        if (!this->prf->set_key(this->prf, this->skd))
        !           655:        {
        !           656:                return FALSE;
        !           657:        }
        !           658: 
        !           659:        if (dh)
        !           660:        {
        !           661:                if (!dh->get_shared_secret(dh, &secret))
        !           662:                {
        !           663:                        return FALSE;
        !           664:                }
        !           665:                DBG4(DBG_CHD, "DH secret %B", &secret);
        !           666:        }
        !           667:        seed = chunk_cata("scc", secret, nonce_i, nonce_r);
        !           668:        DBG4(DBG_CHD, "seed %B", &seed);
        !           669: 
        !           670:        prf_plus = prf_plus_create(this->prf, TRUE, seed);
        !           671:        memwipe(seed.ptr, seed.len);
        !           672: 
        !           673:        if (!prf_plus)
        !           674:        {
        !           675:                return FALSE;
        !           676:        }
        !           677: 
        !           678:        *encr_i = *integ_i = *encr_r = *integ_r = chunk_empty;
        !           679:        if (!prf_plus->allocate_bytes(prf_plus, enc_size, encr_i) ||
        !           680:                !prf_plus->allocate_bytes(prf_plus, int_size, integ_i) ||
        !           681:                !prf_plus->allocate_bytes(prf_plus, enc_size, encr_r) ||
        !           682:                !prf_plus->allocate_bytes(prf_plus, int_size, integ_r))
        !           683:        {
        !           684:                chunk_free(encr_i);
        !           685:                chunk_free(integ_i);
        !           686:                chunk_free(encr_r);
        !           687:                chunk_free(integ_r);
        !           688:                prf_plus->destroy(prf_plus);
        !           689:                return FALSE;
        !           690:        }
        !           691: 
        !           692:        prf_plus->destroy(prf_plus);
        !           693: 
        !           694:        if (enc_size)
        !           695:        {
        !           696:                DBG4(DBG_CHD, "encryption initiator key %B", encr_i);
        !           697:                DBG4(DBG_CHD, "encryption responder key %B", encr_r);
        !           698:        }
        !           699:        if (int_size)
        !           700:        {
        !           701:                DBG4(DBG_CHD, "integrity initiator key %B", integ_i);
        !           702:                DBG4(DBG_CHD, "integrity responder key %B", integ_r);
        !           703:        }
        !           704:        return TRUE;
        !           705: }
        !           706: 
        !           707: METHOD(keymat_v2_t, get_skd, pseudo_random_function_t,
        !           708:        private_keymat_v2_t *this, chunk_t *skd)
        !           709: {
        !           710:        *skd = this->skd;
        !           711:        return this->prf_alg;
        !           712: }
        !           713: 
        !           714: METHOD(keymat_t, get_aead, aead_t*,
        !           715:        private_keymat_v2_t *this, bool in)
        !           716: {
        !           717:        return in ? this->aead_in : this->aead_out;
        !           718: }
        !           719: 
        !           720: METHOD(keymat_v2_t, get_auth_octets, bool,
        !           721:        private_keymat_v2_t *this, bool verify, chunk_t ike_sa_init,
        !           722:        chunk_t nonce, chunk_t ppk, identification_t *id, char reserved[3],
        !           723:        chunk_t *octets, array_t *schemes)
        !           724: {
        !           725:        chunk_t chunk, idx;
        !           726:        chunk_t skp_ppk = chunk_empty;
        !           727:        chunk_t skp;
        !           728: 
        !           729:        skp = verify ? this->skp_verify : this->skp_build;
        !           730:        if (ppk.ptr)
        !           731:        {
        !           732:                DBG4(DBG_IKE, "PPK %B", &ppk);
        !           733:                if (!derive_skp_ppk(this, ppk, skp, &skp_ppk))
        !           734:                {
        !           735:                        return FALSE;
        !           736:                }
        !           737:                skp = skp_ppk;
        !           738:        }
        !           739: 
        !           740:        chunk = chunk_alloca(4);
        !           741:        chunk.ptr[0] = id->get_type(id);
        !           742:        memcpy(chunk.ptr + 1, reserved, 3);
        !           743:        idx = chunk_cata("cc", chunk, id->get_encoding(id));
        !           744: 
        !           745:        DBG3(DBG_IKE, "IDx' %B", &idx);
        !           746:        DBG4(DBG_IKE, "SK_p %B", &skp);
        !           747:        if (!this->prf->set_key(this->prf, skp) ||
        !           748:                !this->prf->allocate_bytes(this->prf, idx, &chunk))
        !           749:        {
        !           750:                chunk_clear(&skp_ppk);
        !           751:                return FALSE;
        !           752:        }
        !           753:        chunk_clear(&skp_ppk);
        !           754:        *octets = chunk_cat("ccm", ike_sa_init, nonce, chunk);
        !           755:        DBG3(DBG_IKE, "octets = message + nonce + prf(Sk_px, IDx') %B", octets);
        !           756:        return TRUE;
        !           757: }
        !           758: 
        !           759: /**
        !           760:  * Key pad for the AUTH method SHARED_KEY_MESSAGE_INTEGRITY_CODE.
        !           761:  */
        !           762: #define IKEV2_KEY_PAD "Key Pad for IKEv2"
        !           763: #define IKEV2_KEY_PAD_LENGTH 17
        !           764: 
        !           765: METHOD(keymat_v2_t, get_psk_sig, bool,
        !           766:        private_keymat_v2_t *this, bool verify, chunk_t ike_sa_init, chunk_t nonce,
        !           767:        chunk_t secret, chunk_t ppk, identification_t *id, char reserved[3],
        !           768:        chunk_t *sig)
        !           769: {
        !           770:        chunk_t skp_ppk = chunk_empty, key = chunk_empty, octets = chunk_empty;
        !           771:        chunk_t key_pad;
        !           772:        bool success = FALSE;
        !           773: 
        !           774:        if (!secret.len)
        !           775:        {       /* EAP uses SK_p if no MSK has been established */
        !           776:                secret = verify ? this->skp_verify : this->skp_build;
        !           777:                if (ppk.ptr)
        !           778:                {
        !           779:                        if (!derive_skp_ppk(this, ppk, secret, &skp_ppk))
        !           780:                        {
        !           781:                                return FALSE;
        !           782:                        }
        !           783:                        secret = skp_ppk;
        !           784:                }
        !           785:        }
        !           786:        if (!get_auth_octets(this, verify, ike_sa_init, nonce, ppk, id, reserved,
        !           787:                                                 &octets, NULL))
        !           788:        {
        !           789:                goto failure;
        !           790:        }
        !           791:        /* AUTH = prf(prf(Shared Secret,"Key Pad for IKEv2"), <msg octets>) */
        !           792:        key_pad = chunk_create(IKEV2_KEY_PAD, IKEV2_KEY_PAD_LENGTH);
        !           793:        if (!this->prf->set_key(this->prf, secret) ||
        !           794:                !this->prf->allocate_bytes(this->prf, key_pad, &key))
        !           795:        {
        !           796:                goto failure;
        !           797:        }
        !           798:        if (!this->prf->set_key(this->prf, key) ||
        !           799:                !this->prf->allocate_bytes(this->prf, octets, sig))
        !           800:        {
        !           801:                goto failure;
        !           802:        }
        !           803:        DBG4(DBG_IKE, "secret %B", &secret);
        !           804:        DBG4(DBG_IKE, "prf(secret, keypad) %B", &key);
        !           805:        DBG3(DBG_IKE, "AUTH = prf(prf(secret, keypad), octets) %B", sig);
        !           806:        success = TRUE;
        !           807: 
        !           808: failure:
        !           809:        chunk_clear(&skp_ppk);
        !           810:        chunk_free(&octets);
        !           811:        chunk_free(&key);
        !           812:        return success;
        !           813: 
        !           814: }
        !           815: 
        !           816: METHOD(keymat_v2_t, hash_algorithm_supported, bool,
        !           817:        private_keymat_v2_t *this, hash_algorithm_t hash)
        !           818: {
        !           819:        if (!this->hash_algorithms)
        !           820:        {
        !           821:                return FALSE;
        !           822:        }
        !           823:        return this->hash_algorithms->contains(this->hash_algorithms, hash);
        !           824: }
        !           825: 
        !           826: METHOD(keymat_v2_t, add_hash_algorithm, void,
        !           827:        private_keymat_v2_t *this, hash_algorithm_t hash)
        !           828: {
        !           829:        if (!this->hash_algorithms)
        !           830:        {
        !           831:                this->hash_algorithms = hash_algorithm_set_create();
        !           832:        }
        !           833:        this->hash_algorithms->add(this->hash_algorithms, hash);
        !           834: }
        !           835: 
        !           836: METHOD(keymat_t, destroy, void,
        !           837:        private_keymat_v2_t *this)
        !           838: {
        !           839:        DESTROY_IF(this->aead_in);
        !           840:        DESTROY_IF(this->aead_out);
        !           841:        DESTROY_IF(this->prf);
        !           842:        chunk_clear(&this->skd);
        !           843:        chunk_clear(&this->skp_verify);
        !           844:        chunk_clear(&this->skp_build);
        !           845:        DESTROY_IF(this->hash_algorithms);
        !           846:        free(this);
        !           847: }
        !           848: 
        !           849: /**
        !           850:  * See header
        !           851:  */
        !           852: keymat_v2_t *keymat_v2_create(bool initiator)
        !           853: {
        !           854:        private_keymat_v2_t *this;
        !           855: 
        !           856:        INIT(this,
        !           857:                .public = {
        !           858:                        .keymat = {
        !           859:                                .get_version = _get_version,
        !           860:                                .create_dh = _create_dh,
        !           861:                                .create_nonce_gen = _create_nonce_gen,
        !           862:                                .get_aead = _get_aead,
        !           863:                                .destroy = _destroy,
        !           864:                        },
        !           865:                        .derive_ike_keys = _derive_ike_keys,
        !           866:                        .derive_ike_keys_ppk = _derive_ike_keys_ppk,
        !           867:                        .derive_child_keys = _derive_child_keys,
        !           868:                        .get_skd = _get_skd,
        !           869:                        .get_auth_octets = _get_auth_octets,
        !           870:                        .get_psk_sig = _get_psk_sig,
        !           871:                        .add_hash_algorithm = _add_hash_algorithm,
        !           872:                        .hash_algorithm_supported = _hash_algorithm_supported,
        !           873: 
        !           874:                },
        !           875:                .initiator = initiator,
        !           876:                .prf_alg = PRF_UNDEFINED,
        !           877:        );
        !           878: 
        !           879:        return &this->public;
        !           880: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>