]> git.ipfire.org Git - people/ms/strongswan.git/commitdiff
tls-hkdf: Add method that allows exporting key material
authorTobias Brunner <tobias@strongswan.org>
Tue, 1 Sep 2020 16:50:47 +0000 (18:50 +0200)
committerTobias Brunner <tobias@strongswan.org>
Fri, 12 Feb 2021 10:45:44 +0000 (11:45 +0100)
src/libtls/tls_hkdf.c
src/libtls/tls_hkdf.h

index be5d57a3d8a587b3dc4c1afeab522e214375ec62..d31a41d79e9b4a6b402cb881c9391648ca879151 100644 (file)
@@ -524,6 +524,54 @@ METHOD(tls_hkdf_t, derive_finished, bool,
                                                                 finished);
 }
 
+METHOD(tls_hkdf_t, export, bool,
+       private_tls_hkdf_t *this, char *label, chunk_t context,
+       chunk_t messages, size_t length, chunk_t *key)
+{
+       chunk_t exporter_master, exporter, hash = chunk_empty;
+
+       if (this->phase != HKDF_PHASE_3)
+       {
+               DBG1(DBG_TLS, "unable to export key material");
+               return FALSE;
+       }
+
+       /**
+        * Export key material according to RFC 8446, section 7.5:
+        *
+        * TLS-Exporter(label, context_value, key_length) =
+        *    HKDF-Expand-Label(Derive-Secret(Secret, label, ""),
+        *                      "exporter", Hash(context_value), key_length)
+        */
+       if (!generate_secret(this, TLS_HKDF_EXP_MASTER, messages, &exporter_master))
+       {
+               DBG1(DBG_TLS, "unable to derive exporter master secret");
+               return FALSE;
+       }
+
+       if (!derive_secret(this, exporter_master, chunk_from_str(label),
+                                          chunk_empty, &exporter))
+       {
+               DBG1(DBG_TLS, "unable to derive exporter secret");
+               chunk_clear(&exporter_master);
+               return FALSE;
+       }
+       chunk_clear(&exporter_master);
+
+       if (!this->hasher->allocate_hash(this->hasher, context, &hash) ||
+               !expand_label(this, exporter, chunk_from_str("exporter"), hash,
+                                         length, key))
+       {
+               DBG1(DBG_TLS, "unable to expand key material");
+               chunk_clear(&exporter);
+               chunk_free(&hash);
+               return FALSE;
+       }
+       chunk_clear(&exporter);
+       chunk_free(&hash);
+       return TRUE;
+}
+
 METHOD(tls_hkdf_t, allocate_bytes, bool,
        private_tls_hkdf_t *this, chunk_t key, chunk_t seed,
        chunk_t *out)
@@ -571,6 +619,7 @@ tls_hkdf_t *tls_hkdf_create(hash_algorithm_t hash_algorithm, chunk_t psk)
                        .derive_key = _derive_key,
                        .derive_iv = _derive_iv,
                        .derive_finished = _derive_finished,
+                       .export = _export,
                        .allocate_bytes = _allocate_bytes,
                        .destroy = _destroy,
                },
index 352d8e3996a1353a3650c361af8f517275b01506..2b2bf3e0345b125b6f9d6dddf35696d223519d0a 100644 (file)
@@ -113,6 +113,19 @@ struct tls_hkdf_t {
        bool (*derive_finished)(tls_hkdf_t *this, bool is_server,
                                                        chunk_t *finished);
 
+       /**
+        * Export key material.
+        *
+        * @param label                         exporter label
+        * @param context                       optional context
+        * @param messages                      handshake messages
+        * @param length                        key length, in bytes
+        * @param key                           exported key material
+        * @return                                      TRUE if key material successfully exported
+        */
+       bool (*export)(tls_hkdf_t *this, char *label, chunk_t context,
+                                  chunk_t messages, size_t length, chunk_t *key);
+
        /**
         * Use the internal PRF to allocate data (mainly for the finished message
         * where the key is from derive_finished() and the seed is the transcript