File Coverage

src/ssl/ssl_rec_ccm.c
Criterion Covered Total %
statement 0 65 0.0
branch 0 8 0.0
condition n/a
subroutine n/a
pod n/a
total 0 73 0.0


line stmt bran cond sub pod time code
1             /*
2             * Copyright (c) 2018 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             * CCM 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_ccm_init(br_sslrec_ccm_context *cc,
34             const br_block_ctrcbc_class *bc_impl,
35             const void *key, size_t key_len,
36             const void *iv, size_t tag_len)
37             {
38 0           cc->seq = 0;
39 0           bc_impl->init(&cc->bc.vtable, key, key_len);
40 0           memcpy(cc->iv, iv, sizeof cc->iv);
41 0           cc->tag_len = tag_len;
42 0           }
43              
44             static void
45 0           in_ccm_init(br_sslrec_ccm_context *cc,
46             const br_block_ctrcbc_class *bc_impl,
47             const void *key, size_t key_len,
48             const void *iv, size_t tag_len)
49             {
50 0           cc->vtable.in = &br_sslrec_in_ccm_vtable;
51 0           gen_ccm_init(cc, bc_impl, key, key_len, iv, tag_len);
52 0           }
53              
54             static int
55 0           ccm_check_length(const br_sslrec_ccm_context *cc, size_t rlen)
56             {
57             /*
58             * CCM overhead is 8 bytes for nonce_explicit, and the tag
59             * (normally 8 or 16 bytes, depending on cipher suite).
60             */
61             size_t over;
62              
63 0           over = 8 + cc->tag_len;
64 0 0         return rlen >= over && rlen <= (16384 + over);
    0          
65             }
66              
67             static unsigned char *
68 0           ccm_decrypt(br_sslrec_ccm_context *cc,
69             int record_type, unsigned version, void *data, size_t *data_len)
70             {
71             br_ccm_context zc;
72             unsigned char *buf;
73             unsigned char nonce[12], header[13];
74             size_t len;
75              
76 0           buf = (unsigned char *)data + 8;
77 0           len = *data_len - (8 + cc->tag_len);
78              
79             /*
80             * Make nonce (implicit + explicit parts).
81             */
82 0           memcpy(nonce, cc->iv, sizeof cc->iv);
83 0           memcpy(nonce + 4, data, 8);
84              
85             /*
86             * Assemble synthetic header for the AAD.
87             */
88 0           br_enc64be(header, cc->seq ++);
89 0           header[8] = (unsigned char)record_type;
90 0           br_enc16be(header + 9, version);
91 0           br_enc16be(header + 11, len);
92              
93             /*
94             * Perform CCM decryption.
95             */
96 0           br_ccm_init(&zc, &cc->bc.vtable);
97 0           br_ccm_reset(&zc, nonce, sizeof nonce, sizeof header, len, cc->tag_len);
98 0           br_ccm_aad_inject(&zc, header, sizeof header);
99 0           br_ccm_flip(&zc);
100 0           br_ccm_run(&zc, 0, buf, len);
101 0 0         if (!br_ccm_check_tag(&zc, buf + len)) {
102 0           return NULL;
103             }
104 0           *data_len = len;
105 0           return buf;
106             }
107              
108             /* see bearssl_ssl.h */
109             const br_sslrec_in_ccm_class br_sslrec_in_ccm_vtable = {
110             {
111             sizeof(br_sslrec_ccm_context),
112             (int (*)(const br_sslrec_in_class *const *, size_t))
113             &ccm_check_length,
114             (unsigned char *(*)(const br_sslrec_in_class **,
115             int, unsigned, void *, size_t *))
116             &ccm_decrypt
117             },
118             (void (*)(const br_sslrec_in_ccm_class **,
119             const br_block_ctrcbc_class *, const void *, size_t,
120             const void *, size_t))
121             &in_ccm_init
122             };
123              
124             static void
125 0           out_ccm_init(br_sslrec_ccm_context *cc,
126             const br_block_ctrcbc_class *bc_impl,
127             const void *key, size_t key_len,
128             const void *iv, size_t tag_len)
129             {
130 0           cc->vtable.out = &br_sslrec_out_ccm_vtable;
131 0           gen_ccm_init(cc, bc_impl, key, key_len, iv, tag_len);
132 0           }
133              
134             static void
135 0           ccm_max_plaintext(const br_sslrec_ccm_context *cc,
136             size_t *start, size_t *end)
137             {
138             size_t len;
139              
140 0           *start += 8;
141 0           len = *end - *start - cc->tag_len;
142 0 0         if (len > 16384) {
143 0           len = 16384;
144             }
145 0           *end = *start + len;
146 0           }
147              
148             static unsigned char *
149 0           ccm_encrypt(br_sslrec_ccm_context *cc,
150             int record_type, unsigned version, void *data, size_t *data_len)
151             {
152             br_ccm_context zc;
153             unsigned char *buf;
154             unsigned char nonce[12], header[13];
155             size_t len;
156              
157 0           buf = (unsigned char *)data;
158 0           len = *data_len;
159              
160             /*
161             * Make nonce; the explicit part is an encoding of the sequence
162             * number.
163             */
164 0           memcpy(nonce, cc->iv, sizeof cc->iv);
165 0           br_enc64be(nonce + 4, cc->seq);
166              
167             /*
168             * Assemble synthetic header for the AAD.
169             */
170 0           br_enc64be(header, cc->seq ++);
171 0           header[8] = (unsigned char)record_type;
172 0           br_enc16be(header + 9, version);
173 0           br_enc16be(header + 11, len);
174              
175             /*
176             * Perform CCM encryption.
177             */
178 0           br_ccm_init(&zc, &cc->bc.vtable);
179 0           br_ccm_reset(&zc, nonce, sizeof nonce, sizeof header, len, cc->tag_len);
180 0           br_ccm_aad_inject(&zc, header, sizeof header);
181 0           br_ccm_flip(&zc);
182 0           br_ccm_run(&zc, 1, buf, len);
183 0           br_ccm_get_tag(&zc, buf + len);
184              
185             /*
186             * Assemble header and adjust pointer/length.
187             */
188 0           len += 8 + cc->tag_len;
189 0           buf -= 13;
190 0           memcpy(buf + 5, nonce + 4, 8);
191 0           buf[0] = (unsigned char)record_type;
192 0           br_enc16be(buf + 1, version);
193 0           br_enc16be(buf + 3, len);
194 0           *data_len = len + 5;
195 0           return buf;
196             }
197              
198             /* see bearssl_ssl.h */
199             const br_sslrec_out_ccm_class br_sslrec_out_ccm_vtable = {
200             {
201             sizeof(br_sslrec_ccm_context),
202             (void (*)(const br_sslrec_out_class *const *,
203             size_t *, size_t *))
204             &ccm_max_plaintext,
205             (unsigned char *(*)(const br_sslrec_out_class **,
206             int, unsigned, void *, size_t *))
207             &ccm_encrypt
208             },
209             (void (*)(const br_sslrec_out_ccm_class **,
210             const br_block_ctrcbc_class *, const void *, size_t,
211             const void *, size_t))
212             &out_ccm_init
213             };