--- /dev/null
+#define _POSIX_C_SOURCE 200809L
+
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <time.h>
+
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+
+#include <errno.h>
+
+#include <tomcrypt.h>
+#include "tlse.h"
+
+int tls_hkdf_extract(unsigned int mac_length,
+ unsigned char *output, unsigned int outlen,
+ const unsigned char *salt,
+ unsigned int salt_len,
+ const unsigned char *ikm,
+ unsigned char ikm_len) {
+ int hash_idx;
+ unsigned long dlen = outlen;
+ unsigned char dummy_label[1] = { 0 };
+
+ if (!salt || salt_len == 0) {
+ salt_len = 1;
+ salt = dummy_label;
+ }
+
+ if (mac_length == TLS_SHA384_MAC_SIZE) {
+ hash_idx = find_hash("sha384");
+ dlen = mac_length;
+ } else {
+ hash_idx = find_hash("sha256");
+ }
+
+ hmac_memory(hash_idx, salt, salt_len, ikm, ikm_len, output, &dlen);
+ return dlen;
+}
+
+static int make_hkdf_label(const char *label, unsigned char label_len,
+ const unsigned char *data,
+ unsigned char data_len,
+ unsigned char *hkdflabel,
+ unsigned short length, const char *prefix) {
+ int prefix_len;
+ *(unsigned short *) &hkdflabel[0] = htons(length);
+
+ if (prefix) {
+ prefix_len = strlen(prefix);
+ memcpy(&hkdflabel[3], prefix, prefix_len);
+ } else {
+ memcpy(&hkdflabel[3], "tls13 ", 6);
+ prefix_len = 6;
+ }
+
+ hkdflabel[2] = (unsigned char) prefix_len + label_len;
+
+ memcpy(&hkdflabel[3 + prefix_len], label, label_len);
+
+ hkdflabel[3 + prefix_len + label_len] = data_len;
+
+ if (data_len) {
+ memcpy(&hkdflabel[4 + prefix_len + label_len], data,
+ data_len);
+ }
+
+ return 4 + prefix_len + label_len + data_len;
+}
+
+void tls_hkdf_expand(unsigned int mac_length,
+ unsigned char *output, unsigned int outlen,
+ const unsigned char *secret,
+ unsigned int secret_len,
+ const unsigned char *info,
+ unsigned char info_len) {
+ unsigned char digest_out[TLS_MAX_HASH_LEN];
+ unsigned long dlen = 32;
+ int hash_idx;
+ unsigned int i;
+ unsigned char i2 = 0;
+ unsigned int idx = 0;
+ hmac_state hmac;
+ unsigned int copylen;
+
+ if (mac_length == TLS_SHA384_MAC_SIZE) {
+ hash_idx = find_hash("sha384");
+ dlen = mac_length;
+ } else {
+ hash_idx = find_hash("sha256");
+ }
+
+ while (outlen) {
+ hmac_init(&hmac, hash_idx, secret, secret_len);
+ if (i2) {
+ hmac_process(&hmac, digest_out, dlen);
+ }
+ if (info && info_len) {
+ hmac_process(&hmac, info, info_len);
+ }
+ i2++;
+ hmac_process(&hmac, &i2, 1);
+ hmac_done(&hmac, digest_out, &dlen);
+
+ copylen = outlen;
+ if (copylen > dlen) {
+ copylen = (unsigned int) dlen;
+ }
+
+ for (i = 0; i < copylen; i++) {
+ output[idx++] = digest_out[i];
+ outlen--;
+ }
+ }
+}
+
+void tls_hkdf_expand_label(unsigned int mac_length, unsigned char *output,
+ unsigned int outlen, const unsigned char *secret, unsigned int
+ secret_len, const char *label, unsigned char label_len, const
+ unsigned char *data, unsigned char data_len) {
+ unsigned char hkdf_label[512];
+ int len = make_hkdf_label(label, label_len, data, data_len, hkdf_label,
+ outlen, NULL);
+ tls_hkdf_expand(mac_length, output, outlen, secret, secret_len,
+ hkdf_label, len);
+}