summaryrefslogtreecommitdiff
path: root/src/utils.cpp
blob: 9af0ffaee28489ef81ef05f31b6b23f39b523b8a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
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;
}