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