1 /*
2 * Copyright 2018-2021 The OpenSSL Project Authors. All Rights Reserved.
3 *
4 * Licensed under the Apache License 2.0 (the "License"). You may not use
5 * this file except in compliance with the License. You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
8 */
9 #include <stdio.h>
10 #include <string.h>
11 #include <openssl/buffer.h>
12 #include <openssl/bio.h>
13
14 #include "testutil.h"
15
test_bio_memleak(void)16 static int test_bio_memleak(void)
17 {
18 int ok = 0;
19 BIO *bio;
20 BUF_MEM bufmem;
21 static const char str[] = "BIO test\n";
22 char buf[100];
23
24 bio = BIO_new(BIO_s_mem());
25 if (!TEST_ptr(bio))
26 goto finish;
27 bufmem.length = sizeof(str);
28 bufmem.data = (char *) str;
29 bufmem.max = bufmem.length;
30 BIO_set_mem_buf(bio, &bufmem, BIO_NOCLOSE);
31 BIO_set_flags(bio, BIO_FLAGS_MEM_RDONLY);
32 if (!TEST_int_eq(BIO_read(bio, buf, sizeof(buf)), sizeof(str)))
33 goto finish;
34 if (!TEST_mem_eq(buf, sizeof(str), str, sizeof(str)))
35 goto finish;
36 ok = 1;
37
38 finish:
39 BIO_free(bio);
40 return ok;
41 }
42
test_bio_get_mem(void)43 static int test_bio_get_mem(void)
44 {
45 int ok = 0;
46 BIO *bio = NULL;
47 BUF_MEM *bufmem = NULL;
48
49 bio = BIO_new(BIO_s_mem());
50 if (!TEST_ptr(bio))
51 goto finish;
52 if (!TEST_int_eq(BIO_puts(bio, "Hello World\n"), 12))
53 goto finish;
54 BIO_get_mem_ptr(bio, &bufmem);
55 if (!TEST_ptr(bufmem))
56 goto finish;
57 if (!TEST_int_gt(BIO_set_close(bio, BIO_NOCLOSE), 0))
58 goto finish;
59 BIO_free(bio);
60 bio = NULL;
61 if (!TEST_mem_eq(bufmem->data, bufmem->length, "Hello World\n", 12))
62 goto finish;
63 ok = 1;
64
65 finish:
66 BIO_free(bio);
67 BUF_MEM_free(bufmem);
68 return ok;
69 }
70
test_bio_new_mem_buf(void)71 static int test_bio_new_mem_buf(void)
72 {
73 int ok = 0;
74 BIO *bio;
75 BUF_MEM *bufmem;
76 char data[16];
77
78 bio = BIO_new_mem_buf("Hello World\n", 12);
79 if (!TEST_ptr(bio))
80 goto finish;
81 if (!TEST_int_eq(BIO_read(bio, data, 5), 5))
82 goto finish;
83 if (!TEST_mem_eq(data, 5, "Hello", 5))
84 goto finish;
85 if (!TEST_int_gt(BIO_get_mem_ptr(bio, &bufmem), 0))
86 goto finish;
87 if (!TEST_int_lt(BIO_write(bio, "test", 4), 0))
88 goto finish;
89 if (!TEST_int_eq(BIO_read(bio, data, 16), 7))
90 goto finish;
91 if (!TEST_mem_eq(data, 7, " World\n", 7))
92 goto finish;
93 if (!TEST_int_gt(BIO_reset(bio), 0))
94 goto finish;
95 if (!TEST_int_eq(BIO_read(bio, data, 16), 12))
96 goto finish;
97 if (!TEST_mem_eq(data, 12, "Hello World\n", 12))
98 goto finish;
99 ok = 1;
100
101 finish:
102 BIO_free(bio);
103 return ok;
104 }
105
test_bio_rdonly_mem_buf(void)106 static int test_bio_rdonly_mem_buf(void)
107 {
108 int ok = 0;
109 BIO *bio, *bio2 = NULL;
110 BUF_MEM *bufmem;
111 char data[16];
112
113 bio = BIO_new_mem_buf("Hello World\n", 12);
114 if (!TEST_ptr(bio))
115 goto finish;
116 if (!TEST_int_eq(BIO_read(bio, data, 5), 5))
117 goto finish;
118 if (!TEST_mem_eq(data, 5, "Hello", 5))
119 goto finish;
120 if (!TEST_int_gt(BIO_get_mem_ptr(bio, &bufmem), 0))
121 goto finish;
122 (void)BIO_set_close(bio, BIO_NOCLOSE);
123
124 bio2 = BIO_new(BIO_s_mem());
125 if (!TEST_ptr(bio2))
126 goto finish;
127 BIO_set_mem_buf(bio2, bufmem, BIO_CLOSE);
128 BIO_set_flags(bio2, BIO_FLAGS_MEM_RDONLY);
129
130 if (!TEST_int_eq(BIO_read(bio2, data, 16), 7))
131 goto finish;
132 if (!TEST_mem_eq(data, 7, " World\n", 7))
133 goto finish;
134 if (!TEST_int_gt(BIO_reset(bio2), 0))
135 goto finish;
136 if (!TEST_int_eq(BIO_read(bio2, data, 16), 7))
137 goto finish;
138 if (!TEST_mem_eq(data, 7, " World\n", 7))
139 goto finish;
140 ok = 1;
141
142 finish:
143 BIO_free(bio);
144 BIO_free(bio2);
145 return ok;
146 }
147
test_bio_rdwr_rdonly(void)148 static int test_bio_rdwr_rdonly(void)
149 {
150 int ok = 0;
151 BIO *bio = NULL;
152 char data[16];
153
154 bio = BIO_new(BIO_s_mem());
155 if (!TEST_ptr(bio))
156 goto finish;
157 if (!TEST_int_eq(BIO_puts(bio, "Hello World\n"), 12))
158 goto finish;
159
160 BIO_set_flags(bio, BIO_FLAGS_MEM_RDONLY);
161 if (!TEST_int_eq(BIO_read(bio, data, 16), 12))
162 goto finish;
163 if (!TEST_mem_eq(data, 12, "Hello World\n", 12))
164 goto finish;
165 if (!TEST_int_gt(BIO_reset(bio), 0))
166 goto finish;
167
168 BIO_clear_flags(bio, BIO_FLAGS_MEM_RDONLY);
169 if (!TEST_int_eq(BIO_puts(bio, "Hi!\n"), 4))
170 goto finish;
171 if (!TEST_int_eq(BIO_read(bio, data, 16), 16))
172 goto finish;
173
174 if (!TEST_mem_eq(data, 16, "Hello World\nHi!\n", 16))
175 goto finish;
176
177 ok = 1;
178
179 finish:
180 BIO_free(bio);
181 return ok;
182 }
183
test_bio_nonclear_rst(void)184 static int test_bio_nonclear_rst(void)
185 {
186 int ok = 0;
187 BIO *bio = NULL;
188 char data[16];
189
190 bio = BIO_new(BIO_s_mem());
191 if (!TEST_ptr(bio))
192 goto finish;
193 if (!TEST_int_eq(BIO_puts(bio, "Hello World\n"), 12))
194 goto finish;
195
196 BIO_set_flags(bio, BIO_FLAGS_NONCLEAR_RST);
197
198 if (!TEST_int_eq(BIO_read(bio, data, 16), 12))
199 goto finish;
200 if (!TEST_mem_eq(data, 12, "Hello World\n", 12))
201 goto finish;
202 if (!TEST_int_gt(BIO_reset(bio), 0))
203 goto finish;
204
205 if (!TEST_int_eq(BIO_read(bio, data, 16), 12))
206 goto finish;
207 if (!TEST_mem_eq(data, 12, "Hello World\n", 12))
208 goto finish;
209
210 BIO_clear_flags(bio, BIO_FLAGS_NONCLEAR_RST);
211 if (!TEST_int_gt(BIO_reset(bio), 0))
212 goto finish;
213
214 if (!TEST_int_lt(BIO_read(bio, data, 16), 1))
215 goto finish;
216
217 ok = 1;
218
219 finish:
220 BIO_free(bio);
221 return ok;
222 }
223
224 static int error_callback_fired;
BIO_error_callback(BIO * bio,int cmd,const char * argp,size_t len,int argi,long argl,int ret,size_t * processed)225 static long BIO_error_callback(BIO *bio, int cmd, const char *argp,
226 size_t len, int argi,
227 long argl, int ret, size_t *processed)
228 {
229 if ((cmd & (BIO_CB_READ | BIO_CB_RETURN)) != 0) {
230 error_callback_fired = 1;
231 ret = 0; /* fail for read operations to simulate error in input BIO */
232 }
233 return ret;
234 }
235
236 /* Checks i2d_ASN1_bio_stream() is freeing all memory when input BIO ends unexpectedly. */
test_bio_i2d_ASN1_mime(void)237 static int test_bio_i2d_ASN1_mime(void)
238 {
239 int ok = 0;
240 BIO *bio = NULL, *out = NULL;
241 BUF_MEM bufmem;
242 static const char str[] = "BIO mime test\n";
243 PKCS7 *p7 = NULL;
244
245 if (!TEST_ptr(bio = BIO_new(BIO_s_mem())))
246 goto finish;
247
248 bufmem.length = sizeof(str);
249 bufmem.data = (char *) str;
250 bufmem.max = bufmem.length;
251 BIO_set_mem_buf(bio, &bufmem, BIO_NOCLOSE);
252 BIO_set_flags(bio, BIO_FLAGS_MEM_RDONLY);
253 BIO_set_callback_ex(bio, BIO_error_callback);
254
255 if (!TEST_ptr(out = BIO_new(BIO_s_mem())))
256 goto finish;
257 if (!TEST_ptr(p7 = PKCS7_new()))
258 goto finish;
259 if (!TEST_true(PKCS7_set_type(p7, NID_pkcs7_data)))
260 goto finish;
261
262 error_callback_fired = 0;
263
264 if (!TEST_false(i2d_ASN1_bio_stream(out, (ASN1_VALUE*) p7, bio,
265 SMIME_STREAM | SMIME_BINARY,
266 ASN1_ITEM_rptr(PKCS7))))
267 goto finish;
268
269 if (!TEST_int_eq(error_callback_fired, 1))
270 goto finish;
271
272 ok = 1;
273
274 finish:
275 BIO_free(bio);
276 BIO_free(out);
277 PKCS7_free(p7);
278 return ok;
279 }
280
setup_tests(void)281 int setup_tests(void)
282 {
283 ADD_TEST(test_bio_memleak);
284 ADD_TEST(test_bio_get_mem);
285 ADD_TEST(test_bio_new_mem_buf);
286 ADD_TEST(test_bio_rdonly_mem_buf);
287 ADD_TEST(test_bio_rdwr_rdonly);
288 ADD_TEST(test_bio_nonclear_rst);
289 ADD_TEST(test_bio_i2d_ASN1_mime);
290 return 1;
291 }
292