Path: blob/main/contrib/bearssl/src/ssl/ssl_rec_ccm.c
39488 views
/*1* Copyright (c) 2018 Thomas Pornin <[email protected]>2*3* Permission is hereby granted, free of charge, to any person obtaining4* a copy of this software and associated documentation files (the5* "Software"), to deal in the Software without restriction, including6* without limitation the rights to use, copy, modify, merge, publish,7* distribute, sublicense, and/or sell copies of the Software, and to8* permit persons to whom the Software is furnished to do so, subject to9* the following conditions:10*11* The above copyright notice and this permission notice shall be12* included in all copies or substantial portions of the Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,15* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF16* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND17* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS18* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN19* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN20* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE21* SOFTWARE.22*/2324#include "inner.h"2526/*27* CCM initialisation. This does everything except setting the vtable,28* which depends on whether this is a context for encrypting or for29* decrypting.30*/31static void32gen_ccm_init(br_sslrec_ccm_context *cc,33const br_block_ctrcbc_class *bc_impl,34const void *key, size_t key_len,35const void *iv, size_t tag_len)36{37cc->seq = 0;38bc_impl->init(&cc->bc.vtable, key, key_len);39memcpy(cc->iv, iv, sizeof cc->iv);40cc->tag_len = tag_len;41}4243static void44in_ccm_init(br_sslrec_ccm_context *cc,45const br_block_ctrcbc_class *bc_impl,46const void *key, size_t key_len,47const void *iv, size_t tag_len)48{49cc->vtable.in = &br_sslrec_in_ccm_vtable;50gen_ccm_init(cc, bc_impl, key, key_len, iv, tag_len);51}5253static int54ccm_check_length(const br_sslrec_ccm_context *cc, size_t rlen)55{56/*57* CCM overhead is 8 bytes for nonce_explicit, and the tag58* (normally 8 or 16 bytes, depending on cipher suite).59*/60size_t over;6162over = 8 + cc->tag_len;63return rlen >= over && rlen <= (16384 + over);64}6566static unsigned char *67ccm_decrypt(br_sslrec_ccm_context *cc,68int record_type, unsigned version, void *data, size_t *data_len)69{70br_ccm_context zc;71unsigned char *buf;72unsigned char nonce[12], header[13];73size_t len;7475buf = (unsigned char *)data + 8;76len = *data_len - (8 + cc->tag_len);7778/*79* Make nonce (implicit + explicit parts).80*/81memcpy(nonce, cc->iv, sizeof cc->iv);82memcpy(nonce + 4, data, 8);8384/*85* Assemble synthetic header for the AAD.86*/87br_enc64be(header, cc->seq ++);88header[8] = (unsigned char)record_type;89br_enc16be(header + 9, version);90br_enc16be(header + 11, len);9192/*93* Perform CCM decryption.94*/95br_ccm_init(&zc, &cc->bc.vtable);96br_ccm_reset(&zc, nonce, sizeof nonce, sizeof header, len, cc->tag_len);97br_ccm_aad_inject(&zc, header, sizeof header);98br_ccm_flip(&zc);99br_ccm_run(&zc, 0, buf, len);100if (!br_ccm_check_tag(&zc, buf + len)) {101return NULL;102}103*data_len = len;104return buf;105}106107/* see bearssl_ssl.h */108const br_sslrec_in_ccm_class br_sslrec_in_ccm_vtable = {109{110sizeof(br_sslrec_ccm_context),111(int (*)(const br_sslrec_in_class *const *, size_t))112&ccm_check_length,113(unsigned char *(*)(const br_sslrec_in_class **,114int, unsigned, void *, size_t *))115&ccm_decrypt116},117(void (*)(const br_sslrec_in_ccm_class **,118const br_block_ctrcbc_class *, const void *, size_t,119const void *, size_t))120&in_ccm_init121};122123static void124out_ccm_init(br_sslrec_ccm_context *cc,125const br_block_ctrcbc_class *bc_impl,126const void *key, size_t key_len,127const void *iv, size_t tag_len)128{129cc->vtable.out = &br_sslrec_out_ccm_vtable;130gen_ccm_init(cc, bc_impl, key, key_len, iv, tag_len);131}132133static void134ccm_max_plaintext(const br_sslrec_ccm_context *cc,135size_t *start, size_t *end)136{137size_t len;138139*start += 8;140len = *end - *start - cc->tag_len;141if (len > 16384) {142len = 16384;143}144*end = *start + len;145}146147static unsigned char *148ccm_encrypt(br_sslrec_ccm_context *cc,149int record_type, unsigned version, void *data, size_t *data_len)150{151br_ccm_context zc;152unsigned char *buf;153unsigned char nonce[12], header[13];154size_t len;155156buf = (unsigned char *)data;157len = *data_len;158159/*160* Make nonce; the explicit part is an encoding of the sequence161* number.162*/163memcpy(nonce, cc->iv, sizeof cc->iv);164br_enc64be(nonce + 4, cc->seq);165166/*167* Assemble synthetic header for the AAD.168*/169br_enc64be(header, cc->seq ++);170header[8] = (unsigned char)record_type;171br_enc16be(header + 9, version);172br_enc16be(header + 11, len);173174/*175* Perform CCM encryption.176*/177br_ccm_init(&zc, &cc->bc.vtable);178br_ccm_reset(&zc, nonce, sizeof nonce, sizeof header, len, cc->tag_len);179br_ccm_aad_inject(&zc, header, sizeof header);180br_ccm_flip(&zc);181br_ccm_run(&zc, 1, buf, len);182br_ccm_get_tag(&zc, buf + len);183184/*185* Assemble header and adjust pointer/length.186*/187len += 8 + cc->tag_len;188buf -= 13;189memcpy(buf + 5, nonce + 4, 8);190buf[0] = (unsigned char)record_type;191br_enc16be(buf + 1, version);192br_enc16be(buf + 3, len);193*data_len = len + 5;194return buf;195}196197/* see bearssl_ssl.h */198const br_sslrec_out_ccm_class br_sslrec_out_ccm_vtable = {199{200sizeof(br_sslrec_ccm_context),201(void (*)(const br_sslrec_out_class *const *,202size_t *, size_t *))203&ccm_max_plaintext,204(unsigned char *(*)(const br_sslrec_out_class **,205int, unsigned, void *, size_t *))206&ccm_encrypt207},208(void (*)(const br_sslrec_out_ccm_class **,209const br_block_ctrcbc_class *, const void *, size_t,210const void *, size_t))211&out_ccm_init212};213214215