| 
									
										
										
										
											2021-03-18 13:00:23 +08:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2025-09-02 21:05:45 +08:00
										 |  |  |  * Copyright 2021-2025 The OpenSSL Project Authors. All Rights Reserved. | 
					
						
							| 
									
										
										
										
											2021-03-18 13:00:23 +08:00
										 |  |  |  * | 
					
						
							|  |  |  |  * Licensed under the Apache License 2.0 (the "License").  You may not use | 
					
						
							|  |  |  |  * this file except in compliance with the License.  You can obtain a copy | 
					
						
							|  |  |  |  * in the file LICENSE in the source distribution or at | 
					
						
							|  |  |  |  * https://www.openssl.org/source/license.html
 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <openssl/bio.h>
 | 
					
						
							|  |  |  | #include "testutil.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const char *filename = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Test that a BIO_f_readbuffer() with a BIO_new_file() behaves nicely if | 
					
						
							|  |  |  |  * BIO_gets() and BIO_read_ex() are both called. | 
					
						
							|  |  |  |  * Since the BIO_gets() calls buffer the reads, the BIO_read_ex() should | 
					
						
							|  |  |  |  * still be able to read the buffered data if we seek back to the start. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * The following cases are tested using tstid: | 
					
						
							|  |  |  |  * 0 : Just use BIO_read_ex(). | 
					
						
							|  |  |  |  * 1 : Try a few reads using BIO_gets() before using BIO_read_ex() | 
					
						
							|  |  |  |  * 2 : Read the entire file using BIO_gets() before using BIO_read_ex(). | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int test_readbuffer_file_bio(int tstid) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int ret = 0, len, partial; | 
					
						
							|  |  |  |     BIO *in = NULL, *in_bio = NULL, *readbuf_bio = NULL; | 
					
						
							|  |  |  |     char buf[255]; | 
					
						
							|  |  |  |     char expected[4096]; | 
					
						
							|  |  |  |     size_t readbytes = 0, bytes = 0, count = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Open a file BIO and read all the data */ | 
					
						
							|  |  |  |     if (!TEST_ptr(in = BIO_new_file(filename, "r")) | 
					
						
							|  |  |  |         || !TEST_int_eq(BIO_read_ex(in, expected, sizeof(expected), | 
					
						
							|  |  |  |                                     &readbytes), 1) | 
					
						
							| 
									
										
										
										
											2025-06-18 17:59:04 +08:00
										 |  |  |         || !TEST_size_t_lt(readbytes, sizeof(expected))) | 
					
						
							| 
									
										
										
										
											2021-03-18 13:00:23 +08:00
										 |  |  |         goto err; | 
					
						
							|  |  |  |     BIO_free(in); | 
					
						
							|  |  |  |     in = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Create a new file bio that sits under a readbuffer BIO */ | 
					
						
							|  |  |  |     if (!TEST_ptr(readbuf_bio = BIO_new(BIO_f_readbuffer())) | 
					
						
							|  |  |  |         || !TEST_ptr(in_bio = BIO_new_file(filename, "r"))) | 
					
						
							|  |  |  |         goto err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     in_bio = BIO_push(readbuf_bio, in_bio); | 
					
						
							|  |  |  |     readbuf_bio = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!TEST_int_eq(BIO_tell(in_bio), 0)) | 
					
						
							|  |  |  |         goto err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (tstid != 0) { | 
					
						
							|  |  |  |         partial = 4; | 
					
						
							|  |  |  |         while (!BIO_eof(in_bio)) { | 
					
						
							|  |  |  |             len = BIO_gets(in_bio, buf, sizeof(buf)); | 
					
						
							|  |  |  |             if (len == 0) { | 
					
						
							|  |  |  |                 if (!TEST_true(BIO_eof(in_bio))) | 
					
						
							|  |  |  |                     goto err; | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 if (!TEST_int_gt(len, 0) | 
					
						
							|  |  |  |                     || !TEST_int_le(len, (int)sizeof(buf) - 1)) | 
					
						
							|  |  |  |                     goto err; | 
					
						
							|  |  |  |                 if (!TEST_true(buf[len] == 0)) | 
					
						
							|  |  |  |                     goto err; | 
					
						
							|  |  |  |                 if (len > 1 | 
					
						
							|  |  |  |                     && !BIO_eof(in_bio) | 
					
						
							|  |  |  |                     && len != ((int)sizeof(buf) - 1) | 
					
						
							|  |  |  |                     && !TEST_true(buf[len - 1] == '\n')) | 
					
						
							|  |  |  |                     goto err; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             if (tstid == 1 && --partial == 0) | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (!TEST_int_eq(BIO_seek(in_bio, 0), 1)) | 
					
						
							|  |  |  |         goto err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     len = 8; /* Do a small partial read to start with */ | 
					
						
							|  |  |  |     while (!BIO_eof(in_bio)) { | 
					
						
							|  |  |  |         if (!TEST_int_eq(BIO_read_ex(in_bio, buf, len, &bytes), 1)) | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         if (!TEST_mem_eq(buf, bytes, expected + count, bytes)) | 
					
						
							|  |  |  |             goto err; | 
					
						
							|  |  |  |         count += bytes; | 
					
						
							|  |  |  |         len = sizeof(buf); /* fill the buffer on subsequent reads */ | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2025-06-18 17:59:04 +08:00
										 |  |  |     if (!TEST_size_t_eq(count, readbytes)) | 
					
						
							| 
									
										
										
										
											2021-03-18 13:00:23 +08:00
										 |  |  |         goto err; | 
					
						
							|  |  |  |     ret = 1; | 
					
						
							|  |  |  | err: | 
					
						
							|  |  |  |     BIO_free(in); | 
					
						
							|  |  |  |     BIO_free_all(in_bio); | 
					
						
							|  |  |  |     BIO_free(readbuf_bio); | 
					
						
							|  |  |  |     return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | typedef enum OPTION_choice { | 
					
						
							|  |  |  |     OPT_ERR = -1, | 
					
						
							|  |  |  |     OPT_EOF = 0, | 
					
						
							|  |  |  |     OPT_TEST_ENUM | 
					
						
							|  |  |  | } OPTION_CHOICE; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const OPTIONS *test_get_options(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     static const OPTIONS test_options[] = { | 
					
						
							|  |  |  |         OPT_TEST_OPTIONS_WITH_EXTRA_USAGE("file\n"), | 
					
						
							|  |  |  |         { OPT_HELP_STR, 1, '-', "file\tFile to run tests on.\n" }, | 
					
						
							|  |  |  |         { NULL } | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |     return test_options; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int setup_tests(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     OPTION_CHOICE o; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     while ((o = opt_next()) != OPT_EOF) { | 
					
						
							|  |  |  |         switch (o) { | 
					
						
							|  |  |  |         case OPT_TEST_CASES: | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         default: | 
					
						
							|  |  |  |             return 0; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     filename = test_get_argument(0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ADD_ALL_TESTS(test_readbuffer_file_bio, 3); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } |