File Coverage

src/ssl/ssl_rec_gcm.c
Criterion Covered Total %
statement 0 72 0.0
branch 0 12 0.0
condition n/a
subroutine n/a
pod n/a
total 0 84 0.0


line stmt bran cond sub pod time code
1             /*
2             * Copyright (c) 2016 Thomas Pornin
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 0           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 0           cc->seq = 0;
42 0           bc_impl->init(&cc->bc.vtable, key, key_len);
43 0           cc->gh = gh_impl;
44 0           memcpy(cc->iv, iv, sizeof cc->iv);
45 0           memset(cc->h, 0, sizeof cc->h);
46 0           memset(tmp, 0, sizeof tmp);
47 0           bc_impl->run(&cc->bc.vtable, tmp, 0, cc->h, sizeof cc->h);
48 0           }
49              
50             static void
51 0           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 0           cc->vtable.in = &br_sslrec_in_gcm_vtable;
58 0           gen_gcm_init(cc, bc_impl, key, key_len, gh_impl, iv);
59 0           }
60              
61             static int
62 0           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 0 0         return rlen >= 24 && rlen <= (16384 + 24);
    0          
71             }
72              
73             /*
74             * Compute the authentication tag. The value written in 'tag' must still
75             * be CTR-encrypted.
76             */
77             static void
78 0           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 0           br_enc64be(header, cc->seq ++);
94 0           header[8] = (unsigned char)record_type;
95 0           br_enc16be(header + 9, version);
96 0           br_enc16be(header + 11, len);
97 0           br_enc64be(footer, (uint64_t)(sizeof header) << 3);
98 0           br_enc64be(footer + 8, (uint64_t)len << 3);
99 0           memset(tag, 0, 16);
100 0           cc->gh(tag, cc->h, header, sizeof header);
101 0           cc->gh(tag, cc->h, data, len);
102 0           cc->gh(tag, cc->h, footer, sizeof footer);
103 0           }
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 0           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 0           memcpy(iv, cc->iv, 4);
117 0           memcpy(iv + 4, nonce, 8);
118 0           cc->bc.vtable->run(&cc->bc.vtable, iv, 2, data, len);
119 0           cc->bc.vtable->run(&cc->bc.vtable, iv, 1, xortag, 16);
120 0           }
121              
122             static unsigned char *
123 0           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 0           buf = (unsigned char *)data + 8;
132 0           len = *data_len - 24;
133 0           do_tag(cc, record_type, version, buf, len, tag);
134 0           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 0           bad = 0;
142 0 0         for (u = 0; u < 16; u ++) {
143 0           bad |= tag[u] ^ buf[len + u];
144             }
145 0 0         if (bad) {
146 0           return NULL;
147             }
148 0           *data_len = len;
149 0           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 0           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 0           cc->vtable.out = &br_sslrec_out_gcm_vtable;
176 0           gen_gcm_init(cc, bc_impl, key, key_len, gh_impl, iv);
177 0           }
178              
179             static void
180 0           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 0           *start += 8;
187 0           len = *end - *start - 16;
188 0 0         if (len > 16384) {
189 0           len = 16384;
190             }
191 0           *end = *start + len;
192 0           }
193              
194             static unsigned char *
195 0           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 0           buf = (unsigned char *)data;
203 0           len = *data_len;
204 0           memset(tmp, 0, sizeof tmp);
205 0           br_enc64be(buf - 8, cc->seq);
206 0           do_ctr(cc, buf - 8, buf, len, tmp);
207 0           do_tag(cc, record_type, version, buf, len, buf + len);
208 0 0         for (u = 0; u < 16; u ++) {
209 0           buf[len + u] ^= tmp[u];
210             }
211 0           len += 24;
212 0           buf -= 13;
213 0           buf[0] = (unsigned char)record_type;
214 0           br_enc16be(buf + 1, version);
215 0           br_enc16be(buf + 3, len);
216 0           *data_len = len + 5;
217 0           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             };