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
tls_is_multiblock_capable(OSSL_RECORD_LAYER * rl,uint8_t type,size_t len,size_t fraglen)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
tls_get_max_records_multiblock(OSSL_RECORD_LAYER * rl,uint8_t type,size_t len,size_t maxfrag,size_t * preffrag)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 */
tls_write_records_multiblock_int(OSSL_RECORD_LAYER * rl,OSSL_RECORD_TEMPLATE * templates,size_t numtempl)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
tls_write_records_multiblock(OSSL_RECORD_LAYER * rl,OSSL_RECORD_TEMPLATE * templates,size_t numtempl)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