]> git.ipfire.org Git - thirdparty/openssl.git/blame - test/asynciotest.c
Ignore -named_curve auto value to improve backwards compatibility
[thirdparty/openssl.git] / test / asynciotest.c
CommitLineData
d7295cd6
MC
1/*
2 * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
3 *
4 * Licensed under the OpenSSL licenses, (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#include <string.h>
12#include <openssl/ssl.h>
13#include <openssl/bio.h>
14#include <openssl/err.h>
15
16#include "../ssl/packet_locl.h"
17
2cb4b5f6 18#include "ssltestlib.h"
c7910796 19#include "testutil.h"
2cb4b5f6 20
d7295cd6
MC
21/* Should we fragment records or not? 0 = no, !0 = yes*/
22static int fragment = 0;
23
c7910796
MC
24static char *cert = NULL;
25static char *privkey = NULL;
26
d7295cd6
MC
27static int async_new(BIO *bi);
28static int async_free(BIO *a);
29static int async_read(BIO *b, char *out, int outl);
30static int async_write(BIO *b, const char *in, int inl);
31static long async_ctrl(BIO *b, int cmd, long num, void *ptr);
32static int async_gets(BIO *bp, char *buf, int size);
33static int async_puts(BIO *bp, const char *str);
34
35/* Choose a sufficiently large type likely to be unused for this custom BIO */
36# define BIO_TYPE_ASYNC_FILTER (0x80 | BIO_TYPE_FILTER)
37
38static BIO_METHOD *methods_async = NULL;
39
40struct async_ctrs {
41 unsigned int rctr;
42 unsigned int wctr;
43};
44
45static const BIO_METHOD *bio_f_async_filter()
46{
47 if (methods_async == NULL) {
48 methods_async = BIO_meth_new(BIO_TYPE_ASYNC_FILTER, "Async filter");
49 if ( methods_async == NULL
50 || !BIO_meth_set_write(methods_async, async_write)
51 || !BIO_meth_set_read(methods_async, async_read)
52 || !BIO_meth_set_puts(methods_async, async_puts)
53 || !BIO_meth_set_gets(methods_async, async_gets)
54 || !BIO_meth_set_ctrl(methods_async, async_ctrl)
55 || !BIO_meth_set_create(methods_async, async_new)
56 || !BIO_meth_set_destroy(methods_async, async_free))
57 return NULL;
58 }
59 return methods_async;
60}
61
62static int async_new(BIO *bio)
63{
64 struct async_ctrs *ctrs;
65
66 ctrs = OPENSSL_zalloc(sizeof(struct async_ctrs));
67 if (ctrs == NULL)
68 return 0;
69
70 BIO_set_data(bio, ctrs);
71 BIO_set_init(bio, 1);
72 return 1;
73}
74
75static int async_free(BIO *bio)
76{
77 struct async_ctrs *ctrs;
78
79 if (bio == NULL)
80 return 0;
81 ctrs = BIO_get_data(bio);
82 OPENSSL_free(ctrs);
83 BIO_set_data(bio, NULL);
84 BIO_set_init(bio, 0);
85
86 return 1;
87}
88
89static int async_read(BIO *bio, char *out, int outl)
90{
91 struct async_ctrs *ctrs;
92 int ret = 0;
93 BIO *next = BIO_next(bio);
94
95 if (outl <= 0)
96 return 0;
97 if (next == NULL)
98 return 0;
99
100 ctrs = BIO_get_data(bio);
101
102 BIO_clear_retry_flags(bio);
103
104 if (ctrs->rctr > 0) {
105 ret = BIO_read(next, out, 1);
106 if (ret <= 0 && BIO_should_read(next))
107 BIO_set_retry_read(bio);
108 ctrs->rctr = 0;
109 } else {
110 ctrs->rctr++;
111 BIO_set_retry_read(bio);
112 }
113
114 return ret;
115}
116
117#define MIN_RECORD_LEN 6
118
119#define CONTENTTYPEPOS 0
120#define VERSIONHIPOS 1
121#define VERSIONLOPOS 2
122#define DATAPOS 5
123
124static int async_write(BIO *bio, const char *in, int inl)
125{
126 struct async_ctrs *ctrs;
127 int ret = 0;
128 size_t written = 0;
129 BIO *next = BIO_next(bio);
130
131 if (inl <= 0)
132 return 0;
133 if (next == NULL)
134 return 0;
135
136 ctrs = BIO_get_data(bio);
137
138 BIO_clear_retry_flags(bio);
139
140 if (ctrs->wctr > 0) {
141 ctrs->wctr = 0;
142 if (fragment) {
143 PACKET pkt;
144
145 if (!PACKET_buf_init(&pkt, (const unsigned char *)in, inl))
c7910796 146 return -1;
d7295cd6
MC
147
148 while (PACKET_remaining(&pkt) > 0) {
9970290e 149 PACKET payload, wholebody;
d7295cd6 150 unsigned int contenttype, versionhi, versionlo, data;
5d8ce306 151 unsigned int msgtype = 0, negversion = 0;
d7295cd6 152
c7910796
MC
153 if (!PACKET_get_1(&pkt, &contenttype)
154 || !PACKET_get_1(&pkt, &versionhi)
155 || !PACKET_get_1(&pkt, &versionlo)
156 || !PACKET_get_length_prefixed_2(&pkt, &payload))
157 return -1;
d7295cd6
MC
158
159 /* Pretend we wrote out the record header */
160 written += SSL3_RT_HEADER_LENGTH;
161
9970290e
MC
162 wholebody = payload;
163 if (contenttype == SSL3_RT_HANDSHAKE
164 && !PACKET_get_1(&wholebody, &msgtype))
c7910796 165 return -1;
9970290e
MC
166
167 if (msgtype == SSL3_MT_SERVER_HELLO
168 && (!PACKET_forward(&wholebody,
169 SSL3_HM_HEADER_LENGTH - 1)
170 || !PACKET_get_net_2(&wholebody, &negversion)))
c7910796 171 return -1;
9970290e 172
d7295cd6
MC
173 while (PACKET_get_1(&payload, &data)) {
174 /* Create a new one byte long record for each byte in the
175 * record in the input buffer
176 */
177 char smallrec[MIN_RECORD_LEN] = {
178 0, /* Content type */
179 0, /* Version hi */
180 0, /* Version lo */
181 0, /* Length hi */
182 1, /* Length lo */
183 0 /* Data */
184 };
185
186 smallrec[CONTENTTYPEPOS] = contenttype;
187 smallrec[VERSIONHIPOS] = versionhi;
188 smallrec[VERSIONLOPOS] = versionlo;
189 smallrec[DATAPOS] = data;
190 ret = BIO_write(next, smallrec, MIN_RECORD_LEN);
191 if (ret <= 0)
c7910796 192 return -1;
d7295cd6
MC
193 written++;
194 }
195 /*
9970290e
MC
196 * We can't fragment anything after the ServerHello (or CCS <=
197 * TLS1.2), otherwise we get a bad record MAC
198 * TODO(TLS1.3): Change TLS1_3_VERSION_DRAFT to TLS1_3_VERSION
199 * before release
d7295cd6 200 */
9970290e
MC
201 if (contenttype == SSL3_RT_CHANGE_CIPHER_SPEC
202 || (negversion == TLS1_3_VERSION_DRAFT
203 && msgtype == SSL3_MT_SERVER_HELLO)) {
d7295cd6
MC
204 fragment = 0;
205 break;
206 }
207 }
208 }
209 /* Write any data we have left after fragmenting */
210 ret = 0;
211 if ((int)written < inl) {
28b86f31 212 ret = BIO_write(next, in + written, inl - written);
d7295cd6
MC
213 }
214
215 if (ret <= 0 && BIO_should_write(next))
216 BIO_set_retry_write(bio);
217 else
218 ret += written;
219 } else {
220 ctrs->wctr++;
221 BIO_set_retry_write(bio);
222 }
223
224 return ret;
225}
226
227static long async_ctrl(BIO *bio, int cmd, long num, void *ptr)
228{
229 long ret;
230 BIO *next = BIO_next(bio);
231
232 if (next == NULL)
233 return 0;
234
235 switch (cmd) {
236 case BIO_CTRL_DUP:
237 ret = 0L;
238 break;
239 default:
240 ret = BIO_ctrl(next, cmd, num, ptr);
241 break;
242 }
243 return ret;
244}
245
246static int async_gets(BIO *bio, char *buf, int size)
247{
248 /* We don't support this - not needed anyway */
249 return -1;
250}
251
252static int async_puts(BIO *bio, const char *str)
253{
254 return async_write(bio, str, strlen(str));
255}
256
a34ac5b8
MC
257#define MAX_ATTEMPTS 100
258
c7910796 259static int test_asyncio(int test)
d7295cd6
MC
260{
261 SSL_CTX *serverctx = NULL, *clientctx = NULL;
262 SSL *serverssl = NULL, *clientssl = NULL;
d7295cd6 263 BIO *s_to_c_fbio = NULL, *c_to_s_fbio = NULL;
c7910796 264 int testresult = 0, ret;
a34ac5b8
MC
265 size_t i, j;
266 const char testdata[] = "Test data";
267 char buf[sizeof(testdata)];
d7295cd6 268
c7910796
MC
269 if (!TEST_true(create_ssl_ctx_pair(TLS_server_method(), TLS_client_method(),
270 &serverctx, &clientctx, cert, privkey)))
d7295cd6 271 goto end;
d7295cd6
MC
272
273 /*
274 * We do 2 test runs. The first time around we just do a normal handshake
275 * with lots of async io going on. The second time around we also break up
276 * all records so that the content is only one byte length (up until the
277 * CCS)
278 */
c7910796
MC
279 if (test == 1)
280 fragment = 1;
d7295cd6 281
d7295cd6 282
c7910796
MC
283 s_to_c_fbio = BIO_new(bio_f_async_filter());
284 c_to_s_fbio = BIO_new(bio_f_async_filter());
285 if (!TEST_ptr(s_to_c_fbio)
286 || !TEST_ptr(c_to_s_fbio)) {
287 BIO_free(s_to_c_fbio);
288 BIO_free(c_to_s_fbio);
289 goto end;
290 }
d7295cd6 291
c7910796
MC
292 /* BIOs get freed on error */
293 if (!TEST_true(create_ssl_objects(serverctx, clientctx, &serverssl,
294 &clientssl, s_to_c_fbio, c_to_s_fbio))
295 || !TEST_true(create_ssl_connection(serverssl, clientssl,
296 SSL_ERROR_NONE)))
297 goto end;
b4982125 298
c7910796
MC
299 /*
300 * Send and receive some test data. Do the whole thing twice to ensure
301 * we hit at least one async event in both reading and writing
302 */
303 for (j = 0; j < 2; j++) {
304 int len;
d7295cd6 305
a34ac5b8 306 /*
c7910796
MC
307 * Write some test data. It should never take more than 2 attempts
308 * (the first one might be a retryable fail).
a34ac5b8 309 */
c7910796
MC
310 for (ret = -1, i = 0, len = 0; len != sizeof(testdata) && i < 2;
311 i++) {
312 ret = SSL_write(clientssl, testdata + len,
313 sizeof(testdata) - len);
314 if (ret > 0) {
315 len += ret;
316 } else {
317 int ssl_error = SSL_get_error(clientssl, ret);
318
319 if (!TEST_false(ssl_error == SSL_ERROR_SYSCALL ||
320 ssl_error == SSL_ERROR_SSL))
321 goto end;
a34ac5b8
MC
322 }
323 }
c7910796
MC
324 if (!TEST_size_t_eq(len, sizeof(testdata)))
325 goto end;
a34ac5b8 326
c7910796
MC
327 /*
328 * Now read the test data. It may take more attemps here because
329 * it could fail once for each byte read, including all overhead
330 * bytes from the record header/padding etc.
331 */
332 for (ret = -1, i = 0, len = 0; len != sizeof(testdata) &&
333 i < MAX_ATTEMPTS; i++) {
334 ret = SSL_read(serverssl, buf + len, sizeof(buf) - len);
335 if (ret > 0) {
336 len += ret;
337 } else {
338 int ssl_error = SSL_get_error(serverssl, ret);
339
340 if (!TEST_false(ssl_error == SSL_ERROR_SYSCALL ||
341 ssl_error == SSL_ERROR_SSL))
342 goto end;
343 }
344 }
345 if (!TEST_mem_eq(testdata, sizeof(testdata), buf, len))
346 goto end;
d7295cd6
MC
347 }
348
c7910796
MC
349 /* Also frees the BIOs */
350 SSL_free(clientssl);
351 SSL_free(serverssl);
352 clientssl = serverssl = NULL;
d7295cd6 353
c7910796 354 testresult = 1;
d7295cd6 355
c7910796 356 end:
d7295cd6
MC
357 SSL_free(clientssl);
358 SSL_free(serverssl);
359 SSL_CTX_free(clientctx);
360 SSL_CTX_free(serverctx);
361
c7910796
MC
362 return testresult;
363}
364
365int test_main(int argc, char *argv[])
366{
367 int testresult = 0;
368
369 if (!TEST_int_eq(argc, 3))
370 goto end;
371
372 cert = argv[1];
373 privkey = argv[2];
374
375 ADD_ALL_TESTS(test_asyncio, 2);
376
377 testresult = run_tests(argv[0]);
378
379 end:
380 BIO_meth_free(methods_async);
d7295cd6 381
c7910796 382 return testresult;
d7295cd6 383}