Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/bearssl/src/ssl/ssl_rec_gcm.c
39483 views
1
/*
2
* Copyright (c) 2016 Thomas Pornin <[email protected]>
3
*
4
* Permission is hereby granted, free of charge, to any person obtaining
5
* a copy of this software and associated documentation files (the
6
* "Software"), to deal in the Software without restriction, including
7
* without limitation the rights to use, copy, modify, merge, publish,
8
* distribute, sublicense, and/or sell copies of the Software, and to
9
* permit persons to whom the Software is furnished to do so, subject to
10
* the following conditions:
11
*
12
* The above copyright notice and this permission notice shall be
13
* included in all copies or substantial portions of the Software.
14
*
15
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
* SOFTWARE.
23
*/
24
25
#include "inner.h"
26
27
/*
28
* GCM initialisation. This does everything except setting the vtable,
29
* which depends on whether this is a context for encrypting or for
30
* decrypting.
31
*/
32
static void
33
gen_gcm_init(br_sslrec_gcm_context *cc,
34
const br_block_ctr_class *bc_impl,
35
const void *key, size_t key_len,
36
br_ghash gh_impl,
37
const void *iv)
38
{
39
unsigned char tmp[12];
40
41
cc->seq = 0;
42
bc_impl->init(&cc->bc.vtable, key, key_len);
43
cc->gh = gh_impl;
44
memcpy(cc->iv, iv, sizeof cc->iv);
45
memset(cc->h, 0, sizeof cc->h);
46
memset(tmp, 0, sizeof tmp);
47
bc_impl->run(&cc->bc.vtable, tmp, 0, cc->h, sizeof cc->h);
48
}
49
50
static void
51
in_gcm_init(br_sslrec_gcm_context *cc,
52
const br_block_ctr_class *bc_impl,
53
const void *key, size_t key_len,
54
br_ghash gh_impl,
55
const void *iv)
56
{
57
cc->vtable.in = &br_sslrec_in_gcm_vtable;
58
gen_gcm_init(cc, bc_impl, key, key_len, gh_impl, iv);
59
}
60
61
static int
62
gcm_check_length(const br_sslrec_gcm_context *cc, size_t rlen)
63
{
64
/*
65
* GCM adds a fixed overhead:
66
* 8 bytes for the nonce_explicit (before the ciphertext)
67
* 16 bytes for the authentication tag (after the ciphertext)
68
*/
69
(void)cc;
70
return rlen >= 24 && rlen <= (16384 + 24);
71
}
72
73
/*
74
* Compute the authentication tag. The value written in 'tag' must still
75
* be CTR-encrypted.
76
*/
77
static void
78
do_tag(br_sslrec_gcm_context *cc,
79
int record_type, unsigned version,
80
void *data, size_t len, void *tag)
81
{
82
unsigned char header[13];
83
unsigned char footer[16];
84
85
/*
86
* Compute authentication tag. Three elements must be injected in
87
* sequence, each possibly 0-padded to reach a length multiple
88
* of the block size: the 13-byte header (sequence number, record
89
* type, protocol version, record length), the cipher text, and
90
* the word containing the encodings of the bit lengths of the two
91
* other elements.
92
*/
93
br_enc64be(header, cc->seq ++);
94
header[8] = (unsigned char)record_type;
95
br_enc16be(header + 9, version);
96
br_enc16be(header + 11, len);
97
br_enc64be(footer, (uint64_t)(sizeof header) << 3);
98
br_enc64be(footer + 8, (uint64_t)len << 3);
99
memset(tag, 0, 16);
100
cc->gh(tag, cc->h, header, sizeof header);
101
cc->gh(tag, cc->h, data, len);
102
cc->gh(tag, cc->h, footer, sizeof footer);
103
}
104
105
/*
106
* Do CTR encryption. This also does CTR encryption of a single block at
107
* address 'xortag' with the counter value appropriate for the final
108
* processing of the authentication tag.
109
*/
110
static void
111
do_ctr(br_sslrec_gcm_context *cc, const void *nonce, void *data, size_t len,
112
void *xortag)
113
{
114
unsigned char iv[12];
115
116
memcpy(iv, cc->iv, 4);
117
memcpy(iv + 4, nonce, 8);
118
cc->bc.vtable->run(&cc->bc.vtable, iv, 2, data, len);
119
cc->bc.vtable->run(&cc->bc.vtable, iv, 1, xortag, 16);
120
}
121
122
static unsigned char *
123
gcm_decrypt(br_sslrec_gcm_context *cc,
124
int record_type, unsigned version, void *data, size_t *data_len)
125
{
126
unsigned char *buf;
127
size_t len, u;
128
uint32_t bad;
129
unsigned char tag[16];
130
131
buf = (unsigned char *)data + 8;
132
len = *data_len - 24;
133
do_tag(cc, record_type, version, buf, len, tag);
134
do_ctr(cc, data, buf, len, tag);
135
136
/*
137
* Compare the computed tag with the value from the record. It
138
* is possibly useless to do a constant-time comparison here,
139
* but it does not hurt.
140
*/
141
bad = 0;
142
for (u = 0; u < 16; u ++) {
143
bad |= tag[u] ^ buf[len + u];
144
}
145
if (bad) {
146
return NULL;
147
}
148
*data_len = len;
149
return buf;
150
}
151
152
/* see bearssl_ssl.h */
153
const br_sslrec_in_gcm_class br_sslrec_in_gcm_vtable = {
154
{
155
sizeof(br_sslrec_gcm_context),
156
(int (*)(const br_sslrec_in_class *const *, size_t))
157
&gcm_check_length,
158
(unsigned char *(*)(const br_sslrec_in_class **,
159
int, unsigned, void *, size_t *))
160
&gcm_decrypt
161
},
162
(void (*)(const br_sslrec_in_gcm_class **,
163
const br_block_ctr_class *, const void *, size_t,
164
br_ghash, const void *))
165
&in_gcm_init
166
};
167
168
static void
169
out_gcm_init(br_sslrec_gcm_context *cc,
170
const br_block_ctr_class *bc_impl,
171
const void *key, size_t key_len,
172
br_ghash gh_impl,
173
const void *iv)
174
{
175
cc->vtable.out = &br_sslrec_out_gcm_vtable;
176
gen_gcm_init(cc, bc_impl, key, key_len, gh_impl, iv);
177
}
178
179
static void
180
gcm_max_plaintext(const br_sslrec_gcm_context *cc,
181
size_t *start, size_t *end)
182
{
183
size_t len;
184
185
(void)cc;
186
*start += 8;
187
len = *end - *start - 16;
188
if (len > 16384) {
189
len = 16384;
190
}
191
*end = *start + len;
192
}
193
194
static unsigned char *
195
gcm_encrypt(br_sslrec_gcm_context *cc,
196
int record_type, unsigned version, void *data, size_t *data_len)
197
{
198
unsigned char *buf;
199
size_t u, len;
200
unsigned char tmp[16];
201
202
buf = (unsigned char *)data;
203
len = *data_len;
204
memset(tmp, 0, sizeof tmp);
205
br_enc64be(buf - 8, cc->seq);
206
do_ctr(cc, buf - 8, buf, len, tmp);
207
do_tag(cc, record_type, version, buf, len, buf + len);
208
for (u = 0; u < 16; u ++) {
209
buf[len + u] ^= tmp[u];
210
}
211
len += 24;
212
buf -= 13;
213
buf[0] = (unsigned char)record_type;
214
br_enc16be(buf + 1, version);
215
br_enc16be(buf + 3, len);
216
*data_len = len + 5;
217
return buf;
218
}
219
220
/* see bearssl_ssl.h */
221
const br_sslrec_out_gcm_class br_sslrec_out_gcm_vtable = {
222
{
223
sizeof(br_sslrec_gcm_context),
224
(void (*)(const br_sslrec_out_class *const *,
225
size_t *, size_t *))
226
&gcm_max_plaintext,
227
(unsigned char *(*)(const br_sslrec_out_class **,
228
int, unsigned, void *, size_t *))
229
&gcm_encrypt
230
},
231
(void (*)(const br_sslrec_out_gcm_class **,
232
const br_block_ctr_class *, const void *, size_t,
233
br_ghash, const void *))
234
&out_gcm_init
235
};
236
237