Home | History | Annotate | Line # | Download | only in methods
      1 /*
      2  * Copyright 2022-2023 The OpenSSL Project Authors. All Rights Reserved.
      3  *
      4  * Licensed under the Apache License 2.0 (the "License").  You may not use
      5  * this file except in compliance with the License.  You can obtain a copy
      6  * in the file LICENSE in the source distribution or at
      7  * https://www.openssl.org/source/license.html
      8  */
      9 
     10 #include "../../ssl_local.h"
     11 #include "../record_local.h"
     12 #include "recmethod_local.h"
     13 
     14 #if defined(OPENSSL_SMALL_FOOTPRINT) \
     15     || !(defined(AES_ASM) && (defined(__x86_64) || defined(__x86_64__) || defined(_M_AMD64) || defined(_M_X64)))
     16 #undef EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK
     17 #define EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK 0
     18 #endif
     19 
     20 static int tls_is_multiblock_capable(OSSL_RECORD_LAYER *rl, uint8_t type,
     21     size_t len, size_t fraglen)
     22 {
     23 #if !defined(OPENSSL_NO_MULTIBLOCK) && EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK
     24     if (type == SSL3_RT_APPLICATION_DATA
     25         && len >= 4 * fraglen
     26         && rl->compctx == NULL
     27         && rl->msg_callback == NULL
     28         && !rl->use_etm
     29         && RLAYER_USE_EXPLICIT_IV(rl)
     30         && !BIO_get_ktls_send(rl->bio)
     31         && (EVP_CIPHER_get_flags(EVP_CIPHER_CTX_get0_cipher(rl->enc_ctx))
     32                & EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK)
     33             != 0)
     34         return 1;
     35 #endif
     36     return 0;
     37 }
     38 
     39 size_t tls_get_max_records_multiblock(OSSL_RECORD_LAYER *rl, uint8_t type,
     40     size_t len, size_t maxfrag,
     41     size_t *preffrag)
     42 {
     43     if (tls_is_multiblock_capable(rl, type, len, *preffrag)) {
     44         /* minimize address aliasing conflicts */
     45         if ((*preffrag & 0xfff) == 0)
     46             *preffrag -= 512;
     47 
     48         if (len >= 8 * (*preffrag))
     49             return 8;
     50 
     51         return 4;
     52     }
     53 
     54     return tls_get_max_records_default(rl, type, len, maxfrag, preffrag);
     55 }
     56 
     57 /*
     58  * Write records using the multiblock method.
     59  *
     60  * Returns 1 on success, 0 if multiblock isn't suitable (non-fatal error), or
     61  * -1 on fatal error.
     62  */
     63 static int tls_write_records_multiblock_int(OSSL_RECORD_LAYER *rl,
     64     OSSL_RECORD_TEMPLATE *templates,
     65     size_t numtempl)
     66 {
     67 #if !defined(OPENSSL_NO_MULTIBLOCK) && EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK
     68     size_t i;
     69     size_t totlen;
     70     TLS_BUFFER *wb;
     71     unsigned char aad[13];
     72     EVP_CTRL_TLS1_1_MULTIBLOCK_PARAM mb_param;
     73     size_t packlen;
     74     int packleni;
     75 
     76     if (numtempl != 4 && numtempl != 8)
     77         return 0;
     78 
     79     /*
     80      * Check templates have contiguous buffers and are all the same type and
     81      * length
     82      */
     83     for (i = 1; i < numtempl; i++) {
     84         if (templates[i - 1].type != templates[i].type
     85             || templates[i - 1].buflen != templates[i].buflen
     86             || templates[i - 1].buf + templates[i - 1].buflen
     87                 != templates[i].buf)
     88             return 0;
     89     }
     90 
     91     totlen = templates[0].buflen * numtempl;
     92     if (!tls_is_multiblock_capable(rl, templates[0].type, totlen,
     93             templates[0].buflen))
     94         return 0;
     95 
     96     /*
     97      * If we get this far, then multiblock is suitable
     98      * Depending on platform multi-block can deliver several *times*
     99      * better performance. Downside is that it has to allocate
    100      * jumbo buffer to accommodate up to 8 records, but the
    101      * compromise is considered worthy.
    102      */
    103 
    104     /*
    105      * Allocate jumbo buffer. This will get freed next time we do a non
    106      * multiblock write in the call to tls_setup_write_buffer() - the different
    107      * buffer sizes will be spotted and the buffer reallocated.
    108      */
    109     packlen = EVP_CIPHER_CTX_ctrl(rl->enc_ctx,
    110         EVP_CTRL_TLS1_1_MULTIBLOCK_MAX_BUFSIZE,
    111         (int)templates[0].buflen, NULL);
    112     packlen *= numtempl;
    113     if (!tls_setup_write_buffer(rl, 1, packlen, packlen)) {
    114         /* RLAYERfatal() already called */
    115         return -1;
    116     }
    117     wb = &rl->wbuf[0];
    118 
    119     mb_param.interleave = numtempl;
    120     memcpy(aad, rl->sequence, 8);
    121     aad[8] = templates[0].type;
    122     aad[9] = (unsigned char)(templates[0].version >> 8);
    123     aad[10] = (unsigned char)(templates[0].version);
    124     aad[11] = 0;
    125     aad[12] = 0;
    126     mb_param.out = NULL;
    127     mb_param.inp = aad;
    128     mb_param.len = totlen;
    129 
    130     packleni = EVP_CIPHER_CTX_ctrl(rl->enc_ctx,
    131         EVP_CTRL_TLS1_1_MULTIBLOCK_AAD,
    132         sizeof(mb_param), &mb_param);
    133     packlen = (size_t)packleni;
    134     if (packleni <= 0 || packlen > wb->len) { /* never happens */
    135         RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
    136         return -1;
    137     }
    138 
    139     mb_param.out = wb->buf;
    140     mb_param.inp = templates[0].buf;
    141     mb_param.len = totlen;
    142 
    143     if (EVP_CIPHER_CTX_ctrl(rl->enc_ctx,
    144             EVP_CTRL_TLS1_1_MULTIBLOCK_ENCRYPT,
    145             sizeof(mb_param), &mb_param)
    146         <= 0) {
    147         RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
    148         return -1;
    149     }
    150 
    151     rl->sequence[7] += mb_param.interleave;
    152     if (rl->sequence[7] < mb_param.interleave) {
    153         int j = 6;
    154         while (j >= 0 && (++rl->sequence[j--]) == 0)
    155             ;
    156     }
    157 
    158     wb->offset = 0;
    159     wb->left = packlen;
    160 
    161     return 1;
    162 #else /* !defined(OPENSSL_NO_MULTIBLOCK) && EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK */
    163     return 0;
    164 #endif
    165 }
    166 
    167 int tls_write_records_multiblock(OSSL_RECORD_LAYER *rl,
    168     OSSL_RECORD_TEMPLATE *templates,
    169     size_t numtempl)
    170 {
    171     int ret;
    172 
    173     ret = tls_write_records_multiblock_int(rl, templates, numtempl);
    174     if (ret < 0) {
    175         /* RLAYERfatal already called */
    176         return 0;
    177     }
    178     if (ret == 0) {
    179         /* Multiblock wasn't suitable so just do a standard write */
    180         if (!tls_write_records_default(rl, templates, numtempl)) {
    181             /* RLAYERfatal already called */
    182             return 0;
    183         }
    184     }
    185 
    186     return 1;
    187 }
    188