]>
Commit | Line | Data |
---|---|---|
bafe524b | 1 | /* |
da1c088f | 2 | * Copyright 2022-2023 The OpenSSL Project Authors. All Rights Reserved. |
bafe524b MC |
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) \ | |
16 | || defined(__x86_64__) \ | |
17 | || defined(_M_AMD64) \ | |
18 | || defined(_M_X64))) | |
19 | # undef EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK | |
20 | # define EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK 0 | |
21 | #endif | |
22 | ||
eb1eaa9a | 23 | static int tls_is_multiblock_capable(OSSL_RECORD_LAYER *rl, uint8_t type, |
bafe524b MC |
24 | size_t len, size_t fraglen) |
25 | { | |
26 | #if !defined(OPENSSL_NO_MULTIBLOCK) && EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK | |
bafe524b MC |
27 | if (type == SSL3_RT_APPLICATION_DATA |
28 | && len >= 4 * fraglen | |
9251c3c4 | 29 | && rl->compctx == NULL |
bafe524b MC |
30 | && rl->msg_callback == NULL |
31 | && !rl->use_etm | |
32 | && RLAYER_USE_EXPLICIT_IV(rl) | |
9251c3c4 MC |
33 | && !BIO_get_ktls_send(rl->bio) |
34 | && (EVP_CIPHER_get_flags(EVP_CIPHER_CTX_get0_cipher(rl->enc_ctx)) | |
bafe524b MC |
35 | & EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK) != 0) |
36 | return 1; | |
37 | #endif | |
38 | return 0; | |
39 | } | |
40 | ||
eb1eaa9a | 41 | size_t tls_get_max_records_multiblock(OSSL_RECORD_LAYER *rl, uint8_t type, |
bafe524b MC |
42 | size_t len, size_t maxfrag, |
43 | size_t *preffrag) | |
44 | { | |
45 | if (tls_is_multiblock_capable(rl, type, len, *preffrag)) { | |
46 | /* minimize address aliasing conflicts */ | |
47 | if ((*preffrag & 0xfff) == 0) | |
48 | *preffrag -= 512; | |
49 | ||
50 | if (len >= 8 * (*preffrag)) | |
51 | return 8; | |
52 | ||
53 | return 4; | |
54 | } | |
55 | ||
56 | return tls_get_max_records_default(rl, type, len, maxfrag, preffrag); | |
57 | } | |
58 | ||
59 | /* | |
60 | * Write records using the multiblock method. | |
61 | * | |
62 | * Returns 1 on success, 0 if multiblock isn't suitable (non-fatal error), or | |
63 | * -1 on fatal error. | |
64 | */ | |
65 | static int tls_write_records_multiblock_int(OSSL_RECORD_LAYER *rl, | |
66 | OSSL_RECORD_TEMPLATE *templates, | |
67 | size_t numtempl) | |
68 | { | |
69 | #if !defined(OPENSSL_NO_MULTIBLOCK) && EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK | |
70 | size_t i; | |
71 | size_t totlen; | |
e9189cc4 | 72 | TLS_BUFFER *wb; |
bafe524b MC |
73 | unsigned char aad[13]; |
74 | EVP_CTRL_TLS1_1_MULTIBLOCK_PARAM mb_param; | |
75 | size_t packlen; | |
76 | int packleni; | |
77 | ||
78 | if (numtempl != 4 && numtempl != 8) | |
79 | return 0; | |
80 | ||
81 | /* | |
82 | * Check templates have contiguous buffers and are all the same type and | |
83 | * length | |
84 | */ | |
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 | |
89 | != templates[i].buf) | |
90 | return 0; | |
91 | } | |
92 | ||
93 | totlen = templates[0].buflen * numtempl; | |
94 | if (!tls_is_multiblock_capable(rl, templates[0].type, totlen, | |
95 | templates[0].buflen)) | |
96 | return 0; | |
97 | ||
98 | /* | |
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. | |
104 | */ | |
105 | ||
106 | /* | |
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. | |
110 | */ | |
9251c3c4 MC |
111 | packlen = EVP_CIPHER_CTX_ctrl(rl->enc_ctx, |
112 | EVP_CTRL_TLS1_1_MULTIBLOCK_MAX_BUFSIZE, | |
113 | (int)templates[0].buflen, NULL); | |
bafe524b MC |
114 | packlen *= numtempl; |
115 | if (!tls_setup_write_buffer(rl, 1, packlen, packlen)) { | |
116 | /* RLAYERfatal() already called */ | |
117 | return -1; | |
118 | } | |
119 | wb = &rl->wbuf[0]; | |
120 | ||
121 | mb_param.interleave = numtempl; | |
9251c3c4 | 122 | memcpy(aad, rl->sequence, 8); |
bafe524b MC |
123 | aad[8] = templates[0].type; |
124 | aad[9] = (unsigned char)(templates[0].version >> 8); | |
125 | aad[10] = (unsigned char)(templates[0].version); | |
126 | aad[11] = 0; | |
127 | aad[12] = 0; | |
128 | mb_param.out = NULL; | |
129 | mb_param.inp = aad; | |
130 | mb_param.len = totlen; | |
131 | ||
9251c3c4 MC |
132 | packleni = EVP_CIPHER_CTX_ctrl(rl->enc_ctx, |
133 | EVP_CTRL_TLS1_1_MULTIBLOCK_AAD, | |
134 | sizeof(mb_param), &mb_param); | |
bafe524b MC |
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); | |
138 | return -1; | |
139 | } | |
140 | ||
141 | mb_param.out = wb->buf; | |
142 | mb_param.inp = templates[0].buf; | |
143 | mb_param.len = totlen; | |
144 | ||
9251c3c4 | 145 | if (EVP_CIPHER_CTX_ctrl(rl->enc_ctx, |
bafe524b MC |
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); | |
149 | return -1; | |
150 | } | |
151 | ||
9251c3c4 MC |
152 | rl->sequence[7] += mb_param.interleave; |
153 | if (rl->sequence[7] < mb_param.interleave) { | |
bafe524b | 154 | int j = 6; |
9251c3c4 | 155 | while (j >= 0 && (++rl->sequence[j--]) == 0) ; |
bafe524b MC |
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 | } |