diff options
34 files changed, 1129 insertions, 28 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7f40ae893d..5bd32341f2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -216,6 +216,20 @@ jobs: - name: make test run: make test HARNESS_JOBS=${HARNESS_JOBS:-4} + enable-tfo: + strategy: + matrix: + os: [ ubuntu-latest, macos-latest ] + runs-on: ${{matrix.os}} + steps: + - uses: actions/checkout@v2 + - name: config + run: CC=gcc ./config --banner=Configured enable-tfo --strict-warnings && perl configdata.pm --dump + - name: make + run: make -s -j4 + - name: make test + run: make test HARNESS_JOBS=${HARNESS_JOBS:-4} + buildtest: runs-on: ubuntu-latest steps: diff --git a/.github/workflows/run-checker-daily.yml b/.github/workflows/run-checker-daily.yml index d16eb41dab..a255a0ed01 100644 --- a/.github/workflows/run-checker-daily.yml +++ b/.github/workflows/run-checker-daily.yml @@ -104,6 +104,7 @@ jobs: no-sm2, no-sm3, no-sm4, + no-sock, no-sse2, no-ssl, no-ssl3, @@ -111,6 +112,7 @@ jobs: no-ssl-trace, no-static-engine no-shared, no-stdio, + enable-tfo, no-tls1, no-tls1_1, no-tls1_1-method, diff --git a/CHANGES.md b/CHANGES.md index 185340d8c1..c7e3391d4b 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -24,6 +24,11 @@ OpenSSL 3.1 ### Changes between 3.0 and 3.1 [xx XXX xxxx] + * Add support for TCP Fast Open (RFC7413) to macOS, Linux, and FreeBSD where + supported and enabled. + + *Todd Short* + * Add ciphersuites based on DHE_PSK (RFC 4279) and ECDHE_PSK (RFC 5489) to the list of ciphersuites providing Perfect Forward Secrecy as required by SECLEVEL >= 3. @@ -492,6 +492,7 @@ my @disablables = ( "static-engine", "stdio", "tests", + "tfo", "threads", "tls", "trace", @@ -551,6 +552,7 @@ our %disabled = ( # "what" => "comment" "sctp" => "default", "ssl3" => "default", "ssl3-method" => "default", + "tfo" => "default", "trace" => "default", "ubsan" => "default", "unit-test" => "default", @@ -576,6 +578,7 @@ my @disable_cascades = ( "seed", "siphash", "siv", "sm3", "sm4", "srp", "srtp", "ssl3-method", "ssl-trace", + "tfo", "ts", "ui-console", "whirlpool", "fips-securitychecks" ], sub { $config{processor} eq "386" } @@ -586,7 +589,7 @@ my @disable_cascades = ( "des" => [ "mdc2" ], "ec" => [ "ec2m", "ecdsa", "ecdh", "sm2", "gost" ], "dgram" => [ "dtls", "sctp" ], - "sock" => [ "dgram" ], + "sock" => [ "dgram", "tfo" ], "dtls" => [ @dtls ], sub { 0 == scalar grep { !$disabled{$_} } @dtls } => [ "dtls" ], diff --git a/INSTALL.md b/INSTALL.md index 09ea2d678f..8d7d7e466a 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -878,6 +878,10 @@ tests also use the command line applications, the tests will also be skipped. Don't build test programs or run any tests. +### enable-tfo + +Build with support for TCP Fast Open (RFC7413). Supported on Linux, macOS and FreeBSD. + ### no-threads Don't build with support for multi-threaded applications. @@ -23,6 +23,8 @@ OpenSSL 3.1 * Subject or issuer names in X.509 objects are now displayed as UTF-8 strings by default. + * TCP Fast Open (RFC7413) support is available on Linux, macOS, and FreeBSD + where enabled and supported. OpenSSL 3.0 ----------- diff --git a/apps/include/s_apps.h b/apps/include/s_apps.h index 5b188b9892..3f00302721 100644 --- a/apps/include/s_apps.h +++ b/apps/include/s_apps.h @@ -23,8 +23,8 @@ void get_sock_info_address(int asock, char **hostname, char **service); int report_server_accept(BIO *out, int asock, int with_address, int with_pid); int do_server(int *accept_sock, const char *host, const char *port, int family, int type, int protocol, do_server_cb cb, - unsigned char *context, int naccept, BIO *bio_s_out); - + unsigned char *context, int naccept, BIO *bio_s_out, + int tfo); int verify_callback(int ok, X509_STORE_CTX *ctx); int set_cert_stuff(SSL_CTX *ctx, char *cert_file, char *key_file); @@ -36,7 +36,8 @@ int ssl_print_groups(BIO *out, SSL *s, int noshared); int ssl_print_tmp_key(BIO *out, SSL *s); int init_client(int *sock, const char *host, const char *port, const char *bindhost, const char *bindport, - int family, int type, int protocol); + int family, int type, int protocol, int tfo, + BIO_ADDR **ba_ret); int should_retry(int i); void do_ssl_shutdown(SSL *ssl); diff --git a/apps/lib/s_socket.c b/apps/lib/s_socket.c index e5802d5054..1ed5a213af 100644 --- a/apps/lib/s_socket.c +++ b/apps/lib/s_socket.c @@ -64,6 +64,8 @@ BIO_ADDR *ourpeer = NULL; * AF_UNSPEC * @type: socket type, must be SOCK_STREAM or SOCK_DGRAM * @protocol: socket protocol, e.g. IPPROTO_TCP or IPPROTO_UDP (or 0 for any) + * @tfo: flag to enable TCP Fast Open + * @ba_ret: BIO_ADDR that was connected to for TFO, to be freed by caller * * This will create a socket and use it to connect to a host:port, or if * family == AF_UNIX, to the path found in host. @@ -76,7 +78,8 @@ BIO_ADDR *ourpeer = NULL; */ int init_client(int *sock, const char *host, const char *port, const char *bindhost, const char *bindport, - int family, int type, int protocol) + int family, int type, int protocol, int tfo, + BIO_ADDR **ba_ret) { BIO_ADDRINFO *res = NULL; BIO_ADDRINFO *bindaddr = NULL; @@ -84,6 +87,10 @@ int init_client(int *sock, const char *host, const char *port, const BIO_ADDRINFO *bi = NULL; int found = 0; int ret; + int options = 0; + + if (tfo && ba_ret != NULL) + *ba_ret = NULL; if (BIO_sock_init() != 1) return 0; @@ -160,14 +167,22 @@ int init_client(int *sock, const char *host, const char *port, BIO_free(tmpbio); } #endif + if (BIO_ADDRINFO_protocol(ai) == IPPROTO_TCP) { + options |= BIO_SOCK_NODELAY; + if (tfo) + options |= BIO_SOCK_TFO; + } - if (!BIO_connect(*sock, BIO_ADDRINFO_address(ai), - BIO_ADDRINFO_protocol(ai) == IPPROTO_TCP ? BIO_SOCK_NODELAY : 0)) { + if (!BIO_connect(*sock, BIO_ADDRINFO_address(ai), options)) { BIO_closesocket(*sock); *sock = INVALID_SOCKET; continue; } + /* Save the address */ + if (tfo && ba_ret != NULL) + *ba_ret = BIO_ADDR_dup(BIO_ADDRINFO_address(ai)); + /* Success, don't try any more addresses */ break; } @@ -278,7 +293,8 @@ int report_server_accept(BIO *out, int asock, int with_address, int with_pid) */ int do_server(int *accept_sock, const char *host, const char *port, int family, int type, int protocol, do_server_cb cb, - unsigned char *context, int naccept, BIO *bio_s_out) + unsigned char *context, int naccept, BIO *bio_s_out, + int tfo) { int asock = 0; int sock; @@ -312,6 +328,8 @@ int do_server(int *accept_sock, const char *host, const char *port, sock_protocol = BIO_ADDRINFO_protocol(res); sock_address = BIO_ADDRINFO_address(res); next = BIO_ADDRINFO_next(res); + if (tfo && sock_type == SOCK_STREAM) + sock_options |= BIO_SOCK_TFO; #ifdef AF_INET6 if (sock_family == AF_INET6) sock_options |= BIO_SOCK_V6_ONLY; diff --git a/apps/s_client.c b/apps/s_client.c index 105a243b8e..f78404c63f 100644 --- a/apps/s_client.c +++ b/apps/s_client.c @@ -456,6 +456,7 @@ typedef enum OPTION_choice { OPT_USE_SRTP, OPT_KEYMATEXPORT, OPT_KEYMATEXPORTLEN, OPT_PROTOHOST, OPT_MAXFRAGLEN, OPT_MAX_SEND_FRAG, OPT_SPLIT_SEND_FRAG, OPT_MAX_PIPELINES, OPT_READ_BUF, OPT_KEYLOG_FILE, OPT_EARLY_DATA, OPT_REQCAFILE, + OPT_TFO, OPT_V_ENUM, OPT_X_ENUM, OPT_S_ENUM, OPT_IGNORE_UNEXPECTED_EOF, @@ -539,6 +540,9 @@ const OPTIONS s_client_options[] = { "Do not load certificates from the default certificates store"}, {"requestCAfile", OPT_REQCAFILE, '<', "PEM format file of CA names to send to the server"}, +#if defined(TCP_FASTOPEN) && !defined(OPENSSL_NO_TFO) + {"tfo", OPT_TFO, '-', "Connect using TCP Fast Open"}, +#endif {"dane_tlsa_domain", OPT_DANE_TLSA_DOMAIN, 's', "DANE TLSA base domain"}, {"dane_tlsa_rrdata", OPT_DANE_TLSA_RRDATA, 's', "DANE TLSA rrdata presentation form"}, @@ -899,6 +903,8 @@ int s_client_main(int argc, char **argv) #ifndef OPENSSL_NO_KTLS int enable_ktls = 0; #endif + int tfo = 0; + BIO_ADDR *tfo_addr = NULL; FD_ZERO(&readfds); FD_ZERO(&writefds); @@ -1413,6 +1419,9 @@ int s_client_main(int argc, char **argv) if (!opt_pair(opt_arg(), services, &starttls_proto)) goto end; break; + case OPT_TFO: + tfo = 1; + break; case OPT_SERVERNAME: servername = opt_arg(); break; @@ -2035,10 +2044,18 @@ int s_client_main(int argc, char **argv) "-dane_tlsa_domain option.\n", prog); goto end; } +#ifndef OPENSSL_NO_DTLS + if (isdtls && tfo) { + BIO_printf(bio_err, "%s: DTLS does not support the -tfo option\n", prog); + goto end; + } +#endif + if (tfo) + BIO_printf(bio_c_out, "Connecting via TFO\n"); re_start: if (init_client(&sock, host, port, bindhost, bindport, socket_family, - socket_type, protocol) == 0) { + socket_type, protocol, tfo, &tfo_addr) == 0) { BIO_printf(bio_err, "connect:errno=%d\n", get_last_socket_error()); BIO_closesocket(sock); goto end; @@ -2120,6 +2137,12 @@ int s_client_main(int argc, char **argv) goto end; } + /* Now that we're using a BIO... */ + if (tfo_addr != NULL) + (void)BIO_set_conn_address(sbio, tfo_addr); + if (tfo) + (void)BIO_set_tfo(sbio, 1); + if (nbio_test) { BIO *test; @@ -2909,9 +2932,12 @@ int s_client_main(int argc, char **argv) case SSL_ERROR_SYSCALL: if ((k != 0) || (cbuf_len != 0)) { - BIO_printf(bio_err, "write:errno=%d\n", - get_last_socket_error()); - goto shut; + int sockerr = get_last_socket_error(); + + if (!tfo || sockerr != EISCONN) { + BIO_printf(bio_err, "write:errno=%d\n", sockerr); + goto shut; + } } else { read_tty = 1; write_ssl = 0; @@ -3131,6 +3157,7 @@ int s_client_main(int argc, char **argv) OPENSSL_free(srp_arg.srppassin); #endif OPENSSL_free(sname_alloc); + BIO_ADDR_free(tfo_addr); OPENSSL_free(connectstr); OPENSSL_free(bindstr); OPENSSL_free(bindhost); diff --git a/apps/s_server.c b/apps/s_server.c index 2036d51795..736d8498d1 100644 --- a/apps/s_server.c +++ b/apps/s_server.c @@ -717,6 +717,7 @@ typedef enum OPTION_choice { OPT_KEYLOG_FILE, OPT_MAX_EARLY, OPT_RECV_MAX_EARLY, OPT_EARLY_DATA, OPT_S_NUM_TICKETS, OPT_ANTI_REPLAY, OPT_NO_ANTI_REPLAY, OPT_SCTP_LABEL_BUG, OPT_HTTP_SERVER_BINMODE, OPT_NOCANAMES, OPT_IGNORE_UNEXPECTED_EOF, OPT_KTLS, + OPT_TFO, OPT_R_ENUM, OPT_S_ENUM, OPT_V_ENUM, @@ -747,6 +748,9 @@ const OPTIONS s_server_options[] = { #endif {"4", OPT_4, '-', "Use IPv4 only"}, {"6", OPT_6, '-', "Use IPv6 only"}, +#if defined(TCP_FASTOPEN) && !defined(OPENSSL_NO_TFO) + {"tfo", OPT_TFO, '-', "Listen for TCP Fast Open connections"}, +#endif OPT_SECTION("Identity"), {"context", OPT_CONTEXT, 's', "Set session ID context"}, @@ -1057,6 +1061,7 @@ int s_server_main(int argc, char *argv[]) #ifndef OPENSSL_NO_KTLS int enable_ktls = 0; #endif + int tfo = 0; /* Init of few remaining global variables */ local_argc = argc; @@ -1649,6 +1654,9 @@ int s_server_main(int argc, char *argv[]) case OPT_IGNORE_UNEXPECTED_EOF: ignore_unexpected_eof = 1; break; + case OPT_TFO: + tfo = 1; + break; } } @@ -1677,6 +1685,11 @@ int s_server_main(int argc, char *argv[]) } #endif + if (tfo && socket_type != SOCK_STREAM) { + BIO_printf(bio_err, "Can only use -tfo with TLS\n"); + goto end; + } + if (stateless && socket_type != SOCK_STREAM) { BIO_printf(bio_err, "Can only use --stateless with TLS\n"); goto end; @@ -2240,8 +2253,10 @@ int s_server_main(int argc, char *argv[]) && unlink_unix_path) unlink(host); #endif + if (tfo) + BIO_printf(bio_s_out, "Listening for TFO\n"); do_server(&accept_socket, host, port, socket_family, socket_type, protocol, - server_cb, context, naccept, bio_s_out); + server_cb, context, naccept, bio_s_out, tfo); print_stats(bio_s_out, ctx); ret = 0; end: diff --git a/crypto/bio/bio_addr.c b/crypto/bio/bio_addr.c index 8c7139691b..5f335c14d8 100644 --- a/crypto/bio/bio_addr.c +++ b/crypto/bio/bio_addr.c @@ -67,6 +67,18 @@ void BIO_ADDR_free(BIO_ADDR *ap) OPENSSL_free(ap); } +BIO_ADDR *BIO_ADDR_dup(const BIO_ADDR *ap) +{ + BIO_ADDR *ret = NULL; + + if (ap != NULL) { + ret = BIO_ADDR_new(); + if (ret != NULL) + memcpy(ret, ap, sizeof(BIO_ADDR)); + } + return ret; +} + void BIO_ADDR_clear(BIO_ADDR *ap) { memset(ap, 0, sizeof(*ap)); diff --git a/crypto/bio/bio_err.c b/crypto/bio/bio_err.c index 7a36c61148..cbe9d30785 100644 --- a/crypto/bio/bio_err.c +++ b/crypto/bio/bio_err.c @@ -46,6 +46,9 @@ static const ERR_STRING_DATA BIO_str_reasons[] = { "no hostname or service specified"}, {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_NO_PORT_DEFINED), "no port defined"}, {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_NO_SUCH_FILE), "no such file"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_TFO_DISABLED), "tfo disabled"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_TFO_NO_KERNEL_SUPPORT), + "tfo no kernel support"}, {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_TRANSFER_ERROR), "transfer error"}, {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_TRANSFER_TIMEOUT), "transfer timeout"}, {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_UNABLE_TO_BIND_SOCKET), @@ -59,6 +62,7 @@ static const ERR_STRING_DATA BIO_str_reasons[] = { {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_UNABLE_TO_NODELAY), "unable to nodelay"}, {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_UNABLE_TO_REUSEADDR), "unable to reuseaddr"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_UNABLE_TO_TFO), "unable to tfo"}, {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_UNAVAILABLE_IP_FAMILY), "unavailable ip family"}, {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_UNINITIALIZED), "uninitialized"}, diff --git a/crypto/bio/bio_sock2.c b/crypto/bio/bio_sock2.c index b6c95913ce..36b071c8e1 100644 --- a/crypto/bio/bio_sock2.c +++ b/crypto/bio/bio_sock2.c @@ -13,6 +13,7 @@ #include "bio_local.h" #include "internal/ktls.h" +#include "internal/bio_tfo.h" #include <openssl/err.h> @@ -79,6 +80,7 @@ int BIO_socket(int domain, int socktype, int protocol, int options) * - BIO_SOCK_KEEPALIVE: enable regularly sending keep-alive messages. * - BIO_SOCK_NONBLOCK: Make the socket non-blocking. * - BIO_SOCK_NODELAY: don't delay small messages. + * - BIO_SOCK_TFO: use TCP Fast Open * * options holds BIO socket options that can be used * You should call this for every address returned by BIO_lookup @@ -118,6 +120,68 @@ int BIO_connect(int sock, const BIO_ADDR *addr, int options) return 0; } } + if (options & BIO_SOCK_TFO) { +# if defined(OSSL_TFO_CLIENT_FLAG) +# if defined(OSSL_TFO_SYSCTL_CLIENT) + int enabled = 0; + size_t enabledlen = sizeof(enabled); + + /* Later FreeBSD */ + if (sysctlbyname(OSSL_TFO_SYSCTL_CLIENT, &enabled, &enabledlen, NULL, 0) < 0) { + ERR_raise(ERR_LIB_BIO, BIO_R_TFO_NO_KERNEL_SUPPORT); + return 0; + } + /* Need to check for client flag */ + if (!(enabled & OSSL_TFO_CLIENT_FLAG)) { + ERR_raise(ERR_LIB_BIO, BIO_R_TFO_DISABLED); + return 0; + } +# elif defined(OSSL_TFO_SYSCTL) + int enabled = 0; + size_t enabledlen = sizeof(enabled); + + /* macOS */ + if (sysctlbyname(OSSL_TFO_SYSCTL, &enabled, &enabledlen, NULL, 0) < 0) { + ERR_raise(ERR_LIB_BIO, BIO_R_TFO_NO_KERNEL_SUPPORT); + return 0; + } + /* Need to check for client flag */ + if (!(enabled & OSSL_TFO_CLIENT_FLAG)) { + ERR_raise(ERR_LIB_BIO, BIO_R_TFO_DISABLED); + return 0; + } +# endif +# endif +# if defined(OSSL_TFO_CONNECTX) + sa_endpoints_t sae; + + memset(&sae, 0, sizeof(sae)); + sae.sae_dstaddr = BIO_ADDR_sockaddr(addr); + sae.sae_dstaddrlen = BIO_ADDR_sockaddr_size(addr); + if (connectx(sock, &sae, SAE_ASSOCID_ANY, + CONNECT_DATA_IDEMPOTENT | CONNECT_RESUME_ON_READ_WRITE, + NULL, 0, NULL, NULL) == -1) { + if (!BIO_sock_should_retry(-1)) { + ERR_raise_data(ERR_LIB_SYS, get_last_socket_error(), + "calling connectx()"); + ERR_raise(ERR_LIB_BIO, BIO_R_CONNECT_ERROR); + } + return 0; + } +# endif +# if defined(OSSL_TFO_CLIENT_SOCKOPT) + if (setsockopt(sock, IPPROTO_TCP, OSSL_TFO_CLIENT_SOCKOPT, + (const void *)&on, sizeof(on)) != 0) { + ERR_raise_data(ERR_LIB_SYS, get_last_socket_error(), + "calling setsockopt()"); + ERR_raise(ERR_LIB_BIO, BIO_R_UNABLE_TO_TFO); + return 0; + } +# endif +# if defined(OSSL_TFO_DO_NOT_CONNECT) + return 1; +# endif + } if (connect(sock, BIO_ADDR_sockaddr(addr), BIO_ADDR_sockaddr_size(addr)) == -1) { @@ -201,6 +265,7 @@ int BIO_bind(int sock, const BIO_ADDR *addr, int options) * for a recently closed port. * - BIO_SOCK_V6_ONLY: When creating an IPv6 socket, make it listen only * for IPv6 addresses and not IPv4 addresses mapped to IPv6. + * - BIO_SOCK_TFO: accept TCP fast open (set TCP_FASTOPEN) * * It's recommended that you set up both an IPv6 and IPv4 listen socket, and * then check both for new clients that connect to it. You want to set up @@ -292,6 +357,54 @@ int BIO_listen(int sock, const BIO_ADDR *addr, int options) return 0; } +# if defined(OSSL_TFO_SERVER_SOCKOPT) + /* + * Must do it explicitly after listen() for macOS, still + * works fine on other OS's + */ + if ((options & BIO_SOCK_TFO) && socktype != SOCK_DGRAM) { + int q = OSSL_TFO_SERVER_SOCKOPT_VALUE; +# if defined(OSSL_TFO_CLIENT_FLAG) +# if defined(OSSL_TFO_SYSCTL_SERVER) + int enabled = 0; + size_t enabledlen = sizeof(enabled); + + /* Later FreeBSD */ + if (sysctlbyname(OSSL_TFO_SYSCTL_SERVER, &enabled, &enabledlen, NULL, 0) < 0) { + ERR_raise(ERR_LIB_BIO, BIO_R_TFO_NO_KERNEL_SUPPORT); + return 0; + } + /* Need to check for server flag */ + if (!(enabled & OSSL_TFO_SERVER_FLAG)) { + ERR_raise(ERR_LIB_BIO, BIO_R_TFO_DISABLED); + return 0; + } +# elif defined(OSSL_TFO_SYSCTL) + int enabled = 0; + size_t enabledlen = sizeof(enabled); + + /* Early FreeBSD, macOS */ + if (sysctlbyname(OSSL_TFO_SYSCTL, &enabled, &enabledlen, NULL, 0) < 0) { + ERR_raise(ERR_LIB_BIO, BIO_R_TFO_NO_KERNEL_SUPPORT); + return 0; + } + /* Need to check for server flag */ + if (!(enabled & OSSL_TFO_SERVER_FLAG)) { + ERR_raise(ERR_LIB_BIO, BIO_R_TFO_DISABLED); + return 0; + } +# endif +# endif + if (setsockopt(sock, IPPROTO_TCP, OSSL_TFO_SERVER_SOCKOPT, + (void *)&q, sizeof(q)) < 0) { + ERR_raise_data(ERR_LIB_SYS, get_last_socket_error(), + "calling setsockopt()"); + ERR_raise(ERR_LIB_BIO, BIO_R_UNABLE_TO_TFO); + return 0; + } + } +# endif + return 1; } diff --git a/crypto/bio/bss_acpt.c b/crypto/bio/bss_acpt.c index 1cda967335..eeac7ca4e1 100644 --- a/crypto/bio/bss_acpt.c +++ b/crypto/bio/bss_acpt.c @@ -452,10 +452,14 @@ static long acpt_ctrl(BIO *b, int cmd, long num, void *ptr) data->bio_chain = (BIO *)ptr; } else if (num == 4) { data->accept_family = *(int *)ptr; + } else if (num == 5) { + data->bind_mode |= BIO_SOCK_TFO; } } else { if (num == 2) { data->bind_mode &= ~BIO_SOCK_NONBLOCK; + } else if (num == 5) { + data->bind_mode &= ~BIO_SOCK_TFO; } } break; diff --git a/crypto/bio/bss_conn.c b/crypto/bio/bss_conn.c index 8bc53548ca..3c61bc91c5 100644 --- a/crypto/bio/bss_conn.c +++ b/crypto/bio/bss_conn.c @@ -11,6 +11,7 @@ #include <errno.h> #include "bio_local.h" +#include "internal/bio_tfo.h" #include "internal/ktls.h" #ifndef OPENSSL_NO_SOCK @@ -24,6 +25,7 @@ typedef struct bio_connect_st { # ifndef OPENSSL_NO_KTLS unsigned char record_type; # endif + int tfo_first; BIO_ADDRINFO *addr_first; const BIO_ADDRINFO *addr_iter; @@ -361,6 +363,15 @@ static int conn_write(BIO *b, const char *in, int inl) } } else # endif +# if defined(OSSL_TFO_SENDTO) + if (data->tfo_first) { + int peerlen = BIO_ADDRINFO_sockaddr_size(data->addr_iter); + + ret = sendto(b->num, in, inl, OSSL_TFO_SENDTO, + BIO_ADDRINFO_sockaddr(data->addr_iter), peerlen); + data->tfo_first = 0; + } else +# endif ret = writesocket(b->num, in, inl); BIO_clear_retry_flags(b); if (ret <= 0) { @@ -425,6 +436,8 @@ static long conn_ctrl(BIO *b, int cmd, long num, void *ptr) ret = -1; break; } + } else if (num == 4) { + ret = data->connect_mode; } else { ret = 0; } @@ -485,8 +498,23 @@ static long conn_ctrl(BIO *b, int cmd, long num, void *ptr) else data->connect_mode &= ~BIO_SOCK_NONBLOCK; break; +#if defined(TCP_FASTOPEN) && !defined(OPENSSL_NO_TFO) + case BIO_C_SET_TFO: + if (num != 0) { + data->connect_mode |= BIO_SOCK_TFO; + data->tfo_first = 1; + } else { + data->connect_mode &= ~BIO_SOCK_TFO; + data->tfo_first = 0; + } + break; +#endif case BIO_C_SET_CONNECT_MODE: data->connect_mode = (int)num; + if (num & BIO_SOCK_TFO) + data->tfo_first = 1; + else + data->tfo_first = 0; break; case BIO_C_GET_FD: if (b->init) { diff --git a/crypto/bio/bss_sock.c b/crypto/bio/bss_sock.c index f5d8810230..201bc9df2b 100644 --- a/crypto/bio/bss_sock.c +++ b/crypto/bio/bss_sock.c @@ -10,6 +10,7 @@ #include <stdio.h> #include <errno.h> #include "bio_local.h" +#include "internal/bio_tfo.h" #include "internal/cryptlib.h" #include "internal/ktls.h" @@ -27,6 +28,14 @@ # define sock_puts SockPut |