xref: /src/crypto/openssl/test/sslbuffertest.c (revision f25b8c9fb4f58cf61adb47d7570abe7caa6d385d)
1 /*
2  * Copyright 2016-2025 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the Apache License 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  * https://www.openssl.org/source/license.html
8  * or in the file LICENSE in the source distribution.
9  */
10 
11 /*
12  * We need access to the deprecated low level Engine APIs for legacy purposes
13  * when the deprecated calls are not hidden
14  */
15 #ifndef OPENSSL_NO_DEPRECATED_3_0
16 #define OPENSSL_SUPPRESS_DEPRECATED
17 #endif
18 
19 #include <string.h>
20 #include <openssl/ssl.h>
21 #include <openssl/bio.h>
22 #include <openssl/err.h>
23 #include <openssl/engine.h>
24 
25 #ifndef OPENSSL_NO_QUIC
26 /* This test does not link libssl so avoid pulling in QUIC unwrappers. */
27 #define OPENSSL_NO_QUIC
28 #endif
29 
30 /* We include internal headers so we can check if the buffers are allocated */
31 #include "../ssl/ssl_local.h"
32 #include "../ssl/record/record_local.h"
33 #include "internal/recordmethod.h"
34 #include "../ssl/record/methods/recmethod_local.h"
35 #include "internal/ssl_unwrap.h"
36 
37 #include "internal/packet.h"
38 
39 #include "helpers/ssltestlib.h"
40 #include "testutil.h"
41 
42 struct async_ctrs {
43     unsigned int rctr;
44     unsigned int wctr;
45 };
46 
47 static SSL_CTX *serverctx = NULL;
48 static SSL_CTX *clientctx = NULL;
49 
50 #define MAX_ATTEMPTS 100
51 
checkbuffers(SSL * s,int isalloced)52 static int checkbuffers(SSL *s, int isalloced)
53 {
54     SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
55     OSSL_RECORD_LAYER *rrl = sc->rlayer.rrl;
56     OSSL_RECORD_LAYER *wrl = sc->rlayer.wrl;
57 
58     if (isalloced)
59         return rrl->rbuf.buf != NULL && wrl->wbuf[0].buf != NULL;
60 
61     return rrl->rbuf.buf == NULL && wrl->wbuf[0].buf == NULL;
62 }
63 
64 /*
65  * There are 9 passes in the tests
66  * 0 = control test
67  * tests during writes
68  * 1 = free buffers
69  * 2 = + allocate buffers after free
70  * 3 = + allocate buffers again
71  * 4 = + free buffers after allocation
72  * tests during reads
73  * 5 = + free buffers
74  * 6 = + free buffers again
75  * 7 = + allocate buffers after free
76  * 8 = + free buffers after allocation
77  */
test_func(int test)78 static int test_func(int test)
79 {
80     int result = 0;
81     SSL *serverssl = NULL, *clientssl = NULL;
82     int ret;
83     size_t i, j;
84     const char testdata[] = "Test data";
85     char buf[sizeof(testdata)];
86 
87     if (!TEST_true(create_ssl_objects(serverctx, clientctx, &serverssl, &clientssl,
88             NULL, NULL))) {
89         TEST_error("Test %d failed: Create SSL objects failed\n", test);
90         goto end;
91     }
92 
93     if (!TEST_true(create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE))) {
94         TEST_error("Test %d failed: Create SSL connection failed\n", test);
95         goto end;
96     }
97 
98     /*
99      * Send and receive some test data. Do the whole thing twice to ensure
100      * we hit at least one async event in both reading and writing
101      */
102     for (j = 0; j < 2; j++) {
103         int len;
104 
105         /*
106 
107          * Write some test data. It should never take more than 2 attempts
108          * (the first one might be a retryable fail).
109          */
110         for (ret = -1, i = 0, len = 0; len != sizeof(testdata) && i < 2;
111             i++) {
112             /* test == 0 mean to free/allocate = control */
113             if (test >= 1 && (!TEST_true(SSL_free_buffers(clientssl)) || !TEST_true(checkbuffers(clientssl, 0))))
114                 goto end;
115             if (test >= 2 && (!TEST_true(SSL_alloc_buffers(clientssl)) || !TEST_true(checkbuffers(clientssl, 1))))
116                 goto end;
117             /* allocate a second time */
118             if (test >= 3 && (!TEST_true(SSL_alloc_buffers(clientssl)) || !TEST_true(checkbuffers(clientssl, 1))))
119                 goto end;
120             if (test >= 4 && (!TEST_true(SSL_free_buffers(clientssl)) || !TEST_true(checkbuffers(clientssl, 0))))
121                 goto end;
122 
123             ret = SSL_write(clientssl, testdata + len,
124                 sizeof(testdata) - len);
125             if (ret > 0) {
126                 len += ret;
127             } else {
128                 int ssl_error = SSL_get_error(clientssl, ret);
129 
130                 if (ssl_error == SSL_ERROR_SYSCALL || ssl_error == SSL_ERROR_SSL) {
131                     TEST_error("Test %d failed: Failed to write app data\n", test);
132                     goto end;
133                 }
134             }
135         }
136         if (!TEST_size_t_eq(len, sizeof(testdata)))
137             goto end;
138         /*
139          * Now read the test data. It may take more attempts here because
140          * it could fail once for each byte read, including all overhead
141          * bytes from the record header/padding etc.
142          */
143         for (ret = -1, i = 0, len = 0; len != sizeof(testdata) && i < MAX_ATTEMPTS; i++) {
144             if (test >= 5 && (!TEST_true(SSL_free_buffers(serverssl)) || !TEST_true(checkbuffers(serverssl, 0))))
145                 goto end;
146             /* free a second time */
147             if (test >= 6 && (!TEST_true(SSL_free_buffers(serverssl)) || !TEST_true(checkbuffers(serverssl, 0))))
148                 goto end;
149             if (test >= 7 && (!TEST_true(SSL_alloc_buffers(serverssl)) || !TEST_true(checkbuffers(serverssl, 1))))
150                 goto end;
151             if (test >= 8 && (!TEST_true(SSL_free_buffers(serverssl)) || !TEST_true(checkbuffers(serverssl, 0))))
152                 goto end;
153 
154             ret = SSL_read(serverssl, buf + len, sizeof(buf) - len);
155             if (ret > 0) {
156                 len += ret;
157             } else {
158                 int ssl_error = SSL_get_error(serverssl, ret);
159 
160                 if (ssl_error == SSL_ERROR_SYSCALL || ssl_error == SSL_ERROR_SSL) {
161                     TEST_error("Test %d failed: Failed to read app data\n", test);
162                     goto end;
163                 }
164             }
165         }
166         if (!TEST_mem_eq(buf, len, testdata, sizeof(testdata)))
167             goto end;
168     }
169 
170     result = 1;
171 end:
172     if (!result)
173         ERR_print_errors_fp(stderr);
174 
175     SSL_free(clientssl);
176     SSL_free(serverssl);
177 
178     return result;
179 }
180 
181 /*
182  * Test that attempting to free the buffers at points where they cannot be freed
183  * works as expected
184  * Test 0: Attempt to free buffers after a full record has been processed, but
185  *         the application has only performed a partial read
186  * Test 1: Attempt to free buffers after only a partial record header has been
187  *         received
188  * Test 2: Attempt to free buffers after a full record header but no record body
189  * Test 3: Attempt to free buffers after a full record hedaer and partial record
190  *         body
191  * Test 4-7: We repeat tests 0-3 but including data from a second pipelined
192  *           record
193  */
test_free_buffers(int test)194 static int test_free_buffers(int test)
195 {
196     int result = 0;
197     SSL *serverssl = NULL, *clientssl = NULL;
198     const char testdata[] = "Test data";
199     char buf[120];
200     size_t written, readbytes;
201     int i, pipeline = test > 3;
202     ENGINE *e = NULL;
203 
204     if (pipeline) {
205         e = load_dasync();
206         if (e == NULL)
207             goto end;
208         test -= 4;
209     }
210 
211     if (!TEST_true(create_ssl_objects(serverctx, clientctx, &serverssl,
212             &clientssl, NULL, NULL)))
213         goto end;
214 
215     if (pipeline) {
216         if (!TEST_true(SSL_set_cipher_list(serverssl, "AES128-SHA"))
217             || !TEST_true(SSL_set_max_proto_version(serverssl,
218                 TLS1_2_VERSION))
219             || !TEST_true(SSL_set_max_pipelines(serverssl, 2)))
220             goto end;
221     }
222 
223     if (!TEST_true(create_ssl_connection(serverssl, clientssl,
224             SSL_ERROR_NONE)))
225         goto end;
226 
227     /*
228      * For the non-pipeline case we write one record. For pipelining we write
229      * two records.
230      */
231     for (i = 0; i <= pipeline; i++) {
232         if (!TEST_true(SSL_write_ex(clientssl, testdata, strlen(testdata),
233                 &written)))
234             goto end;
235     }
236 
237     if (test == 0) {
238         size_t readlen = 1;
239 
240         /*
241          * Deliberately only read the first byte - so the remaining bytes are
242          * still buffered. In the pipelining case we read as far as the first
243          * byte from the second record.
244          */
245         if (pipeline)
246             readlen += strlen(testdata);
247 
248         if (!TEST_true(SSL_read_ex(serverssl, buf, readlen, &readbytes))
249             || !TEST_size_t_eq(readlen, readbytes))
250             goto end;
251     } else {
252         BIO *tmp;
253         size_t partial_len;
254 
255         /* Remove all the data that is pending for read by the server */
256         tmp = SSL_get_rbio(serverssl);
257         if (!TEST_true(BIO_read_ex(tmp, buf, sizeof(buf), &readbytes))
258             || !TEST_size_t_lt(readbytes, sizeof(buf))
259             || !TEST_size_t_gt(readbytes, SSL3_RT_HEADER_LENGTH))
260             goto end;
261 
262         switch (test) {
263         case 1:
264             partial_len = SSL3_RT_HEADER_LENGTH - 1;
265             break;
266         case 2:
267             partial_len = SSL3_RT_HEADER_LENGTH;
268             break;
269         case 3:
270             partial_len = readbytes - 1;
271             break;
272         default:
273             TEST_error("Invalid test index");
274             goto end;
275         }
276 
277         if (pipeline) {
278             /* We happen to know the first record is 57 bytes long */
279             const size_t first_rec_len = 57;
280 
281             if (test != 3)
282                 partial_len += first_rec_len;
283 
284             /*
285              * Sanity check. If we got the record len right then this should
286              * never fail.
287              */
288             if (!TEST_int_eq(buf[first_rec_len], SSL3_RT_APPLICATION_DATA))
289                 goto end;
290         }
291 
292         /*
293          * Put back just the partial record (plus the whole initial record in
294          * the pipelining case)
295          */
296         if (!TEST_true(BIO_write_ex(tmp, buf, partial_len, &written)))
297             goto end;
298 
299         if (pipeline) {
300             /*
301              * Attempt a read. This should pass but only return data from the
302              * first record. Only a partial record is available for the second
303              * record.
304              */
305             if (!TEST_true(SSL_read_ex(serverssl, buf, sizeof(buf),
306                     &readbytes))
307                 || !TEST_size_t_eq(readbytes, strlen(testdata)))
308                 goto end;
309         } else {
310             /*
311              * Attempt a read. This should fail because only a partial record is
312              * available.
313              */
314             if (!TEST_false(SSL_read_ex(serverssl, buf, sizeof(buf),
315                     &readbytes)))
316                 goto end;
317         }
318     }
319 
320     /*
321      * Attempting to free the buffers at this point should fail because they are
322      * still in use
323      */
324     if (!TEST_false(SSL_free_buffers(serverssl)))
325         goto end;
326 
327     result = 1;
328 end:
329     SSL_free(clientssl);
330     SSL_free(serverssl);
331 #ifndef OPENSSL_NO_DYNAMIC_ENGINE
332     if (e != NULL) {
333         ENGINE_unregister_ciphers(e);
334         ENGINE_finish(e);
335         ENGINE_free(e);
336     }
337 #endif
338     return result;
339 }
340 
341 OPT_TEST_DECLARE_USAGE("certfile privkeyfile\n")
342 
setup_tests(void)343 int setup_tests(void)
344 {
345     char *cert, *pkey;
346 
347     if (!test_skip_common_options()) {
348         TEST_error("Error parsing test options\n");
349         return 0;
350     }
351 
352     if (!TEST_ptr(cert = test_get_argument(0))
353         || !TEST_ptr(pkey = test_get_argument(1)))
354         return 0;
355 
356     if (!create_ssl_ctx_pair(NULL, TLS_server_method(), TLS_client_method(),
357             TLS1_VERSION, 0,
358             &serverctx, &clientctx, cert, pkey)) {
359         TEST_error("Failed to create SSL_CTX pair\n");
360         return 0;
361     }
362 
363     ADD_ALL_TESTS(test_func, 9);
364 #if !defined(OPENSSL_NO_TLS1_2) && !defined(OPENSSL_NO_DYNAMIC_ENGINE)
365     ADD_ALL_TESTS(test_free_buffers, 8);
366 #else
367     ADD_ALL_TESTS(test_free_buffers, 4);
368 #endif
369     return 1;
370 }
371 
cleanup_tests(void)372 void cleanup_tests(void)
373 {
374     SSL_CTX_free(clientctx);
375     SSL_CTX_free(serverctx);
376 }
377