Annotation of embedaddon/strongswan/src/libtls/tls_hkdf.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (C) 2020 Tobias Brunner
        !             3:  * Copyright (C) 2020 Pascal Knecht
        !             4:  * Copyright (C) 2020 Méline Sieber
        !             5:  * HSR Hochschule fuer Technik Rapperswil
        !             6:  *
        !             7:  * This program is free software; you can redistribute it and/or modify it
        !             8:  * under the terms of the GNU General Public License as published by the
        !             9:  * Free Software Foundation; either version 2 of the License, or (at your
        !            10:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
        !            11:  *
        !            12:  * This program is distributed in the hope that it will be useful, but
        !            13:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
        !            14:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
        !            15:  * for more details.
        !            16:  */
        !            17: 
        !            18: #include "tls_hkdf.h"
        !            19: 
        !            20: #include <bio/bio_writer.h>
        !            21: #include <crypto/prf_plus.h>
        !            22: 
        !            23: typedef struct private_tls_hkdf_t private_tls_hkdf_t;
        !            24: 
        !            25: typedef struct cached_secrets_t {
        !            26:        chunk_t client;
        !            27:        chunk_t server;
        !            28: } cached_secrets_t;
        !            29: 
        !            30: typedef enum hkdf_phase {
        !            31:        HKDF_PHASE_0,
        !            32:        HKDF_PHASE_1,
        !            33:        HKDF_PHASE_2,
        !            34:        HKDF_PHASE_3,
        !            35: } hkdf_phase;
        !            36: 
        !            37: struct private_tls_hkdf_t {
        !            38: 
        !            39:        /**
        !            40:         * Public tls_hkdf_t interface.
        !            41:         */
        !            42:        struct tls_hkdf_t public;
        !            43: 
        !            44:        /**
        !            45:         * Phase we are in.
        !            46:         */
        !            47:        hkdf_phase phase;
        !            48: 
        !            49:        /**
        !            50:         * Pseudorandom function used.
        !            51:         */
        !            52:        prf_t *prf;
        !            53: 
        !            54:        /**
        !            55:         * Hasher used.
        !            56:         */
        !            57:        hasher_t *hasher;
        !            58: 
        !            59:        /**
        !            60:         * (EC)DHE as IKM to switch from phase 1 to phase 2
        !            61:         */
        !            62:        chunk_t shared_secret;
        !            63: 
        !            64:        /**
        !            65:         * PSK used.
        !            66:         */
        !            67:        chunk_t psk;
        !            68: 
        !            69:        /**
        !            70:         * PRK used.
        !            71:         */
        !            72:        chunk_t prk;
        !            73: 
        !            74:        /**
        !            75:         * Handshake traffic secrets.
        !            76:         */
        !            77:        cached_secrets_t handshake_traffic_secrets;
        !            78: 
        !            79:        /**
        !            80:         * Current traffic secrets.
        !            81:         */
        !            82:        cached_secrets_t traffic_secrets;
        !            83: };
        !            84: 
        !            85: static char *hkdf_labels[] = {
        !            86:        "ext binder",
        !            87:        "res binder",
        !            88:        "c e traffic",
        !            89:        "e exp master",
        !            90:        "c hs traffic",
        !            91:        "s hs traffic",
        !            92:        "c ap traffic",
        !            93:        "s ap traffic",
        !            94:        "exp master",
        !            95:        "res master",
        !            96: };
        !            97: 
        !            98: /**
        !            99:  * Step 1: Extract, as defined in RFC 5869, section 2.2:
        !           100:  * HKDF-Extract(salt, IKM) -> PRK
        !           101:  */
        !           102: static bool extract(private_tls_hkdf_t *this, chunk_t salt, chunk_t ikm,
        !           103:                                        chunk_t *prk)
        !           104: {
        !           105:        if (!this->prf->set_key(this->prf, salt))
        !           106:        {
        !           107:                DBG1(DBG_TLS, "unable to set PRF secret to salt");
        !           108:                return FALSE;
        !           109:        }
        !           110:        chunk_clear(prk);
        !           111:        if(!this->prf->allocate_bytes(this->prf, ikm, prk))
        !           112:        {
        !           113:                DBG1(DBG_TLS, "unable to allocate PRF result");
        !           114:                return FALSE;
        !           115:        }
        !           116: 
        !           117:        DBG4(DBG_TLS, "PRK: %B", prk);
        !           118: 
        !           119:        return TRUE;
        !           120: }
        !           121: 
        !           122: /**
        !           123:  * Step 2: Expand as defined in RFC 5869, section 2.3:
        !           124:  * HKDF-Expand(PRK, info, L) -> OKM
        !           125:  */
        !           126: static bool expand(private_tls_hkdf_t *this, chunk_t prk, chunk_t info,
        !           127:                                   size_t length, chunk_t *okm)
        !           128: {
        !           129:        prf_plus_t *prf_plus;
        !           130: 
        !           131:        if (!this->prf->set_key(this->prf, prk))
        !           132:        {
        !           133:                DBG1(DBG_TLS, "unable to set PRF secret to PRK");
        !           134:                return FALSE;
        !           135:        }
        !           136:        prf_plus = prf_plus_create(this->prf, TRUE, info);
        !           137:        if (!prf_plus || !prf_plus->allocate_bytes(prf_plus, length, okm))
        !           138:        {
        !           139:                DBG1(DBG_TLS, "unable to allocate PRF+ result");
        !           140:                DESTROY_IF(prf_plus);
        !           141:                return FALSE;
        !           142:        }
        !           143:        prf_plus->destroy(prf_plus);
        !           144: 
        !           145:        DBG4(DBG_TLS, "OKM: %B", okm);
        !           146: 
        !           147:        return TRUE;
        !           148: }
        !           149: 
        !           150: /**
        !           151:  * Expand-Label as defined in RFC 8446, section 7.1:
        !           152:  * HKDF-Expand-Label(Secret, Label, Context, Length) -> OKM
        !           153:  */
        !           154: static bool expand_label(private_tls_hkdf_t *this, chunk_t secret,
        !           155:                                                 chunk_t label, chunk_t context, uint16_t length,
        !           156:                                                 chunk_t *key)
        !           157: {
        !           158:        bool success;
        !           159: 
        !           160:        if (!label.len || label.len > 249 || context.len > 255)
        !           161:        {
        !           162:                return FALSE;
        !           163:        }
        !           164: 
        !           165:        /* HKDFLabel as defined in RFC 8446, section 7.1 */
        !           166:        bio_writer_t *writer = bio_writer_create(0);
        !           167:        writer->write_uint16(writer, length);
        !           168:        label = chunk_cata("cc", chunk_from_str("tls13 "), label);
        !           169:        writer->write_data8(writer, label);
        !           170:        writer->write_data8(writer, context);
        !           171: 
        !           172:        success = expand(this, secret, writer->get_buf(writer), length, key);
        !           173:        writer->destroy(writer);
        !           174:        return success;
        !           175: }
        !           176: 
        !           177: /**
        !           178:  * Derive-Secret as defined in RFC 8446, section 7.1:
        !           179:  * Derive-Secret(Secret, Label, Message) -> OKM
        !           180:  */
        !           181: static bool derive_secret(private_tls_hkdf_t *this, chunk_t secret,
        !           182:                                                  chunk_t label, chunk_t messages, chunk_t *okm)
        !           183: {
        !           184:        chunk_t context;
        !           185:        bool success;
        !           186: 
        !           187:        if (!this->hasher->allocate_hash(this->hasher, messages, &context))
        !           188:        {
        !           189:                return FALSE;
        !           190:        }
        !           191: 
        !           192:        success = expand_label(this, secret, label, context,
        !           193:                                                   this->hasher->get_hash_size(this->hasher), okm);
        !           194:        chunk_free(&context);
        !           195:        return success;
        !           196: }
        !           197: 
        !           198: /**
        !           199:  * Move to phase 1 (Early Secret)
        !           200:  *
        !           201:  *            0
        !           202:  *            |
        !           203:  *            v
        !           204:  *  PSK ->  HKDF-Extract = Early Secret
        !           205:  *            |
        !           206:  *            +-----> Derive-Secret(., "ext binder" | "res binder", "")
        !           207:  *            |                     = binder_key
        !           208:  *            |
        !           209:  *            +-----> Derive-Secret(., "c e traffic", ClientHello)
        !           210:  *            |                     = client_early_traffic_secret
        !           211:  *            |
        !           212:  *            +-----> Derive-Secret(., "e exp master", ClientHello)
        !           213:  *            |                     = early_exporter_master_secret
        !           214:  *            v
        !           215:  */
        !           216: static bool move_to_phase_1(private_tls_hkdf_t *this)
        !           217: {
        !           218:        chunk_t salt_zero, psk = this->psk;
        !           219: 
        !           220:        switch (this->phase)
        !           221:        {
        !           222:                case HKDF_PHASE_0:
        !           223:                        salt_zero = chunk_alloca(this->hasher->get_hash_size(this->hasher));
        !           224:                        chunk_copy_pad(salt_zero, chunk_empty, 0);
        !           225:                        if (!psk.ptr)
        !           226:                        {
        !           227:                                psk = salt_zero;
        !           228:                        }
        !           229:                        if (!extract(this, salt_zero, psk, &this->prk))
        !           230:                        {
        !           231:                                DBG1(DBG_TLS, "unable to extract PRK");
        !           232:                                return FALSE;
        !           233:                        }
        !           234:                        this->phase = HKDF_PHASE_1;
        !           235:                        return TRUE;
        !           236:                case HKDF_PHASE_1:
        !           237:                        return TRUE;
        !           238:                default:
        !           239:                        DBG1(DBG_TLS, "invalid HKDF phase");
        !           240:                        return FALSE;
        !           241:        }
        !           242: }
        !           243: 
        !           244: /**
        !           245:  * Move to phase 2 (Handshake Secret)
        !           246:  *
        !           247:  *      Derive-Secret(., "derived", "")
        !           248:  *            |
        !           249:  *            v
        !           250:  *  (EC)DHE -> HKDF-Extract = Handshake Secret
        !           251:  *            |
        !           252:  *            +-----> Derive-Secret(., "c hs traffic",
        !           253:  *            |                     ClientHello...ServerHello)
        !           254:  *            |                     = client_handshake_traffic_secret
        !           255:  *            |
        !           256:  *            +-----> Derive-Secret(., "s hs traffic",
        !           257:  *            |                     ClientHello...ServerHello)
        !           258:  *            |                     = server_handshake_traffic_secret
        !           259:  *            v
        !           260:  */
        !           261: static bool move_to_phase_2(private_tls_hkdf_t *this)
        !           262: {
        !           263:        chunk_t okm;
        !           264: 
        !           265:        switch (this->phase)
        !           266:        {
        !           267:                case HKDF_PHASE_0:
        !           268:                        if (!move_to_phase_1(this))
        !           269:                        {
        !           270:                                DBG1(DBG_TLS, "unable to move to phase 1");
        !           271:                                return FALSE;
        !           272:                        }
        !           273:                        /* fall-through */
        !           274:                case HKDF_PHASE_1:
        !           275:                        if (!derive_secret(this, this->prk, chunk_from_str("derived"),
        !           276:                                                           chunk_empty, &okm))
        !           277:                        {
        !           278:                                DBG1(DBG_TLS, "unable to derive secret");
        !           279:                                return FALSE;
        !           280:                        }
        !           281: 
        !           282:                        if (!this->shared_secret.ptr)
        !           283:                        {
        !           284:                                DBG1(DBG_TLS, "no shared secret set");
        !           285:                                chunk_clear(&okm);
        !           286:                                return FALSE;
        !           287:                        }
        !           288: 
        !           289:                        if (!extract(this, okm, this->shared_secret, &this->prk))
        !           290:                        {
        !           291:                                DBG1(DBG_TLS, "unable extract PRK");
        !           292:                                chunk_clear(&okm);
        !           293:                                return FALSE;
        !           294:                        }
        !           295:                        chunk_clear(&okm);
        !           296:                        this->phase = HKDF_PHASE_2;
        !           297:                        return TRUE;
        !           298:                case HKDF_PHASE_2:
        !           299:                        return TRUE;
        !           300:                default:
        !           301:                        DBG1(DBG_TLS, "invalid HKDF phase");
        !           302:                        return FALSE;
        !           303:        }
        !           304: }
        !           305: 
        !           306: /**
        !           307:  * Move to phase 3 (Master Secret)
        !           308:  *
        !           309:  *      Derive-Secret(., "derived", "")
        !           310:  *            |
        !           311:  *            v
        !           312:  *  0 -> HKDF-Extract = Master Secret
        !           313:  *            |
        !           314:  *            +-----> Derive-Secret(., "c ap traffic",
        !           315:  *            |                     ClientHello...server Finished)
        !           316:  *            |                     = client_application_traffic_secret_0
        !           317:  *            |
        !           318:  *            +-----> Derive-Secret(., "s ap traffic",
        !           319:  *            |                     ClientHello...server Finished)
        !           320:  *            |                     = server_application_traffic_secret_0
        !           321:  *            |
        !           322:  *            +-----> Derive-Secret(., "exp master",
        !           323:  *            |                     ClientHello...server Finished)
        !           324:  *            |                     = exporter_master_secret
        !           325:  *            |
        !           326:  *            +-----> Derive-Secret(., "res master",
        !           327:  *                                  ClientHello...client Finished)
        !           328:  *                                  = resumption_master_secret
        !           329:  */
        !           330: static bool move_to_phase_3(private_tls_hkdf_t *this)
        !           331: {
        !           332:        chunk_t okm, ikm_zero;
        !           333: 
        !           334:        switch (this->phase)
        !           335:        {
        !           336:                case HKDF_PHASE_0:
        !           337:                case HKDF_PHASE_1:
        !           338:                        if (!move_to_phase_2(this))
        !           339:                        {
        !           340:                                DBG1(DBG_TLS, "unable to move to phase 2");
        !           341:                                return FALSE;
        !           342:                        }
        !           343:                        /* fall-through */
        !           344:                case HKDF_PHASE_2:
        !           345:                        /* prepare okm for next extract */
        !           346:                        if (!derive_secret(this, this->prk, chunk_from_str("derived"),
        !           347:                                                           chunk_empty, &okm))
        !           348:                        {
        !           349:                                DBG1(DBG_TLS, "unable to derive secret");
        !           350:                                return FALSE;
        !           351:                        }
        !           352: 
        !           353:                        ikm_zero = chunk_alloca(this->hasher->get_hash_size(this->hasher));
        !           354:                        chunk_copy_pad(ikm_zero, chunk_empty, 0);
        !           355:                        if (!extract(this, okm, ikm_zero, &this->prk))
        !           356:                        {
        !           357:                                DBG1(DBG_TLS, "unable extract PRK");
        !           358:                                chunk_clear(&okm);
        !           359:                                return FALSE;
        !           360:                        }
        !           361:                        chunk_clear(&okm);
        !           362:                        this->phase = HKDF_PHASE_3;
        !           363:                        return TRUE;
        !           364:                case HKDF_PHASE_3:
        !           365:                        return TRUE;
        !           366:                default:
        !           367:                        DBG1(DBG_TLS, "invalid HKDF phase");
        !           368:                        return FALSE;
        !           369:        }
        !           370: }
        !           371: 
        !           372: METHOD(tls_hkdf_t, set_shared_secret, void,
        !           373:        private_tls_hkdf_t *this, chunk_t shared_secret)
        !           374: {
        !           375:        this->shared_secret = chunk_clone(shared_secret);
        !           376: }
        !           377: 
        !           378: METHOD(tls_hkdf_t, generate_secret, bool,
        !           379:        private_tls_hkdf_t *this, tls_hkdf_label_t label, chunk_t messages,
        !           380:        chunk_t *secret)
        !           381: {
        !           382:        chunk_t okm;
        !           383: 
        !           384:        switch (label)
        !           385:        {
        !           386:                case TLS_HKDF_EXT_BINDER:
        !           387:                case TLS_HKDF_RES_BINDER:
        !           388:                case TLS_HKDF_C_E_TRAFFIC:
        !           389:                case TLS_HKDF_E_EXP_MASTER:
        !           390:                        if (!move_to_phase_1(this))
        !           391:                        {
        !           392:                                DBG1(DBG_TLS, "unable to move to phase 1");
        !           393:                                return FALSE;
        !           394:                        }
        !           395:                        break;
        !           396:                case TLS_HKDF_C_HS_TRAFFIC:
        !           397:                case TLS_HKDF_S_HS_TRAFFIC:
        !           398:                        if (!move_to_phase_2(this))
        !           399:                        {
        !           400:                                DBG1(DBG_TLS, "unable to move to phase 2");
        !           401:                                return FALSE;
        !           402:                        }
        !           403:                        break;
        !           404:                case TLS_HKDF_C_AP_TRAFFIC:
        !           405:                case TLS_HKDF_S_AP_TRAFFIC:
        !           406:                case TLS_HKDF_EXP_MASTER:
        !           407:                case TLS_HKDF_RES_MASTER:
        !           408:                        if (!move_to_phase_3(this))
        !           409:                        {
        !           410:                                DBG1(DBG_TLS, "unable to move to phase 3");
        !           411:                                return FALSE;
        !           412:                        }
        !           413:                        break;
        !           414:                case TLS_HKDF_UPD_C_TRAFFIC:
        !           415:                case TLS_HKDF_UPD_S_TRAFFIC:
        !           416:                        if (this->phase != HKDF_PHASE_3)
        !           417:                        {
        !           418:                                DBG1(DBG_TLS, "unable to update traffic keys");
        !           419:                                return FALSE;
        !           420:                        }
        !           421:                        break;
        !           422:                default:
        !           423:                        DBG1(DBG_TLS, "invalid HKDF label");
        !           424:                        return FALSE;
        !           425:        }
        !           426: 
        !           427:        if (label == TLS_HKDF_UPD_C_TRAFFIC || label == TLS_HKDF_UPD_S_TRAFFIC)
        !           428:        {
        !           429:                chunk_t previous = this->traffic_secrets.client;
        !           430: 
        !           431:                if (label == TLS_HKDF_UPD_S_TRAFFIC)
        !           432:                {
        !           433:                        previous = this->traffic_secrets.server;
        !           434:                }
        !           435: 
        !           436:                if (!expand_label(this, previous, chunk_from_str("traffic upd"),
        !           437:                                                  chunk_empty, this->hasher->get_hash_size(this->hasher),
        !           438:                                                  &okm))
        !           439:                {
        !           440:                        DBG1(DBG_TLS, "unable to update secret");
        !           441:                        return FALSE;
        !           442:                }
        !           443:        }
        !           444:        else
        !           445:        {
        !           446:                if (!derive_secret(this, this->prk, chunk_from_str(hkdf_labels[label]),
        !           447:                                                   messages, &okm))
        !           448:                {
        !           449:                        DBG1(DBG_TLS, "unable to derive secret");
        !           450:                        return FALSE;
        !           451:                }
        !           452:        }
        !           453: 
        !           454:        switch (label)
        !           455:        {
        !           456:                case TLS_HKDF_C_HS_TRAFFIC:
        !           457:                        chunk_clear(&this->handshake_traffic_secrets.client);
        !           458:                        this->handshake_traffic_secrets.client = chunk_clone(okm);
        !           459:                        /* fall-through */
        !           460:                case TLS_HKDF_C_AP_TRAFFIC:
        !           461:                case TLS_HKDF_UPD_C_TRAFFIC:
        !           462:                        chunk_clear(&this->traffic_secrets.client);
        !           463:                        this->traffic_secrets.client = chunk_clone(okm);
        !           464:                        break;
        !           465:                case TLS_HKDF_S_HS_TRAFFIC:
        !           466:                        chunk_clear(&this->handshake_traffic_secrets.server);
        !           467:                        this->handshake_traffic_secrets.server = chunk_clone(okm);
        !           468:                        /* fall-through */
        !           469:                case TLS_HKDF_S_AP_TRAFFIC:
        !           470:                case TLS_HKDF_UPD_S_TRAFFIC:
        !           471:                        chunk_clear(&this->traffic_secrets.server);
        !           472:                        this->traffic_secrets.server = chunk_clone(okm);
        !           473:                        break;
        !           474:                default:
        !           475:                        break;
        !           476:        }
        !           477: 
        !           478:        if (secret)
        !           479:        {
        !           480:                *secret = okm;
        !           481:        }
        !           482:        else
        !           483:        {
        !           484:                chunk_clear(&okm);
        !           485:        }
        !           486:        return TRUE;
        !           487: }
        !           488: 
        !           489: /**
        !           490:  * Derive keys/IVs from the current traffic secrets.
        !           491:  */
        !           492: static bool get_shared_label_keys(private_tls_hkdf_t *this, chunk_t label,
        !           493:                                                                  cached_secrets_t *secrets,
        !           494:                                                                  bool server, size_t length, chunk_t *key)
        !           495: {
        !           496:        chunk_t result = chunk_empty, secret;
        !           497: 
        !           498:        secret = server ? secrets->server : secrets->client;
        !           499: 
        !           500:        if (!expand_label(this, secret, label, chunk_empty, length, &result))
        !           501:        {
        !           502:                DBG1(DBG_TLS, "unable to derive labeled secret");
        !           503:                chunk_clear(&result);
        !           504:                return FALSE;
        !           505:        }
        !           506: 
        !           507:        if (key)
        !           508:        {
        !           509:                *key = result;
        !           510:        }
        !           511:        else
        !           512:        {
        !           513:                chunk_clear(&result);
        !           514:        }
        !           515:        return TRUE;
        !           516: }
        !           517: 
        !           518: METHOD(tls_hkdf_t, derive_key, bool,
        !           519:        private_tls_hkdf_t *this, bool is_server, size_t length, chunk_t *key)
        !           520: {
        !           521:        return get_shared_label_keys(this, chunk_from_str("key"),
        !           522:                                                                 &this->traffic_secrets, is_server, length, key);
        !           523: }
        !           524: 
        !           525: METHOD(tls_hkdf_t, derive_iv, bool,
        !           526:        private_tls_hkdf_t *this, bool is_server, size_t length, chunk_t *iv)
        !           527: {
        !           528:        return get_shared_label_keys(this, chunk_from_str("iv"),
        !           529:                                                                 &this->traffic_secrets, is_server, length, iv);
        !           530: }
        !           531: 
        !           532: METHOD(tls_hkdf_t, derive_finished, bool,
        !           533:        private_tls_hkdf_t *this, bool server, chunk_t *finished)
        !           534: {
        !           535:        return get_shared_label_keys(this, chunk_from_str("finished"),
        !           536:                                                                 &this->handshake_traffic_secrets, server,
        !           537:                                                                 this->hasher->get_hash_size(this->hasher),
        !           538:                                                                 finished);
        !           539: }
        !           540: 
        !           541: METHOD(tls_hkdf_t, export, bool,
        !           542:        private_tls_hkdf_t *this, char *label, chunk_t context,
        !           543:        chunk_t messages, size_t length, chunk_t *key)
        !           544: {
        !           545:        chunk_t exporter_master, exporter, hash = chunk_empty;
        !           546: 
        !           547:        if (this->phase != HKDF_PHASE_3)
        !           548:        {
        !           549:                DBG1(DBG_TLS, "unable to export key material");
        !           550:                return FALSE;
        !           551:        }
        !           552: 
        !           553:        /**
        !           554:         * Export key material according to RFC 8446, section 7.5:
        !           555:         *
        !           556:         * TLS-Exporter(label, context_value, key_length) =
        !           557:         *    HKDF-Expand-Label(Derive-Secret(Secret, label, ""),
        !           558:         *                      "exporter", Hash(context_value), key_length)
        !           559:         */
        !           560:        if (!generate_secret(this, TLS_HKDF_EXP_MASTER, messages, &exporter_master))
        !           561:        {
        !           562:                DBG1(DBG_TLS, "unable to derive exporter master secret");
        !           563:                return FALSE;
        !           564:        }
        !           565: 
        !           566:        if (!derive_secret(this, exporter_master, chunk_from_str(label),
        !           567:                                           chunk_empty, &exporter))
        !           568:        {
        !           569:                DBG1(DBG_TLS, "unable to derive exporter secret");
        !           570:                chunk_clear(&exporter_master);
        !           571:                return FALSE;
        !           572:        }
        !           573:        chunk_clear(&exporter_master);
        !           574: 
        !           575:        if (!this->hasher->allocate_hash(this->hasher, context, &hash) ||
        !           576:                !expand_label(this, exporter, chunk_from_str("exporter"), hash,
        !           577:                                          length, key))
        !           578:        {
        !           579:                DBG1(DBG_TLS, "unable to expand key material");
        !           580:                chunk_clear(&exporter);
        !           581:                chunk_free(&hash);
        !           582:                return FALSE;
        !           583:        }
        !           584:        chunk_clear(&exporter);
        !           585:        chunk_free(&hash);
        !           586:        return TRUE;
        !           587: }
        !           588: 
        !           589: METHOD(tls_hkdf_t, resume, bool,
        !           590:        private_tls_hkdf_t *this, chunk_t messages, chunk_t nonce, chunk_t *key)
        !           591: {
        !           592:        chunk_t resumption_master;
        !           593: 
        !           594:        if (this->phase != HKDF_PHASE_3)
        !           595:        {
        !           596:                DBG1(DBG_TLS, "unable to generate resumption key material");
        !           597:                return FALSE;
        !           598:        }
        !           599:        if (!nonce.len)
        !           600:        {
        !           601:                DBG1(DBG_TLS, "no nonce provided");
        !           602:                return FALSE;
        !           603:        }
        !           604: 
        !           605:        /**
        !           606:         * PSK associated with the ticket according to RFC 8446, section 4.6.1
        !           607:         *
        !           608:         *    HKDF-Expand-Label(resumption_master_secret,
        !           609:         *                      "resumption", ticket_nonce, Hash.length)
        !           610:         */
        !           611:        if (!generate_secret(this, TLS_HKDF_RES_MASTER, messages,
        !           612:                                                 &resumption_master))
        !           613:        {
        !           614:                DBG1(DBG_TLS, "unable to derive resumption master secret");
        !           615:                return FALSE;
        !           616:        }
        !           617: 
        !           618:        if (!expand_label(this, resumption_master, chunk_from_str("resumption"),
        !           619:                                          nonce, this->hasher->get_hash_size(this->hasher), key))
        !           620:        {
        !           621:                chunk_clear(&resumption_master);
        !           622:                DBG1(DBG_TLS, "unable to expand key material");
        !           623:                return FALSE;
        !           624:        }
        !           625:        chunk_clear(&resumption_master);
        !           626:        return TRUE;
        !           627: }
        !           628: 
        !           629: METHOD(tls_hkdf_t, binder, bool,
        !           630:        private_tls_hkdf_t *this, chunk_t seed, chunk_t *out)
        !           631: {
        !           632:        chunk_t binder_key, finished_key;
        !           633: 
        !           634:        if (!generate_secret(this, TLS_HKDF_RES_BINDER, chunk_empty, &binder_key))
        !           635:        {
        !           636:                DBG1(DBG_TLS, "unable to derive binder key");
        !           637:                return FALSE;
        !           638:        }
        !           639: 
        !           640:        if (!expand_label(this, binder_key, chunk_from_str("finished"), chunk_empty,
        !           641:                                          this->hasher->get_hash_size(this->hasher), &finished_key))
        !           642:        {
        !           643:                chunk_clear(&binder_key);
        !           644:                return FALSE;
        !           645:        }
        !           646:        chunk_clear(&binder_key);
        !           647: 
        !           648:        if (!this->prf->set_key(this->prf, finished_key) ||
        !           649:                !this->prf->allocate_bytes(this->prf, seed, out))
        !           650:        {
        !           651:                chunk_clear(&finished_key);
        !           652:                return FALSE;
        !           653:        }
        !           654:        chunk_clear(&finished_key);
        !           655:        return TRUE;
        !           656: }
        !           657: 
        !           658: METHOD(tls_hkdf_t, allocate_bytes, bool,
        !           659:        private_tls_hkdf_t *this, chunk_t key, chunk_t seed,
        !           660:        chunk_t *out)
        !           661: {
        !           662:        return this->prf->set_key(this->prf, key) &&
        !           663:                   this->prf->allocate_bytes(this->prf, seed, out);
        !           664: }
        !           665: 
        !           666: /**
        !           667:  * Clean up secrets
        !           668:  */
        !           669: static void destroy_secrets(cached_secrets_t *secrets)
        !           670: {
        !           671:        chunk_clear(&secrets->client);
        !           672:        chunk_clear(&secrets->server);
        !           673: }
        !           674: 
        !           675: METHOD(tls_hkdf_t, destroy, void,
        !           676:        private_tls_hkdf_t *this)
        !           677: {
        !           678:        chunk_clear(&this->psk);
        !           679:        chunk_clear(&this->prk);
        !           680:        chunk_clear(&this->shared_secret);
        !           681:        destroy_secrets(&this->handshake_traffic_secrets);
        !           682:        destroy_secrets(&this->traffic_secrets);
        !           683:        DESTROY_IF(this->prf);
        !           684:        DESTROY_IF(this->hasher);
        !           685:        free(this);
        !           686: }
        !           687: 
        !           688: tls_hkdf_t *tls_hkdf_create(hash_algorithm_t hash_algorithm, chunk_t psk)
        !           689: {
        !           690:        private_tls_hkdf_t *this;
        !           691:        pseudo_random_function_t prf_algorithm;
        !           692: 
        !           693:        switch (hash_algorithm)
        !           694:        {
        !           695:                case HASH_SHA256:
        !           696:                        prf_algorithm = PRF_HMAC_SHA2_256;
        !           697:                        break;
        !           698:                case HASH_SHA384:
        !           699:                        prf_algorithm = PRF_HMAC_SHA2_384;
        !           700:                        break;
        !           701:                default:
        !           702:                        DBG1(DBG_TLS, "unsupported hash algorithm %N", hash_algorithm_names,
        !           703:                                 hash_algorithm);
        !           704:                        return NULL;
        !           705:        }
        !           706: 
        !           707:        INIT(this,
        !           708:                .public = {
        !           709:                        .set_shared_secret = _set_shared_secret,
        !           710:                        .generate_secret = _generate_secret,
        !           711:                        .derive_key = _derive_key,
        !           712:                        .derive_iv = _derive_iv,
        !           713:                        .derive_finished = _derive_finished,
        !           714:                        .export = _export,
        !           715:                        .resume = _resume,
        !           716:                        .binder = _binder,
        !           717:                        .allocate_bytes = _allocate_bytes,
        !           718:                        .destroy = _destroy,
        !           719:                },
        !           720:                .phase = HKDF_PHASE_0,
        !           721:                .psk = psk.ptr ? chunk_clone(psk) : chunk_empty,
        !           722:                .prf = lib->crypto->create_prf(lib->crypto, prf_algorithm),
        !           723:                .hasher = lib->crypto->create_hasher(lib->crypto, hash_algorithm),
        !           724:        );
        !           725: 
        !           726:        if (!this->prf || !this->hasher)
        !           727:        {
        !           728:                if (!this->prf)
        !           729:                {
        !           730:                        DBG1(DBG_TLS, "%N not supported", pseudo_random_function_names,
        !           731:                                 prf_algorithm);
        !           732:                }
        !           733:                if (!this->hasher)
        !           734:                {
        !           735:                        DBG1(DBG_TLS, "%N not supported", hash_algorithm_names,
        !           736:                                 hash_algorithm);
        !           737:                }
        !           738:                DBG1(DBG_TLS, "unable to initialise HKDF");
        !           739:                destroy(this);
        !           740:                return NULL;
        !           741:        }
        !           742:        return &this->public;
        !           743: }

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