X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;ds=sidebyside;f=test%2Fssltestlib.c;h=67d8cd0284c5d49f05c359ecec91efb2385787d6;hb=a397aca43598ef20c84e69f6d6e5d95652aa0325;hp=c7689631f1b0d67b9e2efb4b10d8b65d2e845384;hpb=0d8da77908df1aa3186b00113aab1b338cba9b07;p=oweals%2Fopenssl.git diff --git a/test/ssltestlib.c b/test/ssltestlib.c index c7689631f1..67d8cd0284 100644 --- a/test/ssltestlib.c +++ b/test/ssltestlib.c @@ -1,7 +1,7 @@ /* - * Copyright 2016-2018 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2016-2019 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy * in the file LICENSE in the source distribution or at * https://www.openssl.org/source/license.html @@ -16,19 +16,37 @@ #ifdef OPENSSL_SYS_UNIX # include +#ifndef OPENSSL_NO_KTLS +# include +# include +# include +# include +# include +# include +#endif -static ossl_inline void ossl_sleep(unsigned int millis) { +static ossl_inline void ossl_sleep(unsigned int millis) +{ +# ifdef OPENSSL_SYS_VXWORKS + struct timespec ts; + ts.tv_sec = (long int) (millis / 1000); + ts.tv_nsec = (long int) (millis % 1000) * 1000000ul; + nanosleep(&ts, NULL); +# else usleep(millis * 1000); +# endif } #elif defined(_WIN32) # include -static ossl_inline void ossl_sleep(unsigned int millis) { +static ossl_inline void ossl_sleep(unsigned int millis) +{ Sleep(millis); } #else /* Fallback to a busy wait */ -static ossl_inline void ossl_sleep(unsigned int millis) { +static ossl_inline void ossl_sleep(unsigned int millis) +{ struct timeval start, now; unsigned int elapsedms; @@ -52,9 +70,11 @@ static int tls_dump_puts(BIO *bp, const char *str); /* Choose a sufficiently large type likely to be unused for this custom BIO */ #define BIO_TYPE_TLS_DUMP_FILTER (0x80 | BIO_TYPE_FILTER) #define BIO_TYPE_MEMPACKET_TEST 0x81 +#define BIO_TYPE_ALWAYS_RETRY 0x82 static BIO_METHOD *method_tls_dump = NULL; static BIO_METHOD *meth_mem = NULL; +static BIO_METHOD *meth_always_retry = NULL; /* Note: Not thread safe! */ const BIO_METHOD *bio_f_tls_dump_filter(void) @@ -284,6 +304,7 @@ typedef struct mempacket_test_ctx_st { unsigned int noinject; unsigned int dropepoch; int droprec; + int duprec; } MEMPACKET_TEST_CTX; static int mempacket_test_new(BIO *bi); @@ -426,12 +447,27 @@ int mempacket_test_inject(BIO *bio, const char *in, int inl, int pktnum, int type) { MEMPACKET_TEST_CTX *ctx = BIO_get_data(bio); - MEMPACKET *thispkt, *looppkt, *nextpkt; - int i; + MEMPACKET *thispkt = NULL, *looppkt, *nextpkt, *allpkts[3]; + int i, duprec; + const unsigned char *inu = (const unsigned char *)in; + size_t len = ((inu[RECORD_LEN_HI] << 8) | inu[RECORD_LEN_LO]) + + DTLS1_RT_HEADER_LENGTH; if (ctx == NULL) return -1; + if ((size_t)inl < len) + return -1; + + if ((size_t)inl == len) + duprec = 0; + else + duprec = ctx->duprec > 0; + + /* We don't support arbitrary injection when duplicating records */ + if (duprec && pktnum != -1) + return -1; + /* We only allow injection before we've started writing any data */ if (pktnum >= 0) { if (ctx->noinject) @@ -441,25 +477,36 @@ int mempacket_test_inject(BIO *bio, const char *in, int inl, int pktnum, ctx->noinject = 1; } - if (!TEST_ptr(thispkt = OPENSSL_malloc(sizeof(*thispkt)))) - return -1; - if (!TEST_ptr(thispkt->data = OPENSSL_malloc(inl))) { - mempacket_free(thispkt); - return -1; - } + for (i = 0; i < (duprec ? 3 : 1); i++) { + if (!TEST_ptr(allpkts[i] = OPENSSL_malloc(sizeof(*thispkt)))) + goto err; + thispkt = allpkts[i]; - memcpy(thispkt->data, in, inl); - thispkt->len = inl; - thispkt->num = (pktnum >= 0) ? (unsigned int)pktnum : ctx->lastpkt; - thispkt->type = type; + if (!TEST_ptr(thispkt->data = OPENSSL_malloc(inl))) + goto err; + /* + * If we are duplicating the packet, we duplicate it three times. The + * first two times we drop the first record if there are more than one. + * In this way we know that libssl will not be able to make progress + * until it receives the last packet, and hence will be forced to + * buffer these records. + */ + if (duprec && i != 2) { + memcpy(thispkt->data, in + len, inl - len); + thispkt->len = inl - len; + } else { + memcpy(thispkt->data, in, inl); + thispkt->len = inl; + } + thispkt->num = (pktnum >= 0) ? (unsigned int)pktnum : ctx->lastpkt + i; + thispkt->type = type; + } for(i = 0; (looppkt = sk_MEMPACKET_value(ctx->pkts, i)) != NULL; i++) { /* Check if we found the right place to insert this packet */ if (looppkt->num > thispkt->num) { - if (sk_MEMPACKET_insert(ctx->pkts, thispkt, i) == 0) { - mempacket_free(thispkt); - return -1; - } + if (sk_MEMPACKET_insert(ctx->pkts, thispkt, i) == 0) + goto err; /* If we're doing up front injection then we're done */ if (pktnum >= 0) return inl; @@ -480,7 +527,7 @@ int mempacket_test_inject(BIO *bio, const char *in, int inl, int pktnum, } else if (looppkt->num == thispkt->num) { if (!ctx->noinject) { /* We injected two packets with the same packet number! */ - return -1; + goto err; } ctx->lastpkt++; thispkt->num++; @@ -490,15 +537,21 @@ int mempacket_test_inject(BIO *bio, const char *in, int inl, int pktnum, * We didn't find any packets with a packet number equal to or greater than * this one, so we just add it onto the end */ - if (!sk_MEMPACKET_push(ctx->pkts, thispkt)) { - mempacket_free(thispkt); - return -1; - } + for (i = 0; i < (duprec ? 3 : 1); i++) { + thispkt = allpkts[i]; + if (!sk_MEMPACKET_push(ctx->pkts, thispkt)) + goto err; - if (pktnum < 0) - ctx->lastpkt++; + if (pktnum < 0) + ctx->lastpkt++; + } return inl; + + err: + for (i = 0; i < (ctx->duprec > 0 ? 3 : 1); i++) + mempacket_free(allpkts[i]); + return -1; } static int mempacket_test_write(BIO *bio, const char *in, int inl) @@ -544,6 +597,9 @@ static long mempacket_test_ctrl(BIO *bio, int cmd, long num, void *ptr) case MEMPACKET_CTRL_GET_DROP_REC: ret = ctx->droprec; break; + case MEMPACKET_CTRL_SET_DUPLICATE_REC: + ctx->duprec = (int)num; + break; case BIO_CTRL_RESET: case BIO_CTRL_DUP: case BIO_CTRL_PUSH: @@ -566,6 +622,100 @@ static int mempacket_test_puts(BIO *bio, const char *str) return mempacket_test_write(bio, str, strlen(str)); } +static int always_retry_new(BIO *bi); +static int always_retry_free(BIO *a); +static int always_retry_read(BIO *b, char *out, int outl); +static int always_retry_write(BIO *b, const char *in, int inl); +static long always_retry_ctrl(BIO *b, int cmd, long num, void *ptr); +static int always_retry_gets(BIO *bp, char *buf, int size); +static int always_retry_puts(BIO *bp, const char *str); + +const BIO_METHOD *bio_s_always_retry(void) +{ + if (meth_always_retry == NULL) { + if (!TEST_ptr(meth_always_retry = BIO_meth_new(BIO_TYPE_ALWAYS_RETRY, + "Always Retry")) + || !TEST_true(BIO_meth_set_write(meth_always_retry, + always_retry_write)) + || !TEST_true(BIO_meth_set_read(meth_always_retry, + always_retry_read)) + || !TEST_true(BIO_meth_set_puts(meth_always_retry, + always_retry_puts)) + || !TEST_true(BIO_meth_set_gets(meth_always_retry, + always_retry_gets)) + || !TEST_true(BIO_meth_set_ctrl(meth_always_retry, + always_retry_ctrl)) + || !TEST_true(BIO_meth_set_create(meth_always_retry, + always_retry_new)) + || !TEST_true(BIO_meth_set_destroy(meth_always_retry, + always_retry_free))) + return NULL; + } + return meth_always_retry; +} + +void bio_s_always_retry_free(void) +{ + BIO_meth_free(meth_always_retry); +} + +static int always_retry_new(BIO *bio) +{ + BIO_set_init(bio, 1); + return 1; +} + +static int always_retry_free(BIO *bio) +{ + BIO_set_data(bio, NULL); + BIO_set_init(bio, 0); + return 1; +} + +static int always_retry_read(BIO *bio, char *out, int outl) +{ + BIO_set_retry_read(bio); + return -1; +} + +static int always_retry_write(BIO *bio, const char *in, int inl) +{ + BIO_set_retry_write(bio); + return -1; +} + +static long always_retry_ctrl(BIO *bio, int cmd, long num, void *ptr) +{ + long ret = 1; + + switch (cmd) { + case BIO_CTRL_FLUSH: + BIO_set_retry_write(bio); + /* fall through */ + case BIO_CTRL_EOF: + case BIO_CTRL_RESET: + case BIO_CTRL_DUP: + case BIO_CTRL_PUSH: + case BIO_CTRL_POP: + default: + ret = 0; + break; + } + return ret; +} + +static int always_retry_gets(BIO *bio, char *buf, int size) +{ + BIO_set_retry_read(bio); + return -1; +} + +static int always_retry_puts(BIO *bio, const char *str) +{ + BIO_set_retry_write(bio); + return -1; +} + int create_ssl_ctx_pair(const SSL_METHOD *sm, const SSL_METHOD *cm, int min_proto_version, int max_proto_version, SSL_CTX **sctx, SSL_CTX **cctx, char *certfile, @@ -621,6 +771,114 @@ int create_ssl_ctx_pair(const SSL_METHOD *sm, const SSL_METHOD *cm, #define MAXLOOPS 1000000 +#if !defined(OPENSSL_NO_KTLS) && !defined(OPENSSL_NO_SOCK) +static int set_nb(int fd) +{ + int flags; + + flags = fcntl(fd,F_GETFL,0); + if (flags == -1) + return flags; + flags = fcntl(fd, F_SETFL, flags | O_NONBLOCK); + return flags; +} + +int create_test_sockets(int *cfd, int *sfd) +{ + struct sockaddr_in sin; + const char *host = "127.0.0.1"; + int cfd_connected = 0, ret = 0; + socklen_t slen = sizeof(sin); + int afd = -1; + + *cfd = -1; + *sfd = -1; + + memset ((char *) &sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = inet_addr(host); + + afd = socket(AF_INET, SOCK_STREAM, 0); + if (afd < 0) + return 0; + + if (bind(afd, (struct sockaddr*)&sin, sizeof(sin)) < 0) + goto out; + + if (getsockname(afd, (struct sockaddr*)&sin, &slen) < 0) + goto out; + + if (listen(afd, 1) < 0) + goto out; + + *cfd = socket(AF_INET, SOCK_STREAM, 0); + if (*cfd < 0) + goto out; + + if (set_nb(afd) == -1) + goto out; + + while (*sfd == -1 || !cfd_connected ) { + *sfd = accept(afd, NULL, 0); + if (*sfd == -1 && errno != EAGAIN) + goto out; + + if (!cfd_connected && connect(*cfd, (struct sockaddr*)&sin, sizeof(sin)) < 0) + goto out; + else + cfd_connected = 1; + } + + if (set_nb(*cfd) == -1 || set_nb(*sfd) == -1) + goto out; + ret = 1; + goto success; + +out: + if (*cfd != -1) + close(*cfd); + if (*sfd != -1) + close(*sfd); +success: + if (afd != -1) + close(afd); + return ret; +} + +int create_ssl_objects2(SSL_CTX *serverctx, SSL_CTX *clientctx, SSL **sssl, + SSL **cssl, int sfd, int cfd) +{ + SSL *serverssl = NULL, *clientssl = NULL; + BIO *s_to_c_bio = NULL, *c_to_s_bio = NULL; + + if (*sssl != NULL) + serverssl = *sssl; + else if (!TEST_ptr(serverssl = SSL_new(serverctx))) + goto error; + if (*cssl != NULL) + clientssl = *cssl; + else if (!TEST_ptr(clientssl = SSL_new(clientctx))) + goto error; + + if (!TEST_ptr(s_to_c_bio = BIO_new_socket(sfd, BIO_NOCLOSE)) + || !TEST_ptr(c_to_s_bio = BIO_new_socket(cfd, BIO_NOCLOSE))) + goto error; + + SSL_set_bio(clientssl, c_to_s_bio, c_to_s_bio); + SSL_set_bio(serverssl, s_to_c_bio, s_to_c_bio); + *sssl = serverssl; + *cssl = clientssl; + return 1; + + error: + SSL_free(serverssl); + SSL_free(clientssl); + BIO_free(s_to_c_bio); + BIO_free(c_to_s_bio); + return 0; +} +#endif + /* * NOTE: Transfers control of the BIOs - this function will free them on error */ @@ -680,12 +938,18 @@ int create_ssl_objects(SSL_CTX *serverctx, SSL_CTX *clientctx, SSL **sssl, return 0; } -int create_ssl_connection(SSL *serverssl, SSL *clientssl, int want) +/* + * Create an SSL connection, but does not ready any post-handshake + * NewSessionTicket messages. + * If |read| is set and we're using DTLS then we will attempt to SSL_read on + * the connection once we've completed one half of it, to ensure any retransmits + * get triggered. + */ +int create_bare_ssl_connection(SSL *serverssl, SSL *clientssl, int want, + int read) { int retc = -1, rets = -1, err, abortctr = 0; int clienterr = 0, servererr = 0; - unsigned char buf; - size_t readbytes; int isdtls = SSL_is_dtls(serverssl); do { @@ -710,7 +974,9 @@ int create_ssl_connection(SSL *serverssl, SSL *clientssl, int want) err = SSL_get_error(serverssl, rets); } - if (!servererr && rets <= 0 && err != SSL_ERROR_WANT_READ) { + if (!servererr && rets <= 0 + && err != SSL_ERROR_WANT_READ + && err != SSL_ERROR_WANT_X509_LOOKUP) { TEST_info("SSL_accept() failed %d, %d", rets, err); servererr = 1; } @@ -718,11 +984,24 @@ int create_ssl_connection(SSL *serverssl, SSL *clientssl, int want) return 0; if (clienterr && servererr) return 0; - if (isdtls) { - if (rets > 0 && retc <= 0) - DTLSv1_handle_timeout(serverssl); - if (retc > 0 && rets <= 0) - DTLSv1_handle_timeout(clientssl); + if (isdtls && read) { + unsigned char buf[20]; + + /* Trigger any retransmits that may be appropriate */ + if (rets > 0 && retc <= 0) { + if (SSL_read(serverssl, buf, sizeof(buf)) > 0) { + /* We don't expect this to succeed! */ + TEST_info("Unexpected SSL_read() success!"); + return 0; + } + } + if (retc > 0 && rets <= 0) { + if (SSL_read(clientssl, buf, sizeof(buf)) > 0) { + /* We don't expect this to succeed! */ + TEST_info("Unexpected SSL_read() success!"); + return 0; + } + } } if (++abortctr == MAXLOOPS) { TEST_info("No progress made"); @@ -738,16 +1017,35 @@ int create_ssl_connection(SSL *serverssl, SSL *clientssl, int want) } } while (retc <=0 || rets <= 0); + return 1; +} + +/* + * Create an SSL connection including any post handshake NewSessionTicket + * messages. + */ +int create_ssl_connection(SSL *serverssl, SSL *clientssl, int want) +{ + int i; + unsigned char buf; + size_t readbytes; + + if (!create_bare_ssl_connection(serverssl, clientssl, want, 1)) + return 0; + /* * We attempt to read some data on the client side which we expect to fail. * This will ensure we have received the NewSessionTicket in TLSv1.3 where - * appropriate. + * appropriate. We do this twice because there are 2 NewSessionTickets. */ - if (SSL_read_ex(clientssl, &buf, sizeof(buf), &readbytes) > 0) { - if (!TEST_ulong_eq(readbytes, 0)) + for (i = 0; i < 2; i++) { + if (SSL_read_ex(clientssl, &buf, sizeof(buf), &readbytes) > 0) { + if (!TEST_ulong_eq(readbytes, 0)) + return 0; + } else if (!TEST_int_eq(SSL_get_error(clientssl, 0), + SSL_ERROR_WANT_READ)) { return 0; - } else if (!TEST_int_eq(SSL_get_error(clientssl, 0), SSL_ERROR_WANT_READ)) { - return 0; + } } return 1;