2 * Copyright 2022 The OpenSSL Project Authors. All Rights Reserved.
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
10 #include "../../ssl_local.h"
11 #include "../record_local.h"
12 #include "recmethod_local.h"
14 #if defined(OPENSSL_SMALL_FOOTPRINT) \
15 || !(defined(AES_ASM) && (defined(__x86_64) \
16 || defined(__x86_64__) \
17 || defined(_M_AMD64) \
19 # undef EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK
20 # define EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK 0
23 static int tls_is_multiblock_capable(OSSL_RECORD_LAYER
*rl
, uint8_t type
,
24 size_t len
, size_t fraglen
)
26 #if !defined(OPENSSL_NO_MULTIBLOCK) && EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK
27 if (type
== SSL3_RT_APPLICATION_DATA
29 && rl
->compctx
== NULL
30 && rl
->msg_callback
== NULL
32 && RLAYER_USE_EXPLICIT_IV(rl
)
33 && !BIO_get_ktls_send(rl
->bio
)
34 && (EVP_CIPHER_get_flags(EVP_CIPHER_CTX_get0_cipher(rl
->enc_ctx
))
35 & EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK
) != 0)
41 size_t tls_get_max_records_multiblock(OSSL_RECORD_LAYER
*rl
, uint8_t type
,
42 size_t len
, size_t maxfrag
,
45 if (tls_is_multiblock_capable(rl
, type
, len
, *preffrag
)) {
46 /* minimize address aliasing conflicts */
47 if ((*preffrag
& 0xfff) == 0)
50 if (len
>= 8 * (*preffrag
))
56 return tls_get_max_records_default(rl
, type
, len
, maxfrag
, preffrag
);
60 * Write records using the multiblock method.
62 * Returns 1 on success, 0 if multiblock isn't suitable (non-fatal error), or
65 static int tls_write_records_multiblock_int(OSSL_RECORD_LAYER
*rl
,
66 OSSL_RECORD_TEMPLATE
*templates
,
69 #if !defined(OPENSSL_NO_MULTIBLOCK) && EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK
73 unsigned char aad
[13];
74 EVP_CTRL_TLS1_1_MULTIBLOCK_PARAM mb_param
;
78 if (numtempl
!= 4 && numtempl
!= 8)
82 * Check templates have contiguous buffers and are all the same type and
85 for (i
= 1; i
< numtempl
; i
++) {
86 if (templates
[i
- 1].type
!= templates
[i
].type
87 || templates
[i
- 1].buflen
!= templates
[i
].buflen
88 || templates
[i
- 1].buf
+ templates
[i
- 1].buflen
93 totlen
= templates
[0].buflen
* numtempl
;
94 if (!tls_is_multiblock_capable(rl
, templates
[0].type
, totlen
,
99 * If we get this far, then multiblock is suitable
100 * Depending on platform multi-block can deliver several *times*
101 * better performance. Downside is that it has to allocate
102 * jumbo buffer to accommodate up to 8 records, but the
103 * compromise is considered worthy.
107 * Allocate jumbo buffer. This will get freed next time we do a non
108 * multiblock write in the call to tls_setup_write_buffer() - the different
109 * buffer sizes will be spotted and the buffer reallocated.
111 packlen
= EVP_CIPHER_CTX_ctrl(rl
->enc_ctx
,
112 EVP_CTRL_TLS1_1_MULTIBLOCK_MAX_BUFSIZE
,
113 (int)templates
[0].buflen
, NULL
);
115 if (!tls_setup_write_buffer(rl
, 1, packlen
, packlen
)) {
116 /* RLAYERfatal() already called */
121 mb_param
.interleave
= numtempl
;
122 memcpy(aad
, rl
->sequence
, 8);
123 aad
[8] = templates
[0].type
;
124 aad
[9] = (unsigned char)(templates
[0].version
>> 8);
125 aad
[10] = (unsigned char)(templates
[0].version
);
130 mb_param
.len
= totlen
;
132 packleni
= EVP_CIPHER_CTX_ctrl(rl
->enc_ctx
,
133 EVP_CTRL_TLS1_1_MULTIBLOCK_AAD
,
134 sizeof(mb_param
), &mb_param
);
135 packlen
= (size_t)packleni
;
136 if (packleni
<= 0 || packlen
> wb
->len
) { /* never happens */
137 RLAYERfatal(rl
, SSL_AD_INTERNAL_ERROR
, ERR_R_INTERNAL_ERROR
);
141 mb_param
.out
= wb
->buf
;
142 mb_param
.inp
= templates
[0].buf
;
143 mb_param
.len
= totlen
;
145 if (EVP_CIPHER_CTX_ctrl(rl
->enc_ctx
,
146 EVP_CTRL_TLS1_1_MULTIBLOCK_ENCRYPT
,
147 sizeof(mb_param
), &mb_param
) <= 0) {
148 RLAYERfatal(rl
, SSL_AD_INTERNAL_ERROR
, ERR_R_INTERNAL_ERROR
);
152 rl
->sequence
[7] += mb_param
.interleave
;
153 if (rl
->sequence
[7] < mb_param
.interleave
) {
155 while (j
>= 0 && (++rl
->sequence
[j
--]) == 0) ;
162 #else /* !defined(OPENSSL_NO_MULTIBLOCK) && EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK */
167 int tls_write_records_multiblock(OSSL_RECORD_LAYER
*rl
,
168 OSSL_RECORD_TEMPLATE
*templates
,
173 ret
= tls_write_records_multiblock_int(rl
, templates
, numtempl
);
175 /* RLAYERfatal already called */
179 /* Multiblock wasn't suitable so just do a standard write */
180 if (!tls_write_records_default(rl
, templates
, numtempl
)) {
181 /* RLAYERfatal already called */