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 #if 0
280957b409SSimon J. Gerraty /* obsolete */
290957b409SSimon J. Gerraty
300957b409SSimon J. Gerraty /*
310957b409SSimon J. Gerraty * If BR_USE_URANDOM is not defined, then try to autodetect its presence
320957b409SSimon J. Gerraty * through compiler macros.
330957b409SSimon J. Gerraty */
340957b409SSimon J. Gerraty #ifndef BR_USE_URANDOM
350957b409SSimon J. Gerraty
360957b409SSimon J. Gerraty /*
370957b409SSimon J. Gerraty * Macro values documented on:
380957b409SSimon J. Gerraty * https://sourceforge.net/p/predef/wiki/OperatingSystems/
390957b409SSimon J. Gerraty *
400957b409SSimon J. Gerraty * Only the most common systems have been included here for now. This
410957b409SSimon J. Gerraty * should be enriched later on.
420957b409SSimon J. Gerraty */
430957b409SSimon J. Gerraty #if defined _AIX \
440957b409SSimon J. Gerraty || defined __ANDROID__ \
450957b409SSimon J. Gerraty || defined __FreeBSD__ \
460957b409SSimon J. Gerraty || defined __NetBSD__ \
470957b409SSimon J. Gerraty || defined __OpenBSD__ \
480957b409SSimon J. Gerraty || defined __DragonFly__ \
490957b409SSimon J. Gerraty || defined __linux__ \
500957b409SSimon J. Gerraty || (defined __sun && (defined __SVR4 || defined __svr4__)) \
510957b409SSimon J. Gerraty || (defined __APPLE__ && defined __MACH__)
520957b409SSimon J. Gerraty #define BR_USE_URANDOM 1
530957b409SSimon J. Gerraty #endif
540957b409SSimon J. Gerraty
550957b409SSimon J. Gerraty #endif
560957b409SSimon J. Gerraty
570957b409SSimon J. Gerraty /*
580957b409SSimon J. Gerraty * If BR_USE_WIN32_RAND is not defined, perform autodetection here.
590957b409SSimon J. Gerraty */
600957b409SSimon J. Gerraty #ifndef BR_USE_WIN32_RAND
610957b409SSimon J. Gerraty
620957b409SSimon J. Gerraty #if defined _WIN32 || defined _WIN64
630957b409SSimon J. Gerraty #define BR_USE_WIN32_RAND 1
640957b409SSimon J. Gerraty #endif
650957b409SSimon J. Gerraty
660957b409SSimon J. Gerraty #endif
670957b409SSimon J. Gerraty
680957b409SSimon J. Gerraty #if BR_USE_URANDOM
690957b409SSimon J. Gerraty #include <sys/types.h>
700957b409SSimon J. Gerraty #include <unistd.h>
710957b409SSimon J. Gerraty #include <fcntl.h>
720957b409SSimon J. Gerraty #include <errno.h>
730957b409SSimon J. Gerraty #endif
740957b409SSimon J. Gerraty
750957b409SSimon J. Gerraty #if BR_USE_WIN32_RAND
760957b409SSimon J. Gerraty #include <windows.h>
770957b409SSimon J. Gerraty #include <wincrypt.h>
780957b409SSimon J. Gerraty #pragma comment(lib, "advapi32")
790957b409SSimon J. Gerraty #endif
800957b409SSimon J. Gerraty
810957b409SSimon J. Gerraty #endif
820957b409SSimon J. Gerraty
830957b409SSimon J. Gerraty /* ==================================================================== */
840957b409SSimon J. Gerraty /*
850957b409SSimon J. Gerraty * This part of the file does the low-level record management.
860957b409SSimon J. Gerraty */
870957b409SSimon J. Gerraty
880957b409SSimon J. Gerraty /*
890957b409SSimon J. Gerraty * IMPLEMENTATION NOTES
900957b409SSimon J. Gerraty * ====================
910957b409SSimon J. Gerraty *
920957b409SSimon J. Gerraty * In this file, we designate by "input" (and the "i" letter) the "recv"
930957b409SSimon J. Gerraty * operations: incoming records from the peer, from which payload data
940957b409SSimon J. Gerraty * is obtained, and must be extracted by the application (or the SSL
950957b409SSimon J. Gerraty * handshake engine). Similarly, "output" (and the "o" letter) is for
960957b409SSimon J. Gerraty * "send": payload data injected by the application (and SSL handshake
970957b409SSimon J. Gerraty * engine), to be wrapped into records, that are then conveyed to the
980957b409SSimon J. Gerraty * peer over the transport medium.
990957b409SSimon J. Gerraty *
1000957b409SSimon J. Gerraty * The input and output buffers may be distinct or shared. When
1010957b409SSimon J. Gerraty * shared, input and output cannot occur concurrently; the caller
1020957b409SSimon J. Gerraty * must make sure that it never needs to output data while input
1030957b409SSimon J. Gerraty * data has been received. In practice, a shared buffer prevents
1040957b409SSimon J. Gerraty * pipelining of HTTP requests, or similar protocols; however, a
1050957b409SSimon J. Gerraty * shared buffer saves RAM.
1060957b409SSimon J. Gerraty *
1070957b409SSimon J. Gerraty * The input buffer is pointed to by 'ibuf' and has size 'ibuf_len';
1080957b409SSimon J. Gerraty * the output buffer is pointed to by 'obuf' and has size 'obuf_len'.
1090957b409SSimon J. Gerraty * From the size of these buffers is derived the maximum fragment
1100957b409SSimon J. Gerraty * length, which will be honoured upon sending records; regardless of
1110957b409SSimon J. Gerraty * that length, incoming records will be processed as long as they
1120957b409SSimon J. Gerraty * fit in the input buffer, and their length still complies with the
1130957b409SSimon J. Gerraty * protocol specification (maximum plaintext payload length is 16384
1140957b409SSimon J. Gerraty * bytes).
1150957b409SSimon J. Gerraty *
1160957b409SSimon J. Gerraty * Three registers are used to manage buffering in ibuf, called ixa,
1170957b409SSimon J. Gerraty * ixb and ixc. Similarly, three registers are used to manage buffering
1180957b409SSimon J. Gerraty * in obuf, called oxa, oxb and oxc.
1190957b409SSimon J. Gerraty *
1200957b409SSimon J. Gerraty *
1210957b409SSimon J. Gerraty * At any time, the engine is in one of the following modes:
1220957b409SSimon J. Gerraty * -- Failed mode: an error occurs, no I/O can happen.
1230957b409SSimon J. Gerraty * -- Input mode: the engine can either receive record bytes from the
1240957b409SSimon J. Gerraty * transport layer, or it has some buffered payload bytes to yield.
1250957b409SSimon J. Gerraty * -- Output mode: the engine can either receive payload bytes, or it
1260957b409SSimon J. Gerraty * has some record bytes to send to the transport layer.
1270957b409SSimon J. Gerraty * -- Input/Output mode: both input and output modes are active. When
1280957b409SSimon J. Gerraty * the buffer is shared, this can happen only when the buffer is empty
1290957b409SSimon J. Gerraty * (no buffered payload bytes or record bytes in either direction).
1300957b409SSimon J. Gerraty *
1310957b409SSimon J. Gerraty *
1320957b409SSimon J. Gerraty * Failed mode:
1330957b409SSimon J. Gerraty * ------------
1340957b409SSimon J. Gerraty *
1350957b409SSimon J. Gerraty * I/O failed for some reason (invalid received data, not enough room
1360957b409SSimon J. Gerraty * for the next record...). No I/O may ever occur again for this context,
1370957b409SSimon J. Gerraty * until an explicit reset is performed. This mode, and the error code,
1380957b409SSimon J. Gerraty * are also used for protocol errors, especially handshake errors.
1390957b409SSimon J. Gerraty *
1400957b409SSimon J. Gerraty *
1410957b409SSimon J. Gerraty * Input mode:
1420957b409SSimon J. Gerraty * -----------
1430957b409SSimon J. Gerraty *
1440957b409SSimon J. Gerraty * ixa index within ibuf[] for the currently read data
1450957b409SSimon J. Gerraty * ixb maximum index within ibuf[] for the currently read data
1460957b409SSimon J. Gerraty * ixc number of bytes not yet received for the current record
1470957b409SSimon J. Gerraty *
1480957b409SSimon J. Gerraty * -- When ixa == ixb, there is no available data for readers. When
1490957b409SSimon J. Gerraty * ixa != ixb, there is available data and it starts at offset ixa.
1500957b409SSimon J. Gerraty *
1510957b409SSimon J. Gerraty * -- When waiting for the next record header, ixa and ixb are equal
1520957b409SSimon J. Gerraty * and contain a value ranging from 0 to 4; ixc is equal to 5-ixa.
1530957b409SSimon J. Gerraty *
1540957b409SSimon J. Gerraty * -- When the header has been received, record data is obtained. The
1550957b409SSimon J. Gerraty * ixc field records how many bytes are still needed to reach the
1560957b409SSimon J. Gerraty * end of the current record.
1570957b409SSimon J. Gerraty *
1580957b409SSimon J. Gerraty * ** If encryption is active, then ixa and ixb are kept equal, and
1590957b409SSimon J. Gerraty * point to the end of the currently received record bytes. When
1600957b409SSimon J. Gerraty * ixc reaches 0, decryption/MAC is applied, and ixa and ixb are
1610957b409SSimon J. Gerraty * adjusted.
1620957b409SSimon J. Gerraty *
1630957b409SSimon J. Gerraty * ** If encryption is not active, then ixa and ixb are distinct
1640957b409SSimon J. Gerraty * and data can be read right away. Additional record data is
1650957b409SSimon J. Gerraty * obtained only when ixa == ixb.
1660957b409SSimon J. Gerraty *
1670957b409SSimon J. Gerraty * Note: in input mode and no encryption, records larger than the buffer
1680957b409SSimon J. Gerraty * size are allowed. When encryption is active, the complete record must
1690957b409SSimon J. Gerraty * fit within the buffer, since it cannot be decrypted/MACed until it
1700957b409SSimon J. Gerraty * has been completely received.
1710957b409SSimon J. Gerraty *
1720957b409SSimon J. Gerraty * -- When receiving the next record header, 'version_in' contains the
1730957b409SSimon J. Gerraty * expected input version (0 if not expecting a specific version); on
1740957b409SSimon J. Gerraty * mismatch, the mode switches to 'failed'.
1750957b409SSimon J. Gerraty *
1760957b409SSimon J. Gerraty * -- When the header has been received, 'version_in' contains the received
1770957b409SSimon J. Gerraty * version. It is up to the caller to check and adjust the 'version_in' field
1780957b409SSimon J. Gerraty * to implement the required semantics.
1790957b409SSimon J. Gerraty *
1800957b409SSimon J. Gerraty * -- The 'record_type_in' field is updated with the incoming record type
1810957b409SSimon J. Gerraty * when the next record header has been received.
1820957b409SSimon J. Gerraty *
1830957b409SSimon J. Gerraty *
1840957b409SSimon J. Gerraty * Output mode:
1850957b409SSimon J. Gerraty * ------------
1860957b409SSimon J. Gerraty *
1870957b409SSimon J. Gerraty * oxa index within obuf[] for the currently accumulated data
1880957b409SSimon J. Gerraty * oxb maximum index within obuf[] for record data
1890957b409SSimon J. Gerraty * oxc pointer for start of record data, and for record sending
1900957b409SSimon J. Gerraty *
1910957b409SSimon J. Gerraty * -- When oxa != oxb, more data can be accumulated into the current
1920957b409SSimon J. Gerraty * record; when oxa == oxb, a closed record is being sent.
1930957b409SSimon J. Gerraty *
1940957b409SSimon J. Gerraty * -- When accumulating data, oxc points to the start of the data.
1950957b409SSimon J. Gerraty *
1960957b409SSimon J. Gerraty * -- During record sending, oxa (and oxb) point to the next record byte
1970957b409SSimon J. Gerraty * to send, and oxc indicates the end of the current record.
1980957b409SSimon J. Gerraty *
1990957b409SSimon J. Gerraty * Note: sent records must fit within the buffer, since the header is
2000957b409SSimon J. Gerraty * adjusted only when the complete record has been assembled.
2010957b409SSimon J. Gerraty *
2020957b409SSimon J. Gerraty * -- The 'version_out' and 'record_type_out' fields are used to build the
2030957b409SSimon J. Gerraty * record header when the mode is switched to 'sending'.
2040957b409SSimon J. Gerraty *
2050957b409SSimon J. Gerraty *
2060957b409SSimon J. Gerraty * Modes:
2070957b409SSimon J. Gerraty * ------
2080957b409SSimon J. Gerraty *
2090957b409SSimon J. Gerraty * The state register iomode contains one of the following values:
2100957b409SSimon J. Gerraty *
2110957b409SSimon J. Gerraty * BR_IO_FAILED I/O failed
2120957b409SSimon J. Gerraty * BR_IO_IN input mode
2130957b409SSimon J. Gerraty * BR_IO_OUT output mode
2140957b409SSimon J. Gerraty * BR_IO_INOUT input/output mode
2150957b409SSimon J. Gerraty *
2160957b409SSimon J. Gerraty * Whether encryption is active on incoming records is indicated by the
2170957b409SSimon J. Gerraty * incrypt flag. For outgoing records, there is no such flag; "encryption"
2180957b409SSimon J. Gerraty * is always considered active, but initially uses functions that do not
2190957b409SSimon J. Gerraty * encrypt anything. The 'incrypt' flag is needed because when there is
2200957b409SSimon J. Gerraty * no active encryption, records larger than the I/O buffer are accepted.
2210957b409SSimon J. Gerraty *
2220957b409SSimon J. Gerraty * Note: we do not support no-encryption modes (MAC only).
2230957b409SSimon J. Gerraty *
2240957b409SSimon J. Gerraty * TODO: implement GCM support
2250957b409SSimon J. Gerraty *
2260957b409SSimon J. Gerraty *
2270957b409SSimon J. Gerraty * Misc:
2280957b409SSimon J. Gerraty * -----
2290957b409SSimon J. Gerraty *
2300957b409SSimon J. Gerraty * 'max_frag_len' is the maximum plaintext size for an outgoing record.
2310957b409SSimon J. Gerraty * By default, it is set to the maximum value that fits in the provided
2320957b409SSimon J. Gerraty * buffers, in the following list: 512, 1024, 2048, 4096, 16384. The
2330957b409SSimon J. Gerraty * caller may change it if needed, but the new value MUST still fit in
2340957b409SSimon J. Gerraty * the buffers, and it MUST be one of the list above for compatibility
2350957b409SSimon J. Gerraty * with the Maximum Fragment Length extension.
2360957b409SSimon J. Gerraty *
2370957b409SSimon J. Gerraty * For incoming records, only the total buffer length and current
2380957b409SSimon J. Gerraty * encryption mode impact the maximum length for incoming records. The
2390957b409SSimon J. Gerraty * 'max_frag_len' value is still adjusted so that records up to that
2400957b409SSimon J. Gerraty * length can be both received and sent.
2410957b409SSimon J. Gerraty *
2420957b409SSimon J. Gerraty *
2430957b409SSimon J. Gerraty * Offsets and lengths:
2440957b409SSimon J. Gerraty * --------------------
2450957b409SSimon J. Gerraty *
2460957b409SSimon J. Gerraty * When sending fragments with TLS-1.1+, the maximum overhead is:
2470957b409SSimon J. Gerraty * 5 bytes for the record header
2480957b409SSimon J. Gerraty * 16 bytes for the explicit IV
2490957b409SSimon J. Gerraty * 48 bytes for the MAC (HMAC/SHA-384)
2500957b409SSimon J. Gerraty * 16 bytes for the padding (AES)
2510957b409SSimon J. Gerraty * so a total of 85 extra bytes. Note that we support block cipher sizes
2520957b409SSimon J. Gerraty * up to 16 bytes (AES) and HMAC output sizes up to 48 bytes (SHA-384).
2530957b409SSimon J. Gerraty *
2540957b409SSimon J. Gerraty * With TLS-1.0 and CBC mode, we apply a 1/n-1 split, for a maximum
2550957b409SSimon J. Gerraty * overhead of:
2560957b409SSimon J. Gerraty * 5 bytes for the first record header
2570957b409SSimon J. Gerraty * 32 bytes for the first record payload (AES-CBC + HMAC/SHA-1)
2580957b409SSimon J. Gerraty * 5 bytes for the second record header
2590957b409SSimon J. Gerraty * 20 bytes for the MAC (HMAC/SHA-1)
2600957b409SSimon J. Gerraty * 16 bytes for the padding (AES)
2610957b409SSimon J. Gerraty * -1 byte to account for the payload byte in the first record
2620957b409SSimon J. Gerraty * so a total of 77 extra bytes at most, less than the 85 bytes above.
2630957b409SSimon J. Gerraty * Note that with TLS-1.0, the MAC is HMAC with either MD5 or SHA-1, but
2640957b409SSimon J. Gerraty * no other hash function.
2650957b409SSimon J. Gerraty *
2660957b409SSimon J. Gerraty * The implementation does not try to send larger records when the current
2670957b409SSimon J. Gerraty * encryption mode has less overhead.
2680957b409SSimon J. Gerraty *
2690957b409SSimon J. Gerraty * Maximum input record overhead is:
2700957b409SSimon J. Gerraty * 5 bytes for the record header
2710957b409SSimon J. Gerraty * 16 bytes for the explicit IV (TLS-1.1+)
2720957b409SSimon J. Gerraty * 48 bytes for the MAC (HMAC/SHA-384)
2730957b409SSimon J. Gerraty * 256 bytes for the padding
2740957b409SSimon J. Gerraty * so a total of 325 extra bytes.
2750957b409SSimon J. Gerraty *
2760957b409SSimon J. Gerraty * When receiving the next record header, it is written into the buffer
2770957b409SSimon J. Gerraty * bytes 0 to 4 (inclusive). Record data is always written into buf[]
2780957b409SSimon J. Gerraty * starting at offset 5. When encryption is active, the plaintext data
2790957b409SSimon J. Gerraty * may start at a larger offset (e.g. because of an explicit IV).
2800957b409SSimon J. Gerraty */
2810957b409SSimon J. Gerraty
2820957b409SSimon J. Gerraty #define MAX_OUT_OVERHEAD 85
2830957b409SSimon J. Gerraty #define MAX_IN_OVERHEAD 325
2840957b409SSimon J. Gerraty
2850957b409SSimon J. Gerraty /* see inner.h */
2860957b409SSimon J. Gerraty void
br_ssl_engine_fail(br_ssl_engine_context * rc,int err)2870957b409SSimon J. Gerraty br_ssl_engine_fail(br_ssl_engine_context *rc, int err)
2880957b409SSimon J. Gerraty {
2890957b409SSimon J. Gerraty if (rc->iomode != BR_IO_FAILED) {
2900957b409SSimon J. Gerraty rc->iomode = BR_IO_FAILED;
2910957b409SSimon J. Gerraty rc->err = err;
2920957b409SSimon J. Gerraty }
2930957b409SSimon J. Gerraty }
2940957b409SSimon J. Gerraty
2950957b409SSimon J. Gerraty /*
2960957b409SSimon J. Gerraty * Adjust registers for a new incoming record.
2970957b409SSimon J. Gerraty */
2980957b409SSimon J. Gerraty static void
make_ready_in(br_ssl_engine_context * rc)2990957b409SSimon J. Gerraty make_ready_in(br_ssl_engine_context *rc)
3000957b409SSimon J. Gerraty {
3010957b409SSimon J. Gerraty rc->ixa = rc->ixb = 0;
3020957b409SSimon J. Gerraty rc->ixc = 5;
3030957b409SSimon J. Gerraty if (rc->iomode == BR_IO_IN) {
3040957b409SSimon J. Gerraty rc->iomode = BR_IO_INOUT;
3050957b409SSimon J. Gerraty }
3060957b409SSimon J. Gerraty }
3070957b409SSimon J. Gerraty
3080957b409SSimon J. Gerraty /*
3090957b409SSimon J. Gerraty * Adjust registers for a new outgoing record.
3100957b409SSimon J. Gerraty */
3110957b409SSimon J. Gerraty static void
make_ready_out(br_ssl_engine_context * rc)3120957b409SSimon J. Gerraty make_ready_out(br_ssl_engine_context *rc)
3130957b409SSimon J. Gerraty {
3140957b409SSimon J. Gerraty size_t a, b;
3150957b409SSimon J. Gerraty
3160957b409SSimon J. Gerraty a = 5;
3170957b409SSimon J. Gerraty b = rc->obuf_len - a;
3180957b409SSimon J. Gerraty rc->out.vtable->max_plaintext(&rc->out.vtable, &a, &b);
3190957b409SSimon J. Gerraty if ((b - a) > rc->max_frag_len) {
3200957b409SSimon J. Gerraty b = a + rc->max_frag_len;
3210957b409SSimon J. Gerraty }
3220957b409SSimon J. Gerraty rc->oxa = a;
3230957b409SSimon J. Gerraty rc->oxb = b;
3240957b409SSimon J. Gerraty rc->oxc = a;
3250957b409SSimon J. Gerraty if (rc->iomode == BR_IO_OUT) {
3260957b409SSimon J. Gerraty rc->iomode = BR_IO_INOUT;
3270957b409SSimon J. Gerraty }
3280957b409SSimon J. Gerraty }
3290957b409SSimon J. Gerraty
3300957b409SSimon J. Gerraty /* see inner.h */
3310957b409SSimon J. Gerraty void
br_ssl_engine_new_max_frag_len(br_ssl_engine_context * rc,unsigned max_frag_len)3320957b409SSimon J. Gerraty br_ssl_engine_new_max_frag_len(br_ssl_engine_context *rc, unsigned max_frag_len)
3330957b409SSimon J. Gerraty {
3340957b409SSimon J. Gerraty size_t nxb;
3350957b409SSimon J. Gerraty
3360957b409SSimon J. Gerraty rc->max_frag_len = max_frag_len;
3370957b409SSimon J. Gerraty nxb = rc->oxc + max_frag_len;
3380957b409SSimon J. Gerraty if (rc->oxa < rc->oxb && rc->oxb > nxb && rc->oxa < nxb) {
3390957b409SSimon J. Gerraty rc->oxb = nxb;
3400957b409SSimon J. Gerraty }
3410957b409SSimon J. Gerraty }
3420957b409SSimon J. Gerraty
3430957b409SSimon J. Gerraty /* see bearssl_ssl.h */
3440957b409SSimon J. Gerraty void
br_ssl_engine_set_buffer(br_ssl_engine_context * rc,void * buf,size_t buf_len,int bidi)3450957b409SSimon J. Gerraty br_ssl_engine_set_buffer(br_ssl_engine_context *rc,
3460957b409SSimon J. Gerraty void *buf, size_t buf_len, int bidi)
3470957b409SSimon J. Gerraty {
3480957b409SSimon J. Gerraty if (buf == NULL) {
3490957b409SSimon J. Gerraty br_ssl_engine_set_buffers_bidi(rc, NULL, 0, NULL, 0);
3500957b409SSimon J. Gerraty } else {
3510957b409SSimon J. Gerraty /*
3520957b409SSimon J. Gerraty * In bidirectional mode, we want to maximise input
3530957b409SSimon J. Gerraty * buffer size, since we support arbitrary fragmentation
3540957b409SSimon J. Gerraty * when sending, but the peer will not necessarily
3550957b409SSimon J. Gerraty * comply to any low fragment length (in particular if
3560957b409SSimon J. Gerraty * we are the server, because the maximum fragment
3570957b409SSimon J. Gerraty * length extension is under client control).
3580957b409SSimon J. Gerraty *
3590957b409SSimon J. Gerraty * We keep a minimum size of 512 bytes for the plaintext
3600957b409SSimon J. Gerraty * of our outgoing records.
3610957b409SSimon J. Gerraty *
3620957b409SSimon J. Gerraty * br_ssl_engine_set_buffers_bidi() will compute the maximum
3630957b409SSimon J. Gerraty * fragment length for outgoing records by using the minimum
3640957b409SSimon J. Gerraty * of allocated spaces for both input and output records,
3650957b409SSimon J. Gerraty * rounded down to a standard length.
3660957b409SSimon J. Gerraty */
3670957b409SSimon J. Gerraty if (bidi) {
3680957b409SSimon J. Gerraty size_t w;
3690957b409SSimon J. Gerraty
3700957b409SSimon J. Gerraty if (buf_len < (512 + MAX_IN_OVERHEAD
3710957b409SSimon J. Gerraty + 512 + MAX_OUT_OVERHEAD))
3720957b409SSimon J. Gerraty {
3730957b409SSimon J. Gerraty rc->iomode = BR_IO_FAILED;
3740957b409SSimon J. Gerraty rc->err = BR_ERR_BAD_PARAM;
3750957b409SSimon J. Gerraty return;
3760957b409SSimon J. Gerraty } else if (buf_len < (16384 + MAX_IN_OVERHEAD
3770957b409SSimon J. Gerraty + 512 + MAX_OUT_OVERHEAD))
3780957b409SSimon J. Gerraty {
3790957b409SSimon J. Gerraty w = 512 + MAX_OUT_OVERHEAD;
3800957b409SSimon J. Gerraty } else {
3810957b409SSimon J. Gerraty w = buf_len - (16384 + MAX_IN_OVERHEAD);
3820957b409SSimon J. Gerraty }
3830957b409SSimon J. Gerraty br_ssl_engine_set_buffers_bidi(rc,
3840957b409SSimon J. Gerraty buf, buf_len - w,
3850957b409SSimon J. Gerraty (unsigned char *)buf + w, w);
3860957b409SSimon J. Gerraty } else {
3870957b409SSimon J. Gerraty br_ssl_engine_set_buffers_bidi(rc,
3880957b409SSimon J. Gerraty buf, buf_len, NULL, 0);
3890957b409SSimon J. Gerraty }
3900957b409SSimon J. Gerraty }
3910957b409SSimon J. Gerraty }
3920957b409SSimon J. Gerraty
3930957b409SSimon J. Gerraty /* see bearssl_ssl.h */
3940957b409SSimon J. Gerraty void
br_ssl_engine_set_buffers_bidi(br_ssl_engine_context * rc,void * ibuf,size_t ibuf_len,void * obuf,size_t obuf_len)3950957b409SSimon J. Gerraty br_ssl_engine_set_buffers_bidi(br_ssl_engine_context *rc,
3960957b409SSimon J. Gerraty void *ibuf, size_t ibuf_len, void *obuf, size_t obuf_len)
3970957b409SSimon J. Gerraty {
3980957b409SSimon J. Gerraty rc->iomode = BR_IO_INOUT;
3990957b409SSimon J. Gerraty rc->incrypt = 0;
4000957b409SSimon J. Gerraty rc->err = BR_ERR_OK;
4010957b409SSimon J. Gerraty rc->version_in = 0;
4020957b409SSimon J. Gerraty rc->record_type_in = 0;
4030957b409SSimon J. Gerraty rc->version_out = 0;
4040957b409SSimon J. Gerraty rc->record_type_out = 0;
4050957b409SSimon J. Gerraty if (ibuf == NULL) {
4060957b409SSimon J. Gerraty if (rc->ibuf == NULL) {
4070957b409SSimon J. Gerraty br_ssl_engine_fail(rc, BR_ERR_BAD_PARAM);
4080957b409SSimon J. Gerraty }
4090957b409SSimon J. Gerraty } else {
4100957b409SSimon J. Gerraty unsigned u;
4110957b409SSimon J. Gerraty
4120957b409SSimon J. Gerraty rc->ibuf = ibuf;
4130957b409SSimon J. Gerraty rc->ibuf_len = ibuf_len;
4140957b409SSimon J. Gerraty if (obuf == NULL) {
4150957b409SSimon J. Gerraty obuf = ibuf;
4160957b409SSimon J. Gerraty obuf_len = ibuf_len;
4170957b409SSimon J. Gerraty }
4180957b409SSimon J. Gerraty rc->obuf = obuf;
4190957b409SSimon J. Gerraty rc->obuf_len = obuf_len;
4200957b409SSimon J. Gerraty
4210957b409SSimon J. Gerraty /*
4220957b409SSimon J. Gerraty * Compute the maximum fragment length, that fits for
4230957b409SSimon J. Gerraty * both incoming and outgoing records. This length will
4240957b409SSimon J. Gerraty * be used in fragment length negotiation, so we must
4250957b409SSimon J. Gerraty * honour it both ways. Regardless, larger incoming
4260957b409SSimon J. Gerraty * records will be accepted, as long as they fit in the
4270957b409SSimon J. Gerraty * actual buffer size.
4280957b409SSimon J. Gerraty */
4290957b409SSimon J. Gerraty for (u = 14; u >= 9; u --) {
4300957b409SSimon J. Gerraty size_t flen;
4310957b409SSimon J. Gerraty
4320957b409SSimon J. Gerraty flen = (size_t)1 << u;
4330957b409SSimon J. Gerraty if (obuf_len >= flen + MAX_OUT_OVERHEAD
4340957b409SSimon J. Gerraty && ibuf_len >= flen + MAX_IN_OVERHEAD)
4350957b409SSimon J. Gerraty {
4360957b409SSimon J. Gerraty break;
4370957b409SSimon J. Gerraty }
4380957b409SSimon J. Gerraty }
4390957b409SSimon J. Gerraty if (u == 8) {
4400957b409SSimon J. Gerraty br_ssl_engine_fail(rc, BR_ERR_BAD_PARAM);
4410957b409SSimon J. Gerraty return;
4420957b409SSimon J. Gerraty } else if (u == 13) {
4430957b409SSimon J. Gerraty u = 12;
4440957b409SSimon J. Gerraty }
4450957b409SSimon J. Gerraty rc->max_frag_len = (size_t)1 << u;
4460957b409SSimon J. Gerraty rc->log_max_frag_len = u;
4470957b409SSimon J. Gerraty rc->peer_log_max_frag_len = 0;
4480957b409SSimon J. Gerraty }
4490957b409SSimon J. Gerraty rc->out.vtable = &br_sslrec_out_clear_vtable;
4500957b409SSimon J. Gerraty make_ready_in(rc);
4510957b409SSimon J. Gerraty make_ready_out(rc);
4520957b409SSimon J. Gerraty }
4530957b409SSimon J. Gerraty
4540957b409SSimon J. Gerraty /*
4550957b409SSimon J. Gerraty * Clear buffers in both directions.
4560957b409SSimon J. Gerraty */
4570957b409SSimon J. Gerraty static void
engine_clearbuf(br_ssl_engine_context * rc)4580957b409SSimon J. Gerraty engine_clearbuf(br_ssl_engine_context *rc)
4590957b409SSimon J. Gerraty {
4600957b409SSimon J. Gerraty make_ready_in(rc);
4610957b409SSimon J. Gerraty make_ready_out(rc);
4620957b409SSimon J. Gerraty }
4630957b409SSimon J. Gerraty
4640957b409SSimon J. Gerraty /*
4650957b409SSimon J. Gerraty * Make sure the internal PRNG is initialised (but not necessarily
4660957b409SSimon J. Gerraty * seeded properly yet).
4670957b409SSimon J. Gerraty */
4680957b409SSimon J. Gerraty static int
rng_init(br_ssl_engine_context * cc)4690957b409SSimon J. Gerraty rng_init(br_ssl_engine_context *cc)
4700957b409SSimon J. Gerraty {
4710957b409SSimon J. Gerraty const br_hash_class *h;
4720957b409SSimon J. Gerraty
4730957b409SSimon J. Gerraty if (cc->rng_init_done != 0) {
4740957b409SSimon J. Gerraty return 1;
4750957b409SSimon J. Gerraty }
4760957b409SSimon J. Gerraty
4770957b409SSimon J. Gerraty /*
4780957b409SSimon J. Gerraty * If using TLS-1.2, then SHA-256 or SHA-384 must be present (or
4790957b409SSimon J. Gerraty * both); we prefer SHA-256 which is faster for 32-bit systems.
4800957b409SSimon J. Gerraty *
4810957b409SSimon J. Gerraty * If using TLS-1.0 or 1.1 then SHA-1 must be present.
4820957b409SSimon J. Gerraty *
4830957b409SSimon J. Gerraty * Though HMAC_DRBG/SHA-1 is, as far as we know, as safe as
4840957b409SSimon J. Gerraty * these things can be, we still prefer the SHA-2 functions over
4850957b409SSimon J. Gerraty * SHA-1, if only for public relations (known theoretical
4860957b409SSimon J. Gerraty * weaknesses of SHA-1 with regards to collisions are mostly
4870957b409SSimon J. Gerraty * irrelevant here, but they still make people nervous).
4880957b409SSimon J. Gerraty */
4890957b409SSimon J. Gerraty h = br_multihash_getimpl(&cc->mhash, br_sha256_ID);
4900957b409SSimon J. Gerraty if (!h) {
4910957b409SSimon J. Gerraty h = br_multihash_getimpl(&cc->mhash, br_sha384_ID);
4920957b409SSimon J. Gerraty if (!h) {
4930957b409SSimon J. Gerraty h = br_multihash_getimpl(&cc->mhash,
4940957b409SSimon J. Gerraty br_sha1_ID);
4950957b409SSimon J. Gerraty if (!h) {
4960957b409SSimon J. Gerraty br_ssl_engine_fail(cc, BR_ERR_BAD_STATE);
4970957b409SSimon J. Gerraty return 0;
4980957b409SSimon J. Gerraty }
4990957b409SSimon J. Gerraty }
5000957b409SSimon J. Gerraty }
5010957b409SSimon J. Gerraty br_hmac_drbg_init(&cc->rng, h, NULL, 0);
5020957b409SSimon J. Gerraty cc->rng_init_done = 1;
5030957b409SSimon J. Gerraty return 1;
5040957b409SSimon J. Gerraty }
5050957b409SSimon J. Gerraty
5060957b409SSimon J. Gerraty /* see inner.h */
5070957b409SSimon J. Gerraty int
br_ssl_engine_init_rand(br_ssl_engine_context * cc)5080957b409SSimon J. Gerraty br_ssl_engine_init_rand(br_ssl_engine_context *cc)
5090957b409SSimon J. Gerraty {
5100957b409SSimon J. Gerraty if (!rng_init(cc)) {
5110957b409SSimon J. Gerraty return 0;
5120957b409SSimon J. Gerraty }
5130957b409SSimon J. Gerraty
5140957b409SSimon J. Gerraty /*
5150957b409SSimon J. Gerraty * We always try OS/hardware seeding once. If it works, then
5160957b409SSimon J. Gerraty * we assume proper seeding. If not, then external entropy must
5170957b409SSimon J. Gerraty * have been injected; otherwise, we report an error.
5180957b409SSimon J. Gerraty */
5190957b409SSimon J. Gerraty if (!cc->rng_os_rand_done) {
5200957b409SSimon J. Gerraty br_prng_seeder sd;
5210957b409SSimon J. Gerraty
5220957b409SSimon J. Gerraty sd = br_prng_seeder_system(NULL);
5230957b409SSimon J. Gerraty if (sd != 0 && sd(&cc->rng.vtable)) {
5240957b409SSimon J. Gerraty cc->rng_init_done = 2;
5250957b409SSimon J. Gerraty }
5260957b409SSimon J. Gerraty cc->rng_os_rand_done = 1;
5270957b409SSimon J. Gerraty }
5280957b409SSimon J. Gerraty if (cc->rng_init_done < 2) {
5290957b409SSimon J. Gerraty br_ssl_engine_fail(cc, BR_ERR_NO_RANDOM);
5300957b409SSimon J. Gerraty return 0;
5310957b409SSimon J. Gerraty }
5320957b409SSimon J. Gerraty return 1;
5330957b409SSimon J. Gerraty }
5340957b409SSimon J. Gerraty
5350957b409SSimon J. Gerraty /* see bearssl_ssl.h */
5360957b409SSimon J. Gerraty void
br_ssl_engine_inject_entropy(br_ssl_engine_context * cc,const void * data,size_t len)5370957b409SSimon J. Gerraty br_ssl_engine_inject_entropy(br_ssl_engine_context *cc,
5380957b409SSimon J. Gerraty const void *data, size_t len)
5390957b409SSimon J. Gerraty {
5400957b409SSimon J. Gerraty /*
5410957b409SSimon J. Gerraty * Externally provided entropy is assumed to be "good enough"
5420957b409SSimon J. Gerraty * (we cannot really test its quality) so if the RNG structure
5430957b409SSimon J. Gerraty * could be initialised at all, then we marked the RNG as
5440957b409SSimon J. Gerraty * "properly seeded".
5450957b409SSimon J. Gerraty */
5460957b409SSimon J. Gerraty if (!rng_init(cc)) {
5470957b409SSimon J. Gerraty return;
5480957b409SSimon J. Gerraty }
5490957b409SSimon J. Gerraty br_hmac_drbg_update(&cc->rng, data, len);
5500957b409SSimon J. Gerraty cc->rng_init_done = 2;
5510957b409SSimon J. Gerraty }
5520957b409SSimon J. Gerraty
5530957b409SSimon J. Gerraty /*
5540957b409SSimon J. Gerraty * We define a few internal functions that implement the low-level engine
5550957b409SSimon J. Gerraty * API for I/O; the external API (br_ssl_engine_sendapp_buf() and similar
5560957b409SSimon J. Gerraty * functions) is built upon these function, with special processing for
5570957b409SSimon J. Gerraty * records which are not of type "application data".
5580957b409SSimon J. Gerraty *
5590957b409SSimon J. Gerraty * recvrec_buf, recvrec_ack receives bytes from transport medium
5600957b409SSimon J. Gerraty * sendrec_buf, sendrec_ack send bytes to transport medium
5610957b409SSimon J. Gerraty * recvpld_buf, recvpld_ack receives payload data from engine
5620957b409SSimon J. Gerraty * sendpld_buf, sendpld_ack send payload data to engine
5630957b409SSimon J. Gerraty */
5640957b409SSimon J. Gerraty
5650957b409SSimon J. Gerraty static unsigned char *
recvrec_buf(const br_ssl_engine_context * rc,size_t * len)5660957b409SSimon J. Gerraty recvrec_buf(const br_ssl_engine_context *rc, size_t *len)
5670957b409SSimon J. Gerraty {
5680957b409SSimon J. Gerraty if (rc->shutdown_recv) {
5690957b409SSimon J. Gerraty *len = 0;
5700957b409SSimon J. Gerraty return NULL;
5710957b409SSimon J. Gerraty }
5720957b409SSimon J. Gerraty
5730957b409SSimon J. Gerraty /*
5740957b409SSimon J. Gerraty * Bytes from the transport can be injected only if the mode is
5750957b409SSimon J. Gerraty * compatible (in or in/out), and ixa == ixb; ixc then contains
5760957b409SSimon J. Gerraty * the number of bytes that are still expected (but it may
5770957b409SSimon J. Gerraty * exceed our buffer size).
5780957b409SSimon J. Gerraty *
5790957b409SSimon J. Gerraty * We cannot get "stuck" here (buffer is full, but still more
5800957b409SSimon J. Gerraty * data is expected) because oversized records are detected when
5810957b409SSimon J. Gerraty * their header is processed.
5820957b409SSimon J. Gerraty */
5830957b409SSimon J. Gerraty switch (rc->iomode) {
5840957b409SSimon J. Gerraty case BR_IO_IN:
5850957b409SSimon J. Gerraty case BR_IO_INOUT:
5860957b409SSimon J. Gerraty if (rc->ixa == rc->ixb) {
5870957b409SSimon J. Gerraty size_t z;
5880957b409SSimon J. Gerraty
5890957b409SSimon J. Gerraty z = rc->ixc;
5900957b409SSimon J. Gerraty if (z > rc->ibuf_len - rc->ixa) {
5910957b409SSimon J. Gerraty z = rc->ibuf_len - rc->ixa;
5920957b409SSimon J. Gerraty }
5930957b409SSimon J. Gerraty *len = z;
5940957b409SSimon J. Gerraty return rc->ibuf + rc->ixa;
5950957b409SSimon J. Gerraty }
5960957b409SSimon J. Gerraty break;
5970957b409SSimon J. Gerraty }
5980957b409SSimon J. Gerraty *len = 0;
5990957b409SSimon J. Gerraty return NULL;
6000957b409SSimon J. Gerraty }
6010957b409SSimon J. Gerraty
6020957b409SSimon J. Gerraty static void
recvrec_ack(br_ssl_engine_context * rc,size_t len)6030957b409SSimon J. Gerraty recvrec_ack(br_ssl_engine_context *rc, size_t len)
6040957b409SSimon J. Gerraty {
6050957b409SSimon J. Gerraty unsigned char *pbuf;
6060957b409SSimon J. Gerraty size_t pbuf_len;
6070957b409SSimon J. Gerraty
6080957b409SSimon J. Gerraty /*
6090957b409SSimon J. Gerraty * Adjust state if necessary (for a shared input/output buffer):
6100957b409SSimon J. Gerraty * we got some incoming bytes, so we cannot (temporarily) handle
6110957b409SSimon J. Gerraty * outgoing data.
6120957b409SSimon J. Gerraty */
6130957b409SSimon J. Gerraty if (rc->iomode == BR_IO_INOUT && rc->ibuf == rc->obuf) {
6140957b409SSimon J. Gerraty rc->iomode = BR_IO_IN;
6150957b409SSimon J. Gerraty }
6160957b409SSimon J. Gerraty
6170957b409SSimon J. Gerraty /*
6180957b409SSimon J. Gerraty * Adjust data pointers.
6190957b409SSimon J. Gerraty */
6200957b409SSimon J. Gerraty rc->ixb = (rc->ixa += len);
6210957b409SSimon J. Gerraty rc->ixc -= len;
6220957b409SSimon J. Gerraty
6230957b409SSimon J. Gerraty /*
6240957b409SSimon J. Gerraty * If we are receiving a header and did not fully obtained it
6250957b409SSimon J. Gerraty * yet, then just wait for the next bytes.
6260957b409SSimon J. Gerraty */
6270957b409SSimon J. Gerraty if (rc->ixa < 5) {
6280957b409SSimon J. Gerraty return;
6290957b409SSimon J. Gerraty }
6300957b409SSimon J. Gerraty
6310957b409SSimon J. Gerraty /*
6320957b409SSimon J. Gerraty * If we just obtained a full header, process it.
6330957b409SSimon J. Gerraty */
6340957b409SSimon J. Gerraty if (rc->ixa == 5) {
6350957b409SSimon J. Gerraty unsigned version;
6360957b409SSimon J. Gerraty unsigned rlen;
6370957b409SSimon J. Gerraty
6380957b409SSimon J. Gerraty /*
6390957b409SSimon J. Gerraty * Get record type and version. We support only versions
6400957b409SSimon J. Gerraty * 3.x (if the version major number does not match, then
6410957b409SSimon J. Gerraty * we suppose that the record format is too alien for us
6420957b409SSimon J. Gerraty * to process it).
6430957b409SSimon J. Gerraty *
6440957b409SSimon J. Gerraty * Note: right now, we reject clients that try to send
6450957b409SSimon J. Gerraty * a ClientHello in a format compatible with SSL-2.0. It
6460957b409SSimon J. Gerraty * is unclear whether this will ever be supported; and
6470957b409SSimon J. Gerraty * if we want to support it, then this might be done in
6480957b409SSimon J. Gerraty * in the server-specific code, not here.
6490957b409SSimon J. Gerraty */
6500957b409SSimon J. Gerraty rc->record_type_in = rc->ibuf[0];
6510957b409SSimon J. Gerraty version = br_dec16be(rc->ibuf + 1);
6520957b409SSimon J. Gerraty if ((version >> 8) != 3) {
6530957b409SSimon J. Gerraty br_ssl_engine_fail(rc, BR_ERR_UNSUPPORTED_VERSION);
6540957b409SSimon J. Gerraty return;
6550957b409SSimon J. Gerraty }
6560957b409SSimon J. Gerraty
6570957b409SSimon J. Gerraty /*
6580957b409SSimon J. Gerraty * We ensure that successive records have the same
6590957b409SSimon J. Gerraty * version. The handshake code must check and adjust the
6600957b409SSimon J. Gerraty * variables when necessary to accommodate the protocol
6610957b409SSimon J. Gerraty * negotiation details.
6620957b409SSimon J. Gerraty */
6630957b409SSimon J. Gerraty if (rc->version_in != 0 && rc->version_in != version) {
6640957b409SSimon J. Gerraty br_ssl_engine_fail(rc, BR_ERR_BAD_VERSION);
6650957b409SSimon J. Gerraty return;
6660957b409SSimon J. Gerraty }
6670957b409SSimon J. Gerraty rc->version_in = version;
6680957b409SSimon J. Gerraty
6690957b409SSimon J. Gerraty /*
6700957b409SSimon J. Gerraty * Decode record length. We must check that the length
6710957b409SSimon J. Gerraty * is valid (relatively to the current encryption mode)
6720957b409SSimon J. Gerraty * and also (if encryption is active) that the record
6730957b409SSimon J. Gerraty * will fit in our buffer.
6740957b409SSimon J. Gerraty *
6750957b409SSimon J. Gerraty * When no encryption is active, we can process records
6760957b409SSimon J. Gerraty * by chunks, and thus accept any record up to the
6770957b409SSimon J. Gerraty * maximum allowed plaintext length (16384 bytes).
6780957b409SSimon J. Gerraty */
6790957b409SSimon J. Gerraty rlen = br_dec16be(rc->ibuf + 3);
6800957b409SSimon J. Gerraty if (rc->incrypt) {
6810957b409SSimon J. Gerraty if (!rc->in.vtable->check_length(
6820957b409SSimon J. Gerraty &rc->in.vtable, rlen))
6830957b409SSimon J. Gerraty {
6840957b409SSimon J. Gerraty br_ssl_engine_fail(rc, BR_ERR_BAD_LENGTH);
6850957b409SSimon J. Gerraty return;
6860957b409SSimon J. Gerraty }
6870957b409SSimon J. Gerraty if (rlen > (rc->ibuf_len - 5)) {
6880957b409SSimon J. Gerraty br_ssl_engine_fail(rc, BR_ERR_TOO_LARGE);
6890957b409SSimon J. Gerraty return;
6900957b409SSimon J. Gerraty }
6910957b409SSimon J. Gerraty } else {
6920957b409SSimon J. Gerraty if (rlen > 16384) {
6930957b409SSimon J. Gerraty br_ssl_engine_fail(rc, BR_ERR_BAD_LENGTH);
6940957b409SSimon J. Gerraty return;
6950957b409SSimon J. Gerraty }
6960957b409SSimon J. Gerraty }
6970957b409SSimon J. Gerraty
6980957b409SSimon J. Gerraty /*
6990957b409SSimon J. Gerraty * If the record is completely empty then we must switch
7000957b409SSimon J. Gerraty * to a new record. Note that, in that case, we
7010957b409SSimon J. Gerraty * completely ignore the record type, which is fitting
7020957b409SSimon J. Gerraty * since we received no actual data of that type.
7030957b409SSimon J. Gerraty *
7040957b409SSimon J. Gerraty * A completely empty record is technically allowed as
7050957b409SSimon J. Gerraty * long as encryption/MAC is not active, i.e. before
7060957b409SSimon J. Gerraty * completion of the first handshake. It it still weird;
7070957b409SSimon J. Gerraty * it might conceptually be useful as a heartbeat or
7080957b409SSimon J. Gerraty * keep-alive mechanism while some lengthy operation is
7090957b409SSimon J. Gerraty * going on, e.g. interaction with a human user.
7100957b409SSimon J. Gerraty */
7110957b409SSimon J. Gerraty if (rlen == 0) {
7120957b409SSimon J. Gerraty make_ready_in(rc);
7130957b409SSimon J. Gerraty } else {
7140957b409SSimon J. Gerraty rc->ixa = rc->ixb = 5;
7150957b409SSimon J. Gerraty rc->ixc = rlen;
7160957b409SSimon J. Gerraty }
7170957b409SSimon J. Gerraty return;
7180957b409SSimon J. Gerraty }
7190957b409SSimon J. Gerraty
7200957b409SSimon J. Gerraty /*
7210957b409SSimon J. Gerraty * If there is no active encryption, then the data can be read
7220957b409SSimon J. Gerraty * right away. Note that we do not receive bytes from the
7230957b409SSimon J. Gerraty * transport medium when we still have payload bytes to be
7240957b409SSimon J. Gerraty * acknowledged.
7250957b409SSimon J. Gerraty */
7260957b409SSimon J. Gerraty if (!rc->incrypt) {
7270957b409SSimon J. Gerraty rc->ixa = 5;
7280957b409SSimon J. Gerraty return;
7290957b409SSimon J. Gerraty }
7300957b409SSimon J. Gerraty
7310957b409SSimon J. Gerraty /*
7320957b409SSimon J. Gerraty * Since encryption is active, we must wait for a full record
7330957b409SSimon J. Gerraty * before processing it.
7340957b409SSimon J. Gerraty */
7350957b409SSimon J. Gerraty if (rc->ixc != 0) {
7360957b409SSimon J. Gerraty return;
7370957b409SSimon J. Gerraty }
7380957b409SSimon J. Gerraty
7390957b409SSimon J. Gerraty /*
7400957b409SSimon J. Gerraty * We got the full record. Decrypt it.
7410957b409SSimon J. Gerraty */
7420957b409SSimon J. Gerraty pbuf_len = rc->ixa - 5;
7430957b409SSimon J. Gerraty pbuf = rc->in.vtable->decrypt(&rc->in.vtable,
7440957b409SSimon J. Gerraty rc->record_type_in, rc->version_in, rc->ibuf + 5, &pbuf_len);
7450957b409SSimon J. Gerraty if (pbuf == 0) {
7460957b409SSimon J. Gerraty br_ssl_engine_fail(rc, BR_ERR_BAD_MAC);
7470957b409SSimon J. Gerraty return;
7480957b409SSimon J. Gerraty }
7490957b409SSimon J. Gerraty rc->ixa = (size_t)(pbuf - rc->ibuf);
7500957b409SSimon J. Gerraty rc->ixb = rc->ixa + pbuf_len;
7510957b409SSimon J. Gerraty
7520957b409SSimon J. Gerraty /*
7530957b409SSimon J. Gerraty * Decryption may have yielded an empty record, in which case
7540957b409SSimon J. Gerraty * we get back to "ready" state immediately.
7550957b409SSimon J. Gerraty */
7560957b409SSimon J. Gerraty if (rc->ixa == rc->ixb) {
7570957b409SSimon J. Gerraty make_ready_in(rc);
7580957b409SSimon J. Gerraty }
7590957b409SSimon J. Gerraty }
7600957b409SSimon J. Gerraty
7610957b409SSimon J. Gerraty /* see inner.h */
7620957b409SSimon J. Gerraty int
br_ssl_engine_recvrec_finished(const br_ssl_engine_context * rc)7630957b409SSimon J. Gerraty br_ssl_engine_recvrec_finished(const br_ssl_engine_context *rc)
7640957b409SSimon J. Gerraty {
7650957b409SSimon J. Gerraty switch (rc->iomode) {
7660957b409SSimon J. Gerraty case BR_IO_IN:
7670957b409SSimon J. Gerraty case BR_IO_INOUT:
7680957b409SSimon J. Gerraty return rc->ixc == 0 || rc->ixa < 5;
7690957b409SSimon J. Gerraty default:
7700957b409SSimon J. Gerraty return 1;
7710957b409SSimon J. Gerraty }
7720957b409SSimon J. Gerraty }
7730957b409SSimon J. Gerraty
7740957b409SSimon J. Gerraty static unsigned char *
recvpld_buf(const br_ssl_engine_context * rc,size_t * len)7750957b409SSimon J. Gerraty recvpld_buf(const br_ssl_engine_context *rc, size_t *len)
7760957b409SSimon J. Gerraty {
7770957b409SSimon J. Gerraty /*
7780957b409SSimon J. Gerraty * There is payload data to be read only if the mode is
7790957b409SSimon J. Gerraty * compatible, and ixa != ixb.
7800957b409SSimon J. Gerraty */
7810957b409SSimon J. Gerraty switch (rc->iomode) {
7820957b409SSimon J. Gerraty case BR_IO_IN:
7830957b409SSimon J. Gerraty case BR_IO_INOUT:
7840957b409SSimon J. Gerraty *len = rc->ixb - rc->ixa;
7850957b409SSimon J. Gerraty return (*len == 0) ? NULL : (rc->ibuf + rc->ixa);
7860957b409SSimon J. Gerraty default:
7870957b409SSimon J. Gerraty *len = 0;
7880957b409SSimon J. Gerraty return NULL;
7890957b409SSimon J. Gerraty }
7900957b409SSimon J. Gerraty }
7910957b409SSimon J. Gerraty
7920957b409SSimon J. Gerraty static void
recvpld_ack(br_ssl_engine_context * rc,size_t len)7930957b409SSimon J. Gerraty recvpld_ack(br_ssl_engine_context *rc, size_t len)
7940957b409SSimon J. Gerraty {
7950957b409SSimon J. Gerraty rc->ixa += len;
7960957b409SSimon J. Gerraty
7970957b409SSimon J. Gerraty /*
7980957b409SSimon J. Gerraty * If we read all the available data, then we either expect
7990957b409SSimon J. Gerraty * the remainder of the current record (if the current record
8000957b409SSimon J. Gerraty * was not finished; this may happen when encryption is not
8010957b409SSimon J. Gerraty * active), or go to "ready" state.
8020957b409SSimon J. Gerraty */
8030957b409SSimon J. Gerraty if (rc->ixa == rc->ixb) {
8040957b409SSimon J. Gerraty if (rc->ixc == 0) {
8050957b409SSimon J. Gerraty make_ready_in(rc);
8060957b409SSimon J. Gerraty } else {
8070957b409SSimon J. Gerraty rc->ixa = rc->ixb = 5;
8080957b409SSimon J. Gerraty }
8090957b409SSimon J. Gerraty }
8100957b409SSimon J. Gerraty }
8110957b409SSimon J. Gerraty
8120957b409SSimon J. Gerraty static unsigned char *
sendpld_buf(const br_ssl_engine_context * rc,size_t * len)8130957b409SSimon J. Gerraty sendpld_buf(const br_ssl_engine_context *rc, size_t *len)
8140957b409SSimon J. Gerraty {
8150957b409SSimon J. Gerraty /*
8160957b409SSimon J. Gerraty * Payload data can be injected only if the current mode is
8170957b409SSimon J. Gerraty * compatible, and oxa != oxb.
8180957b409SSimon J. Gerraty */
8190957b409SSimon J. Gerraty switch (rc->iomode) {
8200957b409SSimon J. Gerraty case BR_IO_OUT:
8210957b409SSimon J. Gerraty case BR_IO_INOUT:
8220957b409SSimon J. Gerraty *len = rc->oxb - rc->oxa;
8230957b409SSimon J. Gerraty return (*len == 0) ? NULL : (rc->obuf + rc->oxa);
8240957b409SSimon J. Gerraty default:
8250957b409SSimon J. Gerraty *len = 0;
8260957b409SSimon J. Gerraty return NULL;
8270957b409SSimon J. Gerraty }
8280957b409SSimon J. Gerraty }
8290957b409SSimon J. Gerraty
8300957b409SSimon J. Gerraty /*
8310957b409SSimon J. Gerraty * If some payload bytes have been accumulated, then wrap them into
8320957b409SSimon J. Gerraty * an outgoing record. Otherwise, this function does nothing, unless
8330957b409SSimon J. Gerraty * 'force' is non-zero, in which case an empty record is assembled.
8340957b409SSimon J. Gerraty *
8350957b409SSimon J. Gerraty * The caller must take care not to invoke this function if the engine
8360957b409SSimon J. Gerraty * is not currently ready to receive payload bytes to send.
8370957b409SSimon J. Gerraty */
8380957b409SSimon J. Gerraty static void
sendpld_flush(br_ssl_engine_context * rc,int force)8390957b409SSimon J. Gerraty sendpld_flush(br_ssl_engine_context *rc, int force)
8400957b409SSimon J. Gerraty {
8410957b409SSimon J. Gerraty size_t xlen;
8420957b409SSimon J. Gerraty unsigned char *buf;
8430957b409SSimon J. Gerraty
8440957b409SSimon J. Gerraty if (rc->oxa == rc->oxb) {
8450957b409SSimon J. Gerraty return;
8460957b409SSimon J. Gerraty }
8470957b409SSimon J. Gerraty xlen = rc->oxa - rc->oxc;
8480957b409SSimon J. Gerraty if (xlen == 0 && !force) {
8490957b409SSimon J. Gerraty return;
8500957b409SSimon J. Gerraty }
8510957b409SSimon J. Gerraty buf = rc->out.vtable->encrypt(&rc->out.vtable,
8520957b409SSimon J. Gerraty rc->record_type_out, rc->version_out,
8530957b409SSimon J. Gerraty rc->obuf + rc->oxc, &xlen);
8540957b409SSimon J. Gerraty rc->oxb = rc->oxa = (size_t)(buf - rc->obuf);
8550957b409SSimon J. Gerraty rc->oxc = rc->oxa + xlen;
8560957b409SSimon J. Gerraty }
8570957b409SSimon J. Gerraty
8580957b409SSimon J. Gerraty static void
sendpld_ack(br_ssl_engine_context * rc,size_t len)8590957b409SSimon J. Gerraty sendpld_ack(br_ssl_engine_context *rc, size_t len)
8600957b409SSimon J. Gerraty {
8610957b409SSimon J. Gerraty /*
8620957b409SSimon J. Gerraty * If using a shared buffer, then we may have to modify the
8630957b409SSimon J. Gerraty * current mode.
8640957b409SSimon J. Gerraty */
8650957b409SSimon J. Gerraty if (rc->iomode == BR_IO_INOUT && rc->ibuf == rc->obuf) {
8660957b409SSimon J. Gerraty rc->iomode = BR_IO_OUT;
8670957b409SSimon J. Gerraty }
8680957b409SSimon J. Gerraty rc->oxa += len;
8690957b409SSimon J. Gerraty if (rc->oxa >= rc->oxb) {
8700957b409SSimon J. Gerraty /*
8710957b409SSimon J. Gerraty * Set oxb to one more than oxa so that sendpld_flush()
8720957b409SSimon J. Gerraty * does not mistakingly believe that a record is
8730957b409SSimon J. Gerraty * already prepared and being sent.
8740957b409SSimon J. Gerraty */
8750957b409SSimon J. Gerraty rc->oxb = rc->oxa + 1;
8760957b409SSimon J. Gerraty sendpld_flush(rc, 0);
8770957b409SSimon J. Gerraty }
8780957b409SSimon J. Gerraty }
8790957b409SSimon J. Gerraty
8800957b409SSimon J. Gerraty static unsigned char *
sendrec_buf(const br_ssl_engine_context * rc,size_t * len)8810957b409SSimon J. Gerraty sendrec_buf(const br_ssl_engine_context *rc, size_t *len)
8820957b409SSimon J. Gerraty {
8830957b409SSimon J. Gerraty /*
8840957b409SSimon J. Gerraty * When still gathering payload bytes, oxc points to the start
8850957b409SSimon J. Gerraty * of the record data, so oxc <= oxa. However, when a full
8860957b409SSimon J. Gerraty * record has been completed, oxc points to the end of the record,
8870957b409SSimon J. Gerraty * so oxc > oxa.
8880957b409SSimon J. Gerraty */
8890957b409SSimon J. Gerraty switch (rc->iomode) {
8900957b409SSimon J. Gerraty case BR_IO_OUT:
8910957b409SSimon J. Gerraty case BR_IO_INOUT:
8920957b409SSimon J. Gerraty if (rc->oxc > rc->oxa) {
8930957b409SSimon J. Gerraty *len = rc->oxc - rc->oxa;
8940957b409SSimon J. Gerraty return rc->obuf + rc->oxa;
8950957b409SSimon J. Gerraty }
8960957b409SSimon J. Gerraty break;
8970957b409SSimon J. Gerraty }
8980957b409SSimon J. Gerraty *len = 0;
8990957b409SSimon J. Gerraty return NULL;
9000957b409SSimon J. Gerraty }
9010957b409SSimon J. Gerraty
9020957b409SSimon J. Gerraty static void
sendrec_ack(br_ssl_engine_context * rc,size_t len)9030957b409SSimon J. Gerraty sendrec_ack(br_ssl_engine_context *rc, size_t len)
9040957b409SSimon J. Gerraty {
9050957b409SSimon J. Gerraty rc->oxb = (rc->oxa += len);
9060957b409SSimon J. Gerraty if (rc->oxa == rc->oxc) {
9070957b409SSimon J. Gerraty make_ready_out(rc);
9080957b409SSimon J. Gerraty }
9090957b409SSimon J. Gerraty }
9100957b409SSimon J. Gerraty
9110957b409SSimon J. Gerraty /*
9120957b409SSimon J. Gerraty * Test whether there is some buffered outgoing record that still must
9130957b409SSimon J. Gerraty * sent.
9140957b409SSimon J. Gerraty */
9150957b409SSimon J. Gerraty static inline int
has_rec_tosend(const br_ssl_engine_context * rc)9160957b409SSimon J. Gerraty has_rec_tosend(const br_ssl_engine_context *rc)
9170957b409SSimon J. Gerraty {
9180957b409SSimon J. Gerraty return rc->oxa == rc->oxb && rc->oxa != rc->oxc;
9190957b409SSimon J. Gerraty }
9200957b409SSimon J. Gerraty
9210957b409SSimon J. Gerraty /*
9220957b409SSimon J. Gerraty * The "no encryption" mode has no overhead. It limits the payload size
9230957b409SSimon J. Gerraty * to the maximum size allowed by the standard (16384 bytes); the caller
9240957b409SSimon J. Gerraty * is responsible for possibly enforcing a smaller fragment length.
9250957b409SSimon J. Gerraty */
9260957b409SSimon J. Gerraty static void
clear_max_plaintext(const br_sslrec_out_clear_context * cc,size_t * start,size_t * end)9270957b409SSimon J. Gerraty clear_max_plaintext(const br_sslrec_out_clear_context *cc,
9280957b409SSimon J. Gerraty size_t *start, size_t *end)
9290957b409SSimon J. Gerraty {
9300957b409SSimon J. Gerraty size_t len;
9310957b409SSimon J. Gerraty
9320957b409SSimon J. Gerraty (void)cc;
9330957b409SSimon J. Gerraty len = *end - *start;
9340957b409SSimon J. Gerraty if (len > 16384) {
9350957b409SSimon J. Gerraty *end = *start + 16384;
9360957b409SSimon J. Gerraty }
9370957b409SSimon J. Gerraty }
9380957b409SSimon J. Gerraty
9390957b409SSimon J. Gerraty /*
9400957b409SSimon J. Gerraty * In "no encryption" mode, encryption is trivial (a no-operation) so
9410957b409SSimon J. Gerraty * we just have to encode the header.
9420957b409SSimon J. Gerraty */
9430957b409SSimon J. Gerraty static unsigned char *
clear_encrypt(br_sslrec_out_clear_context * cc,int record_type,unsigned version,void * data,size_t * data_len)9440957b409SSimon J. Gerraty clear_encrypt(br_sslrec_out_clear_context *cc,
9450957b409SSimon J. Gerraty int record_type, unsigned version, void *data, size_t *data_len)
9460957b409SSimon J. Gerraty {
9470957b409SSimon J. Gerraty unsigned char *buf;
9480957b409SSimon J. Gerraty
9490957b409SSimon J. Gerraty (void)cc;
9500957b409SSimon J. Gerraty buf = (unsigned char *)data - 5;
9510957b409SSimon J. Gerraty buf[0] = record_type;
9520957b409SSimon J. Gerraty br_enc16be(buf + 1, version);
9530957b409SSimon J. Gerraty br_enc16be(buf + 3, *data_len);
9540957b409SSimon J. Gerraty *data_len += 5;
9550957b409SSimon J. Gerraty return buf;
9560957b409SSimon J. Gerraty }
9570957b409SSimon J. Gerraty
9580957b409SSimon J. Gerraty /* see bearssl_ssl.h */
9590957b409SSimon J. Gerraty const br_sslrec_out_class br_sslrec_out_clear_vtable = {
9600957b409SSimon J. Gerraty sizeof(br_sslrec_out_clear_context),
9610957b409SSimon J. Gerraty (void (*)(const br_sslrec_out_class *const *, size_t *, size_t *))
9620957b409SSimon J. Gerraty &clear_max_plaintext,
9630957b409SSimon J. Gerraty (unsigned char *(*)(const br_sslrec_out_class **,
9640957b409SSimon J. Gerraty int, unsigned, void *, size_t *))
9650957b409SSimon J. Gerraty &clear_encrypt
9660957b409SSimon J. Gerraty };
9670957b409SSimon J. Gerraty
9680957b409SSimon J. Gerraty /* ==================================================================== */
9690957b409SSimon J. Gerraty /*
9700957b409SSimon J. Gerraty * In this part of the file, we handle the various record types, and
9710957b409SSimon J. Gerraty * communications with the handshake processor.
9720957b409SSimon J. Gerraty */
9730957b409SSimon J. Gerraty
9740957b409SSimon J. Gerraty /*
9750957b409SSimon J. Gerraty * IMPLEMENTATION NOTES
9760957b409SSimon J. Gerraty * ====================
9770957b409SSimon J. Gerraty *
9780957b409SSimon J. Gerraty * The handshake processor is written in T0 and runs as a coroutine.
9790957b409SSimon J. Gerraty * It receives the contents of all records except application data, and
9800957b409SSimon J. Gerraty * is responsible for producing the contents of all records except
9810957b409SSimon J. Gerraty * application data.
9820957b409SSimon J. Gerraty *
9830957b409SSimon J. Gerraty * A state flag is maintained, which specifies whether application data
9840957b409SSimon J. Gerraty * is acceptable or not. When it is set:
9850957b409SSimon J. Gerraty *
9860957b409SSimon J. Gerraty * -- Application data can be injected as payload data (provided that
9870957b409SSimon J. Gerraty * the output buffer is ready for that).
9880957b409SSimon J. Gerraty *
9890957b409SSimon J. Gerraty * -- Incoming application data records are accepted, and yield data
9900957b409SSimon J. Gerraty * that the caller may retrieve.
9910957b409SSimon J. Gerraty *
9920957b409SSimon J. Gerraty * When the flag is cleared, application data is not accepted from the
9930957b409SSimon J. Gerraty * application, and incoming application data records trigger an error.
9940957b409SSimon J. Gerraty *
9950957b409SSimon J. Gerraty *
9960957b409SSimon J. Gerraty * Records of type handshake, alert or change-cipher-spec are handled
9970957b409SSimon J. Gerraty * by the handshake processor. The handshake processor is written in T0
9980957b409SSimon J. Gerraty * and runs as a coroutine; it gets invoked whenever one of the following
9990957b409SSimon J. Gerraty * situations is reached:
10000957b409SSimon J. Gerraty *
10010957b409SSimon J. Gerraty * -- An incoming record has type handshake, alert or change-cipher-spec,
10020957b409SSimon J. Gerraty * and yields data that can be read (zero-length records are thus
10030957b409SSimon J. Gerraty * ignored).
10040957b409SSimon J. Gerraty *
10050957b409SSimon J. Gerraty * -- An outgoing record has just finished being sent, and the "application
10060957b409SSimon J. Gerraty * data" flag is cleared.
10070957b409SSimon J. Gerraty *
10080957b409SSimon J. Gerraty * -- The caller wishes to perform a close (call to br_ssl_engine_close()).
10090957b409SSimon J. Gerraty *
10100957b409SSimon J. Gerraty * -- The caller wishes to perform a renegotiation (call to
10110957b409SSimon J. Gerraty * br_ssl_engine_renegotiate()).
10120957b409SSimon J. Gerraty *
10130957b409SSimon J. Gerraty * Whenever the handshake processor is entered, access to the payload
10140957b409SSimon J. Gerraty * buffers is provided, along with some information about explicit
10150957b409SSimon J. Gerraty * closures or renegotiations.
10160957b409SSimon J. Gerraty */
10170957b409SSimon J. Gerraty
10180957b409SSimon J. Gerraty /* see bearssl_ssl.h */
10190957b409SSimon J. Gerraty void
br_ssl_engine_set_suites(br_ssl_engine_context * cc,const uint16_t * suites,size_t suites_num)10200957b409SSimon J. Gerraty br_ssl_engine_set_suites(br_ssl_engine_context *cc,
10210957b409SSimon J. Gerraty const uint16_t *suites, size_t suites_num)
10220957b409SSimon J. Gerraty {
10230957b409SSimon J. Gerraty if ((suites_num * sizeof *suites) > sizeof cc->suites_buf) {
10240957b409SSimon J. Gerraty br_ssl_engine_fail(cc, BR_ERR_BAD_PARAM);
10250957b409SSimon J. Gerraty return;
10260957b409SSimon J. Gerraty }
10270957b409SSimon J. Gerraty memcpy(cc->suites_buf, suites, suites_num * sizeof *suites);
10280957b409SSimon J. Gerraty cc->suites_num = suites_num;
10290957b409SSimon J. Gerraty }
10300957b409SSimon J. Gerraty
10310957b409SSimon J. Gerraty /*
10320957b409SSimon J. Gerraty * Give control to handshake processor. 'action' is 1 for a close,
10330957b409SSimon J. Gerraty * 2 for a renegotiation, or 0 for a jump due to I/O completion.
10340957b409SSimon J. Gerraty */
10350957b409SSimon J. Gerraty static void
jump_handshake(br_ssl_engine_context * cc,int action)10360957b409SSimon J. Gerraty jump_handshake(br_ssl_engine_context *cc, int action)
10370957b409SSimon J. Gerraty {
10380957b409SSimon J. Gerraty /*
10390957b409SSimon J. Gerraty * We use a loop because the handshake processor actions may
10400957b409SSimon J. Gerraty * allow for more actions; namely, if the processor reads all
10410957b409SSimon J. Gerraty * input data, then it may allow for output data to be produced,
10420957b409SSimon J. Gerraty * in case of a shared in/out buffer.
10430957b409SSimon J. Gerraty */
10440957b409SSimon J. Gerraty for (;;) {
10450957b409SSimon J. Gerraty size_t hlen_in, hlen_out;
10460957b409SSimon J. Gerraty
10470957b409SSimon J. Gerraty /*
10480957b409SSimon J. Gerraty * Get input buffer. We do not want to provide
10490957b409SSimon J. Gerraty * application data to the handshake processor (we could
10500957b409SSimon J. Gerraty * get called with an explicit close or renegotiation
10510957b409SSimon J. Gerraty * while there is application data ready to be read).
10520957b409SSimon J. Gerraty */
10530957b409SSimon J. Gerraty cc->hbuf_in = recvpld_buf(cc, &hlen_in);
10540957b409SSimon J. Gerraty if (cc->hbuf_in != NULL
10550957b409SSimon J. Gerraty && cc->record_type_in == BR_SSL_APPLICATION_DATA)
10560957b409SSimon J. Gerraty {
10570957b409SSimon J. Gerraty hlen_in = 0;
10580957b409SSimon J. Gerraty }
10590957b409SSimon J. Gerraty
10600957b409SSimon J. Gerraty /*
10610957b409SSimon J. Gerraty * Get output buffer. The handshake processor never
10620957b409SSimon J. Gerraty * leaves an unfinished outgoing record, so if there is
10630957b409SSimon J. Gerraty * buffered output, then it MUST be some application
10640957b409SSimon J. Gerraty * data, so the processor cannot write to it.
10650957b409SSimon J. Gerraty */
10660957b409SSimon J. Gerraty cc->saved_hbuf_out = cc->hbuf_out = sendpld_buf(cc, &hlen_out);
10670957b409SSimon J. Gerraty if (cc->hbuf_out != NULL && br_ssl_engine_has_pld_to_send(cc)) {
10680957b409SSimon J. Gerraty hlen_out = 0;
10690957b409SSimon J. Gerraty }
10700957b409SSimon J. Gerraty
10710957b409SSimon J. Gerraty /*
10720957b409SSimon J. Gerraty * Note: hlen_in and hlen_out can be both non-zero only if
10730957b409SSimon J. Gerraty * the input and output buffers are disjoint. Thus, we can
10740957b409SSimon J. Gerraty * offer both buffers to the handshake code.
10750957b409SSimon J. Gerraty */
10760957b409SSimon J. Gerraty
10770957b409SSimon J. Gerraty cc->hlen_in = hlen_in;
10780957b409SSimon J. Gerraty cc->hlen_out = hlen_out;
10790957b409SSimon J. Gerraty cc->action = action;
10800957b409SSimon J. Gerraty cc->hsrun(&cc->cpu);
10810957b409SSimon J. Gerraty if (br_ssl_engine_closed(cc)) {
10820957b409SSimon J. Gerraty return;
10830957b409SSimon J. Gerraty }
10840957b409SSimon J. Gerraty if (cc->hbuf_out != cc->saved_hbuf_out) {
10850957b409SSimon J. Gerraty sendpld_ack(cc, cc->hbuf_out - cc->saved_hbuf_out);
10860957b409SSimon J. Gerraty }
10870957b409SSimon J. Gerraty if (hlen_in != cc->hlen_in) {
10880957b409SSimon J. Gerraty recvpld_ack(cc, hlen_in - cc->hlen_in);
10890957b409SSimon J. Gerraty if (cc->hlen_in == 0) {
10900957b409SSimon J. Gerraty /*
10910957b409SSimon J. Gerraty * We read all data bytes, which may have
10920957b409SSimon J. Gerraty * released the output buffer in case it
10930957b409SSimon J. Gerraty * is shared with the input buffer, and
10940957b409SSimon J. Gerraty * the handshake code might be waiting for
10950957b409SSimon J. Gerraty * that.
10960957b409SSimon J. Gerraty */
10970957b409SSimon J. Gerraty action = 0;
10980957b409SSimon J. Gerraty continue;
10990957b409SSimon J. Gerraty }
11000957b409SSimon J. Gerraty }
11010957b409SSimon J. Gerraty break;
11020957b409SSimon J. Gerraty }
11030957b409SSimon J. Gerraty }
11040957b409SSimon J. Gerraty
11050957b409SSimon J. Gerraty /* see inner.h */
11060957b409SSimon J. Gerraty void
br_ssl_engine_flush_record(br_ssl_engine_context * cc)11070957b409SSimon J. Gerraty br_ssl_engine_flush_record(br_ssl_engine_context *cc)
11080957b409SSimon J. Gerraty {
11090957b409SSimon J. Gerraty if (cc->hbuf_out != cc->saved_hbuf_out) {
11100957b409SSimon J. Gerraty sendpld_ack(cc, cc->hbuf_out - cc->saved_hbuf_out);
11110957b409SSimon J. Gerraty }
11120957b409SSimon J. Gerraty if (br_ssl_engine_has_pld_to_send(cc)) {
11130957b409SSimon J. Gerraty sendpld_flush(cc, 0);
11140957b409SSimon J. Gerraty }
11150957b409SSimon J. Gerraty cc->saved_hbuf_out = cc->hbuf_out = sendpld_buf(cc, &cc->hlen_out);
11160957b409SSimon J. Gerraty }
11170957b409SSimon J. Gerraty
11180957b409SSimon J. Gerraty /* see bearssl_ssl.h */
11190957b409SSimon J. Gerraty unsigned char *
br_ssl_engine_sendapp_buf(const br_ssl_engine_context * cc,size_t * len)11200957b409SSimon J. Gerraty br_ssl_engine_sendapp_buf(const br_ssl_engine_context *cc, size_t *len)
11210957b409SSimon J. Gerraty {
11220957b409SSimon J. Gerraty if (!(cc->application_data & 1)) {
11230957b409SSimon J. Gerraty *len = 0;
11240957b409SSimon J. Gerraty return NULL;
11250957b409SSimon J. Gerraty }
11260957b409SSimon J. Gerraty return sendpld_buf(cc, len);
11270957b409SSimon J. Gerraty }
11280957b409SSimon J. Gerraty
11290957b409SSimon J. Gerraty /* see bearssl_ssl.h */
11300957b409SSimon J. Gerraty void
br_ssl_engine_sendapp_ack(br_ssl_engine_context * cc,size_t len)11310957b409SSimon J. Gerraty br_ssl_engine_sendapp_ack(br_ssl_engine_context *cc, size_t len)
11320957b409SSimon J. Gerraty {
11330957b409SSimon J. Gerraty sendpld_ack(cc, len);
11340957b409SSimon J. Gerraty }
11350957b409SSimon J. Gerraty
11360957b409SSimon J. Gerraty /* see bearssl_ssl.h */
11370957b409SSimon J. Gerraty unsigned char *
br_ssl_engine_recvapp_buf(const br_ssl_engine_context * cc,size_t * len)11380957b409SSimon J. Gerraty br_ssl_engine_recvapp_buf(const br_ssl_engine_context *cc, size_t *len)
11390957b409SSimon J. Gerraty {
11400957b409SSimon J. Gerraty if (!(cc->application_data & 1)
11410957b409SSimon J. Gerraty || cc->record_type_in != BR_SSL_APPLICATION_DATA)
11420957b409SSimon J. Gerraty {
11430957b409SSimon J. Gerraty *len = 0;
11440957b409SSimon J. Gerraty return NULL;
11450957b409SSimon J. Gerraty }
11460957b409SSimon J. Gerraty return recvpld_buf(cc, len);
11470957b409SSimon J. Gerraty }
11480957b409SSimon J. Gerraty
11490957b409SSimon J. Gerraty /* see bearssl_ssl.h */
11500957b409SSimon J. Gerraty void
br_ssl_engine_recvapp_ack(br_ssl_engine_context * cc,size_t len)11510957b409SSimon J. Gerraty br_ssl_engine_recvapp_ack(br_ssl_engine_context *cc, size_t len)
11520957b409SSimon J. Gerraty {
11530957b409SSimon J. Gerraty recvpld_ack(cc, len);
11540957b409SSimon J. Gerraty }
11550957b409SSimon J. Gerraty
11560957b409SSimon J. Gerraty /* see bearssl_ssl.h */
11570957b409SSimon J. Gerraty unsigned char *
br_ssl_engine_sendrec_buf(const br_ssl_engine_context * cc,size_t * len)11580957b409SSimon J. Gerraty br_ssl_engine_sendrec_buf(const br_ssl_engine_context *cc, size_t *len)
11590957b409SSimon J. Gerraty {
11600957b409SSimon J. Gerraty return sendrec_buf(cc, len);
11610957b409SSimon J. Gerraty }
11620957b409SSimon J. Gerraty
11630957b409SSimon J. Gerraty /* see bearssl_ssl.h */
11640957b409SSimon J. Gerraty void
br_ssl_engine_sendrec_ack(br_ssl_engine_context * cc,size_t len)11650957b409SSimon J. Gerraty br_ssl_engine_sendrec_ack(br_ssl_engine_context *cc, size_t len)
11660957b409SSimon J. Gerraty {
11670957b409SSimon J. Gerraty sendrec_ack(cc, len);
11680957b409SSimon J. Gerraty if (len != 0 && !has_rec_tosend(cc)
11690957b409SSimon J. Gerraty && (cc->record_type_out != BR_SSL_APPLICATION_DATA
11700957b409SSimon J. Gerraty || (cc->application_data & 1) == 0))
11710957b409SSimon J. Gerraty {
11720957b409SSimon J. Gerraty jump_handshake(cc, 0);
11730957b409SSimon J. Gerraty }
11740957b409SSimon J. Gerraty }
11750957b409SSimon J. Gerraty
11760957b409SSimon J. Gerraty /* see bearssl_ssl.h */
11770957b409SSimon J. Gerraty unsigned char *
br_ssl_engine_recvrec_buf(const br_ssl_engine_context * cc,size_t * len)11780957b409SSimon J. Gerraty br_ssl_engine_recvrec_buf(const br_ssl_engine_context *cc, size_t *len)
11790957b409SSimon J. Gerraty {
11800957b409SSimon J. Gerraty return recvrec_buf(cc, len);
11810957b409SSimon J. Gerraty }
11820957b409SSimon J. Gerraty
11830957b409SSimon J. Gerraty /* see bearssl_ssl.h */
11840957b409SSimon J. Gerraty void
br_ssl_engine_recvrec_ack(br_ssl_engine_context * cc,size_t len)11850957b409SSimon J. Gerraty br_ssl_engine_recvrec_ack(br_ssl_engine_context *cc, size_t len)
11860957b409SSimon J. Gerraty {
11870957b409SSimon J. Gerraty unsigned char *buf;
11880957b409SSimon J. Gerraty
11890957b409SSimon J. Gerraty recvrec_ack(cc, len);
11900957b409SSimon J. Gerraty if (br_ssl_engine_closed(cc)) {
11910957b409SSimon J. Gerraty return;
11920957b409SSimon J. Gerraty }
11930957b409SSimon J. Gerraty
11940957b409SSimon J. Gerraty /*
11950957b409SSimon J. Gerraty * We just received some bytes from the peer. This may have
11960957b409SSimon J. Gerraty * yielded some payload bytes, in which case we must process
11970957b409SSimon J. Gerraty * them according to the record type.
11980957b409SSimon J. Gerraty */
11990957b409SSimon J. Gerraty buf = recvpld_buf(cc, &len);
12000957b409SSimon J. Gerraty if (buf != NULL) {
12010957b409SSimon J. Gerraty switch (cc->record_type_in) {
12020957b409SSimon J. Gerraty case BR_SSL_CHANGE_CIPHER_SPEC:
12030957b409SSimon J. Gerraty case BR_SSL_ALERT:
12040957b409SSimon J. Gerraty case BR_SSL_HANDSHAKE:
12050957b409SSimon J. Gerraty jump_handshake(cc, 0);
12060957b409SSimon J. Gerraty break;
12070957b409SSimon J. Gerraty case BR_SSL_APPLICATION_DATA:
12080957b409SSimon J. Gerraty if (cc->application_data == 1) {
12090957b409SSimon J. Gerraty break;
12100957b409SSimon J. Gerraty }
12110957b409SSimon J. Gerraty
12120957b409SSimon J. Gerraty /*
12130957b409SSimon J. Gerraty * If we are currently closing, and waiting for
12140957b409SSimon J. Gerraty * a close_notify from the peer, then incoming
12150957b409SSimon J. Gerraty * application data should be discarded.
12160957b409SSimon J. Gerraty */
12170957b409SSimon J. Gerraty if (cc->application_data == 2) {
12180957b409SSimon J. Gerraty recvpld_ack(cc, len);
12190957b409SSimon J. Gerraty break;
12200957b409SSimon J. Gerraty }
12210957b409SSimon J. Gerraty
12220957b409SSimon J. Gerraty /* Fall through */
12230957b409SSimon J. Gerraty default:
12240957b409SSimon J. Gerraty br_ssl_engine_fail(cc, BR_ERR_UNEXPECTED);
12250957b409SSimon J. Gerraty break;
12260957b409SSimon J. Gerraty }
12270957b409SSimon J. Gerraty }
12280957b409SSimon J. Gerraty }
12290957b409SSimon J. Gerraty
12300957b409SSimon J. Gerraty /* see bearssl_ssl.h */
12310957b409SSimon J. Gerraty void
br_ssl_engine_close(br_ssl_engine_context * cc)12320957b409SSimon J. Gerraty br_ssl_engine_close(br_ssl_engine_context *cc)
12330957b409SSimon J. Gerraty {
12340957b409SSimon J. Gerraty if (!br_ssl_engine_closed(cc)) {
1235*cc9e6590SSimon J. Gerraty /*
1236*cc9e6590SSimon J. Gerraty * If we are not already closed, then we need to
1237*cc9e6590SSimon J. Gerraty * initiate the closure. Once closing, any incoming
1238*cc9e6590SSimon J. Gerraty * application data is discarded; we should also discard
1239*cc9e6590SSimon J. Gerraty * application data which is already there but has not
1240*cc9e6590SSimon J. Gerraty * been acknowledged by the application yet (this mimics
1241*cc9e6590SSimon J. Gerraty * usual semantics on BSD sockets: you cannot read()
1242*cc9e6590SSimon J. Gerraty * once you called close(), even if there was some
1243*cc9e6590SSimon J. Gerraty * unread data already buffered).
1244*cc9e6590SSimon J. Gerraty */
1245*cc9e6590SSimon J. Gerraty size_t len;
1246*cc9e6590SSimon J. Gerraty
1247*cc9e6590SSimon J. Gerraty if (br_ssl_engine_recvapp_buf(cc, &len) != NULL && len != 0) {
1248*cc9e6590SSimon J. Gerraty br_ssl_engine_recvapp_ack(cc, len);
1249*cc9e6590SSimon J. Gerraty }
12500957b409SSimon J. Gerraty jump_handshake(cc, 1);
12510957b409SSimon J. Gerraty }
12520957b409SSimon J. Gerraty }
12530957b409SSimon J. Gerraty
12540957b409SSimon J. Gerraty /* see bearssl_ssl.h */
12550957b409SSimon J. Gerraty int
br_ssl_engine_renegotiate(br_ssl_engine_context * cc)12560957b409SSimon J. Gerraty br_ssl_engine_renegotiate(br_ssl_engine_context *cc)
12570957b409SSimon J. Gerraty {
12580957b409SSimon J. Gerraty size_t len;
12590957b409SSimon J. Gerraty
12600957b409SSimon J. Gerraty if (br_ssl_engine_closed(cc) || cc->reneg == 1
12610957b409SSimon J. Gerraty || (cc->flags & BR_OPT_NO_RENEGOTIATION) != 0
12620957b409SSimon J. Gerraty || br_ssl_engine_recvapp_buf(cc, &len) != NULL)
12630957b409SSimon J. Gerraty {
12640957b409SSimon J. Gerraty return 0;
12650957b409SSimon J. Gerraty }
12660957b409SSimon J. Gerraty jump_handshake(cc, 2);
12670957b409SSimon J. Gerraty return 1;
12680957b409SSimon J. Gerraty }
12690957b409SSimon J. Gerraty
12700957b409SSimon J. Gerraty /* see bearssl.h */
12710957b409SSimon J. Gerraty unsigned
br_ssl_engine_current_state(const br_ssl_engine_context * cc)12720957b409SSimon J. Gerraty br_ssl_engine_current_state(const br_ssl_engine_context *cc)
12730957b409SSimon J. Gerraty {
12740957b409SSimon J. Gerraty unsigned s;
12750957b409SSimon J. Gerraty size_t len;
12760957b409SSimon J. Gerraty
12770957b409SSimon J. Gerraty if (br_ssl_engine_closed(cc)) {
12780957b409SSimon J. Gerraty return BR_SSL_CLOSED;
12790957b409SSimon J. Gerraty }
12800957b409SSimon J. Gerraty
12810957b409SSimon J. Gerraty s = 0;
12820957b409SSimon J. Gerraty if (br_ssl_engine_sendrec_buf(cc, &len) != NULL) {
12830957b409SSimon J. Gerraty s |= BR_SSL_SENDREC;
12840957b409SSimon J. Gerraty }
12850957b409SSimon J. Gerraty if (br_ssl_engine_recvrec_buf(cc, &len) != NULL) {
12860957b409SSimon J. Gerraty s |= BR_SSL_RECVREC;
12870957b409SSimon J. Gerraty }
12880957b409SSimon J. Gerraty if (br_ssl_engine_sendapp_buf(cc, &len) != NULL) {
12890957b409SSimon J. Gerraty s |= BR_SSL_SENDAPP;
12900957b409SSimon J. Gerraty }
12910957b409SSimon J. Gerraty if (br_ssl_engine_recvapp_buf(cc, &len) != NULL) {
12920957b409SSimon J. Gerraty s |= BR_SSL_RECVAPP;
12930957b409SSimon J. Gerraty }
12940957b409SSimon J. Gerraty return s;
12950957b409SSimon J. Gerraty }
12960957b409SSimon J. Gerraty
12970957b409SSimon J. Gerraty /* see bearssl_ssl.h */
12980957b409SSimon J. Gerraty void
br_ssl_engine_flush(br_ssl_engine_context * cc,int force)12990957b409SSimon J. Gerraty br_ssl_engine_flush(br_ssl_engine_context *cc, int force)
13000957b409SSimon J. Gerraty {
13010957b409SSimon J. Gerraty if (!br_ssl_engine_closed(cc) && (cc->application_data & 1) != 0) {
13020957b409SSimon J. Gerraty sendpld_flush(cc, force);
13030957b409SSimon J. Gerraty }
13040957b409SSimon J. Gerraty }
13050957b409SSimon J. Gerraty
13060957b409SSimon J. Gerraty /* see inner.h */
13070957b409SSimon J. Gerraty void
br_ssl_engine_hs_reset(br_ssl_engine_context * cc,void (* hsinit)(void *),void (* hsrun)(void *))13080957b409SSimon J. Gerraty br_ssl_engine_hs_reset(br_ssl_engine_context *cc,
13090957b409SSimon J. Gerraty void (*hsinit)(void *), void (*hsrun)(void *))
13100957b409SSimon J. Gerraty {
13110957b409SSimon J. Gerraty engine_clearbuf(cc);
13120957b409SSimon J. Gerraty cc->cpu.dp = cc->dp_stack;
13130957b409SSimon J. Gerraty cc->cpu.rp = cc->rp_stack;
13140957b409SSimon J. Gerraty hsinit(&cc->cpu);
13150957b409SSimon J. Gerraty cc->hsrun = hsrun;
13160957b409SSimon J. Gerraty cc->shutdown_recv = 0;
13170957b409SSimon J. Gerraty cc->application_data = 0;
13180957b409SSimon J. Gerraty cc->alert = 0;
13190957b409SSimon J. Gerraty jump_handshake(cc, 0);
13200957b409SSimon J. Gerraty }
13210957b409SSimon J. Gerraty
13220957b409SSimon J. Gerraty /* see inner.h */
13230957b409SSimon J. Gerraty br_tls_prf_impl
br_ssl_engine_get_PRF(br_ssl_engine_context * cc,int prf_id)13240957b409SSimon J. Gerraty br_ssl_engine_get_PRF(br_ssl_engine_context *cc, int prf_id)
13250957b409SSimon J. Gerraty {
13260957b409SSimon J. Gerraty if (cc->session.version >= BR_TLS12) {
13270957b409SSimon J. Gerraty if (prf_id == br_sha384_ID) {
13280957b409SSimon J. Gerraty return cc->prf_sha384;
13290957b409SSimon J. Gerraty } else {
13300957b409SSimon J. Gerraty return cc->prf_sha256;
13310957b409SSimon J. Gerraty }
13320957b409SSimon J. Gerraty } else {
13330957b409SSimon J. Gerraty return cc->prf10;
13340957b409SSimon J. Gerraty }
13350957b409SSimon J. Gerraty }
13360957b409SSimon J. Gerraty
13370957b409SSimon J. Gerraty /* see inner.h */
13380957b409SSimon J. Gerraty void
br_ssl_engine_compute_master(br_ssl_engine_context * cc,int prf_id,const void * pms,size_t pms_len)13390957b409SSimon J. Gerraty br_ssl_engine_compute_master(br_ssl_engine_context *cc,
13400957b409SSimon J. Gerraty int prf_id, const void *pms, size_t pms_len)
13410957b409SSimon J. Gerraty {
13420957b409SSimon J. Gerraty br_tls_prf_impl iprf;
13430957b409SSimon J. Gerraty br_tls_prf_seed_chunk seed[2] = {
13440957b409SSimon J. Gerraty { cc->client_random, sizeof cc->client_random },
13450957b409SSimon J. Gerraty { cc->server_random, sizeof cc->server_random }
13460957b409SSimon J. Gerraty };
13470957b409SSimon J. Gerraty
13480957b409SSimon J. Gerraty iprf = br_ssl_engine_get_PRF(cc, prf_id);
13490957b409SSimon J. Gerraty iprf(cc->session.master_secret, sizeof cc->session.master_secret,
13500957b409SSimon J. Gerraty pms, pms_len, "master secret", 2, seed);
13510957b409SSimon J. Gerraty }
13520957b409SSimon J. Gerraty
13530957b409SSimon J. Gerraty /*
13540957b409SSimon J. Gerraty * Compute key block.
13550957b409SSimon J. Gerraty */
13560957b409SSimon J. Gerraty static void
compute_key_block(br_ssl_engine_context * cc,int prf_id,size_t half_len,unsigned char * kb)13570957b409SSimon J. Gerraty compute_key_block(br_ssl_engine_context *cc, int prf_id,
13580957b409SSimon J. Gerraty size_t half_len, unsigned char *kb)
13590957b409SSimon J. Gerraty {
13600957b409SSimon J. Gerraty br_tls_prf_impl iprf;
13610957b409SSimon J. Gerraty br_tls_prf_seed_chunk seed[2] = {
13620957b409SSimon J. Gerraty { cc->server_random, sizeof cc->server_random },
13630957b409SSimon J. Gerraty { cc->client_random, sizeof cc->client_random }
13640957b409SSimon J. Gerraty };
13650957b409SSimon J. Gerraty
13660957b409SSimon J. Gerraty iprf = br_ssl_engine_get_PRF(cc, prf_id);
13670957b409SSimon J. Gerraty iprf(kb, half_len << 1,
13680957b409SSimon J. Gerraty cc->session.master_secret, sizeof cc->session.master_secret,
13690957b409SSimon J. Gerraty "key expansion", 2, seed);
13700957b409SSimon J. Gerraty }
13710957b409SSimon J. Gerraty
13720957b409SSimon J. Gerraty /* see inner.h */
13730957b409SSimon J. Gerraty void
br_ssl_engine_switch_cbc_in(br_ssl_engine_context * cc,int is_client,int prf_id,int mac_id,const br_block_cbcdec_class * bc_impl,size_t cipher_key_len)13740957b409SSimon J. Gerraty br_ssl_engine_switch_cbc_in(br_ssl_engine_context *cc,
13750957b409SSimon J. Gerraty int is_client, int prf_id, int mac_id,
13760957b409SSimon J. Gerraty const br_block_cbcdec_class *bc_impl, size_t cipher_key_len)
13770957b409SSimon J. Gerraty {
13780957b409SSimon J. Gerraty unsigned char kb[192];
13790957b409SSimon J. Gerraty unsigned char *cipher_key, *mac_key, *iv;
13800957b409SSimon J. Gerraty const br_hash_class *imh;
13810957b409SSimon J. Gerraty size_t mac_key_len, mac_out_len, iv_len;
13820957b409SSimon J. Gerraty
13830957b409SSimon J. Gerraty imh = br_ssl_engine_get_hash(cc, mac_id);
13840957b409SSimon J. Gerraty mac_out_len = (imh->desc >> BR_HASHDESC_OUT_OFF) & BR_HASHDESC_OUT_MASK;
13850957b409SSimon J. Gerraty mac_key_len = mac_out_len;
13860957b409SSimon J. Gerraty
13870957b409SSimon J. Gerraty /*
13880957b409SSimon J. Gerraty * TLS 1.1+ uses per-record explicit IV, so no IV to generate here.
13890957b409SSimon J. Gerraty */
13900957b409SSimon J. Gerraty if (cc->session.version >= BR_TLS11) {
13910957b409SSimon J. Gerraty iv_len = 0;
13920957b409SSimon J. Gerraty } else {
13930957b409SSimon J. Gerraty iv_len = bc_impl->block_size;
13940957b409SSimon J. Gerraty }
13950957b409SSimon J. Gerraty compute_key_block(cc, prf_id,
13960957b409SSimon J. Gerraty mac_key_len + cipher_key_len + iv_len, kb);
13970957b409SSimon J. Gerraty if (is_client) {
13980957b409SSimon J. Gerraty mac_key = &kb[mac_key_len];
13990957b409SSimon J. Gerraty cipher_key = &kb[(mac_key_len << 1) + cipher_key_len];
14000957b409SSimon J. Gerraty iv = &kb[((mac_key_len + cipher_key_len) << 1) + iv_len];
14010957b409SSimon J. Gerraty } else {
14020957b409SSimon J. Gerraty mac_key = &kb[0];
14030957b409SSimon J. Gerraty cipher_key = &kb[mac_key_len << 1];
14040957b409SSimon J. Gerraty iv = &kb[(mac_key_len + cipher_key_len) << 1];
14050957b409SSimon J. Gerraty }
14060957b409SSimon J. Gerraty if (iv_len == 0) {
14070957b409SSimon J. Gerraty iv = NULL;
14080957b409SSimon J. Gerraty }
14090957b409SSimon J. Gerraty cc->icbc_in->init(&cc->in.cbc.vtable,
14100957b409SSimon J. Gerraty bc_impl, cipher_key, cipher_key_len,
14110957b409SSimon J. Gerraty imh, mac_key, mac_key_len, mac_out_len, iv);
14120957b409SSimon J. Gerraty cc->incrypt = 1;
14130957b409SSimon J. Gerraty }
14140957b409SSimon J. Gerraty
14150957b409SSimon J. Gerraty /* see inner.h */
14160957b409SSimon J. Gerraty void
br_ssl_engine_switch_cbc_out(br_ssl_engine_context * cc,int is_client,int prf_id,int mac_id,const br_block_cbcenc_class * bc_impl,size_t cipher_key_len)14170957b409SSimon J. Gerraty br_ssl_engine_switch_cbc_out(br_ssl_engine_context *cc,
14180957b409SSimon J. Gerraty int is_client, int prf_id, int mac_id,
14190957b409SSimon J. Gerraty const br_block_cbcenc_class *bc_impl, size_t cipher_key_len)
14200957b409SSimon J. Gerraty {
14210957b409SSimon J. Gerraty unsigned char kb[192];
14220957b409SSimon J. Gerraty unsigned char *cipher_key, *mac_key, *iv;
14230957b409SSimon J. Gerraty const br_hash_class *imh;
14240957b409SSimon J. Gerraty size_t mac_key_len, mac_out_len, iv_len;
14250957b409SSimon J. Gerraty
14260957b409SSimon J. Gerraty imh = br_ssl_engine_get_hash(cc, mac_id);
14270957b409SSimon J. Gerraty mac_out_len = (imh->desc >> BR_HASHDESC_OUT_OFF) & BR_HASHDESC_OUT_MASK;
14280957b409SSimon J. Gerraty mac_key_len = mac_out_len;
14290957b409SSimon J. Gerraty
14300957b409SSimon J. Gerraty /*
14310957b409SSimon J. Gerraty * TLS 1.1+ uses per-record explicit IV, so no IV to generate here.
14320957b409SSimon J. Gerraty */
14330957b409SSimon J. Gerraty if (cc->session.version >= BR_TLS11) {
14340957b409SSimon J. Gerraty iv_len = 0;
14350957b409SSimon J. Gerraty } else {
14360957b409SSimon J. Gerraty iv_len = bc_impl->block_size;
14370957b409SSimon J. Gerraty }
14380957b409SSimon J. Gerraty compute_key_block(cc, prf_id,
14390957b409SSimon J. Gerraty mac_key_len + cipher_key_len + iv_len, kb);
14400957b409SSimon J. Gerraty if (is_client) {
14410957b409SSimon J. Gerraty mac_key = &kb[0];
14420957b409SSimon J. Gerraty cipher_key = &kb[mac_key_len << 1];
14430957b409SSimon J. Gerraty iv = &kb[(mac_key_len + cipher_key_len) << 1];
14440957b409SSimon J. Gerraty } else {
14450957b409SSimon J. Gerraty mac_key = &kb[mac_key_len];
14460957b409SSimon J. Gerraty cipher_key = &kb[(mac_key_len << 1) + cipher_key_len];
14470957b409SSimon J. Gerraty iv = &kb[((mac_key_len + cipher_key_len) << 1) + iv_len];
14480957b409SSimon J. Gerraty }
14490957b409SSimon J. Gerraty if (iv_len == 0) {
14500957b409SSimon J. Gerraty iv = NULL;
14510957b409SSimon J. Gerraty }
14520957b409SSimon J. Gerraty cc->icbc_out->init(&cc->out.cbc.vtable,
14530957b409SSimon J. Gerraty bc_impl, cipher_key, cipher_key_len,
14540957b409SSimon J. Gerraty imh, mac_key, mac_key_len, mac_out_len, iv);
14550957b409SSimon J. Gerraty }
14560957b409SSimon J. Gerraty
14570957b409SSimon J. Gerraty /* see inner.h */
14580957b409SSimon J. Gerraty void
br_ssl_engine_switch_gcm_in(br_ssl_engine_context * cc,int is_client,int prf_id,const br_block_ctr_class * bc_impl,size_t cipher_key_len)14590957b409SSimon J. Gerraty br_ssl_engine_switch_gcm_in(br_ssl_engine_context *cc,
14600957b409SSimon J. Gerraty int is_client, int prf_id,
14610957b409SSimon J. Gerraty const br_block_ctr_class *bc_impl, size_t cipher_key_len)
14620957b409SSimon J. Gerraty {
14630957b409SSimon J. Gerraty unsigned char kb[72];
14640957b409SSimon J. Gerraty unsigned char *cipher_key, *iv;
14650957b409SSimon J. Gerraty
14660957b409SSimon J. Gerraty compute_key_block(cc, prf_id, cipher_key_len + 4, kb);
14670957b409SSimon J. Gerraty if (is_client) {
14680957b409SSimon J. Gerraty cipher_key = &kb[cipher_key_len];
14690957b409SSimon J. Gerraty iv = &kb[(cipher_key_len << 1) + 4];
14700957b409SSimon J. Gerraty } else {
14710957b409SSimon J. Gerraty cipher_key = &kb[0];
14720957b409SSimon J. Gerraty iv = &kb[cipher_key_len << 1];
14730957b409SSimon J. Gerraty }
14740957b409SSimon J. Gerraty cc->igcm_in->init(&cc->in.gcm.vtable.in,
14750957b409SSimon J. Gerraty bc_impl, cipher_key, cipher_key_len, cc->ighash, iv);
14760957b409SSimon J. Gerraty cc->incrypt = 1;
14770957b409SSimon J. Gerraty }
14780957b409SSimon J. Gerraty
14790957b409SSimon J. Gerraty /* see inner.h */
14800957b409SSimon J. Gerraty void
br_ssl_engine_switch_gcm_out(br_ssl_engine_context * cc,int is_client,int prf_id,const br_block_ctr_class * bc_impl,size_t cipher_key_len)14810957b409SSimon J. Gerraty br_ssl_engine_switch_gcm_out(br_ssl_engine_context *cc,
14820957b409SSimon J. Gerraty int is_client, int prf_id,
14830957b409SSimon J. Gerraty const br_block_ctr_class *bc_impl, size_t cipher_key_len)
14840957b409SSimon J. Gerraty {
14850957b409SSimon J. Gerraty unsigned char kb[72];
14860957b409SSimon J. Gerraty unsigned char *cipher_key, *iv;
14870957b409SSimon J. Gerraty
14880957b409SSimon J. Gerraty compute_key_block(cc, prf_id, cipher_key_len + 4, kb);
14890957b409SSimon J. Gerraty if (is_client) {
14900957b409SSimon J. Gerraty cipher_key = &kb[0];
14910957b409SSimon J. Gerraty iv = &kb[cipher_key_len << 1];
14920957b409SSimon J. Gerraty } else {
14930957b409SSimon J. Gerraty cipher_key = &kb[cipher_key_len];
14940957b409SSimon J. Gerraty iv = &kb[(cipher_key_len << 1) + 4];
14950957b409SSimon J. Gerraty }
14960957b409SSimon J. Gerraty cc->igcm_out->init(&cc->out.gcm.vtable.out,
14970957b409SSimon J. Gerraty bc_impl, cipher_key, cipher_key_len, cc->ighash, iv);
14980957b409SSimon J. Gerraty }
14990957b409SSimon J. Gerraty
15000957b409SSimon J. Gerraty /* see inner.h */
15010957b409SSimon J. Gerraty void
br_ssl_engine_switch_chapol_in(br_ssl_engine_context * cc,int is_client,int prf_id)15020957b409SSimon J. Gerraty br_ssl_engine_switch_chapol_in(br_ssl_engine_context *cc,
15030957b409SSimon J. Gerraty int is_client, int prf_id)
15040957b409SSimon J. Gerraty {
15050957b409SSimon J. Gerraty unsigned char kb[88];
15060957b409SSimon J. Gerraty unsigned char *cipher_key, *iv;
15070957b409SSimon J. Gerraty
15080957b409SSimon J. Gerraty compute_key_block(cc, prf_id, 44, kb);
15090957b409SSimon J. Gerraty if (is_client) {
15100957b409SSimon J. Gerraty cipher_key = &kb[32];
15110957b409SSimon J. Gerraty iv = &kb[76];
15120957b409SSimon J. Gerraty } else {
15130957b409SSimon J. Gerraty cipher_key = &kb[0];
15140957b409SSimon J. Gerraty iv = &kb[64];
15150957b409SSimon J. Gerraty }
15160957b409SSimon J. Gerraty cc->ichapol_in->init(&cc->in.chapol.vtable.in,
15170957b409SSimon J. Gerraty cc->ichacha, cc->ipoly, cipher_key, iv);
15180957b409SSimon J. Gerraty cc->incrypt = 1;
15190957b409SSimon J. Gerraty }
15200957b409SSimon J. Gerraty
15210957b409SSimon J. Gerraty /* see inner.h */
15220957b409SSimon J. Gerraty void
br_ssl_engine_switch_chapol_out(br_ssl_engine_context * cc,int is_client,int prf_id)15230957b409SSimon J. Gerraty br_ssl_engine_switch_chapol_out(br_ssl_engine_context *cc,
15240957b409SSimon J. Gerraty int is_client, int prf_id)
15250957b409SSimon J. Gerraty {
15260957b409SSimon J. Gerraty unsigned char kb[88];
15270957b409SSimon J. Gerraty unsigned char *cipher_key, *iv;
15280957b409SSimon J. Gerraty
15290957b409SSimon J. Gerraty compute_key_block(cc, prf_id, 44, kb);
15300957b409SSimon J. Gerraty if (is_client) {
15310957b409SSimon J. Gerraty cipher_key = &kb[0];
15320957b409SSimon J. Gerraty iv = &kb[64];
15330957b409SSimon J. Gerraty } else {
15340957b409SSimon J. Gerraty cipher_key = &kb[32];
15350957b409SSimon J. Gerraty iv = &kb[76];
15360957b409SSimon J. Gerraty }
15370957b409SSimon J. Gerraty cc->ichapol_out->init(&cc->out.chapol.vtable.out,
15380957b409SSimon J. Gerraty cc->ichacha, cc->ipoly, cipher_key, iv);
15390957b409SSimon J. Gerraty }
15400957b409SSimon J. Gerraty
15410957b409SSimon J. Gerraty /* see inner.h */
15420957b409SSimon J. Gerraty void
br_ssl_engine_switch_ccm_in(br_ssl_engine_context * cc,int is_client,int prf_id,const br_block_ctrcbc_class * bc_impl,size_t cipher_key_len,size_t tag_len)15430957b409SSimon J. Gerraty br_ssl_engine_switch_ccm_in(br_ssl_engine_context *cc,
15440957b409SSimon J. Gerraty int is_client, int prf_id,
15450957b409SSimon J. Gerraty const br_block_ctrcbc_class *bc_impl,
15460957b409SSimon J. Gerraty size_t cipher_key_len, size_t tag_len)
15470957b409SSimon J. Gerraty {
15480957b409SSimon J. Gerraty unsigned char kb[72];
15490957b409SSimon J. Gerraty unsigned char *cipher_key, *iv;
15500957b409SSimon J. Gerraty
15510957b409SSimon J. Gerraty compute_key_block(cc, prf_id, cipher_key_len + 4, kb);
15520957b409SSimon J. Gerraty if (is_client) {
15530957b409SSimon J. Gerraty cipher_key = &kb[cipher_key_len];
15540957b409SSimon J. Gerraty iv = &kb[(cipher_key_len << 1) + 4];
15550957b409SSimon J. Gerraty } else {
15560957b409SSimon J. Gerraty cipher_key = &kb[0];
15570957b409SSimon J. Gerraty iv = &kb[cipher_key_len << 1];
15580957b409SSimon J. Gerraty }
15590957b409SSimon J. Gerraty cc->iccm_in->init(&cc->in.ccm.vtable.in,
15600957b409SSimon J. Gerraty bc_impl, cipher_key, cipher_key_len, iv, tag_len);
15610957b409SSimon J. Gerraty cc->incrypt = 1;
15620957b409SSimon J. Gerraty }
15630957b409SSimon J. Gerraty
15640957b409SSimon J. Gerraty /* see inner.h */
15650957b409SSimon J. Gerraty void
br_ssl_engine_switch_ccm_out(br_ssl_engine_context * cc,int is_client,int prf_id,const br_block_ctrcbc_class * bc_impl,size_t cipher_key_len,size_t tag_len)15660957b409SSimon J. Gerraty br_ssl_engine_switch_ccm_out(br_ssl_engine_context *cc,
15670957b409SSimon J. Gerraty int is_client, int prf_id,
15680957b409SSimon J. Gerraty const br_block_ctrcbc_class *bc_impl,
15690957b409SSimon J. Gerraty size_t cipher_key_len, size_t tag_len)
15700957b409SSimon J. Gerraty {
15710957b409SSimon J. Gerraty unsigned char kb[72];
15720957b409SSimon J. Gerraty unsigned char *cipher_key, *iv;
15730957b409SSimon J. Gerraty
15740957b409SSimon J. Gerraty compute_key_block(cc, prf_id, cipher_key_len + 4, kb);
15750957b409SSimon J. Gerraty if (is_client) {
15760957b409SSimon J. Gerraty cipher_key = &kb[0];
15770957b409SSimon J. Gerraty iv = &kb[cipher_key_len << 1];
15780957b409SSimon J. Gerraty } else {
15790957b409SSimon J. Gerraty cipher_key = &kb[cipher_key_len];
15800957b409SSimon J. Gerraty iv = &kb[(cipher_key_len << 1) + 4];
15810957b409SSimon J. Gerraty }
15820957b409SSimon J. Gerraty cc->iccm_out->init(&cc->out.ccm.vtable.out,
15830957b409SSimon J. Gerraty bc_impl, cipher_key, cipher_key_len, iv, tag_len);
15840957b409SSimon J. Gerraty }
1585