xref: /freebsd/contrib/bearssl/src/ssl/ssl_rec_cbc.c (revision cc9e6590773dba57440750c124173ed531349a06)
10957b409SSimon J. Gerraty /*
20957b409SSimon J. Gerraty  * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
30957b409SSimon J. Gerraty  *
40957b409SSimon J. Gerraty  * Permission is hereby granted, free of charge, to any person obtaining
50957b409SSimon J. Gerraty  * a copy of this software and associated documentation files (the
60957b409SSimon J. Gerraty  * "Software"), to deal in the Software without restriction, including
70957b409SSimon J. Gerraty  * without limitation the rights to use, copy, modify, merge, publish,
80957b409SSimon J. Gerraty  * distribute, sublicense, and/or sell copies of the Software, and to
90957b409SSimon J. Gerraty  * permit persons to whom the Software is furnished to do so, subject to
100957b409SSimon J. Gerraty  * the following conditions:
110957b409SSimon J. Gerraty  *
120957b409SSimon J. Gerraty  * The above copyright notice and this permission notice shall be
130957b409SSimon J. Gerraty  * included in all copies or substantial portions of the Software.
140957b409SSimon J. Gerraty  *
150957b409SSimon J. Gerraty  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
160957b409SSimon J. Gerraty  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
170957b409SSimon J. Gerraty  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
180957b409SSimon J. Gerraty  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
190957b409SSimon J. Gerraty  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
200957b409SSimon J. Gerraty  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
210957b409SSimon J. Gerraty  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
220957b409SSimon J. Gerraty  * SOFTWARE.
230957b409SSimon J. Gerraty  */
240957b409SSimon J. Gerraty 
250957b409SSimon J. Gerraty #include "inner.h"
260957b409SSimon J. Gerraty 
270957b409SSimon J. Gerraty static void
in_cbc_init(br_sslrec_in_cbc_context * cc,const br_block_cbcdec_class * bc_impl,const void * bc_key,size_t bc_key_len,const br_hash_class * dig_impl,const void * mac_key,size_t mac_key_len,size_t mac_out_len,const void * iv)280957b409SSimon J. Gerraty in_cbc_init(br_sslrec_in_cbc_context *cc,
290957b409SSimon J. Gerraty 	const br_block_cbcdec_class *bc_impl,
300957b409SSimon J. Gerraty 	const void *bc_key, size_t bc_key_len,
310957b409SSimon J. Gerraty 	const br_hash_class *dig_impl,
320957b409SSimon J. Gerraty 	const void *mac_key, size_t mac_key_len, size_t mac_out_len,
330957b409SSimon J. Gerraty 	const void *iv)
340957b409SSimon J. Gerraty {
350957b409SSimon J. Gerraty 	cc->vtable = &br_sslrec_in_cbc_vtable;
360957b409SSimon J. Gerraty 	cc->seq = 0;
370957b409SSimon J. Gerraty 	bc_impl->init(&cc->bc.vtable, bc_key, bc_key_len);
380957b409SSimon J. Gerraty 	br_hmac_key_init(&cc->mac, dig_impl, mac_key, mac_key_len);
390957b409SSimon J. Gerraty 	cc->mac_len = mac_out_len;
400957b409SSimon J. Gerraty 	if (iv == NULL) {
410957b409SSimon J. Gerraty 		memset(cc->iv, 0, sizeof cc->iv);
420957b409SSimon J. Gerraty 		cc->explicit_IV = 1;
430957b409SSimon J. Gerraty 	} else {
440957b409SSimon J. Gerraty 		memcpy(cc->iv, iv, bc_impl->block_size);
450957b409SSimon J. Gerraty 		cc->explicit_IV = 0;
460957b409SSimon J. Gerraty 	}
470957b409SSimon J. Gerraty }
480957b409SSimon J. Gerraty 
490957b409SSimon J. Gerraty static int
cbc_check_length(const br_sslrec_in_cbc_context * cc,size_t rlen)500957b409SSimon J. Gerraty cbc_check_length(const br_sslrec_in_cbc_context *cc, size_t rlen)
510957b409SSimon J. Gerraty {
520957b409SSimon J. Gerraty 	/*
530957b409SSimon J. Gerraty 	 * Plaintext size: at most 16384 bytes
540957b409SSimon J. Gerraty 	 * Padding: at most 256 bytes
550957b409SSimon J. Gerraty 	 * MAC: mac_len extra bytes
560957b409SSimon J. Gerraty 	 * TLS 1.1+: each record has an explicit IV
570957b409SSimon J. Gerraty 	 *
580957b409SSimon J. Gerraty 	 * Minimum length includes at least one byte of padding, and the
590957b409SSimon J. Gerraty 	 * MAC.
600957b409SSimon J. Gerraty 	 *
610957b409SSimon J. Gerraty 	 * Total length must be a multiple of the block size.
620957b409SSimon J. Gerraty 	 */
630957b409SSimon J. Gerraty 	size_t blen;
640957b409SSimon J. Gerraty 	size_t min_len, max_len;
650957b409SSimon J. Gerraty 
660957b409SSimon J. Gerraty 	blen = cc->bc.vtable->block_size;
670957b409SSimon J. Gerraty 	min_len = (blen + cc->mac_len) & ~(blen - 1);
680957b409SSimon J. Gerraty 	max_len = (16384 + 256 + cc->mac_len) & ~(blen - 1);
690957b409SSimon J. Gerraty 	if (cc->explicit_IV) {
700957b409SSimon J. Gerraty 		min_len += blen;
710957b409SSimon J. Gerraty 		max_len += blen;
720957b409SSimon J. Gerraty 	}
730957b409SSimon J. Gerraty 	return min_len <= rlen && rlen <= max_len;
740957b409SSimon J. Gerraty }
750957b409SSimon J. Gerraty 
760957b409SSimon J. Gerraty /*
770957b409SSimon J. Gerraty  * Rotate array buf[] of length 'len' to the left (towards low indices)
780957b409SSimon J. Gerraty  * by 'num' bytes if ctl is 1; otherwise, leave it unchanged. This is
790957b409SSimon J. Gerraty  * constant-time. 'num' MUST be lower than 'len'. 'len' MUST be lower
800957b409SSimon J. Gerraty  * than or equal to 64.
810957b409SSimon J. Gerraty  */
820957b409SSimon J. Gerraty static void
cond_rotate(uint32_t ctl,unsigned char * buf,size_t len,size_t num)830957b409SSimon J. Gerraty cond_rotate(uint32_t ctl, unsigned char *buf, size_t len, size_t num)
840957b409SSimon J. Gerraty {
850957b409SSimon J. Gerraty 	unsigned char tmp[64];
860957b409SSimon J. Gerraty 	size_t u, v;
870957b409SSimon J. Gerraty 
880957b409SSimon J. Gerraty 	for (u = 0, v = num; u < len; u ++) {
890957b409SSimon J. Gerraty 		tmp[u] = MUX(ctl, buf[v], buf[u]);
900957b409SSimon J. Gerraty 		if (++ v == len) {
910957b409SSimon J. Gerraty 			v = 0;
920957b409SSimon J. Gerraty 		}
930957b409SSimon J. Gerraty 	}
940957b409SSimon J. Gerraty 	memcpy(buf, tmp, len);
950957b409SSimon J. Gerraty }
960957b409SSimon J. Gerraty 
970957b409SSimon J. Gerraty static unsigned char *
cbc_decrypt(br_sslrec_in_cbc_context * cc,int record_type,unsigned version,void * data,size_t * data_len)980957b409SSimon J. Gerraty cbc_decrypt(br_sslrec_in_cbc_context *cc,
990957b409SSimon J. Gerraty 	int record_type, unsigned version, void *data, size_t *data_len)
1000957b409SSimon J. Gerraty {
1010957b409SSimon J. Gerraty 	/*
1020957b409SSimon J. Gerraty 	 * We represent all lengths on 32-bit integers, because:
1030957b409SSimon J. Gerraty 	 * -- SSL record lengths always fit in 32 bits;
1040957b409SSimon J. Gerraty 	 * -- our constant-time primitives operate on 32-bit integers.
1050957b409SSimon J. Gerraty 	 */
1060957b409SSimon J. Gerraty 	unsigned char *buf;
1070957b409SSimon J. Gerraty 	uint32_t u, v, len, blen, min_len, max_len;
1080957b409SSimon J. Gerraty 	uint32_t good, pad_len, rot_count, len_withmac, len_nomac;
1090957b409SSimon J. Gerraty 	unsigned char tmp1[64], tmp2[64];
1100957b409SSimon J. Gerraty 	int i;
1110957b409SSimon J. Gerraty 	br_hmac_context hc;
1120957b409SSimon J. Gerraty 
1130957b409SSimon J. Gerraty 	buf = data;
1140957b409SSimon J. Gerraty 	len = *data_len;
1150957b409SSimon J. Gerraty 	blen = cc->bc.vtable->block_size;
1160957b409SSimon J. Gerraty 
1170957b409SSimon J. Gerraty 	/*
1180957b409SSimon J. Gerraty 	 * Decrypt data, and skip the explicit IV (if applicable). Note
1190957b409SSimon J. Gerraty 	 * that the total length is supposed to have been verified by
1200957b409SSimon J. Gerraty 	 * the caller. If there is an explicit IV, then we actually
1210957b409SSimon J. Gerraty 	 * "decrypt" it using the implicit IV (from previous record),
1220957b409SSimon J. Gerraty 	 * which is useless but harmless.
1230957b409SSimon J. Gerraty 	 */
1240957b409SSimon J. Gerraty 	cc->bc.vtable->run(&cc->bc.vtable, cc->iv, data, len);
1250957b409SSimon J. Gerraty 	if (cc->explicit_IV) {
1260957b409SSimon J. Gerraty 		buf += blen;
1270957b409SSimon J. Gerraty 		len -= blen;
1280957b409SSimon J. Gerraty 	}
1290957b409SSimon J. Gerraty 
1300957b409SSimon J. Gerraty 	/*
1310957b409SSimon J. Gerraty 	 * Compute minimum and maximum length of plaintext + MAC. These
1320957b409SSimon J. Gerraty 	 * lengths can be inferred from the outside: they are not secret.
1330957b409SSimon J. Gerraty 	 */
1340957b409SSimon J. Gerraty 	min_len = (cc->mac_len + 256 < len) ? len - 256 : cc->mac_len;
1350957b409SSimon J. Gerraty 	max_len = len - 1;
1360957b409SSimon J. Gerraty 
1370957b409SSimon J. Gerraty 	/*
1380957b409SSimon J. Gerraty 	 * Use the last decrypted byte to compute the actual payload
139*cc9e6590SSimon J. Gerraty 	 * length. Take care not to overflow (we use unsigned types).
1400957b409SSimon J. Gerraty 	 */
1410957b409SSimon J. Gerraty 	pad_len = buf[max_len];
1420957b409SSimon J. Gerraty 	good = LE(pad_len, (uint32_t)(max_len - min_len));
1430957b409SSimon J. Gerraty 	len = MUX(good, (uint32_t)(max_len - pad_len), min_len);
1440957b409SSimon J. Gerraty 
1450957b409SSimon J. Gerraty 	/*
1460957b409SSimon J. Gerraty 	 * Check padding contents: all padding bytes must be equal to
1470957b409SSimon J. Gerraty 	 * the value of pad_len.
1480957b409SSimon J. Gerraty 	 */
1490957b409SSimon J. Gerraty 	for (u = min_len; u < max_len; u ++) {
1500957b409SSimon J. Gerraty 		good &= LT(u, len) | EQ(buf[u], pad_len);
1510957b409SSimon J. Gerraty 	}
1520957b409SSimon J. Gerraty 
1530957b409SSimon J. Gerraty 	/*
1540957b409SSimon J. Gerraty 	 * Extract the MAC value. This is done in one pass, but results
1550957b409SSimon J. Gerraty 	 * in a "rotated" MAC value depending on where it actually
1560957b409SSimon J. Gerraty 	 * occurs. The 'rot_count' value is set to the offset of the
1570957b409SSimon J. Gerraty 	 * first MAC byte within tmp1[].
1580957b409SSimon J. Gerraty 	 *
1590957b409SSimon J. Gerraty 	 * min_len and max_len are also adjusted to the minimum and
1600957b409SSimon J. Gerraty 	 * maximum lengths of the plaintext alone (without the MAC).
1610957b409SSimon J. Gerraty 	 */
1620957b409SSimon J. Gerraty 	len_withmac = (uint32_t)len;
1630957b409SSimon J. Gerraty 	len_nomac = len_withmac - cc->mac_len;
1640957b409SSimon J. Gerraty 	min_len -= cc->mac_len;
1650957b409SSimon J. Gerraty 	rot_count = 0;
1660957b409SSimon J. Gerraty 	memset(tmp1, 0, cc->mac_len);
1670957b409SSimon J. Gerraty 	v = 0;
1680957b409SSimon J. Gerraty 	for (u = min_len; u < max_len; u ++) {
1690957b409SSimon J. Gerraty 		tmp1[v] |= MUX(GE(u, len_nomac) & LT(u, len_withmac),
1700957b409SSimon J. Gerraty 			buf[u], 0x00);
1710957b409SSimon J. Gerraty 		rot_count = MUX(EQ(u, len_nomac), v, rot_count);
1720957b409SSimon J. Gerraty 		if (++ v == cc->mac_len) {
1730957b409SSimon J. Gerraty 			v = 0;
1740957b409SSimon J. Gerraty 		}
1750957b409SSimon J. Gerraty 	}
1760957b409SSimon J. Gerraty 	max_len -= cc->mac_len;
1770957b409SSimon J. Gerraty 
1780957b409SSimon J. Gerraty 	/*
1790957b409SSimon J. Gerraty 	 * Rotate back the MAC value. The loop below does the constant-time
1800957b409SSimon J. Gerraty 	 * rotation in time n*log n for a MAC output of length n. We assume
1810957b409SSimon J. Gerraty 	 * that the MAC output length is no more than 64 bytes, so the
1820957b409SSimon J. Gerraty 	 * rotation count fits on 6 bits.
1830957b409SSimon J. Gerraty 	 */
1840957b409SSimon J. Gerraty 	for (i = 5; i >= 0; i --) {
1850957b409SSimon J. Gerraty 		uint32_t rc;
1860957b409SSimon J. Gerraty 
1870957b409SSimon J. Gerraty 		rc = (uint32_t)1 << i;
1880957b409SSimon J. Gerraty 		cond_rotate(rot_count >> i, tmp1, cc->mac_len, rc);
1890957b409SSimon J. Gerraty 		rot_count &= ~rc;
1900957b409SSimon J. Gerraty 	}
1910957b409SSimon J. Gerraty 
1920957b409SSimon J. Gerraty 	/*
1930957b409SSimon J. Gerraty 	 * Recompute the HMAC value. The input is the concatenation of
1940957b409SSimon J. Gerraty 	 * the sequence number (8 bytes), the record header (5 bytes),
1950957b409SSimon J. Gerraty 	 * and the payload.
1960957b409SSimon J. Gerraty 	 *
1970957b409SSimon J. Gerraty 	 * At that point, min_len is the minimum plaintext length, but
1980957b409SSimon J. Gerraty 	 * max_len still includes the MAC length.
1990957b409SSimon J. Gerraty 	 */
2000957b409SSimon J. Gerraty 	br_enc64be(tmp2, cc->seq ++);
2010957b409SSimon J. Gerraty 	tmp2[8] = (unsigned char)record_type;
2020957b409SSimon J. Gerraty 	br_enc16be(tmp2 + 9, version);
2030957b409SSimon J. Gerraty 	br_enc16be(tmp2 + 11, len_nomac);
2040957b409SSimon J. Gerraty 	br_hmac_init(&hc, &cc->mac, cc->mac_len);
2050957b409SSimon J. Gerraty 	br_hmac_update(&hc, tmp2, 13);
2060957b409SSimon J. Gerraty 	br_hmac_outCT(&hc, buf, len_nomac, min_len, max_len, tmp2);
2070957b409SSimon J. Gerraty 
2080957b409SSimon J. Gerraty 	/*
2090957b409SSimon J. Gerraty 	 * Compare the extracted and recomputed MAC values.
2100957b409SSimon J. Gerraty 	 */
2110957b409SSimon J. Gerraty 	for (u = 0; u < cc->mac_len; u ++) {
2120957b409SSimon J. Gerraty 		good &= EQ0(tmp1[u] ^ tmp2[u]);
2130957b409SSimon J. Gerraty 	}
2140957b409SSimon J. Gerraty 
2150957b409SSimon J. Gerraty 	/*
2160957b409SSimon J. Gerraty 	 * Check that the plaintext length is valid. The previous
2170957b409SSimon J. Gerraty 	 * check was on the encrypted length, but the padding may have
2180957b409SSimon J. Gerraty 	 * turned shorter than expected.
2190957b409SSimon J. Gerraty 	 *
2200957b409SSimon J. Gerraty 	 * Once this final test is done, the critical "constant-time"
2210957b409SSimon J. Gerraty 	 * section ends and we can make conditional jumps again.
2220957b409SSimon J. Gerraty 	 */
2230957b409SSimon J. Gerraty 	good &= LE(len_nomac, 16384);
2240957b409SSimon J. Gerraty 
2250957b409SSimon J. Gerraty 	if (!good) {
2260957b409SSimon J. Gerraty 		return 0;
2270957b409SSimon J. Gerraty 	}
2280957b409SSimon J. Gerraty 	*data_len = len_nomac;
2290957b409SSimon J. Gerraty 	return buf;
2300957b409SSimon J. Gerraty }
2310957b409SSimon J. Gerraty 
2320957b409SSimon J. Gerraty /* see bearssl_ssl.h */
2330957b409SSimon J. Gerraty const br_sslrec_in_cbc_class br_sslrec_in_cbc_vtable = {
2340957b409SSimon J. Gerraty 	{
2350957b409SSimon J. Gerraty 		sizeof(br_sslrec_in_cbc_context),
2360957b409SSimon J. Gerraty 		(int (*)(const br_sslrec_in_class *const *, size_t))
2370957b409SSimon J. Gerraty 			&cbc_check_length,
2380957b409SSimon J. Gerraty 		(unsigned char *(*)(const br_sslrec_in_class **,
2390957b409SSimon J. Gerraty 			int, unsigned, void *, size_t *))
2400957b409SSimon J. Gerraty 			&cbc_decrypt
2410957b409SSimon J. Gerraty 	},
2420957b409SSimon J. Gerraty 	(void (*)(const br_sslrec_in_cbc_class **,
2430957b409SSimon J. Gerraty 		const br_block_cbcdec_class *, const void *, size_t,
2440957b409SSimon J. Gerraty 		const br_hash_class *, const void *, size_t, size_t,
2450957b409SSimon J. Gerraty 		const void *))
2460957b409SSimon J. Gerraty 		&in_cbc_init
2470957b409SSimon J. Gerraty };
2480957b409SSimon J. Gerraty 
2490957b409SSimon J. Gerraty /*
2500957b409SSimon J. Gerraty  * For CBC output:
2510957b409SSimon J. Gerraty  *
2520957b409SSimon J. Gerraty  * -- With TLS 1.1+, there is an explicit IV. Generation method uses
2530957b409SSimon J. Gerraty  * HMAC, computed over the current sequence number, and the current MAC
2540957b409SSimon J. Gerraty  * key. The resulting value is truncated to the size of a block, and
2550957b409SSimon J. Gerraty  * added at the head of the plaintext; it will get encrypted along with
2560957b409SSimon J. Gerraty  * the data. This custom generation mechanism is "safe" under the
2570957b409SSimon J. Gerraty  * assumption that HMAC behaves like a random oracle; since the MAC for
2580957b409SSimon J. Gerraty  * a record is computed over the concatenation of the sequence number,
2590957b409SSimon J. Gerraty  * the record header and the plaintext, the HMAC-for-IV will not collide
2600957b409SSimon J. Gerraty  * with the normal HMAC.
2610957b409SSimon J. Gerraty  *
2620957b409SSimon J. Gerraty  * -- With TLS 1.0, for application data, we want to enforce a 1/n-1
2630957b409SSimon J. Gerraty  * split, as a countermeasure against chosen-plaintext attacks. We thus
2640957b409SSimon J. Gerraty  * need to leave some room in the buffer for that extra record.
2650957b409SSimon J. Gerraty  */
2660957b409SSimon J. Gerraty 
2670957b409SSimon J. Gerraty static void
out_cbc_init(br_sslrec_out_cbc_context * cc,const br_block_cbcenc_class * bc_impl,const void * bc_key,size_t bc_key_len,const br_hash_class * dig_impl,const void * mac_key,size_t mac_key_len,size_t mac_out_len,const void * iv)2680957b409SSimon J. Gerraty out_cbc_init(br_sslrec_out_cbc_context *cc,
2690957b409SSimon J. Gerraty 	const br_block_cbcenc_class *bc_impl,
2700957b409SSimon J. Gerraty 	const void *bc_key, size_t bc_key_len,
2710957b409SSimon J. Gerraty 	const br_hash_class *dig_impl,
2720957b409SSimon J. Gerraty 	const void *mac_key, size_t mac_key_len, size_t mac_out_len,
2730957b409SSimon J. Gerraty 	const void *iv)
2740957b409SSimon J. Gerraty {
2750957b409SSimon J. Gerraty 	cc->vtable = &br_sslrec_out_cbc_vtable;
2760957b409SSimon J. Gerraty 	cc->seq = 0;
2770957b409SSimon J. Gerraty 	bc_impl->init(&cc->bc.vtable, bc_key, bc_key_len);
2780957b409SSimon J. Gerraty 	br_hmac_key_init(&cc->mac, dig_impl, mac_key, mac_key_len);
2790957b409SSimon J. Gerraty 	cc->mac_len = mac_out_len;
2800957b409SSimon J. Gerraty 	if (iv == NULL) {
2810957b409SSimon J. Gerraty 		memset(cc->iv, 0, sizeof cc->iv);
2820957b409SSimon J. Gerraty 		cc->explicit_IV = 1;
2830957b409SSimon J. Gerraty 	} else {
2840957b409SSimon J. Gerraty 		memcpy(cc->iv, iv, bc_impl->block_size);
2850957b409SSimon J. Gerraty 		cc->explicit_IV = 0;
2860957b409SSimon J. Gerraty 	}
2870957b409SSimon J. Gerraty }
2880957b409SSimon J. Gerraty 
2890957b409SSimon J. Gerraty static void
cbc_max_plaintext(const br_sslrec_out_cbc_context * cc,size_t * start,size_t * end)2900957b409SSimon J. Gerraty cbc_max_plaintext(const br_sslrec_out_cbc_context *cc,
2910957b409SSimon J. Gerraty 	size_t *start, size_t *end)
2920957b409SSimon J. Gerraty {
2930957b409SSimon J. Gerraty 	size_t blen, len;
2940957b409SSimon J. Gerraty 
2950957b409SSimon J. Gerraty 	blen = cc->bc.vtable->block_size;
2960957b409SSimon J. Gerraty 	if (cc->explicit_IV) {
2970957b409SSimon J. Gerraty 		*start += blen;
2980957b409SSimon J. Gerraty 	} else {
2990957b409SSimon J. Gerraty 		*start += 4 + ((cc->mac_len + blen + 1) & ~(blen - 1));
3000957b409SSimon J. Gerraty 	}
3010957b409SSimon J. Gerraty 	len = (*end - *start) & ~(blen - 1);
3020957b409SSimon J. Gerraty 	len -= 1 + cc->mac_len;
3030957b409SSimon J. Gerraty 	if (len > 16384) {
3040957b409SSimon J. Gerraty 		len = 16384;
3050957b409SSimon J. Gerraty 	}
3060957b409SSimon J. Gerraty 	*end = *start + len;
3070957b409SSimon J. Gerraty }
3080957b409SSimon J. Gerraty 
3090957b409SSimon J. Gerraty static unsigned char *
cbc_encrypt(br_sslrec_out_cbc_context * cc,int record_type,unsigned version,void * data,size_t * data_len)3100957b409SSimon J. Gerraty cbc_encrypt(br_sslrec_out_cbc_context *cc,
3110957b409SSimon J. Gerraty 	int record_type, unsigned version, void *data, size_t *data_len)
3120957b409SSimon J. Gerraty {
3130957b409SSimon J. Gerraty 	unsigned char *buf, *rbuf;
3140957b409SSimon J. Gerraty 	size_t len, blen, plen;
3150957b409SSimon J. Gerraty 	unsigned char tmp[13];
3160957b409SSimon J. Gerraty 	br_hmac_context hc;
3170957b409SSimon J. Gerraty 
3180957b409SSimon J. Gerraty 	buf = data;
3190957b409SSimon J. Gerraty 	len = *data_len;
3200957b409SSimon J. Gerraty 	blen = cc->bc.vtable->block_size;
3210957b409SSimon J. Gerraty 
3220957b409SSimon J. Gerraty 	/*
3230957b409SSimon J. Gerraty 	 * If using TLS 1.0, with more than one byte of plaintext, and
3240957b409SSimon J. Gerraty 	 * the record is application data, then we need to compute
3250957b409SSimon J. Gerraty 	 * a "split". We do not perform the split on other record types
3260957b409SSimon J. Gerraty 	 * because it turned out that some existing, deployed
3270957b409SSimon J. Gerraty 	 * implementations of SSL/TLS do not tolerate the splitting of
3280957b409SSimon J. Gerraty 	 * some message types (in particular the Finished message).
3290957b409SSimon J. Gerraty 	 *
3300957b409SSimon J. Gerraty 	 * If using TLS 1.1+, then there is an explicit IV. We produce
3310957b409SSimon J. Gerraty 	 * that IV by adding an extra initial plaintext block, whose
3320957b409SSimon J. Gerraty 	 * value is computed with HMAC over the record sequence number.
3330957b409SSimon J. Gerraty 	 */
3340957b409SSimon J. Gerraty 	if (cc->explicit_IV) {
3350957b409SSimon J. Gerraty 		/*
3360957b409SSimon J. Gerraty 		 * We use here the fact that all the HMAC variants we
3370957b409SSimon J. Gerraty 		 * support can produce at least 16 bytes, while all the
3380957b409SSimon J. Gerraty 		 * block ciphers we support have blocks of no more than
3390957b409SSimon J. Gerraty 		 * 16 bytes. Thus, we can always truncate the HMAC output
3400957b409SSimon J. Gerraty 		 * down to the block size.
3410957b409SSimon J. Gerraty 		 */
3420957b409SSimon J. Gerraty 		br_enc64be(tmp, cc->seq);
3430957b409SSimon J. Gerraty 		br_hmac_init(&hc, &cc->mac, blen);
3440957b409SSimon J. Gerraty 		br_hmac_update(&hc, tmp, 8);
3450957b409SSimon J. Gerraty 		br_hmac_out(&hc, buf - blen);
3460957b409SSimon J. Gerraty 		rbuf = buf - blen - 5;
3470957b409SSimon J. Gerraty 	} else {
3480957b409SSimon J. Gerraty 		if (len > 1 && record_type == BR_SSL_APPLICATION_DATA) {
3490957b409SSimon J. Gerraty 			/*
3500957b409SSimon J. Gerraty 			 * To do the split, we use a recursive invocation;
3510957b409SSimon J. Gerraty 			 * since we only give one byte to the inner call,
3520957b409SSimon J. Gerraty 			 * the recursion stops there.
3530957b409SSimon J. Gerraty 			 *
3540957b409SSimon J. Gerraty 			 * We need to compute the exact size of the extra
3550957b409SSimon J. Gerraty 			 * record, so that the two resulting records end up
3560957b409SSimon J. Gerraty 			 * being sequential in RAM.
3570957b409SSimon J. Gerraty 			 *
3580957b409SSimon J. Gerraty 			 * We use here the fact that cbc_max_plaintext()
3590957b409SSimon J. Gerraty 			 * adjusted the start offset to leave room for the
3600957b409SSimon J. Gerraty 			 * initial fragment.
3610957b409SSimon J. Gerraty 			 */
3620957b409SSimon J. Gerraty 			size_t xlen;
3630957b409SSimon J. Gerraty 
3640957b409SSimon J. Gerraty 			rbuf = buf - 4
3650957b409SSimon J. Gerraty 				- ((cc->mac_len + blen + 1) & ~(blen - 1));
3660957b409SSimon J. Gerraty 			rbuf[0] = buf[0];
3670957b409SSimon J. Gerraty 			xlen = 1;
3680957b409SSimon J. Gerraty 			rbuf = cbc_encrypt(cc, record_type,
3690957b409SSimon J. Gerraty 				version, rbuf, &xlen);
3700957b409SSimon J. Gerraty 			buf ++;
3710957b409SSimon J. Gerraty 			len --;
3720957b409SSimon J. Gerraty 		} else {
3730957b409SSimon J. Gerraty 			rbuf = buf - 5;
3740957b409SSimon J. Gerraty 		}
3750957b409SSimon J. Gerraty 	}
3760957b409SSimon J. Gerraty 
3770957b409SSimon J. Gerraty 	/*
3780957b409SSimon J. Gerraty 	 * Compute MAC.
3790957b409SSimon J. Gerraty 	 */
3800957b409SSimon J. Gerraty 	br_enc64be(tmp, cc->seq ++);
3810957b409SSimon J. Gerraty 	tmp[8] = record_type;
3820957b409SSimon J. Gerraty 	br_enc16be(tmp + 9, version);
3830957b409SSimon J. Gerraty 	br_enc16be(tmp + 11, len);
3840957b409SSimon J. Gerraty 	br_hmac_init(&hc, &cc->mac, cc->mac_len);
3850957b409SSimon J. Gerraty 	br_hmac_update(&hc, tmp, 13);
3860957b409SSimon J. Gerraty 	br_hmac_update(&hc, buf, len);
3870957b409SSimon J. Gerraty 	br_hmac_out(&hc, buf + len);
3880957b409SSimon J. Gerraty 	len += cc->mac_len;
3890957b409SSimon J. Gerraty 
3900957b409SSimon J. Gerraty 	/*
3910957b409SSimon J. Gerraty 	 * Add padding.
3920957b409SSimon J. Gerraty 	 */
3930957b409SSimon J. Gerraty 	plen = blen - (len & (blen - 1));
3940957b409SSimon J. Gerraty 	memset(buf + len, (unsigned)plen - 1, plen);
3950957b409SSimon J. Gerraty 	len += plen;
3960957b409SSimon J. Gerraty 
3970957b409SSimon J. Gerraty 	/*
3980957b409SSimon J. Gerraty 	 * If an explicit IV is used, the corresponding extra block was
3990957b409SSimon J. Gerraty 	 * already put in place earlier; we just have to account for it
4000957b409SSimon J. Gerraty 	 * here.
4010957b409SSimon J. Gerraty 	 */
4020957b409SSimon J. Gerraty 	if (cc->explicit_IV) {
4030957b409SSimon J. Gerraty 		buf -= blen;
4040957b409SSimon J. Gerraty 		len += blen;
4050957b409SSimon J. Gerraty 	}
4060957b409SSimon J. Gerraty 
4070957b409SSimon J. Gerraty 	/*
4080957b409SSimon J. Gerraty 	 * Encrypt the whole thing. If there is an explicit IV, we also
4090957b409SSimon J. Gerraty 	 * encrypt it, which is fine (encryption of a uniformly random
4100957b409SSimon J. Gerraty 	 * block is still a uniformly random block).
4110957b409SSimon J. Gerraty 	 */
4120957b409SSimon J. Gerraty 	cc->bc.vtable->run(&cc->bc.vtable, cc->iv, buf, len);
4130957b409SSimon J. Gerraty 
4140957b409SSimon J. Gerraty 	/*
4150957b409SSimon J. Gerraty 	 * Add the header and return.
4160957b409SSimon J. Gerraty 	 */
4170957b409SSimon J. Gerraty 	buf[-5] = record_type;
4180957b409SSimon J. Gerraty 	br_enc16be(buf - 4, version);
4190957b409SSimon J. Gerraty 	br_enc16be(buf - 2, len);
4200957b409SSimon J. Gerraty 	*data_len = (size_t)((buf + len) - rbuf);
4210957b409SSimon J. Gerraty 	return rbuf;
4220957b409SSimon J. Gerraty }
4230957b409SSimon J. Gerraty 
4240957b409SSimon J. Gerraty /* see bearssl_ssl.h */
4250957b409SSimon J. Gerraty const br_sslrec_out_cbc_class br_sslrec_out_cbc_vtable = {
4260957b409SSimon J. Gerraty 	{
4270957b409SSimon J. Gerraty 		sizeof(br_sslrec_out_cbc_context),
4280957b409SSimon J. Gerraty 		(void (*)(const br_sslrec_out_class *const *,
4290957b409SSimon J. Gerraty 			size_t *, size_t *))
4300957b409SSimon J. Gerraty 			&cbc_max_plaintext,
4310957b409SSimon J. Gerraty 		(unsigned char *(*)(const br_sslrec_out_class **,
4320957b409SSimon J. Gerraty 			int, unsigned, void *, size_t *))
4330957b409SSimon J. Gerraty 			&cbc_encrypt
4340957b409SSimon J. Gerraty 	},
4350957b409SSimon J. Gerraty 	(void (*)(const br_sslrec_out_cbc_class **,
4360957b409SSimon J. Gerraty 		const br_block_cbcenc_class *, const void *, size_t,
4370957b409SSimon J. Gerraty 		const br_hash_class *, const void *, size_t, size_t,
4380957b409SSimon J. Gerraty 		const void *))
4390957b409SSimon J. Gerraty 		&out_cbc_init
4400957b409SSimon J. Gerraty };
441