diff options
Diffstat (limited to 'src/utils.cpp')
| -rw-r--r-- | src/utils.cpp | 136 |
1 files changed, 136 insertions, 0 deletions
diff --git a/src/utils.cpp b/src/utils.cpp new file mode 100644 index 0000000..9af0ffa --- /dev/null +++ b/src/utils.cpp @@ -0,0 +1,136 @@ +/** + * utils.c + * + * Created on 2020-11-27 + * @author: qyc + * + * @explain: + */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "utils.h" +#include "wsgcrypt.h" +#include "pint.h" + +/* + * Computes HKDF-Expand-Label(Secret, Label, Hash(context_value), Length) with a + * custom label prefix. If "context_hash" is NULL, then an empty context is + * used. Otherwise it must have the same length as the hash algorithm output. + */ +static gboolean tls13_hkdf_expand_label_context(int md, const StringInfo *secret, const char *label_prefix, const char *label, const guint8 *context_hash, guint8 context_length, guint16 out_len, guchar **out) +{ + /* RFC 8446 Section 7.1: + * HKDF-Expand-Label(Secret, Label, Context, Length) = + * HKDF-Expand(Secret, HkdfLabel, Length) + * struct { + * uint16 length = Length; + * opaque label<7..255> = "tls13 " + Label; // "tls13 " is label prefix. + * opaque context<0..255> = Context; + * } HkdfLabel; + * + * RFC 5869 HMAC-based Extract-and-Expand Key Derivation Function (HKDF): + * HKDF-Expand(PRK, info, L) -> OKM + */ + gcry_error_t err; + const guint label_prefix_length = (guint)strlen(label_prefix); + const guint label_length = (guint)strlen(label); + + // Some sanity checks + g_assert(label_length > 0 && label_prefix_length + label_length <= 255); + + // info = HkdfLabel { length, label, context } + GByteArray *info = g_byte_array_new(); + const guint16 length = g_htons(out_len); + g_byte_array_append(info, (const guint8 *)&length, sizeof(length)); + + const guint8 label_vector_length = label_prefix_length + label_length; + g_byte_array_append(info, &label_vector_length, 1); + g_byte_array_append(info, (const guint8 *)label_prefix, label_prefix_length); + g_byte_array_append(info, (const guint8 *)label, label_length); + + g_byte_array_append(info, &context_length, 1); + if (context_length) + g_byte_array_append(info, context_hash, context_length); + + *out = (guchar *)g_malloc(out_len); + err = hkdf_expand(md, secret->data, secret->data_len, info->data, info->len, *out, out_len); + g_byte_array_free(info, TRUE); + + if (err) { + printf("%s failed %d: %s\n", G_STRFUNC, md, gcry_strerror(err)); + g_free(*out); + *out = NULL; + return FALSE; + } + + return TRUE; +} + +gboolean tls13_hkdf_expand_label(int md, const StringInfo *secret, const char *label_prefix, const char *label, guint16 out_len, guchar **out) +{ + return tls13_hkdf_expand_label_context(md, secret, label_prefix, label, NULL, 0, out_len, out); +} + +static guint8 tvb_get_guint8(const char *tvb, const gint offset) +{ + const guint8 *ptr; + + ptr = (guint8 *)tvb + offset; + return *ptr; +} + +static guint16 tvb_get_ntohs(const char *tvb, const gint offset) +{ + const guint8 *ptr; + + ptr = (guint8 *)tvb + offset; + return pntoh16(ptr); +} + +static guint32 tvb_get_ntohl(const char *tvb, const gint offset) +{ + const guint8 *ptr; + + ptr = (guint8 *)tvb + offset; + return pntoh32(ptr); +} + +static guint64 tvb_get_ntoh64(const char *tvb, const gint offset) +{ + const guint8 *ptr; + + ptr = (guint8 *)tvb + offset; + return pntoh64(ptr); +} + +guint tvb_get_varint(const char *tvb, guint offset, guint maxlen, guint64 *value, const guint encoding) +{ + *value = 0; + + if (encoding & ENC_VARINT_QUIC) { + // calculate variable length + *value = tvb_get_guint8(tvb, offset); + switch((*value) >> 6) { + case 0: /* 0b00 => 1 byte length (6 bits Usable) */ + (*value) &= 0x3F; + return 1; + case 1: /* 0b01 => 2 bytes length (14 bits Usable) */ + *value = tvb_get_ntohs(tvb, offset) & 0x3FFF; + return 2; + case 2: /* 0b10 => 4 bytes length (30 bits Usable) */ + *value = tvb_get_ntohl(tvb, offset) & 0x3FFFFFFF; + return 4; + case 3: /* 0b11 => 8 bytes length (62 bits Usable) */ + *value = tvb_get_ntoh64(tvb, offset) & G_GUINT64_CONSTANT(0x3FFFFFFFFFFFFFFF); + return 8; + default: /* No Possible */ + g_assert_not_reached(); + break; + } + } + + // 10 bytes scanned, but no bytes' msb is zero + return 0; +} |
