xref: /freebsd/crypto/openssl/test/sslbuffertest.c (revision e7be843b4a162e68651d3911f0357ed464915629)
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))
114                               || !TEST_true(checkbuffers(clientssl, 0))))
115                 goto end;
116             if (test >= 2 && (!TEST_true(SSL_alloc_buffers(clientssl))
117                               || !TEST_true(checkbuffers(clientssl, 1))))
118                 goto end;
119             /* allocate a second time */
120             if (test >= 3 && (!TEST_true(SSL_alloc_buffers(clientssl))
121                               || !TEST_true(checkbuffers(clientssl, 1))))
122                 goto end;
123             if (test >= 4 && (!TEST_true(SSL_free_buffers(clientssl))
124                               || !TEST_true(checkbuffers(clientssl, 0))))
125                 goto end;
126 
127             ret = SSL_write(clientssl, testdata + len,
128                             sizeof(testdata) - len);
129             if (ret > 0) {
130                 len += ret;
131             } else {
132                 int ssl_error = SSL_get_error(clientssl, ret);
133 
134                 if (ssl_error == SSL_ERROR_SYSCALL ||
135                     ssl_error == SSL_ERROR_SSL) {
136                     TEST_error("Test %d failed: Failed to write app data\n", test);
137                     goto end;
138                 }
139             }
140         }
141         if (!TEST_size_t_eq(len, sizeof(testdata)))
142             goto end;
143         /*
144          * Now read the test data. It may take more attempts here because
145          * it could fail once for each byte read, including all overhead
146          * bytes from the record header/padding etc.
147          */
148         for (ret = -1, i = 0, len = 0; len != sizeof(testdata) &&
149                                        i < MAX_ATTEMPTS; i++) {
150             if (test >= 5 && (!TEST_true(SSL_free_buffers(serverssl))
151                               || !TEST_true(checkbuffers(serverssl, 0))))
152                 goto end;
153             /* free a second time */
154             if (test >= 6 && (!TEST_true(SSL_free_buffers(serverssl))
155                               || !TEST_true(checkbuffers(serverssl, 0))))
156                 goto end;
157             if (test >= 7 && (!TEST_true(SSL_alloc_buffers(serverssl))
158                               || !TEST_true(checkbuffers(serverssl, 1))))
159                 goto end;
160             if (test >= 8 && (!TEST_true(SSL_free_buffers(serverssl))
161                               || !TEST_true(checkbuffers(serverssl, 0))))
162                 goto end;
163 
164             ret = SSL_read(serverssl, buf + len, sizeof(buf) - len);
165             if (ret > 0) {
166                 len += ret;
167             } else {
168                 int ssl_error = SSL_get_error(serverssl, ret);
169 
170                 if (ssl_error == SSL_ERROR_SYSCALL ||
171                     ssl_error == SSL_ERROR_SSL) {
172                     TEST_error("Test %d failed: Failed to read app data\n", test);
173                     goto end;
174                 }
175             }
176         }
177         if (!TEST_mem_eq(buf, len, testdata, sizeof(testdata)))
178             goto end;
179     }
180 
181     result = 1;
182  end:
183     if (!result)
184         ERR_print_errors_fp(stderr);
185 
186     SSL_free(clientssl);
187     SSL_free(serverssl);
188 
189     return result;
190 }
191 
192 /*
193  * Test that attempting to free the buffers at points where they cannot be freed
194  * works as expected
195  * Test 0: Attempt to free buffers after a full record has been processed, but
196  *         the application has only performed a partial read
197  * Test 1: Attempt to free buffers after only a partial record header has been
198  *         received
199  * Test 2: Attempt to free buffers after a full record header but no record body
200  * Test 3: Attempt to free buffers after a full record hedaer and partial record
201  *         body
202  * Test 4-7: We repeat tests 0-3 but including data from a second pipelined
203  *           record
204  */
test_free_buffers(int test)205 static int test_free_buffers(int test)
206 {
207     int result = 0;
208     SSL *serverssl = NULL, *clientssl = NULL;
209     const char testdata[] = "Test data";
210     char buf[120];
211     size_t written, readbytes;
212     int i, pipeline = test > 3;
213     ENGINE *e = NULL;
214 
215     if (pipeline) {
216         e = load_dasync();
217         if (e == NULL)
218             goto end;
219         test -= 4;
220     }
221 
222     if (!TEST_true(create_ssl_objects(serverctx, clientctx, &serverssl,
223                                       &clientssl, NULL, NULL)))
224         goto end;
225 
226     if (pipeline) {
227         if (!TEST_true(SSL_set_cipher_list(serverssl, "AES128-SHA"))
228                 || !TEST_true(SSL_set_max_proto_version(serverssl,
229                                                         TLS1_2_VERSION))
230                 || !TEST_true(SSL_set_max_pipelines(serverssl, 2)))
231             goto end;
232     }
233 
234     if (!TEST_true(create_ssl_connection(serverssl, clientssl,
235                                          SSL_ERROR_NONE)))
236         goto end;
237 
238     /*
239      * For the non-pipeline case we write one record. For pipelining we write
240      * two records.
241      */
242     for (i = 0; i <= pipeline; i++) {
243         if (!TEST_true(SSL_write_ex(clientssl, testdata, strlen(testdata),
244                                     &written)))
245             goto end;
246     }
247 
248     if (test == 0) {
249         size_t readlen = 1;
250 
251         /*
252          * Deliberately only read the first byte - so the remaining bytes are
253          * still buffered. In the pipelining case we read as far as the first
254          * byte from the second record.
255          */
256         if (pipeline)
257             readlen += strlen(testdata);
258 
259         if (!TEST_true(SSL_read_ex(serverssl, buf, readlen, &readbytes))
260                 || !TEST_size_t_eq(readlen, readbytes))
261             goto end;
262     } else {
263         BIO *tmp;
264         size_t partial_len;
265 
266         /* Remove all the data that is pending for read by the server */
267         tmp = SSL_get_rbio(serverssl);
268         if (!TEST_true(BIO_read_ex(tmp, buf, sizeof(buf), &readbytes))
269                 || !TEST_size_t_lt(readbytes, sizeof(buf))
270                 || !TEST_size_t_gt(readbytes, SSL3_RT_HEADER_LENGTH))
271             goto end;
272 
273         switch(test) {
274         case 1:
275             partial_len = SSL3_RT_HEADER_LENGTH - 1;
276             break;
277         case 2:
278             partial_len = SSL3_RT_HEADER_LENGTH;
279             break;
280         case 3:
281             partial_len = readbytes - 1;
282             break;
283         default:
284             TEST_error("Invalid test index");
285             goto end;
286         }
287 
288         if (pipeline) {
289             /* We happen to know the first record is 57 bytes long */
290             const size_t first_rec_len = 57;
291 
292             if (test != 3)
293                 partial_len += first_rec_len;
294 
295             /*
296              * Sanity check. If we got the record len right then this should
297              * never fail.
298              */
299             if (!TEST_int_eq(buf[first_rec_len], SSL3_RT_APPLICATION_DATA))
300                 goto end;
301         }
302 
303         /*
304          * Put back just the partial record (plus the whole initial record in
305          * the pipelining case)
306          */
307         if (!TEST_true(BIO_write_ex(tmp, buf, partial_len, &written)))
308             goto end;
309 
310         if (pipeline) {
311             /*
312              * Attempt a read. This should pass but only return data from the
313              * first record. Only a partial record is available for the second
314              * record.
315              */
316             if (!TEST_true(SSL_read_ex(serverssl, buf, sizeof(buf),
317                                         &readbytes))
318                     || !TEST_size_t_eq(readbytes, strlen(testdata)))
319                 goto end;
320         } else {
321             /*
322             * Attempt a read. This should fail because only a partial record is
323             * available.
324             */
325             if (!TEST_false(SSL_read_ex(serverssl, buf, sizeof(buf),
326                                         &readbytes)))
327                 goto end;
328         }
329     }
330 
331     /*
332      * Attempting to free the buffers at this point should fail because they are
333      * still in use
334      */
335     if (!TEST_false(SSL_free_buffers(serverssl)))
336         goto end;
337 
338     result = 1;
339  end:
340     SSL_free(clientssl);
341     SSL_free(serverssl);
342 #ifndef OPENSSL_NO_DYNAMIC_ENGINE
343     if (e != NULL) {
344         ENGINE_unregister_ciphers(e);
345         ENGINE_finish(e);
346         ENGINE_free(e);
347     }
348 #endif
349     return result;
350 }
351 
352 OPT_TEST_DECLARE_USAGE("certfile privkeyfile\n")
353 
setup_tests(void)354 int setup_tests(void)
355 {
356     char *cert, *pkey;
357 
358     if (!test_skip_common_options()) {
359         TEST_error("Error parsing test options\n");
360         return 0;
361     }
362 
363     if (!TEST_ptr(cert = test_get_argument(0))
364             || !TEST_ptr(pkey = test_get_argument(1)))
365         return 0;
366 
367     if (!create_ssl_ctx_pair(NULL, TLS_server_method(), TLS_client_method(),
368                              TLS1_VERSION, 0,
369                              &serverctx, &clientctx, cert, pkey)) {
370         TEST_error("Failed to create SSL_CTX pair\n");
371         return 0;
372     }
373 
374     ADD_ALL_TESTS(test_func, 9);
375 #if !defined(OPENSSL_NO_TLS1_2) && !defined(OPENSSL_NO_DYNAMIC_ENGINE)
376     ADD_ALL_TESTS(test_free_buffers, 8);
377 #else
378     ADD_ALL_TESTS(test_free_buffers, 4);
379 #endif
380     return 1;
381 }
382 
cleanup_tests(void)383 void cleanup_tests(void)
384 {
385     SSL_CTX_free(clientctx);
386     SSL_CTX_free(serverctx);
387 }
388