1*e0c4386eSCy Schubert /*
2*e0c4386eSCy Schubert  * Copyright 2021 The OpenSSL Project Authors. All Rights Reserved.
3*e0c4386eSCy Schubert  *
4*e0c4386eSCy Schubert  * Licensed under the Apache License 2.0 (the "License").  You may not use
5*e0c4386eSCy Schubert  * this file except in compliance with the License.  You can obtain a copy
6*e0c4386eSCy Schubert  * in the file LICENSE in the source distribution or at
7*e0c4386eSCy Schubert  * https://www.openssl.org/source/license.html
8*e0c4386eSCy Schubert  */
9*e0c4386eSCy Schubert 
10*e0c4386eSCy Schubert #include <openssl/bio.h>
11*e0c4386eSCy Schubert #include "testutil.h"
12*e0c4386eSCy Schubert 
13*e0c4386eSCy Schubert static const char *filename = NULL;
14*e0c4386eSCy Schubert 
15*e0c4386eSCy Schubert /*
16*e0c4386eSCy Schubert  * Test that a BIO_f_readbuffer() with a BIO_new_file() behaves nicely if
17*e0c4386eSCy Schubert  * BIO_gets() and BIO_read_ex() are both called.
18*e0c4386eSCy Schubert  * Since the BIO_gets() calls buffer the reads, the BIO_read_ex() should
19*e0c4386eSCy Schubert  * still be able to read the buffered data if we seek back to the start.
20*e0c4386eSCy Schubert  *
21*e0c4386eSCy Schubert  * The following cases are tested using tstid:
22*e0c4386eSCy Schubert  * 0 : Just use BIO_read_ex().
23*e0c4386eSCy Schubert  * 1 : Try a few reads using BIO_gets() before using BIO_read_ex()
24*e0c4386eSCy Schubert  * 2 : Read the entire file using BIO_gets() before using BIO_read_ex().
25*e0c4386eSCy Schubert  */
test_readbuffer_file_bio(int tstid)26*e0c4386eSCy Schubert static int test_readbuffer_file_bio(int tstid)
27*e0c4386eSCy Schubert {
28*e0c4386eSCy Schubert     int ret = 0, len, partial;
29*e0c4386eSCy Schubert     BIO *in = NULL, *in_bio = NULL, *readbuf_bio = NULL;
30*e0c4386eSCy Schubert     char buf[255];
31*e0c4386eSCy Schubert     char expected[4096];
32*e0c4386eSCy Schubert     size_t readbytes = 0, bytes = 0, count = 0;
33*e0c4386eSCy Schubert 
34*e0c4386eSCy Schubert     /* Open a file BIO and read all the data */
35*e0c4386eSCy Schubert     if (!TEST_ptr(in = BIO_new_file(filename, "r"))
36*e0c4386eSCy Schubert         || !TEST_int_eq(BIO_read_ex(in, expected, sizeof(expected),
37*e0c4386eSCy Schubert                                     &readbytes), 1)
38*e0c4386eSCy Schubert         || !TEST_int_lt(readbytes, sizeof(expected)))
39*e0c4386eSCy Schubert         goto err;
40*e0c4386eSCy Schubert     BIO_free(in);
41*e0c4386eSCy Schubert     in = NULL;
42*e0c4386eSCy Schubert 
43*e0c4386eSCy Schubert     /* Create a new file bio that sits under a readbuffer BIO */
44*e0c4386eSCy Schubert     if (!TEST_ptr(readbuf_bio = BIO_new(BIO_f_readbuffer()))
45*e0c4386eSCy Schubert         || !TEST_ptr(in_bio = BIO_new_file(filename, "r")))
46*e0c4386eSCy Schubert         goto err;
47*e0c4386eSCy Schubert 
48*e0c4386eSCy Schubert     in_bio = BIO_push(readbuf_bio, in_bio);
49*e0c4386eSCy Schubert     readbuf_bio = NULL;
50*e0c4386eSCy Schubert 
51*e0c4386eSCy Schubert     if (!TEST_int_eq(BIO_tell(in_bio), 0))
52*e0c4386eSCy Schubert         goto err;
53*e0c4386eSCy Schubert 
54*e0c4386eSCy Schubert     if (tstid != 0) {
55*e0c4386eSCy Schubert         partial = 4;
56*e0c4386eSCy Schubert         while (!BIO_eof(in_bio)) {
57*e0c4386eSCy Schubert             len = BIO_gets(in_bio, buf, sizeof(buf));
58*e0c4386eSCy Schubert             if (len == 0) {
59*e0c4386eSCy Schubert                 if (!TEST_true(BIO_eof(in_bio)))
60*e0c4386eSCy Schubert                     goto err;
61*e0c4386eSCy Schubert             } else {
62*e0c4386eSCy Schubert                 if (!TEST_int_gt(len, 0)
63*e0c4386eSCy Schubert                     || !TEST_int_le(len, (int)sizeof(buf) - 1))
64*e0c4386eSCy Schubert                     goto err;
65*e0c4386eSCy Schubert                 if (!TEST_true(buf[len] == 0))
66*e0c4386eSCy Schubert                     goto err;
67*e0c4386eSCy Schubert                 if (len > 1
68*e0c4386eSCy Schubert                     && !BIO_eof(in_bio)
69*e0c4386eSCy Schubert                     && len != ((int)sizeof(buf) - 1)
70*e0c4386eSCy Schubert                     && !TEST_true(buf[len - 1] == '\n'))
71*e0c4386eSCy Schubert                     goto err;
72*e0c4386eSCy Schubert             }
73*e0c4386eSCy Schubert             if (tstid == 1 && --partial == 0)
74*e0c4386eSCy Schubert                 break;
75*e0c4386eSCy Schubert         }
76*e0c4386eSCy Schubert     }
77*e0c4386eSCy Schubert     if (!TEST_int_eq(BIO_seek(in_bio, 0), 1))
78*e0c4386eSCy Schubert         goto err;
79*e0c4386eSCy Schubert 
80*e0c4386eSCy Schubert     len = 8; /* Do a small partial read to start with */
81*e0c4386eSCy Schubert     while (!BIO_eof(in_bio)) {
82*e0c4386eSCy Schubert         if (!TEST_int_eq(BIO_read_ex(in_bio, buf, len, &bytes), 1))
83*e0c4386eSCy Schubert             break;
84*e0c4386eSCy Schubert         if (!TEST_mem_eq(buf, bytes, expected + count, bytes))
85*e0c4386eSCy Schubert             goto err;
86*e0c4386eSCy Schubert         count += bytes;
87*e0c4386eSCy Schubert         len = sizeof(buf); /* fill the buffer on subsequent reads */
88*e0c4386eSCy Schubert     }
89*e0c4386eSCy Schubert     if (!TEST_int_eq(count, readbytes))
90*e0c4386eSCy Schubert         goto err;
91*e0c4386eSCy Schubert     ret = 1;
92*e0c4386eSCy Schubert err:
93*e0c4386eSCy Schubert     BIO_free(in);
94*e0c4386eSCy Schubert     BIO_free_all(in_bio);
95*e0c4386eSCy Schubert     BIO_free(readbuf_bio);
96*e0c4386eSCy Schubert     return ret;
97*e0c4386eSCy Schubert }
98*e0c4386eSCy Schubert 
99*e0c4386eSCy Schubert typedef enum OPTION_choice {
100*e0c4386eSCy Schubert     OPT_ERR = -1,
101*e0c4386eSCy Schubert     OPT_EOF = 0,
102*e0c4386eSCy Schubert     OPT_TEST_ENUM
103*e0c4386eSCy Schubert } OPTION_CHOICE;
104*e0c4386eSCy Schubert 
test_get_options(void)105*e0c4386eSCy Schubert const OPTIONS *test_get_options(void)
106*e0c4386eSCy Schubert {
107*e0c4386eSCy Schubert     static const OPTIONS test_options[] = {
108*e0c4386eSCy Schubert         OPT_TEST_OPTIONS_WITH_EXTRA_USAGE("file\n"),
109*e0c4386eSCy Schubert         { OPT_HELP_STR, 1, '-', "file\tFile to run tests on.\n" },
110*e0c4386eSCy Schubert         { NULL }
111*e0c4386eSCy Schubert     };
112*e0c4386eSCy Schubert     return test_options;
113*e0c4386eSCy Schubert }
114*e0c4386eSCy Schubert 
setup_tests(void)115*e0c4386eSCy Schubert int setup_tests(void)
116*e0c4386eSCy Schubert {
117*e0c4386eSCy Schubert     OPTION_CHOICE o;
118*e0c4386eSCy Schubert 
119*e0c4386eSCy Schubert     while ((o = opt_next()) != OPT_EOF) {
120*e0c4386eSCy Schubert         switch (o) {
121*e0c4386eSCy Schubert         case OPT_TEST_CASES:
122*e0c4386eSCy Schubert             break;
123*e0c4386eSCy Schubert         default:
124*e0c4386eSCy Schubert             return 0;
125*e0c4386eSCy Schubert         }
126*e0c4386eSCy Schubert     }
127*e0c4386eSCy Schubert     filename = test_get_argument(0);
128*e0c4386eSCy Schubert 
129*e0c4386eSCy Schubert     ADD_ALL_TESTS(test_readbuffer_file_bio, 3);
130*e0c4386eSCy Schubert     return 1;
131*e0c4386eSCy Schubert }
132