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)
.derive_key = _derive_key,
.derive_iv = _derive_iv,
.derive_finished = _derive_finished,
+ .export = _export,
.allocate_bytes = _allocate_bytes,
.destroy = _destroy,
},
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