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