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