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