diff options
Diffstat (limited to 'crypto/openssl/ssl/record/methods/tls_multib.c')
| -rw-r--r-- | crypto/openssl/ssl/record/methods/tls_multib.c | 187 | 
1 files changed, 187 insertions, 0 deletions
| diff --git a/crypto/openssl/ssl/record/methods/tls_multib.c b/crypto/openssl/ssl/record/methods/tls_multib.c new file mode 100644 index 000000000000..3c2c30ef162a --- /dev/null +++ b/crypto/openssl/ssl/record/methods/tls_multib.c @@ -0,0 +1,187 @@ +/* + * Copyright 2022-2023 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License").  You may not use + * this file except in compliance with the License.  You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include "../../ssl_local.h" +#include "../record_local.h" +#include "recmethod_local.h" + +#if defined(OPENSSL_SMALL_FOOTPRINT) \ +    || !(defined(AES_ASM) && (defined(__x86_64) \ +                              || defined(__x86_64__) \ +                              || defined(_M_AMD64) \ +                              || defined(_M_X64))) +# undef EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK +# define EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK 0 +#endif + +static int tls_is_multiblock_capable(OSSL_RECORD_LAYER *rl, uint8_t type, +                                     size_t len, size_t fraglen) +{ +#if !defined(OPENSSL_NO_MULTIBLOCK) && EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK +    if (type == SSL3_RT_APPLICATION_DATA +            && len >= 4 * fraglen +            && rl->compctx == NULL +            && rl->msg_callback == NULL +            && !rl->use_etm +            && RLAYER_USE_EXPLICIT_IV(rl) +            && !BIO_get_ktls_send(rl->bio) +            && (EVP_CIPHER_get_flags(EVP_CIPHER_CTX_get0_cipher(rl->enc_ctx)) +                & EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK) != 0) +        return 1; +#endif +    return 0; +} + +size_t tls_get_max_records_multiblock(OSSL_RECORD_LAYER *rl, uint8_t type, +                                      size_t len, size_t maxfrag, +                                      size_t *preffrag) +{ +    if (tls_is_multiblock_capable(rl, type, len, *preffrag)) { +        /* minimize address aliasing conflicts */ +        if ((*preffrag & 0xfff) == 0) +            *preffrag -= 512; + +        if (len >= 8 * (*preffrag)) +            return 8; + +        return 4; +    } + +    return tls_get_max_records_default(rl, type, len, maxfrag, preffrag); +} + +/* + * Write records using the multiblock method. + * + * Returns 1 on success, 0 if multiblock isn't suitable (non-fatal error), or + * -1 on fatal error. + */ +static int tls_write_records_multiblock_int(OSSL_RECORD_LAYER *rl, +                                            OSSL_RECORD_TEMPLATE *templates, +                                            size_t numtempl) +{ +#if !defined(OPENSSL_NO_MULTIBLOCK) && EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK +    size_t i; +    size_t totlen; +    TLS_BUFFER *wb; +    unsigned char aad[13]; +    EVP_CTRL_TLS1_1_MULTIBLOCK_PARAM mb_param; +    size_t packlen; +    int packleni; + +    if (numtempl != 4 && numtempl != 8) +        return 0; + +    /* +     * Check templates have contiguous buffers and are all the same type and +     * length +     */ +    for (i = 1; i < numtempl; i++) { +        if (templates[i - 1].type != templates[i].type +                || templates[i - 1].buflen != templates[i].buflen +                || templates[i - 1].buf + templates[i - 1].buflen +                   != templates[i].buf) +            return 0; +    } + +    totlen = templates[0].buflen * numtempl; +    if (!tls_is_multiblock_capable(rl, templates[0].type, totlen, +                                   templates[0].buflen)) +        return 0; + +    /* +     * If we get this far, then multiblock is suitable +     * Depending on platform multi-block can deliver several *times* +     * better performance. Downside is that it has to allocate +     * jumbo buffer to accommodate up to 8 records, but the +     * compromise is considered worthy. +     */ + +    /* +     * Allocate jumbo buffer. This will get freed next time we do a non +     * multiblock write in the call to tls_setup_write_buffer() - the different +     * buffer sizes will be spotted and the buffer reallocated. +     */ +    packlen = EVP_CIPHER_CTX_ctrl(rl->enc_ctx, +                                  EVP_CTRL_TLS1_1_MULTIBLOCK_MAX_BUFSIZE, +                                  (int)templates[0].buflen, NULL); +    packlen *= numtempl; +    if (!tls_setup_write_buffer(rl, 1, packlen, packlen)) { +        /* RLAYERfatal() already called */ +        return -1; +    } +    wb = &rl->wbuf[0]; + +    mb_param.interleave = numtempl; +    memcpy(aad, rl->sequence, 8); +    aad[8] = templates[0].type; +    aad[9] = (unsigned char)(templates[0].version >> 8); +    aad[10] = (unsigned char)(templates[0].version); +    aad[11] = 0; +    aad[12] = 0; +    mb_param.out = NULL; +    mb_param.inp = aad; +    mb_param.len = totlen; + +    packleni = EVP_CIPHER_CTX_ctrl(rl->enc_ctx, +                                   EVP_CTRL_TLS1_1_MULTIBLOCK_AAD, +                                   sizeof(mb_param), &mb_param); +    packlen = (size_t)packleni; +    if (packleni <= 0 || packlen > wb->len) { /* never happens */ +        RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); +        return -1; +    } + +    mb_param.out = wb->buf; +    mb_param.inp = templates[0].buf; +    mb_param.len = totlen; + +    if (EVP_CIPHER_CTX_ctrl(rl->enc_ctx, +                            EVP_CTRL_TLS1_1_MULTIBLOCK_ENCRYPT, +                            sizeof(mb_param), &mb_param) <= 0) { +        RLAYERfatal(rl, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); +        return -1; +    } + +    rl->sequence[7] += mb_param.interleave; +    if (rl->sequence[7] < mb_param.interleave) { +        int j = 6; +        while (j >= 0 && (++rl->sequence[j--]) == 0) ; +    } + +    wb->offset = 0; +    wb->left = packlen; + +    return 1; +#else  /* !defined(OPENSSL_NO_MULTIBLOCK) && EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK */ +    return 0; +#endif +} + +int tls_write_records_multiblock(OSSL_RECORD_LAYER *rl, +                                 OSSL_RECORD_TEMPLATE *templates, +                                 size_t numtempl) +{ +    int ret; + +    ret = tls_write_records_multiblock_int(rl, templates, numtempl); +    if (ret < 0) { +        /* RLAYERfatal already called */ +        return 0; +    } +    if (ret == 0) { +        /* Multiblock wasn't suitable so just do a standard write */ +        if (!tls_write_records_default(rl, templates, numtempl)) { +            /* RLAYERfatal already called */ +            return 0; +        } +    } + +    return 1; +} | 
