From c90e0e21910385ed930865b7dc3d34c6e11685a6 Mon Sep 17 00:00:00 2001 From: Jack Lloyd Date: Wed, 27 Sep 2017 10:14:34 -0400 Subject: Add HKDF-Expand-Label Step 1/n of TLS 1.3 --- src/lib/kdf/hkdf/hkdf.cpp | 48 ++++++++++++++++++++++++++++++++++++++++++++++- src/lib/kdf/hkdf/hkdf.h | 14 ++++++++++++++ src/lib/kdf/hkdf/info.txt | 2 +- 3 files changed, 62 insertions(+), 2 deletions(-) (limited to 'src/lib/kdf') diff --git a/src/lib/kdf/hkdf/hkdf.cpp b/src/lib/kdf/hkdf/hkdf.cpp index 20215125b..d66847244 100644 --- a/src/lib/kdf/hkdf/hkdf.cpp +++ b/src/lib/kdf/hkdf/hkdf.cpp @@ -1,6 +1,6 @@ /* * HKDF -* (C) 2013,2015 Jack Lloyd +* (C) 2013,2015,2017 Jack Lloyd * (C) 2016 René Korthaus, Rohde & Schwarz Cybersecurity * * Botan is released under the Simplified BSD License (see license.txt) @@ -73,4 +73,50 @@ size_t HKDF_Expand::kdf(uint8_t key[], size_t key_len, return offset; } +secure_vector +hkdf_expand_label(const std::string& hash_fn, + const uint8_t secret[], size_t secret_len, + const std::string& label, + const uint8_t hash_val[], size_t hash_val_len, + size_t length) + { + if(length > 0xFFFF) + throw Invalid_Argument("HKDF-Expand-Label requested output too large"); + if(label.size() > 0xFF) + throw Invalid_Argument("HKDF-Expand-Label label too long"); + if(hash_val_len > 0xFF) + throw Invalid_Argument("HKDF-Expand-Label hash too long"); + + auto mac = MessageAuthenticationCode::create("HMAC(" + hash_fn + ")"); + if(!mac) + throw Invalid_Argument("HKDF-Expand-Label with HMAC(" + hash_fn + ") not available"); + + HKDF_Expand hkdf(mac.release()); + + secure_vector output(length); + std::vector prefix(3 + label.size() + 1); + + prefix[0] = get_byte(0, length); + prefix[1] = get_byte(1, length); + prefix[2] = static_cast(label.size()); + + copy_mem(prefix.data() + 3, + reinterpret_cast(label.data()), + label.size()); + + prefix[3 + label.size()] = static_cast(hash_val_len); + + /* + * We do something a little dirty here to avoid copying the hash_val, + * making use of the fact that Botan's KDF interface supports label+salt, + * and knowing that our HKDF hashes first param label then param salt. + */ + hkdf.kdf(output.data(), output.size(), + secret, secret_len, + hash_val, hash_val_len, + prefix.data(), prefix.size()); + + return output; + } + } diff --git a/src/lib/kdf/hkdf/hkdf.h b/src/lib/kdf/hkdf/hkdf.h index e63973497..7d2b7f8b2 100644 --- a/src/lib/kdf/hkdf/hkdf.h +++ b/src/lib/kdf/hkdf/hkdf.h @@ -86,6 +86,20 @@ class BOTAN_PUBLIC_API(2,0) HKDF_Expand final : public KDF std::unique_ptr m_prf; }; +/** +* HKDF-Expand-Label from TLS 1.3/QUIC +* @param label the full label (no "TLS 1.3, " or "tls13 " prefix +* is applied) +*/ +secure_vector +BOTAN_PUBLIC_API(2,3) hkdf_expand_label( + const std::string& hash_fn, + const uint8_t secret[], size_t secret_len, + const std::string& label, + const uint8_t hash_val[], size_t hash_val_len, + size_t length); + + } #endif diff --git a/src/lib/kdf/hkdf/info.txt b/src/lib/kdf/hkdf/info.txt index db6618c3c..b9b17b3b8 100644 --- a/src/lib/kdf/hkdf/info.txt +++ b/src/lib/kdf/hkdf/info.txt @@ -1,3 +1,3 @@ -HKDF -> 20131128 +HKDF -> 20170927 -- cgit v1.2.3