Return to tls_hkdf.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / libtls |
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: }