Annotation of embedaddon/strongswan/src/libcharon/sa/ikev1/keymat_v1.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (C) 2011 Tobias Brunner
        !             3:  * HSR Hochschule fuer Technik Rapperswil
        !             4:  *
        !             5:  * This program is free software; you can redistribute it and/or modify it
        !             6:  * under the terms of the GNU General Public License as published by the
        !             7:  * Free Software Foundation; either version 2 of the License, or (at your
        !             8:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
        !             9:  *
        !            10:  * This program is distributed in the hope that it will be useful, but
        !            11:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
        !            12:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
        !            13:  * for more details.
        !            14:  */
        !            15: 
        !            16: #include "keymat_v1.h"
        !            17: 
        !            18: #include <daemon.h>
        !            19: #include <sa/ikev1/iv_manager.h>
        !            20: #include <encoding/generator.h>
        !            21: #include <encoding/payloads/nonce_payload.h>
        !            22: 
        !            23: typedef struct private_keymat_v1_t private_keymat_v1_t;
        !            24: 
        !            25: /**
        !            26:  * Private data of an keymat_t object.
        !            27:  */
        !            28: struct private_keymat_v1_t {
        !            29: 
        !            30:        /**
        !            31:         * Public keymat_v1_t interface.
        !            32:         */
        !            33:        keymat_v1_t public;
        !            34: 
        !            35:        /**
        !            36:         * IKE_SA Role, initiator or responder
        !            37:         */
        !            38:        bool initiator;
        !            39: 
        !            40:        /**
        !            41:         * General purpose PRF
        !            42:         */
        !            43:        prf_t *prf;
        !            44: 
        !            45:        /**
        !            46:         * PRF to create Phase 1 HASH payloads
        !            47:         */
        !            48:        prf_t *prf_auth;
        !            49: 
        !            50:        /**
        !            51:         * Crypter wrapped in an aead_t interface
        !            52:         */
        !            53:        aead_t *aead;
        !            54: 
        !            55:        /**
        !            56:         * Hasher used for IV generation (and other things like e.g. NAT-T)
        !            57:         */
        !            58:        hasher_t *hasher;
        !            59: 
        !            60:        /**
        !            61:         * Key to derive key material from for non-ISAKMP SAs, rekeying
        !            62:         */
        !            63:        chunk_t skeyid_d;
        !            64: 
        !            65:        /**
        !            66:         * Key used for authentication after main mode
        !            67:         */
        !            68:        chunk_t skeyid_a;
        !            69: 
        !            70:        /**
        !            71:         * IV and QM manager
        !            72:         */
        !            73:        iv_manager_t *iv_manager;
        !            74: };
        !            75: 
        !            76: /**
        !            77:  * Constants used in key derivation.
        !            78:  */
        !            79: static const chunk_t octet_0 = chunk_from_chars(0x00);
        !            80: static const chunk_t octet_1 = chunk_from_chars(0x01);
        !            81: static const chunk_t octet_2 = chunk_from_chars(0x02);
        !            82: 
        !            83: /**
        !            84:  * Simple aead_t implementation without support for authentication.
        !            85:  */
        !            86: typedef struct {
        !            87:        /** implements aead_t interface */
        !            88:        aead_t aead;
        !            89:        /** crypter to be used */
        !            90:        crypter_t *crypter;
        !            91: } private_aead_t;
        !            92: 
        !            93: 
        !            94: METHOD(aead_t, encrypt, bool,
        !            95:        private_aead_t *this, chunk_t plain, chunk_t assoc, chunk_t iv,
        !            96:        chunk_t *encrypted)
        !            97: {
        !            98:        return this->crypter->encrypt(this->crypter, plain, iv, encrypted);
        !            99: }
        !           100: 
        !           101: METHOD(aead_t, decrypt, bool,
        !           102:        private_aead_t *this, chunk_t encrypted, chunk_t assoc, chunk_t iv,
        !           103:        chunk_t *plain)
        !           104: {
        !           105:        return this->crypter->decrypt(this->crypter, encrypted, iv, plain);
        !           106: }
        !           107: 
        !           108: METHOD(aead_t, get_block_size, size_t,
        !           109:        private_aead_t *this)
        !           110: {
        !           111:        return this->crypter->get_block_size(this->crypter);
        !           112: }
        !           113: 
        !           114: METHOD(aead_t, get_icv_size, size_t,
        !           115:        private_aead_t *this)
        !           116: {
        !           117:        return 0;
        !           118: }
        !           119: 
        !           120: METHOD(aead_t, get_iv_size, size_t,
        !           121:        private_aead_t *this)
        !           122: {
        !           123:        /* in order to create the messages properly we return 0 here */
        !           124:        return 0;
        !           125: }
        !           126: 
        !           127: METHOD(aead_t, get_iv_gen, iv_gen_t*,
        !           128:        private_aead_t *this)
        !           129: {
        !           130:        /* IVs are retrieved via keymat_v1.get_iv() */
        !           131:        return NULL;
        !           132: }
        !           133: 
        !           134: METHOD(aead_t, get_key_size, size_t,
        !           135:        private_aead_t *this)
        !           136: {
        !           137:        return this->crypter->get_key_size(this->crypter);
        !           138: }
        !           139: 
        !           140: METHOD(aead_t, set_key, bool,
        !           141:        private_aead_t *this, chunk_t key)
        !           142: {
        !           143:        return this->crypter->set_key(this->crypter, key);
        !           144: }
        !           145: 
        !           146: METHOD(aead_t, aead_destroy, void,
        !           147:        private_aead_t *this)
        !           148: {
        !           149:        this->crypter->destroy(this->crypter);
        !           150:        free(this);
        !           151: }
        !           152: 
        !           153: /**
        !           154:  * Expand SKEYID_e according to Appendix B in RFC 2409.
        !           155:  * TODO-IKEv1: verify keys (e.g. for weak keys, see Appendix B)
        !           156:  */
        !           157: static bool expand_skeyid_e(chunk_t skeyid_e, size_t key_size, prf_t *prf,
        !           158:                                                        chunk_t *ka)
        !           159: {
        !           160:        size_t block_size;
        !           161:        chunk_t seed;
        !           162:        int i;
        !           163: 
        !           164:        if (skeyid_e.len >= key_size)
        !           165:        {       /* no expansion required, reduce to key_size */
        !           166:                skeyid_e.len = key_size;
        !           167:                *ka = skeyid_e;
        !           168:                return TRUE;
        !           169:        }
        !           170:        block_size = prf->get_block_size(prf);
        !           171:        *ka = chunk_alloc((key_size / block_size + 1) * block_size);
        !           172:        ka->len = key_size;
        !           173: 
        !           174:        /* Ka = K1 | K2 | ..., K1 = prf(SKEYID_e, 0), K2 = prf(SKEYID_e, K1) ... */
        !           175:        if (!prf->set_key(prf, skeyid_e))
        !           176:        {
        !           177:                chunk_clear(ka);
        !           178:                chunk_clear(&skeyid_e);
        !           179:                return FALSE;
        !           180:        }
        !           181:        seed = octet_0;
        !           182:        for (i = 0; i < key_size; i += block_size)
        !           183:        {
        !           184:                if (!prf->get_bytes(prf, seed, ka->ptr + i))
        !           185:                {
        !           186:                        chunk_clear(ka);
        !           187:                        chunk_clear(&skeyid_e);
        !           188:                        return FALSE;
        !           189:                }
        !           190:                seed = chunk_create(ka->ptr + i, block_size);
        !           191:        }
        !           192:        chunk_clear(&skeyid_e);
        !           193:        return TRUE;
        !           194: }
        !           195: 
        !           196: /**
        !           197:  * Create a simple implementation of the aead_t interface which only encrypts
        !           198:  * or decrypts data.
        !           199:  */
        !           200: static aead_t *create_aead(proposal_t *proposal, prf_t *prf, chunk_t skeyid_e,
        !           201:                                                   chunk_t *ka)
        !           202: {
        !           203:        private_aead_t *this;
        !           204:        uint16_t alg, key_size;
        !           205:        crypter_t *crypter;
        !           206: 
        !           207:        if (!proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &alg,
        !           208:                                                                 &key_size))
        !           209:        {
        !           210:                DBG1(DBG_IKE, "no %N selected",
        !           211:                         transform_type_names, ENCRYPTION_ALGORITHM);
        !           212:                return NULL;
        !           213:        }
        !           214:        crypter = lib->crypto->create_crypter(lib->crypto, alg, key_size / 8);
        !           215:        if (!crypter)
        !           216:        {
        !           217:                DBG1(DBG_IKE, "%N %N (key size %d) not supported!",
        !           218:                         transform_type_names, ENCRYPTION_ALGORITHM,
        !           219:                         encryption_algorithm_names, alg, key_size);
        !           220:                return NULL;
        !           221:        }
        !           222:        if (!expand_skeyid_e(skeyid_e, crypter->get_key_size(crypter), prf, ka))
        !           223:        {
        !           224:                return NULL;
        !           225:        }
        !           226:        DBG4(DBG_IKE, "encryption key Ka %B", ka);
        !           227:        if (!crypter->set_key(crypter, *ka))
        !           228:        {
        !           229:                chunk_clear(ka);
        !           230:                return NULL;
        !           231:        }
        !           232: 
        !           233:        INIT(this,
        !           234:                .aead = {
        !           235:                        .encrypt = _encrypt,
        !           236:                        .decrypt = _decrypt,
        !           237:                        .get_block_size = _get_block_size,
        !           238:                        .get_icv_size = _get_icv_size,
        !           239:                        .get_iv_size = _get_iv_size,
        !           240:                        .get_iv_gen = _get_iv_gen,
        !           241:                        .get_key_size = _get_key_size,
        !           242:                        .set_key = _set_key,
        !           243:                        .destroy = _aead_destroy,
        !           244:                },
        !           245:                .crypter = crypter,
        !           246:        );
        !           247:        return &this->aead;
        !           248: }
        !           249: 
        !           250: /**
        !           251:  * Converts integrity algorithm to PRF algorithm
        !           252:  */
        !           253: static uint16_t auth_to_prf(uint16_t alg)
        !           254: {
        !           255:        switch (alg)
        !           256:        {
        !           257:                case AUTH_HMAC_SHA1_96:
        !           258:                        return PRF_HMAC_SHA1;
        !           259:                case AUTH_HMAC_SHA2_256_128:
        !           260:                        return PRF_HMAC_SHA2_256;
        !           261:                case AUTH_HMAC_SHA2_384_192:
        !           262:                        return PRF_HMAC_SHA2_384;
        !           263:                case AUTH_HMAC_SHA2_512_256:
        !           264:                        return PRF_HMAC_SHA2_512;
        !           265:                case AUTH_HMAC_MD5_96:
        !           266:                        return PRF_HMAC_MD5;
        !           267:                case AUTH_AES_XCBC_96:
        !           268:                        return PRF_AES128_XCBC;
        !           269:                default:
        !           270:                        return PRF_UNDEFINED;
        !           271:        }
        !           272: }
        !           273: 
        !           274: /**
        !           275:  * Converts integrity algorithm to hash algorithm
        !           276:  */
        !           277: static uint16_t auth_to_hash(uint16_t alg)
        !           278: {
        !           279:        switch (alg)
        !           280:        {
        !           281:                case AUTH_HMAC_SHA1_96:
        !           282:                        return HASH_SHA1;
        !           283:                case AUTH_HMAC_SHA2_256_128:
        !           284:                        return HASH_SHA256;
        !           285:                case AUTH_HMAC_SHA2_384_192:
        !           286:                        return HASH_SHA384;
        !           287:                case AUTH_HMAC_SHA2_512_256:
        !           288:                        return HASH_SHA512;
        !           289:                case AUTH_HMAC_MD5_96:
        !           290:                        return HASH_MD5;
        !           291:                default:
        !           292:                        return HASH_UNKNOWN;
        !           293:        }
        !           294: }
        !           295: 
        !           296: /**
        !           297:  * Adjust the key length for PRF algorithms that expect a fixed key length.
        !           298:  */
        !           299: static void adjust_keylen(uint16_t alg, chunk_t *key)
        !           300: {
        !           301:        switch (alg)
        !           302:        {
        !           303:                case PRF_AES128_XCBC:
        !           304:                        /* while rfc4434 defines variable keys for AES-XCBC, rfc3664 does
        !           305:                         * not and therefore fixed key semantics apply to XCBC for key
        !           306:                         * derivation. */
        !           307:                        key->len = min(key->len, 16);
        !           308:                        break;
        !           309:                default:
        !           310:                        /* all other algorithms use variable key length */
        !           311:                        break;
        !           312:        }
        !           313: }
        !           314: 
        !           315: METHOD(keymat_v1_t, derive_ike_keys, bool,
        !           316:        private_keymat_v1_t *this, proposal_t *proposal, diffie_hellman_t *dh,
        !           317:        chunk_t dh_other, chunk_t nonce_i, chunk_t nonce_r, ike_sa_id_t *id,
        !           318:        auth_method_t auth, shared_key_t *shared_key)
        !           319: {
        !           320:        chunk_t g_xy, g_xi, g_xr, dh_me, spi_i, spi_r, nonces, data, skeyid_e;
        !           321:        chunk_t skeyid, ka;
        !           322:        uint16_t alg;
        !           323: 
        !           324:        spi_i = chunk_alloca(sizeof(uint64_t));
        !           325:        spi_r = chunk_alloca(sizeof(uint64_t));
        !           326: 
        !           327:        if (!proposal->get_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, &alg, NULL))
        !           328:        {       /* no PRF negotiated, use HMAC version of integrity algorithm instead */
        !           329:                if (!proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, &alg, NULL)
        !           330:                        || (alg = auth_to_prf(alg)) == PRF_UNDEFINED)
        !           331:                {
        !           332:                        DBG1(DBG_IKE, "no %N selected",
        !           333:                                 transform_type_names, PSEUDO_RANDOM_FUNCTION);
        !           334:                        return FALSE;
        !           335:                }
        !           336:        }
        !           337:        this->prf = lib->crypto->create_prf(lib->crypto, alg);
        !           338:        if (!this->prf)
        !           339:        {
        !           340:                DBG1(DBG_IKE, "%N %N not supported!",
        !           341:                         transform_type_names, PSEUDO_RANDOM_FUNCTION,
        !           342:                         pseudo_random_function_names, alg);
        !           343:                return FALSE;
        !           344:        }
        !           345:        if (this->prf->get_block_size(this->prf) <
        !           346:                this->prf->get_key_size(this->prf))
        !           347:        {       /* TODO-IKEv1: support PRF output expansion (RFC 2409, Appendix B) */
        !           348:                DBG1(DBG_IKE, "expansion of %N %N output not supported!",
        !           349:                         transform_type_names, PSEUDO_RANDOM_FUNCTION,
        !           350:                         pseudo_random_function_names, alg);
        !           351:                return FALSE;
        !           352:        }
        !           353: 
        !           354:        if (!dh->get_shared_secret(dh, &g_xy))
        !           355:        {
        !           356:                return FALSE;
        !           357:        }
        !           358:        DBG4(DBG_IKE, "shared Diffie Hellman secret %B", &g_xy);
        !           359: 
        !           360:        *((uint64_t*)spi_i.ptr) = id->get_initiator_spi(id);
        !           361:        *((uint64_t*)spi_r.ptr) = id->get_responder_spi(id);
        !           362:        nonces = chunk_cata("cc", nonce_i, nonce_r);
        !           363: 
        !           364:        switch (auth)
        !           365:        {
        !           366:                case AUTH_PSK:
        !           367:                case AUTH_XAUTH_INIT_PSK:
        !           368:                case AUTH_XAUTH_RESP_PSK:
        !           369:                {       /* SKEYID = prf(pre-shared-key, Ni_b | Nr_b) */
        !           370:                        chunk_t psk;
        !           371:                        if (!shared_key)
        !           372:                        {
        !           373:                                chunk_clear(&g_xy);
        !           374:                                return FALSE;
        !           375:                        }
        !           376:                        psk = shared_key->get_key(shared_key);
        !           377:                        adjust_keylen(alg, &psk);
        !           378:                        if (!this->prf->set_key(this->prf, psk) ||
        !           379:                                !this->prf->allocate_bytes(this->prf, nonces, &skeyid))
        !           380:                        {
        !           381:                                chunk_clear(&g_xy);
        !           382:                                return FALSE;
        !           383:                        }
        !           384:                        break;
        !           385:                }
        !           386:                case AUTH_RSA:
        !           387:                case AUTH_ECDSA_256:
        !           388:                case AUTH_ECDSA_384:
        !           389:                case AUTH_ECDSA_521:
        !           390:                case AUTH_XAUTH_INIT_RSA:
        !           391:                case AUTH_XAUTH_RESP_RSA:
        !           392:                case AUTH_HYBRID_INIT_RSA:
        !           393:                case AUTH_HYBRID_RESP_RSA:
        !           394:                {
        !           395:                        if (!this->prf->set_key(this->prf, nonces) ||
        !           396:                                !this->prf->allocate_bytes(this->prf, g_xy, &skeyid))
        !           397:                        {
        !           398:                                chunk_clear(&g_xy);
        !           399:                                return FALSE;
        !           400:                        }
        !           401:                        break;
        !           402:                }
        !           403:                default:
        !           404:                        /* TODO-IKEv1: implement key derivation for other schemes */
        !           405:                        /* authentication class not supported */
        !           406:                        chunk_clear(&g_xy);
        !           407:                        return FALSE;
        !           408:        }
        !           409:        adjust_keylen(alg, &skeyid);
        !           410:        DBG4(DBG_IKE, "SKEYID %B", &skeyid);
        !           411: 
        !           412:        /* SKEYID_d = prf(SKEYID, g^xy | CKY-I | CKY-R | 0) */
        !           413:        data = chunk_cat("cccc", g_xy, spi_i, spi_r, octet_0);
        !           414:        if (!this->prf->set_key(this->prf, skeyid) ||
        !           415:                !this->prf->allocate_bytes(this->prf, data, &this->skeyid_d))
        !           416:        {
        !           417:                chunk_clear(&g_xy);
        !           418:                chunk_clear(&data);
        !           419:                chunk_clear(&skeyid);
        !           420:                return FALSE;
        !           421:        }
        !           422:        chunk_clear(&data);
        !           423:        DBG4(DBG_IKE, "SKEYID_d %B", &this->skeyid_d);
        !           424: 
        !           425:        /* SKEYID_a = prf(SKEYID, SKEYID_d | g^xy | CKY-I | CKY-R | 1) */
        !           426:        data = chunk_cat("ccccc", this->skeyid_d, g_xy, spi_i, spi_r, octet_1);
        !           427:        if (!this->prf->allocate_bytes(this->prf, data, &this->skeyid_a))
        !           428:        {
        !           429:                chunk_clear(&g_xy);
        !           430:                chunk_clear(&data);
        !           431:                chunk_clear(&skeyid);
        !           432:                return FALSE;
        !           433:        }
        !           434:        chunk_clear(&data);
        !           435:        DBG4(DBG_IKE, "SKEYID_a %B", &this->skeyid_a);
        !           436: 
        !           437:        /* SKEYID_e = prf(SKEYID, SKEYID_a | g^xy | CKY-I | CKY-R | 2) */
        !           438:        data = chunk_cat("ccccc", this->skeyid_a, g_xy, spi_i, spi_r, octet_2);
        !           439:        if (!this->prf->allocate_bytes(this->prf, data, &skeyid_e))
        !           440:        {
        !           441:                chunk_clear(&g_xy);
        !           442:                chunk_clear(&data);
        !           443:                chunk_clear(&skeyid);
        !           444:                return FALSE;
        !           445:        }
        !           446:        chunk_clear(&data);
        !           447:        DBG4(DBG_IKE, "SKEYID_e %B", &skeyid_e);
        !           448: 
        !           449:        chunk_clear(&g_xy);
        !           450: 
        !           451:        switch (auth)
        !           452:        {
        !           453:                case AUTH_ECDSA_256:
        !           454:                        alg = PRF_HMAC_SHA2_256;
        !           455:                        break;
        !           456:                case AUTH_ECDSA_384:
        !           457:                        alg =  PRF_HMAC_SHA2_384;
        !           458:                        break;
        !           459:                case AUTH_ECDSA_521:
        !           460:                        alg = PRF_HMAC_SHA2_512;
        !           461:                        break;
        !           462:                default:
        !           463:                        /* use proposal algorithm */
        !           464:                        break;
        !           465:        }
        !           466:        this->prf_auth = lib->crypto->create_prf(lib->crypto, alg);
        !           467:        if (!this->prf_auth)
        !           468:        {
        !           469:                DBG1(DBG_IKE, "%N %N not supported!",
        !           470:                         transform_type_names, PSEUDO_RANDOM_FUNCTION,
        !           471:                         pseudo_random_function_names, alg);
        !           472:                chunk_clear(&skeyid);
        !           473:                return FALSE;
        !           474:        }
        !           475:        if (!this->prf_auth->set_key(this->prf_auth, skeyid))
        !           476:        {
        !           477:                chunk_clear(&skeyid);
        !           478:                return FALSE;
        !           479:        }
        !           480:        chunk_clear(&skeyid);
        !           481: 
        !           482:        this->aead = create_aead(proposal, this->prf, skeyid_e, &ka);
        !           483:        if (!this->aead)
        !           484:        {
        !           485:                return FALSE;
        !           486:        }
        !           487:        charon->bus->ike_derived_keys(charon->bus, ka, chunk_empty, this->skeyid_a,
        !           488:                                                                  chunk_empty);
        !           489:        chunk_clear(&ka);
        !           490:        if (!this->hasher && !this->public.create_hasher(&this->public, proposal))
        !           491:        {
        !           492:                return FALSE;
        !           493:        }
        !           494: 
        !           495:        if (!dh->get_my_public_value(dh, &dh_me))
        !           496:        {
        !           497:                return FALSE;
        !           498:        }
        !           499:        g_xi = this->initiator ? dh_me : dh_other;
        !           500:        g_xr = this->initiator ? dh_other : dh_me;
        !           501: 
        !           502:        /* initial IV = hash(g^xi | g^xr) */
        !           503:        data = chunk_cata("cc", g_xi, g_xr);
        !           504:        chunk_free(&dh_me);
        !           505:        return this->iv_manager->init_iv_chain(this->iv_manager, data, this->hasher,
        !           506:                                                                                this->aead->get_block_size(this->aead));
        !           507: }
        !           508: 
        !           509: METHOD(keymat_v1_t, derive_child_keys, bool,
        !           510:        private_keymat_v1_t *this, proposal_t *proposal, diffie_hellman_t *dh,
        !           511:        uint32_t spi_i, uint32_t spi_r, chunk_t nonce_i, chunk_t nonce_r,
        !           512:        chunk_t *encr_i, chunk_t *integ_i, chunk_t *encr_r, chunk_t *integ_r)
        !           513: {
        !           514:        uint16_t enc_alg, int_alg, enc_size = 0, int_size = 0;
        !           515:        uint8_t protocol;
        !           516:        prf_plus_t *prf_plus;
        !           517:        chunk_t seed, secret = chunk_empty;
        !           518:        bool success = FALSE;
        !           519: 
        !           520:        if (proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM,
        !           521:                                                                &enc_alg, &enc_size))
        !           522:        {
        !           523:                DBG2(DBG_CHD, "  using %N for encryption",
        !           524:                         encryption_algorithm_names, enc_alg);
        !           525: 
        !           526:                if (!enc_size)
        !           527:                {
        !           528:                        enc_size = keymat_get_keylen_encr(enc_alg);
        !           529:                }
        !           530:                if (enc_alg != ENCR_NULL && !enc_size)
        !           531:                {
        !           532:                        DBG1(DBG_CHD, "no keylength defined for %N",
        !           533:                                 encryption_algorithm_names, enc_alg);
        !           534:                        return FALSE;
        !           535:                }
        !           536:                /* to bytes */
        !           537:                enc_size /= 8;
        !           538: 
        !           539:                /* CCM/GCM/CTR/GMAC needs additional bytes */
        !           540:                switch (enc_alg)
        !           541:                {
        !           542:                        case ENCR_AES_CCM_ICV8:
        !           543:                        case ENCR_AES_CCM_ICV12:
        !           544:                        case ENCR_AES_CCM_ICV16:
        !           545:                        case ENCR_CAMELLIA_CCM_ICV8:
        !           546:                        case ENCR_CAMELLIA_CCM_ICV12:
        !           547:                        case ENCR_CAMELLIA_CCM_ICV16:
        !           548:                                enc_size += 3;
        !           549:                                break;
        !           550:                        case ENCR_AES_GCM_ICV8:
        !           551:                        case ENCR_AES_GCM_ICV12:
        !           552:                        case ENCR_AES_GCM_ICV16:
        !           553:                        case ENCR_AES_CTR:
        !           554:                        case ENCR_NULL_AUTH_AES_GMAC:
        !           555:                                enc_size += 4;
        !           556:                                break;
        !           557:                        default:
        !           558:                                break;
        !           559:                }
        !           560:        }
        !           561: 
        !           562:        if (proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM,
        !           563:                                                                &int_alg, &int_size))
        !           564:        {
        !           565:                DBG2(DBG_CHD, "  using %N for integrity",
        !           566:                         integrity_algorithm_names, int_alg);
        !           567: 
        !           568:                if (!int_size)
        !           569:                {
        !           570:                        int_size = keymat_get_keylen_integ(int_alg);
        !           571:                }
        !           572:                if (!int_size)
        !           573:                {
        !           574:                        DBG1(DBG_CHD, "no keylength defined for %N",
        !           575:                                 integrity_algorithm_names, int_alg);
        !           576:                        return FALSE;
        !           577:                }
        !           578:                /* to bytes */
        !           579:                int_size /= 8;
        !           580:        }
        !           581: 
        !           582:        /* KEYMAT = prf+(SKEYID_d, [ g(qm)^xy | ] protocol | SPI | Ni_b | Nr_b) */
        !           583:        if (!this->prf->set_key(this->prf, this->skeyid_d))
        !           584:        {
        !           585:                return FALSE;
        !           586:        }
        !           587:        protocol = proposal->get_protocol(proposal);
        !           588:        if (dh)
        !           589:        {
        !           590:                if (!dh->get_shared_secret(dh, &secret))
        !           591:                {
        !           592:                        return FALSE;
        !           593:                }
        !           594:                DBG4(DBG_CHD, "DH secret %B", &secret);
        !           595:        }
        !           596: 
        !           597:        *encr_r = *integ_r = *encr_i = *integ_i = chunk_empty;
        !           598:        seed = chunk_cata("ccccc", secret, chunk_from_thing(protocol),
        !           599:                                          chunk_from_thing(spi_r), nonce_i, nonce_r);
        !           600:        DBG4(DBG_CHD, "initiator SA seed %B", &seed);
        !           601: 
        !           602:        prf_plus = prf_plus_create(this->prf, FALSE, seed);
        !           603:        if (!prf_plus ||
        !           604:                !prf_plus->allocate_bytes(prf_plus, enc_size, encr_i) ||
        !           605:                !prf_plus->allocate_bytes(prf_plus, int_size, integ_i))
        !           606:        {
        !           607:                goto failure;
        !           608:        }
        !           609: 
        !           610:        seed = chunk_cata("ccccc", secret, chunk_from_thing(protocol),
        !           611:                                          chunk_from_thing(spi_i), nonce_i, nonce_r);
        !           612:        DBG4(DBG_CHD, "responder SA seed %B", &seed);
        !           613:        prf_plus->destroy(prf_plus);
        !           614:        prf_plus = prf_plus_create(this->prf, FALSE, seed);
        !           615:        if (!prf_plus ||
        !           616:                !prf_plus->allocate_bytes(prf_plus, enc_size, encr_r) ||
        !           617:                !prf_plus->allocate_bytes(prf_plus, int_size, integ_r))
        !           618:        {
        !           619:                goto failure;
        !           620:        }
        !           621: 
        !           622:        if (enc_size)
        !           623:        {
        !           624:                DBG4(DBG_CHD, "encryption initiator key %B", encr_i);
        !           625:                DBG4(DBG_CHD, "encryption responder key %B", encr_r);
        !           626:        }
        !           627:        if (int_size)
        !           628:        {
        !           629:                DBG4(DBG_CHD, "integrity initiator key %B", integ_i);
        !           630:                DBG4(DBG_CHD, "integrity responder key %B", integ_r);
        !           631:        }
        !           632:        success = TRUE;
        !           633: 
        !           634: failure:
        !           635:        if (!success)
        !           636:        {
        !           637:                chunk_clear(encr_i);
        !           638:                chunk_clear(integ_i);
        !           639:                chunk_clear(encr_r);
        !           640:                chunk_clear(integ_r);
        !           641:        }
        !           642:        DESTROY_IF(prf_plus);
        !           643:        chunk_clear(&secret);
        !           644: 
        !           645:        return success;
        !           646: }
        !           647: 
        !           648: METHOD(keymat_v1_t, create_hasher, bool,
        !           649:        private_keymat_v1_t *this, proposal_t *proposal)
        !           650: {
        !           651:        uint16_t alg;
        !           652:        if (!proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, &alg, NULL) ||
        !           653:                (alg = auth_to_hash(alg)) == HASH_UNKNOWN)
        !           654:        {
        !           655:                DBG1(DBG_IKE, "no %N selected", transform_type_names, HASH_ALGORITHM);
        !           656:                return FALSE;
        !           657:        }
        !           658:        this->hasher = lib->crypto->create_hasher(lib->crypto, alg);
        !           659:        if (!this->hasher)
        !           660:        {
        !           661:                DBG1(DBG_IKE, "%N %N not supported!",
        !           662:                         transform_type_names, HASH_ALGORITHM,
        !           663:                         hash_algorithm_names, alg);
        !           664:                return FALSE;
        !           665:        }
        !           666:        return TRUE;
        !           667: }
        !           668: 
        !           669: METHOD(keymat_v1_t, get_hasher, hasher_t*,
        !           670:        private_keymat_v1_t *this)
        !           671: {
        !           672:        return this->hasher;
        !           673: }
        !           674: 
        !           675: METHOD(keymat_v1_t, get_hash, bool,
        !           676:        private_keymat_v1_t *this, bool initiator, chunk_t dh, chunk_t dh_other,
        !           677:        ike_sa_id_t *ike_sa_id, chunk_t sa_i, chunk_t id, chunk_t *hash,
        !           678:        signature_scheme_t *scheme)
        !           679: {
        !           680:        chunk_t data;
        !           681:        uint64_t spi, spi_other;
        !           682: 
        !           683:        /* HASH_I = prf(SKEYID, g^xi | g^xr | CKY-I | CKY-R | SAi_b | IDii_b )
        !           684:         * HASH_R = prf(SKEYID, g^xr | g^xi | CKY-R | CKY-I | SAi_b | IDir_b )
        !           685:         */
        !           686:        if (initiator)
        !           687:        {
        !           688:                spi = ike_sa_id->get_initiator_spi(ike_sa_id);
        !           689:                spi_other = ike_sa_id->get_responder_spi(ike_sa_id);
        !           690:        }
        !           691:        else
        !           692:        {
        !           693:                spi_other = ike_sa_id->get_initiator_spi(ike_sa_id);
        !           694:                spi = ike_sa_id->get_responder_spi(ike_sa_id);
        !           695:        }
        !           696:        data = chunk_cat("cccccc", dh, dh_other,
        !           697:                                         chunk_from_thing(spi), chunk_from_thing(spi_other),
        !           698:                                         sa_i, id);
        !           699: 
        !           700:        DBG3(DBG_IKE, "HASH_%c data %B", initiator ? 'I' : 'R', &data);
        !           701: 
        !           702:        if (!this->prf_auth->allocate_bytes(this->prf_auth, data, hash))
        !           703:        {
        !           704:                free(data.ptr);
        !           705:                return FALSE;
        !           706:        }
        !           707: 
        !           708:        DBG3(DBG_IKE, "HASH_%c %B", initiator ? 'I' : 'R', hash);
        !           709: 
        !           710:        free(data.ptr);
        !           711:        return TRUE;
        !           712: }
        !           713: 
        !           714: /**
        !           715:  * Get the nonce value found in the given message.
        !           716:  * Returns FALSE if none is found.
        !           717:  */
        !           718: static bool get_nonce(message_t *message, chunk_t *n)
        !           719: {
        !           720:        nonce_payload_t *nonce;
        !           721:        nonce = (nonce_payload_t*)message->get_payload(message, PLV1_NONCE);
        !           722:        if (nonce)
        !           723:        {
        !           724:                *n = nonce->get_nonce(nonce);
        !           725:                return TRUE;
        !           726:        }
        !           727:        return FALSE;
        !           728: }
        !           729: 
        !           730: /**
        !           731:  * Generate the message data in order to generate the hashes.
        !           732:  */
        !           733: static chunk_t get_message_data(message_t *message, generator_t *generator)
        !           734: {
        !           735:        payload_t *payload, *next;
        !           736:        enumerator_t *enumerator;
        !           737:        uint32_t *lenpos;
        !           738: 
        !           739:        if (message->is_encoded(message))
        !           740:        {       /* inbound, although the message is generated, we cannot access the
        !           741:                 * cleartext message data, so generate it anyway */
        !           742:                enumerator = message->create_payload_enumerator(message);
        !           743:                while (enumerator->enumerate(enumerator, &payload))
        !           744:                {
        !           745:                        if (payload->get_type(payload) == PLV1_HASH)
        !           746:                        {
        !           747:                                continue;
        !           748:                        }
        !           749:                        generator->generate_payload(generator, payload);
        !           750:                }
        !           751:                enumerator->destroy(enumerator);
        !           752:        }
        !           753:        else
        !           754:        {
        !           755:                /* outbound, generate the payloads (there is no HASH payload yet) */
        !           756:                enumerator = message->create_payload_enumerator(message);
        !           757:                if (enumerator->enumerate(enumerator, &payload))
        !           758:                {
        !           759:                        while (enumerator->enumerate(enumerator, &next))
        !           760:                        {
        !           761:                                payload->set_next_type(payload, next->get_type(next));
        !           762:                                generator->generate_payload(generator, payload);
        !           763:                                payload = next;
        !           764:                        }
        !           765:                        payload->set_next_type(payload, PL_NONE);
        !           766:                        generator->generate_payload(generator, payload);
        !           767:                }
        !           768:                enumerator->destroy(enumerator);
        !           769:        }
        !           770:        return generator->get_chunk(generator, &lenpos);
        !           771: }
        !           772: 
        !           773: METHOD(keymat_v1_t, get_hash_phase2, bool,
        !           774:        private_keymat_v1_t *this, message_t *message, chunk_t *hash)
        !           775: {
        !           776:        uint32_t mid, mid_n;
        !           777:        chunk_t data = chunk_empty, *n_i, *n_r;
        !           778:        bool add_message = TRUE;
        !           779:        char *name = "Hash";
        !           780: 
        !           781:        if (!this->prf)
        !           782:        {       /* no keys derived yet */
        !           783:                return FALSE;
        !           784:        }
        !           785: 
        !           786:        mid = message->get_message_id(message);
        !           787:        mid_n = htonl(mid);
        !           788: 
        !           789:        /* Hashes are simple for most exchanges in Phase 2:
        !           790:         *   Hash = prf(SKEYID_a, M-ID | Complete message after HASH payload)
        !           791:         * For Quick Mode there are three hashes:
        !           792:         *   Hash(1) = same as above
        !           793:         *   Hash(2) = prf(SKEYID_a, M-ID | Ni_b | Message after HASH payload)
        !           794:         *   Hash(3) = prf(SKEYID_a, 0 | M-ID | Ni_b | Nr_b)
        !           795:         * So, for Quick Mode we keep track of the nonce values.
        !           796:         */
        !           797:        switch (message->get_exchange_type(message))
        !           798:        {
        !           799:                case QUICK_MODE:
        !           800:                {
        !           801:                        this->iv_manager->lookup_quick_mode(this->iv_manager, mid, &n_i,
        !           802:                                                                                                &n_r);
        !           803:                        if (!n_i->ptr)
        !           804:                        {       /* Hash(1) = prf(SKEYID_a, M-ID | Message after HASH payload) */
        !           805:                                name = "Hash(1)";
        !           806:                                if (!get_nonce(message, n_i))
        !           807:                                {
        !           808:                                        return FALSE;
        !           809:                                }
        !           810:                                data = chunk_from_thing(mid_n);
        !           811:                        }
        !           812:                        else if (!n_r->ptr)
        !           813:                        {       /* Hash(2) = prf(SKEYID_a, M-ID | Ni_b | Message after HASH) */
        !           814:                                name = "Hash(2)";
        !           815:                                if (!get_nonce(message, n_r))
        !           816:                                {
        !           817:                                        return FALSE;
        !           818:                                }
        !           819:                                data = chunk_cata("cc", chunk_from_thing(mid_n), *n_i);
        !           820:                        }
        !           821:                        else
        !           822:                        {       /* Hash(3) = prf(SKEYID_a, 0 | M-ID | Ni_b | Nr_b) */
        !           823:                                name = "Hash(3)";
        !           824:                                data = chunk_cata("cccc", octet_0, chunk_from_thing(mid_n),
        !           825:                                                                  *n_i, *n_r);
        !           826:                                add_message = FALSE;
        !           827:                                /* we don't need the state anymore */
        !           828:                                this->iv_manager->remove_quick_mode(this->iv_manager, mid);
        !           829:                        }
        !           830:                        break;
        !           831:                }
        !           832:                case TRANSACTION:
        !           833:                case INFORMATIONAL_V1:
        !           834:                        /* Hash = prf(SKEYID_a, M-ID | Message after HASH payload) */
        !           835:                        data = chunk_from_thing(mid_n);
        !           836:                        break;
        !           837:                default:
        !           838:                        return FALSE;
        !           839:        }
        !           840:        if (!this->prf->set_key(this->prf, this->skeyid_a))
        !           841:        {
        !           842:                return FALSE;
        !           843:        }
        !           844:        if (add_message)
        !           845:        {
        !           846:                generator_t *generator;
        !           847:                chunk_t msg;
        !           848: 
        !           849:                generator = generator_create_no_dbg();
        !           850:                msg = get_message_data(message, generator);
        !           851:                if (!this->prf->allocate_bytes(this->prf, data, NULL) ||
        !           852:                        !this->prf->allocate_bytes(this->prf, msg, hash))
        !           853:                {
        !           854:                        generator->destroy(generator);
        !           855:                        return FALSE;
        !           856:                }
        !           857:                generator->destroy(generator);
        !           858:        }
        !           859:        else
        !           860:        {
        !           861:                if (!this->prf->allocate_bytes(this->prf, data, hash))
        !           862:                {
        !           863:                        return FALSE;
        !           864:                }
        !           865:        }
        !           866:        DBG3(DBG_IKE, "%s %B", name, hash);
        !           867:        return TRUE;
        !           868: }
        !           869: 
        !           870: METHOD(keymat_v1_t, get_iv, bool,
        !           871:        private_keymat_v1_t *this, uint32_t mid, chunk_t *out)
        !           872: {
        !           873:        return this->iv_manager->get_iv(this->iv_manager, mid, out);
        !           874: }
        !           875: 
        !           876: METHOD(keymat_v1_t, update_iv, bool,
        !           877:        private_keymat_v1_t *this, uint32_t mid, chunk_t last_block)
        !           878: {
        !           879:        return this->iv_manager->update_iv(this->iv_manager, mid, last_block);
        !           880: }
        !           881: 
        !           882: METHOD(keymat_v1_t, confirm_iv, bool,
        !           883:        private_keymat_v1_t *this, uint32_t mid)
        !           884: {
        !           885:        return this->iv_manager->confirm_iv(this->iv_manager, mid);
        !           886: }
        !           887: 
        !           888: METHOD(keymat_t, get_version, ike_version_t,
        !           889:        private_keymat_v1_t *this)
        !           890: {
        !           891:        return IKEV1;
        !           892: }
        !           893: 
        !           894: METHOD(keymat_t, create_dh, diffie_hellman_t*,
        !           895:        private_keymat_v1_t *this, diffie_hellman_group_t group)
        !           896: {
        !           897:        return lib->crypto->create_dh(lib->crypto, group);
        !           898: }
        !           899: 
        !           900: METHOD(keymat_t, create_nonce_gen, nonce_gen_t*,
        !           901:        private_keymat_v1_t *this)
        !           902: {
        !           903:        return lib->crypto->create_nonce_gen(lib->crypto);
        !           904: }
        !           905: 
        !           906: METHOD(keymat_t, get_aead, aead_t*,
        !           907:        private_keymat_v1_t *this, bool in)
        !           908: {
        !           909:        return this->aead;
        !           910: }
        !           911: 
        !           912: METHOD(keymat_t, destroy, void,
        !           913:        private_keymat_v1_t *this)
        !           914: {
        !           915:        DESTROY_IF(this->prf);
        !           916:        DESTROY_IF(this->prf_auth);
        !           917:        DESTROY_IF(this->aead);
        !           918:        DESTROY_IF(this->hasher);
        !           919:        chunk_clear(&this->skeyid_d);
        !           920:        chunk_clear(&this->skeyid_a);
        !           921:        this->iv_manager->destroy(this->iv_manager);
        !           922:        free(this);
        !           923: }
        !           924: 
        !           925: /**
        !           926:  * See header
        !           927:  */
        !           928: keymat_v1_t *keymat_v1_create(bool initiator)
        !           929: {
        !           930:        private_keymat_v1_t *this;
        !           931: 
        !           932:        INIT(this,
        !           933:                .public = {
        !           934:                        .keymat = {
        !           935:                                .get_version = _get_version,
        !           936:                                .create_dh = _create_dh,
        !           937:                                .create_nonce_gen = _create_nonce_gen,
        !           938:                                .get_aead = _get_aead,
        !           939:                                .destroy = _destroy,
        !           940:                        },
        !           941:                        .derive_ike_keys = _derive_ike_keys,
        !           942:                        .derive_child_keys = _derive_child_keys,
        !           943:                        .create_hasher = _create_hasher,
        !           944:                        .get_hasher = _get_hasher,
        !           945:                        .get_hash = _get_hash,
        !           946:                        .get_hash_phase2 = _get_hash_phase2,
        !           947:                        .get_iv = _get_iv,
        !           948:                        .update_iv = _update_iv,
        !           949:                        .confirm_iv = _confirm_iv,
        !           950:                },
        !           951:                .initiator = initiator,
        !           952:                .iv_manager = iv_manager_create(0),
        !           953:        );
        !           954:        return &this->public;
        !           955: }

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