1 /* 2 * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org> 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