mirror of https://github.com/openssl/openssl.git
Add TFO support to socket BIO and s_client/s_server
Supports Linux, MacOS and FreeBSD Disabled by default, enabled via `enabled-tfo` Some tests Reviewed-by: Matt Caswell <matt@openssl.org> Reviewed-by: Tomas Mraz <tomas@openssl.org> Reviewed-by: Tim Hudson <tjh@openssl.org> (Merged from https://github.com/openssl/openssl/pull/8692)
This commit is contained in:
parent
97896f744d
commit
a3e53d5683
|
@ -216,6 +216,20 @@ jobs:
|
||||||
- name: make test
|
- name: make test
|
||||||
run: make test HARNESS_JOBS=${HARNESS_JOBS:-4}
|
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:
|
buildtest:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
|
|
|
@ -104,6 +104,7 @@ jobs:
|
||||||
no-sm2,
|
no-sm2,
|
||||||
no-sm3,
|
no-sm3,
|
||||||
no-sm4,
|
no-sm4,
|
||||||
|
no-sock,
|
||||||
no-sse2,
|
no-sse2,
|
||||||
no-ssl,
|
no-ssl,
|
||||||
no-ssl3,
|
no-ssl3,
|
||||||
|
@ -111,6 +112,7 @@ jobs:
|
||||||
no-ssl-trace,
|
no-ssl-trace,
|
||||||
no-static-engine no-shared,
|
no-static-engine no-shared,
|
||||||
no-stdio,
|
no-stdio,
|
||||||
|
enable-tfo,
|
||||||
no-tls1,
|
no-tls1,
|
||||||
no-tls1_1,
|
no-tls1_1,
|
||||||
no-tls1_1-method,
|
no-tls1_1-method,
|
||||||
|
|
|
@ -24,6 +24,11 @@ OpenSSL 3.1
|
||||||
|
|
||||||
### Changes between 3.0 and 3.1 [xx XXX xxxx]
|
### 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)
|
* Add ciphersuites based on DHE_PSK (RFC 4279) and ECDHE_PSK (RFC 5489)
|
||||||
to the list of ciphersuites providing Perfect Forward Secrecy as
|
to the list of ciphersuites providing Perfect Forward Secrecy as
|
||||||
required by SECLEVEL >= 3.
|
required by SECLEVEL >= 3.
|
||||||
|
|
|
@ -492,6 +492,7 @@ my @disablables = (
|
||||||
"static-engine",
|
"static-engine",
|
||||||
"stdio",
|
"stdio",
|
||||||
"tests",
|
"tests",
|
||||||
|
"tfo",
|
||||||
"threads",
|
"threads",
|
||||||
"tls",
|
"tls",
|
||||||
"trace",
|
"trace",
|
||||||
|
@ -551,6 +552,7 @@ our %disabled = ( # "what" => "comment"
|
||||||
"sctp" => "default",
|
"sctp" => "default",
|
||||||
"ssl3" => "default",
|
"ssl3" => "default",
|
||||||
"ssl3-method" => "default",
|
"ssl3-method" => "default",
|
||||||
|
"tfo" => "default",
|
||||||
"trace" => "default",
|
"trace" => "default",
|
||||||
"ubsan" => "default",
|
"ubsan" => "default",
|
||||||
"unit-test" => "default",
|
"unit-test" => "default",
|
||||||
|
@ -576,6 +578,7 @@ my @disable_cascades = (
|
||||||
"seed", "siphash", "siv",
|
"seed", "siphash", "siv",
|
||||||
"sm3", "sm4", "srp",
|
"sm3", "sm4", "srp",
|
||||||
"srtp", "ssl3-method", "ssl-trace",
|
"srtp", "ssl3-method", "ssl-trace",
|
||||||
|
"tfo",
|
||||||
"ts", "ui-console", "whirlpool",
|
"ts", "ui-console", "whirlpool",
|
||||||
"fips-securitychecks" ],
|
"fips-securitychecks" ],
|
||||||
sub { $config{processor} eq "386" }
|
sub { $config{processor} eq "386" }
|
||||||
|
@ -586,7 +589,7 @@ my @disable_cascades = (
|
||||||
"des" => [ "mdc2" ],
|
"des" => [ "mdc2" ],
|
||||||
"ec" => [ "ec2m", "ecdsa", "ecdh", "sm2", "gost" ],
|
"ec" => [ "ec2m", "ecdsa", "ecdh", "sm2", "gost" ],
|
||||||
"dgram" => [ "dtls", "sctp" ],
|
"dgram" => [ "dtls", "sctp" ],
|
||||||
"sock" => [ "dgram" ],
|
"sock" => [ "dgram", "tfo" ],
|
||||||
"dtls" => [ @dtls ],
|
"dtls" => [ @dtls ],
|
||||||
sub { 0 == scalar grep { !$disabled{$_} } @dtls }
|
sub { 0 == scalar grep { !$disabled{$_} } @dtls }
|
||||||
=> [ "dtls" ],
|
=> [ "dtls" ],
|
||||||
|
|
|
@ -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.
|
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
|
### no-threads
|
||||||
|
|
||||||
Don't build with support for multi-threaded applications.
|
Don't build with support for multi-threaded applications.
|
||||||
|
|
2
NEWS.md
2
NEWS.md
|
@ -23,6 +23,8 @@ OpenSSL 3.1
|
||||||
|
|
||||||
* Subject or issuer names in X.509 objects are now displayed as UTF-8 strings
|
* Subject or issuer names in X.509 objects are now displayed as UTF-8 strings
|
||||||
by default.
|
by default.
|
||||||
|
* TCP Fast Open (RFC7413) support is available on Linux, macOS, and FreeBSD
|
||||||
|
where enabled and supported.
|
||||||
|
|
||||||
OpenSSL 3.0
|
OpenSSL 3.0
|
||||||
-----------
|
-----------
|
||||||
|
|
|
@ -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 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 do_server(int *accept_sock, const char *host, const char *port,
|
||||||
int family, int type, int protocol, do_server_cb cb,
|
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 verify_callback(int ok, X509_STORE_CTX *ctx);
|
||||||
|
|
||||||
int set_cert_stuff(SSL_CTX *ctx, char *cert_file, char *key_file);
|
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 ssl_print_tmp_key(BIO *out, SSL *s);
|
||||||
int init_client(int *sock, const char *host, const char *port,
|
int init_client(int *sock, const char *host, const char *port,
|
||||||
const char *bindhost, const char *bindport,
|
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);
|
int should_retry(int i);
|
||||||
void do_ssl_shutdown(SSL *ssl);
|
void do_ssl_shutdown(SSL *ssl);
|
||||||
|
|
||||||
|
|
|
@ -64,6 +64,8 @@ BIO_ADDR *ourpeer = NULL;
|
||||||
* AF_UNSPEC
|
* AF_UNSPEC
|
||||||
* @type: socket type, must be SOCK_STREAM or SOCK_DGRAM
|
* @type: socket type, must be SOCK_STREAM or SOCK_DGRAM
|
||||||
* @protocol: socket protocol, e.g. IPPROTO_TCP or IPPROTO_UDP (or 0 for any)
|
* @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
|
* 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.
|
* 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,
|
int init_client(int *sock, const char *host, const char *port,
|
||||||
const char *bindhost, const char *bindport,
|
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 *res = NULL;
|
||||||
BIO_ADDRINFO *bindaddr = 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;
|
const BIO_ADDRINFO *bi = NULL;
|
||||||
int found = 0;
|
int found = 0;
|
||||||
int ret;
|
int ret;
|
||||||
|
int options = 0;
|
||||||
|
|
||||||
|
if (tfo && ba_ret != NULL)
|
||||||
|
*ba_ret = NULL;
|
||||||
|
|
||||||
if (BIO_sock_init() != 1)
|
if (BIO_sock_init() != 1)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -160,14 +167,22 @@ int init_client(int *sock, const char *host, const char *port,
|
||||||
BIO_free(tmpbio);
|
BIO_free(tmpbio);
|
||||||
}
|
}
|
||||||
#endif
|
#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),
|
if (!BIO_connect(*sock, BIO_ADDRINFO_address(ai), options)) {
|
||||||
BIO_ADDRINFO_protocol(ai) == IPPROTO_TCP ? BIO_SOCK_NODELAY : 0)) {
|
|
||||||
BIO_closesocket(*sock);
|
BIO_closesocket(*sock);
|
||||||
*sock = INVALID_SOCKET;
|
*sock = INVALID_SOCKET;
|
||||||
continue;
|
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 */
|
/* Success, don't try any more addresses */
|
||||||
break;
|
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 do_server(int *accept_sock, const char *host, const char *port,
|
||||||
int family, int type, int protocol, do_server_cb cb,
|
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 asock = 0;
|
||||||
int sock;
|
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_protocol = BIO_ADDRINFO_protocol(res);
|
||||||
sock_address = BIO_ADDRINFO_address(res);
|
sock_address = BIO_ADDRINFO_address(res);
|
||||||
next = BIO_ADDRINFO_next(res);
|
next = BIO_ADDRINFO_next(res);
|
||||||
|
if (tfo && sock_type == SOCK_STREAM)
|
||||||
|
sock_options |= BIO_SOCK_TFO;
|
||||||
#ifdef AF_INET6
|
#ifdef AF_INET6
|
||||||
if (sock_family == AF_INET6)
|
if (sock_family == AF_INET6)
|
||||||
sock_options |= BIO_SOCK_V6_ONLY;
|
sock_options |= BIO_SOCK_V6_ONLY;
|
||||||
|
|
|
@ -456,6 +456,7 @@ typedef enum OPTION_choice {
|
||||||
OPT_USE_SRTP, OPT_KEYMATEXPORT, OPT_KEYMATEXPORTLEN, OPT_PROTOHOST,
|
OPT_USE_SRTP, OPT_KEYMATEXPORT, OPT_KEYMATEXPORTLEN, OPT_PROTOHOST,
|
||||||
OPT_MAXFRAGLEN, OPT_MAX_SEND_FRAG, OPT_SPLIT_SEND_FRAG, OPT_MAX_PIPELINES,
|
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_READ_BUF, OPT_KEYLOG_FILE, OPT_EARLY_DATA, OPT_REQCAFILE,
|
||||||
|
OPT_TFO,
|
||||||
OPT_V_ENUM,
|
OPT_V_ENUM,
|
||||||
OPT_X_ENUM,
|
OPT_X_ENUM,
|
||||||
OPT_S_ENUM, OPT_IGNORE_UNEXPECTED_EOF,
|
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"},
|
"Do not load certificates from the default certificates store"},
|
||||||
{"requestCAfile", OPT_REQCAFILE, '<',
|
{"requestCAfile", OPT_REQCAFILE, '<',
|
||||||
"PEM format file of CA names to send to the server"},
|
"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_domain", OPT_DANE_TLSA_DOMAIN, 's', "DANE TLSA base domain"},
|
||||||
{"dane_tlsa_rrdata", OPT_DANE_TLSA_RRDATA, 's',
|
{"dane_tlsa_rrdata", OPT_DANE_TLSA_RRDATA, 's',
|
||||||
"DANE TLSA rrdata presentation form"},
|
"DANE TLSA rrdata presentation form"},
|
||||||
|
@ -899,6 +903,8 @@ int s_client_main(int argc, char **argv)
|
||||||
#ifndef OPENSSL_NO_KTLS
|
#ifndef OPENSSL_NO_KTLS
|
||||||
int enable_ktls = 0;
|
int enable_ktls = 0;
|
||||||
#endif
|
#endif
|
||||||
|
int tfo = 0;
|
||||||
|
BIO_ADDR *tfo_addr = NULL;
|
||||||
|
|
||||||
FD_ZERO(&readfds);
|
FD_ZERO(&readfds);
|
||||||
FD_ZERO(&writefds);
|
FD_ZERO(&writefds);
|
||||||
|
@ -1413,6 +1419,9 @@ int s_client_main(int argc, char **argv)
|
||||||
if (!opt_pair(opt_arg(), services, &starttls_proto))
|
if (!opt_pair(opt_arg(), services, &starttls_proto))
|
||||||
goto end;
|
goto end;
|
||||||
break;
|
break;
|
||||||
|
case OPT_TFO:
|
||||||
|
tfo = 1;
|
||||||
|
break;
|
||||||
case OPT_SERVERNAME:
|
case OPT_SERVERNAME:
|
||||||
servername = opt_arg();
|
servername = opt_arg();
|
||||||
break;
|
break;
|
||||||
|
@ -2035,10 +2044,18 @@ int s_client_main(int argc, char **argv)
|
||||||
"-dane_tlsa_domain option.\n", prog);
|
"-dane_tlsa_domain option.\n", prog);
|
||||||
goto end;
|
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:
|
re_start:
|
||||||
if (init_client(&sock, host, port, bindhost, bindport, socket_family,
|
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_printf(bio_err, "connect:errno=%d\n", get_last_socket_error());
|
||||||
BIO_closesocket(sock);
|
BIO_closesocket(sock);
|
||||||
goto end;
|
goto end;
|
||||||
|
@ -2120,6 +2137,12 @@ int s_client_main(int argc, char **argv)
|
||||||
goto end;
|
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) {
|
if (nbio_test) {
|
||||||
BIO *test;
|
BIO *test;
|
||||||
|
|
||||||
|
@ -2909,9 +2932,12 @@ int s_client_main(int argc, char **argv)
|
||||||
|
|
||||||
case SSL_ERROR_SYSCALL:
|
case SSL_ERROR_SYSCALL:
|
||||||
if ((k != 0) || (cbuf_len != 0)) {
|
if ((k != 0) || (cbuf_len != 0)) {
|
||||||
BIO_printf(bio_err, "write:errno=%d\n",
|
int sockerr = get_last_socket_error();
|
||||||
get_last_socket_error());
|
|
||||||
goto shut;
|
if (!tfo || sockerr != EISCONN) {
|
||||||
|
BIO_printf(bio_err, "write:errno=%d\n", sockerr);
|
||||||
|
goto shut;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
read_tty = 1;
|
read_tty = 1;
|
||||||
write_ssl = 0;
|
write_ssl = 0;
|
||||||
|
@ -3131,6 +3157,7 @@ int s_client_main(int argc, char **argv)
|
||||||
OPENSSL_free(srp_arg.srppassin);
|
OPENSSL_free(srp_arg.srppassin);
|
||||||
#endif
|
#endif
|
||||||
OPENSSL_free(sname_alloc);
|
OPENSSL_free(sname_alloc);
|
||||||
|
BIO_ADDR_free(tfo_addr);
|
||||||
OPENSSL_free(connectstr);
|
OPENSSL_free(connectstr);
|
||||||
OPENSSL_free(bindstr);
|
OPENSSL_free(bindstr);
|
||||||
OPENSSL_free(bindhost);
|
OPENSSL_free(bindhost);
|
||||||
|
|
|
@ -717,6 +717,7 @@ typedef enum OPTION_choice {
|
||||||
OPT_KEYLOG_FILE, OPT_MAX_EARLY, OPT_RECV_MAX_EARLY, OPT_EARLY_DATA,
|
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_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_HTTP_SERVER_BINMODE, OPT_NOCANAMES, OPT_IGNORE_UNEXPECTED_EOF, OPT_KTLS,
|
||||||
|
OPT_TFO,
|
||||||
OPT_R_ENUM,
|
OPT_R_ENUM,
|
||||||
OPT_S_ENUM,
|
OPT_S_ENUM,
|
||||||
OPT_V_ENUM,
|
OPT_V_ENUM,
|
||||||
|
@ -747,6 +748,9 @@ const OPTIONS s_server_options[] = {
|
||||||
#endif
|
#endif
|
||||||
{"4", OPT_4, '-', "Use IPv4 only"},
|
{"4", OPT_4, '-', "Use IPv4 only"},
|
||||||
{"6", OPT_6, '-', "Use IPv6 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"),
|
OPT_SECTION("Identity"),
|
||||||
{"context", OPT_CONTEXT, 's', "Set session ID context"},
|
{"context", OPT_CONTEXT, 's', "Set session ID context"},
|
||||||
|
@ -1057,6 +1061,7 @@ int s_server_main(int argc, char *argv[])
|
||||||
#ifndef OPENSSL_NO_KTLS
|
#ifndef OPENSSL_NO_KTLS
|
||||||
int enable_ktls = 0;
|
int enable_ktls = 0;
|
||||||
#endif
|
#endif
|
||||||
|
int tfo = 0;
|
||||||
|
|
||||||
/* Init of few remaining global variables */
|
/* Init of few remaining global variables */
|
||||||
local_argc = argc;
|
local_argc = argc;
|
||||||
|
@ -1649,6 +1654,9 @@ int s_server_main(int argc, char *argv[])
|
||||||
case OPT_IGNORE_UNEXPECTED_EOF:
|
case OPT_IGNORE_UNEXPECTED_EOF:
|
||||||
ignore_unexpected_eof = 1;
|
ignore_unexpected_eof = 1;
|
||||||
break;
|
break;
|
||||||
|
case OPT_TFO:
|
||||||
|
tfo = 1;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1677,6 +1685,11 @@ int s_server_main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
#endif
|
#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) {
|
if (stateless && socket_type != SOCK_STREAM) {
|
||||||
BIO_printf(bio_err, "Can only use --stateless with TLS\n");
|
BIO_printf(bio_err, "Can only use --stateless with TLS\n");
|
||||||
goto end;
|
goto end;
|
||||||
|
@ -2240,8 +2253,10 @@ int s_server_main(int argc, char *argv[])
|
||||||
&& unlink_unix_path)
|
&& unlink_unix_path)
|
||||||
unlink(host);
|
unlink(host);
|
||||||
#endif
|
#endif
|
||||||
|
if (tfo)
|
||||||
|
BIO_printf(bio_s_out, "Listening for TFO\n");
|
||||||
do_server(&accept_socket, host, port, socket_family, socket_type, protocol,
|
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);
|
print_stats(bio_s_out, ctx);
|
||||||
ret = 0;
|
ret = 0;
|
||||||
end:
|
end:
|
||||||
|
|
|
@ -67,6 +67,18 @@ void BIO_ADDR_free(BIO_ADDR *ap)
|
||||||
OPENSSL_free(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)
|
void BIO_ADDR_clear(BIO_ADDR *ap)
|
||||||
{
|
{
|
||||||
memset(ap, 0, sizeof(*ap));
|
memset(ap, 0, sizeof(*ap));
|
||||||
|
|
|
@ -46,6 +46,9 @@ static const ERR_STRING_DATA BIO_str_reasons[] = {
|
||||||
"no hostname or service specified"},
|
"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_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_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_ERROR), "transfer error"},
|
||||||
{ERR_PACK(ERR_LIB_BIO, 0, BIO_R_TRANSFER_TIMEOUT), "transfer timeout"},
|
{ERR_PACK(ERR_LIB_BIO, 0, BIO_R_TRANSFER_TIMEOUT), "transfer timeout"},
|
||||||
{ERR_PACK(ERR_LIB_BIO, 0, BIO_R_UNABLE_TO_BIND_SOCKET),
|
{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_NODELAY), "unable to nodelay"},
|
||||||
{ERR_PACK(ERR_LIB_BIO, 0, BIO_R_UNABLE_TO_REUSEADDR),
|
{ERR_PACK(ERR_LIB_BIO, 0, BIO_R_UNABLE_TO_REUSEADDR),
|
||||||
"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),
|
{ERR_PACK(ERR_LIB_BIO, 0, BIO_R_UNAVAILABLE_IP_FAMILY),
|
||||||
"unavailable ip family"},
|
"unavailable ip family"},
|
||||||
{ERR_PACK(ERR_LIB_BIO, 0, BIO_R_UNINITIALIZED), "uninitialized"},
|
{ERR_PACK(ERR_LIB_BIO, 0, BIO_R_UNINITIALIZED), "uninitialized"},
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
|
|
||||||
#include "bio_local.h"
|
#include "bio_local.h"
|
||||||
#include "internal/ktls.h"
|
#include "internal/ktls.h"
|
||||||
|
#include "internal/bio_tfo.h"
|
||||||
|
|
||||||
#include <openssl/err.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_KEEPALIVE: enable regularly sending keep-alive messages.
|
||||||
* - BIO_SOCK_NONBLOCK: Make the socket non-blocking.
|
* - BIO_SOCK_NONBLOCK: Make the socket non-blocking.
|
||||||
* - BIO_SOCK_NODELAY: don't delay small messages.
|
* - BIO_SOCK_NODELAY: don't delay small messages.
|
||||||
|
* - BIO_SOCK_TFO: use TCP Fast Open
|
||||||
*
|
*
|
||||||
* options holds BIO socket options that can be used
|
* options holds BIO socket options that can be used
|
||||||
* You should call this for every address returned by BIO_lookup
|
* 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;
|
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),
|
if (connect(sock, BIO_ADDR_sockaddr(addr),
|
||||||
BIO_ADDR_sockaddr_size(addr)) == -1) {
|
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.
|
* for a recently closed port.
|
||||||
* - BIO_SOCK_V6_ONLY: When creating an IPv6 socket, make it listen only
|
* - BIO_SOCK_V6_ONLY: When creating an IPv6 socket, make it listen only
|
||||||
* for IPv6 addresses and not IPv4 addresses mapped to IPv6.
|
* 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
|
* 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
|
* 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;
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -452,10 +452,14 @@ static long acpt_ctrl(BIO *b, int cmd, long num, void *ptr)
|
||||||
data->bio_chain = (BIO *)ptr;
|
data->bio_chain = (BIO *)ptr;
|
||||||
} else if (num == 4) {
|
} else if (num == 4) {
|
||||||
data->accept_family = *(int *)ptr;
|
data->accept_family = *(int *)ptr;
|
||||||
|
} else if (num == 5) {
|
||||||
|
data->bind_mode |= BIO_SOCK_TFO;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (num == 2) {
|
if (num == 2) {
|
||||||
data->bind_mode &= ~BIO_SOCK_NONBLOCK;
|
data->bind_mode &= ~BIO_SOCK_NONBLOCK;
|
||||||
|
} else if (num == 5) {
|
||||||
|
data->bind_mode &= ~BIO_SOCK_TFO;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
#include "bio_local.h"
|
#include "bio_local.h"
|
||||||
|
#include "internal/bio_tfo.h"
|
||||||
#include "internal/ktls.h"
|
#include "internal/ktls.h"
|
||||||
|
|
||||||
#ifndef OPENSSL_NO_SOCK
|
#ifndef OPENSSL_NO_SOCK
|
||||||
|
@ -24,6 +25,7 @@ typedef struct bio_connect_st {
|
||||||
# ifndef OPENSSL_NO_KTLS
|
# ifndef OPENSSL_NO_KTLS
|
||||||
unsigned char record_type;
|
unsigned char record_type;
|
||||||
# endif
|
# endif
|
||||||
|
int tfo_first;
|
||||||
|
|
||||||
BIO_ADDRINFO *addr_first;
|
BIO_ADDRINFO *addr_first;
|
||||||
const BIO_ADDRINFO *addr_iter;
|
const BIO_ADDRINFO *addr_iter;
|
||||||
|
@ -360,6 +362,15 @@ static int conn_write(BIO *b, const char *in, int inl)
|
||||||
BIO_clear_ktls_ctrl_msg_flag(b);
|
BIO_clear_ktls_ctrl_msg_flag(b);
|
||||||
}
|
}
|
||||||
} else
|
} 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
|
# endif
|
||||||
ret = writesocket(b->num, in, inl);
|
ret = writesocket(b->num, in, inl);
|
||||||
BIO_clear_retry_flags(b);
|
BIO_clear_retry_flags(b);
|
||||||
|
@ -425,6 +436,8 @@ static long conn_ctrl(BIO *b, int cmd, long num, void *ptr)
|
||||||
ret = -1;
|
ret = -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
} else if (num == 4) {
|
||||||
|
ret = data->connect_mode;
|
||||||
} else {
|
} else {
|
||||||
ret = 0;
|
ret = 0;
|
||||||
}
|
}
|
||||||
|
@ -485,8 +498,23 @@ static long conn_ctrl(BIO *b, int cmd, long num, void *ptr)
|
||||||
else
|
else
|
||||||
data->connect_mode &= ~BIO_SOCK_NONBLOCK;
|
data->connect_mode &= ~BIO_SOCK_NONBLOCK;
|
||||||
break;
|
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:
|
case BIO_C_SET_CONNECT_MODE:
|
||||||
data->connect_mode = (int)num;
|
data->connect_mode = (int)num;
|
||||||
|
if (num & BIO_SOCK_TFO)
|
||||||
|
data->tfo_first = 1;
|
||||||
|
else
|
||||||
|
data->tfo_first = 0;
|
||||||
break;
|
break;
|
||||||
case BIO_C_GET_FD:
|
case BIO_C_GET_FD:
|
||||||
if (b->init) {
|
if (b->init) {
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include "bio_local.h"
|
#include "bio_local.h"
|
||||||
|
#include "internal/bio_tfo.h"
|
||||||
#include "internal/cryptlib.h"
|
#include "internal/cryptlib.h"
|
||||||
#include "internal/ktls.h"
|
#include "internal/ktls.h"
|
||||||
|
|
||||||
|
@ -27,6 +28,14 @@
|
||||||
# define sock_puts SockPuts
|
# define sock_puts SockPuts
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
|
struct bss_sock_st {
|
||||||
|
BIO_ADDR tfo_peer;
|
||||||
|
int tfo_first;
|
||||||
|
#ifndef OPENSSL_NO_KTLS
|
||||||
|
unsigned char ktls_record_type;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
static int sock_write(BIO *h, const char *buf, int num);
|
static int sock_write(BIO *h, const char *buf, int num);
|
||||||
static int sock_read(BIO *h, char *buf, int size);
|
static int sock_read(BIO *h, char *buf, int size);
|
||||||
static int sock_puts(BIO *h, const char *str);
|
static int sock_puts(BIO *h, const char *str);
|
||||||
|
@ -81,8 +90,10 @@ static int sock_new(BIO *bi)
|
||||||
{
|
{
|
||||||
bi->init = 0;
|
bi->init = 0;
|
||||||
bi->num = 0;
|
bi->num = 0;
|
||||||
bi->ptr = NULL;
|
|
||||||
bi->flags = 0;
|
bi->flags = 0;
|
||||||
|
bi->ptr = OPENSSL_zalloc(sizeof(struct bss_sock_st));
|
||||||
|
if (bi->ptr == NULL)
|
||||||
|
return 0;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,6 +108,8 @@ static int sock_free(BIO *a)
|
||||||
a->init = 0;
|
a->init = 0;
|
||||||
a->flags = 0;
|
a->flags = 0;
|
||||||
}
|
}
|
||||||
|
OPENSSL_free(a->ptr);
|
||||||
|
a->ptr = NULL;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,17 +139,30 @@ static int sock_read(BIO *b, char *out, int outl)
|
||||||
static int sock_write(BIO *b, const char *in, int inl)
|
static int sock_write(BIO *b, const char *in, int inl)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
# if !defined(OPENSSL_NO_KTLS) || defined(OSSL_TFO_SENDTO)
|
||||||
|
struct bss_sock_st *data = (struct bss_sock_st *)b->ptr;
|
||||||
|
# endif
|
||||||
|
|
||||||
clear_socket_error();
|
clear_socket_error();
|
||||||
# ifndef OPENSSL_NO_KTLS
|
# ifndef OPENSSL_NO_KTLS
|
||||||
if (BIO_should_ktls_ctrl_msg_flag(b)) {
|
if (BIO_should_ktls_ctrl_msg_flag(b)) {
|
||||||
unsigned char record_type = (intptr_t)b->ptr;
|
unsigned char record_type = data->ktls_record_type;
|
||||||
ret = ktls_send_ctrl_message(b->num, record_type, in, inl);
|
ret = ktls_send_ctrl_message(b->num, record_type, in, inl);
|
||||||
if (ret >= 0) {
|
if (ret >= 0) {
|
||||||
ret = inl;
|
ret = inl;
|
||||||
BIO_clear_ktls_ctrl_msg_flag(b);
|
BIO_clear_ktls_ctrl_msg_flag(b);
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
|
# endif
|
||||||
|
# if defined(OSSL_TFO_SENDTO)
|
||||||
|
if (data->tfo_first) {
|
||||||
|
struct bss_sock_st *data = (struct bss_sock_st *)b->ptr;
|
||||||
|
socklen_t peerlen = BIO_ADDR_sockaddr_size(&data->tfo_peer);
|
||||||
|
|
||||||
|
ret = sendto(b->num, in, inl, OSSL_TFO_SENDTO,
|
||||||
|
BIO_ADDR_sockaddr(&data->tfo_peer), peerlen);
|
||||||
|
data->tfo_first = 0;
|
||||||
|
} else
|
||||||
# endif
|
# endif
|
||||||
ret = writesocket(b->num, in, inl);
|
ret = writesocket(b->num, in, inl);
|
||||||
BIO_clear_retry_flags(b);
|
BIO_clear_retry_flags(b);
|
||||||
|
@ -151,16 +177,24 @@ static long sock_ctrl(BIO *b, int cmd, long num, void *ptr)
|
||||||
{
|
{
|
||||||
long ret = 1;
|
long ret = 1;
|
||||||
int *ip;
|
int *ip;
|
||||||
|
struct bss_sock_st *data = (struct bss_sock_st *)b->ptr;
|
||||||
# ifndef OPENSSL_NO_KTLS
|
# ifndef OPENSSL_NO_KTLS
|
||||||
ktls_crypto_info_t *crypto_info;
|
ktls_crypto_info_t *crypto_info;
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case BIO_C_SET_FD:
|
case BIO_C_SET_FD:
|
||||||
sock_free(b);
|
/* minimal sock_free() */
|
||||||
|
if (b->shutdown) {
|
||||||
|
if (b->init)
|
||||||
|
BIO_closesocket(b->num);
|
||||||
|
b->flags = 0;
|
||||||
|
}
|
||||||
b->num = *((int *)ptr);
|
b->num = *((int *)ptr);
|
||||||
b->shutdown = (int)num;
|
b->shutdown = (int)num;
|
||||||
b->init = 1;
|
b->init = 1;
|
||||||
|
data->tfo_first = 0;
|
||||||
|
memset(&data->tfo_peer, 0, sizeof(data->tfo_peer));
|
||||||
break;
|
break;
|
||||||
case BIO_C_GET_FD:
|
case BIO_C_GET_FD:
|
||||||
if (b->init) {
|
if (b->init) {
|
||||||
|
@ -194,7 +228,7 @@ static long sock_ctrl(BIO *b, int cmd, long num, void *ptr)
|
||||||
return BIO_should_ktls_flag(b, 0) != 0;
|
return BIO_should_ktls_flag(b, 0) != 0;
|
||||||
case BIO_CTRL_SET_KTLS_TX_SEND_CTRL_MSG:
|
case BIO_CTRL_SET_KTLS_TX_SEND_CTRL_MSG:
|
||||||
BIO_set_ktls_ctrl_msg_flag(b);
|
BIO_set_ktls_ctrl_msg_flag(b);
|
||||||
b->ptr = (void *)num;
|
data->ktls_record_type = (unsigned char)num;
|
||||||
ret = 0;
|
ret = 0;
|
||||||
break;
|
break;
|
||||||
case BIO_CTRL_CLEAR_KTLS_TX_CTRL_MSG:
|
case BIO_CTRL_CLEAR_KTLS_TX_CTRL_MSG:
|
||||||
|
@ -205,6 +239,25 @@ static long sock_ctrl(BIO *b, int cmd, long num, void *ptr)
|
||||||
case BIO_CTRL_EOF:
|
case BIO_CTRL_EOF:
|
||||||
ret = (b->flags & BIO_FLAGS_IN_EOF) != 0;
|
ret = (b->flags & BIO_FLAGS_IN_EOF) != 0;
|
||||||
break;
|
break;
|
||||||
|
case BIO_C_GET_CONNECT:
|
||||||
|
if (ptr != NULL && num == 2) {
|
||||||
|
const char **pptr = (const char **)ptr;
|
||||||
|
|
||||||
|
*pptr = (const char *)&data->tfo_peer;
|
||||||
|
} else {
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BIO_C_SET_CONNECT:
|
||||||
|
if (ptr != NULL && num == 2) {
|
||||||
|
ret = BIO_ADDR_make(&data->tfo_peer,
|
||||||
|
BIO_ADDR_sockaddr((const BIO_ADDR *)ptr));
|
||||||
|
if (ret)
|
||||||
|
data->tfo_first = 1;
|
||||||
|
} else {
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
ret = 0;
|
ret = 0;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -150,6 +150,8 @@ BIO_R_NO_ACCEPT_ADDR_OR_SERVICE_SPECIFIED:143:\
|
||||||
BIO_R_NO_HOSTNAME_OR_SERVICE_SPECIFIED:144:no hostname or service specified
|
BIO_R_NO_HOSTNAME_OR_SERVICE_SPECIFIED:144:no hostname or service specified
|
||||||
BIO_R_NO_PORT_DEFINED:113:no port defined
|
BIO_R_NO_PORT_DEFINED:113:no port defined
|
||||||
BIO_R_NO_SUCH_FILE:128:no such file
|
BIO_R_NO_SUCH_FILE:128:no such file
|
||||||
|
BIO_R_TFO_DISABLED:106:tfo disabled
|
||||||
|
BIO_R_TFO_NO_KERNEL_SUPPORT:108:tfo no kernel support
|
||||||
BIO_R_TRANSFER_ERROR:104:transfer error
|
BIO_R_TRANSFER_ERROR:104:transfer error
|
||||||
BIO_R_TRANSFER_TIMEOUT:105:transfer timeout
|
BIO_R_TRANSFER_TIMEOUT:105:transfer timeout
|
||||||
BIO_R_UNABLE_TO_BIND_SOCKET:117:unable to bind socket
|
BIO_R_UNABLE_TO_BIND_SOCKET:117:unable to bind socket
|
||||||
|
@ -158,6 +160,7 @@ BIO_R_UNABLE_TO_KEEPALIVE:137:unable to keepalive
|
||||||
BIO_R_UNABLE_TO_LISTEN_SOCKET:119:unable to listen socket
|
BIO_R_UNABLE_TO_LISTEN_SOCKET:119:unable to listen socket
|
||||||
BIO_R_UNABLE_TO_NODELAY:138:unable to nodelay
|
BIO_R_UNABLE_TO_NODELAY:138:unable to nodelay
|
||||||
BIO_R_UNABLE_TO_REUSEADDR:139:unable to reuseaddr
|
BIO_R_UNABLE_TO_REUSEADDR:139:unable to reuseaddr
|
||||||
|
BIO_R_UNABLE_TO_TFO:109:unable to tfo
|
||||||
BIO_R_UNAVAILABLE_IP_FAMILY:145:unavailable ip family
|
BIO_R_UNAVAILABLE_IP_FAMILY:145:unavailable ip family
|
||||||
BIO_R_UNINITIALIZED:120:uninitialized
|
BIO_R_UNINITIALIZED:120:uninitialized
|
||||||
BIO_R_UNKNOWN_INFO_TYPE:140:unknown info type
|
BIO_R_UNKNOWN_INFO_TYPE:140:unknown info type
|
||||||
|
|
|
@ -119,6 +119,7 @@ B<openssl> B<s_client>
|
||||||
[B<-srp_moregroups>]
|
[B<-srp_moregroups>]
|
||||||
[B<-srp_strength> I<number>]
|
[B<-srp_strength> I<number>]
|
||||||
[B<-ktls>]
|
[B<-ktls>]
|
||||||
|
[B<-tfo>]
|
||||||
{- $OpenSSL::safe::opt_name_synopsis -}
|
{- $OpenSSL::safe::opt_name_synopsis -}
|
||||||
{- $OpenSSL::safe::opt_version_synopsis -}
|
{- $OpenSSL::safe::opt_version_synopsis -}
|
||||||
{- $OpenSSL::safe::opt_x_synopsis -}
|
{- $OpenSSL::safe::opt_x_synopsis -}
|
||||||
|
@ -782,6 +783,10 @@ Enable Kernel TLS for sending and receiving.
|
||||||
This option was introduced in OpenSSL 3.1.0.
|
This option was introduced in OpenSSL 3.1.0.
|
||||||
Kernel TLS is off by default as of OpenSSL 3.1.0.
|
Kernel TLS is off by default as of OpenSSL 3.1.0.
|
||||||
|
|
||||||
|
=item B<-tfo>
|
||||||
|
|
||||||
|
Enable creation of connections via TCP fast open (RFC7413).
|
||||||
|
|
||||||
{- $OpenSSL::safe::opt_version_item -}
|
{- $OpenSSL::safe::opt_version_item -}
|
||||||
|
|
||||||
{- $OpenSSL::safe::opt_name_item -}
|
{- $OpenSSL::safe::opt_name_item -}
|
||||||
|
@ -924,6 +929,8 @@ The B<-certform> option has become obsolete in OpenSSL 3.0.0 and has no effect.
|
||||||
|
|
||||||
The B<-engine> option was deprecated in OpenSSL 3.0.
|
The B<-engine> option was deprecated in OpenSSL 3.0.
|
||||||
|
|
||||||
|
The -tfo option was added in OpenSSL 3.1.
|
||||||
|
|
||||||
=head1 COPYRIGHT
|
=head1 COPYRIGHT
|
||||||
|
|
||||||
Copyright 2000-2021 The OpenSSL Project Authors. All Rights Reserved.
|
Copyright 2000-2021 The OpenSSL Project Authors. All Rights Reserved.
|
||||||
|
|
|
@ -139,6 +139,7 @@ B<openssl> B<s_server>
|
||||||
[B<-anti_replay>]
|
[B<-anti_replay>]
|
||||||
[B<-no_anti_replay>]
|
[B<-no_anti_replay>]
|
||||||
[B<-num_tickets>]
|
[B<-num_tickets>]
|
||||||
|
[B<-tfo>]
|
||||||
{- $OpenSSL::safe::opt_name_synopsis -}
|
{- $OpenSSL::safe::opt_name_synopsis -}
|
||||||
{- $OpenSSL::safe::opt_version_synopsis -}
|
{- $OpenSSL::safe::opt_version_synopsis -}
|
||||||
{- $OpenSSL::safe::opt_v_synopsis -}
|
{- $OpenSSL::safe::opt_v_synopsis -}
|
||||||
|
@ -816,6 +817,11 @@ has been negotiated, and early data is enabled on the server. A full handshake
|
||||||
is forced if a session ticket is used a second or subsequent time. Any early
|
is forced if a session ticket is used a second or subsequent time. Any early
|
||||||
data that was sent will be rejected.
|
data that was sent will be rejected.
|
||||||
|
|
||||||
|
=item B<-tfo>
|
||||||
|
|
||||||
|
Enable acceptance of TCP Fast Open (RFC7413) connections.
|
||||||
|
|
||||||
|
|
||||||
{- $OpenSSL::safe::opt_name_item -}
|
{- $OpenSSL::safe::opt_name_item -}
|
||||||
|
|
||||||
{- $OpenSSL::safe::opt_version_item -}
|
{- $OpenSSL::safe::opt_version_item -}
|
||||||
|
@ -942,6 +948,8 @@ The
|
||||||
The B<-srpvfile>, B<-srpuserseed>, and B<-engine>
|
The B<-srpvfile>, B<-srpuserseed>, and B<-engine>
|
||||||
option were deprecated in OpenSSL 3.0.
|
option were deprecated in OpenSSL 3.0.
|
||||||
|
|
||||||
|
The -tfo option was added in OpenSSL 3.1.
|
||||||
|
|
||||||
=head1 COPYRIGHT
|
=head1 COPYRIGHT
|
||||||
|
|
||||||
Copyright 2000-2021 The OpenSSL Project Authors. All Rights Reserved.
|
Copyright 2000-2021 The OpenSSL Project Authors. All Rights Reserved.
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
=head1 NAME
|
=head1 NAME
|
||||||
|
|
||||||
BIO_ADDR, BIO_ADDR_new, BIO_ADDR_clear, BIO_ADDR_free, BIO_ADDR_rawmake,
|
BIO_ADDR, BIO_ADDR_new, BIO_ADDR_dup, BIO_ADDR_clear, BIO_ADDR_free,
|
||||||
|
BIO_ADDR_rawmake,
|
||||||
BIO_ADDR_family, BIO_ADDR_rawaddress, BIO_ADDR_rawport,
|
BIO_ADDR_family, BIO_ADDR_rawaddress, BIO_ADDR_rawport,
|
||||||
BIO_ADDR_hostname_string, BIO_ADDR_service_string,
|
BIO_ADDR_hostname_string, BIO_ADDR_service_string,
|
||||||
BIO_ADDR_path_string - BIO_ADDR routines
|
BIO_ADDR_path_string - BIO_ADDR routines
|
||||||
|
@ -15,6 +16,7 @@ BIO_ADDR_path_string - BIO_ADDR routines
|
||||||
typedef union bio_addr_st BIO_ADDR;
|
typedef union bio_addr_st BIO_ADDR;
|
||||||
|
|
||||||
BIO_ADDR *BIO_ADDR_new(void);
|
BIO_ADDR *BIO_ADDR_new(void);
|
||||||
|
BIO_ADDR *BIO_ADDR_dup(const BIO_ADDR *ap);
|
||||||
void BIO_ADDR_free(BIO_ADDR *);
|
void BIO_ADDR_free(BIO_ADDR *);
|
||||||
void BIO_ADDR_clear(BIO_ADDR *ap);
|
void BIO_ADDR_clear(BIO_ADDR *ap);
|
||||||
int BIO_ADDR_rawmake(BIO_ADDR *ap, int family,
|
int BIO_ADDR_rawmake(BIO_ADDR *ap, int family,
|
||||||
|
@ -37,7 +39,11 @@ BIO_ADDR_new() creates a new unfilled B<BIO_ADDR>, to be used
|
||||||
with routines that will fill it with information, such as
|
with routines that will fill it with information, such as
|
||||||
BIO_accept_ex().
|
BIO_accept_ex().
|
||||||
|
|
||||||
BIO_ADDR_free() frees a B<BIO_ADDR> created with BIO_ADDR_new().
|
BIO_ADDR_dup() creates a new B<BIO_ADDR>, with a copy of the
|
||||||
|
address data in B<ap>.
|
||||||
|
|
||||||
|
BIO_ADDR_free() frees a B<BIO_ADDR> created with BIO_ADDR_new()
|
||||||
|
or BIO_ADDR_dup();
|
||||||
|
|
||||||
BIO_ADDR_clear() clears any data held within the provided B<BIO_ADDR> and sets
|
BIO_ADDR_clear() clears any data held within the provided B<BIO_ADDR> and sets
|
||||||
it back to an uninitialised state.
|
it back to an uninitialised state.
|
||||||
|
@ -113,6 +119,10 @@ information they should return isn't available.
|
||||||
|
|
||||||
L<BIO_connect(3)>, L<BIO_s_connect(3)>
|
L<BIO_connect(3)>, L<BIO_s_connect(3)>
|
||||||
|
|
||||||
|
=head1 HISTORY
|
||||||
|
|
||||||
|
BIO_ADDR_dup() was added in OpenSSL 3.1.
|
||||||
|
|
||||||
=head1 COPYRIGHT
|
=head1 COPYRIGHT
|
||||||
|
|
||||||
Copyright 2016-2020 The OpenSSL Project Authors. All Rights Reserved.
|
Copyright 2016-2020 The OpenSSL Project Authors. All Rights Reserved.
|
||||||
|
|
|
@ -73,6 +73,15 @@ port.
|
||||||
When creating an IPv6 socket, make it only listen for IPv6 addresses
|
When creating an IPv6 socket, make it only listen for IPv6 addresses
|
||||||
and not IPv4 addresses mapped to IPv6.
|
and not IPv4 addresses mapped to IPv6.
|
||||||
|
|
||||||
|
=item BIO_SOCK_TFO
|
||||||
|
|
||||||
|
Enables TCP Fast Open on the socket. Uses appropriate APIs on
|
||||||
|
supported operating systems, including Linux, macOS and FreeBSD. Can
|
||||||
|
be used with BIO_connect(), BIO_set_conn_mode(), BIO_set_bind_mode(),
|
||||||
|
and BIO_listen().
|
||||||
|
On Linux kernels before 4.14, use BIO_set_conn_address() to specify
|
||||||
|
the peer address before starting the TLS handshake.
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
These flags are bit flags, so they are to be combined with the
|
These flags are bit flags, so they are to be combined with the
|
||||||
|
|
|
@ -6,7 +6,7 @@ BIO_ctrl, BIO_callback_ctrl, BIO_ptr_ctrl, BIO_int_ctrl, BIO_reset,
|
||||||
BIO_seek, BIO_tell, BIO_flush, BIO_eof, BIO_set_close, BIO_get_close,
|
BIO_seek, BIO_tell, BIO_flush, BIO_eof, BIO_set_close, BIO_get_close,
|
||||||
BIO_pending, BIO_wpending, BIO_ctrl_pending, BIO_ctrl_wpending,
|
BIO_pending, BIO_wpending, BIO_ctrl_pending, BIO_ctrl_wpending,
|
||||||
BIO_get_info_callback, BIO_set_info_callback, BIO_info_cb, BIO_get_ktls_send,
|
BIO_get_info_callback, BIO_set_info_callback, BIO_info_cb, BIO_get_ktls_send,
|
||||||
BIO_get_ktls_recv
|
BIO_get_ktls_recv, BIO_set_conn_mode, BIO_get_conn_mode, BIO_set_tfo
|
||||||
- BIO control operations
|
- BIO control operations
|
||||||
|
|
||||||
=head1 SYNOPSIS
|
=head1 SYNOPSIS
|
||||||
|
@ -38,6 +38,11 @@ BIO_get_ktls_recv
|
||||||
int BIO_get_ktls_send(BIO *b);
|
int BIO_get_ktls_send(BIO *b);
|
||||||
int BIO_get_ktls_recv(BIO *b);
|
int BIO_get_ktls_recv(BIO *b);
|
||||||
|
|
||||||
|
int BIO_set_conn_mode(BIO *b, int mode);
|
||||||
|
int BIO_get_conn_mode(BIO *b);
|
||||||
|
|
||||||
|
int BIO_set_tfo(BIO *b, int onoff);
|
||||||
|
|
||||||
=head1 DESCRIPTION
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
BIO_ctrl(), BIO_callback_ctrl(), BIO_ptr_ctrl() and BIO_int_ctrl()
|
BIO_ctrl(), BIO_callback_ctrl(), BIO_ptr_ctrl() and BIO_int_ctrl()
|
||||||
|
@ -81,6 +86,13 @@ sending. Otherwise, it returns zero. It also returns negative values for failure
|
||||||
BIO_get_ktls_recv() returns 1 if the BIO is using the Kernel TLS data-path for
|
BIO_get_ktls_recv() returns 1 if the BIO is using the Kernel TLS data-path for
|
||||||
receiving. Otherwise, it returns zero. It also returns negative values for failure.
|
receiving. Otherwise, it returns zero. It also returns negative values for failure.
|
||||||
|
|
||||||
|
BIO_get_conn_mode() returns the BIO connection mode. BIO_set_conn_mode() sets
|
||||||
|
the BIO connection mode.
|
||||||
|
|
||||||
|
BIO_set_tfo() disables TCP Fast Open when B<onoff> is 0, and enables TCP Fast
|
||||||
|
Open when B<onoff> is nonzero. Setting the value to 1 is equivalent to setting
|
||||||
|
B<BIO_SOCK_TFO> in BIO_set_conn_mode().
|
||||||
|
|
||||||
=head1 RETURN VALUES
|
=head1 RETURN VALUES
|
||||||
|
|
||||||
BIO_reset() normally returns 1 for success and <=0 for failure. File
|
BIO_reset() normally returns 1 for success and <=0 for failure. File
|
||||||
|
@ -107,6 +119,19 @@ sending. Otherwise, it returns zero.
|
||||||
BIO_get_ktls_recv() returns 1 if the BIO is using the Kernel TLS data-path for
|
BIO_get_ktls_recv() returns 1 if the BIO is using the Kernel TLS data-path for
|
||||||
receiving. Otherwise, it returns zero.
|
receiving. Otherwise, it returns zero.
|
||||||
|
|
||||||
|
BIO_set_conn_mode() returns 1 for success and 0 for failure. BIO_get_conn_mode()
|
||||||
|
returns the current connection mode. Which may contain the bitwise-or of the
|
||||||
|
following flags:
|
||||||
|
|
||||||
|
BIO_SOCK_REUSEADDR
|
||||||
|
BIO_SOCK_V6_ONLY
|
||||||
|
BIO_SOCK_KEEPALIVE
|
||||||
|
BIO_SOCK_NONBLOCK
|
||||||
|
BIO_SOCK_NODELAY
|
||||||
|
BIO_SOCK_TFO
|
||||||
|
|
||||||
|
BIO_set_tfo() returns 1 for success, and 0 for failure.
|
||||||
|
|
||||||
=head1 NOTES
|
=head1 NOTES
|
||||||
|
|
||||||
BIO_flush(), because it can write data may return 0 or -1 indicating
|
BIO_flush(), because it can write data may return 0 or -1 indicating
|
||||||
|
@ -144,6 +169,9 @@ the case of BIO_seek() on a file BIO for a successful operation.
|
||||||
The BIO_get_ktls_send() and BIO_get_ktls_recv() functions were added in
|
The BIO_get_ktls_send() and BIO_get_ktls_recv() functions were added in
|
||||||
OpenSSL 3.0.
|
OpenSSL 3.0.
|
||||||
|
|
||||||
|
The BIO_get_conn_mode(), BIO_set_conn_mode() and BIO_set_tfo() functions
|
||||||
|
were added in OpenSSL 3.1.
|
||||||
|
|
||||||
=head1 COPYRIGHT
|
=head1 COPYRIGHT
|
||||||
|
|
||||||
Copyright 2000-2021 The OpenSSL Project Authors. All Rights Reserved.
|
Copyright 2000-2021 The OpenSSL Project Authors. All Rights Reserved.
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
=head1 NAME
|
=head1 NAME
|
||||||
|
|
||||||
BIO_s_accept, BIO_set_accept_name, BIO_set_accept_port, BIO_get_accept_name,
|
BIO_s_accept, BIO_set_accept_name, BIO_set_accept_port, BIO_get_accept_name,
|
||||||
BIO_get_accept_port, BIO_new_accept, BIO_set_nbio_accept, BIO_set_accept_bios,
|
BIO_get_accept_port, BIO_new_accept, BIO_set_nbio_accept, BIO_set_tfo_accept, BIO_set_accept_bios,
|
||||||
BIO_get_peer_name, BIO_get_peer_port,
|
BIO_get_peer_name, BIO_get_peer_port,
|
||||||
BIO_get_accept_ip_family, BIO_set_accept_ip_family,
|
BIO_get_accept_ip_family, BIO_set_accept_ip_family,
|
||||||
BIO_set_bind_mode, BIO_get_bind_mode, BIO_do_accept - accept BIO
|
BIO_set_bind_mode, BIO_get_bind_mode, BIO_do_accept - accept BIO
|
||||||
|
@ -23,6 +23,7 @@ BIO_set_bind_mode, BIO_get_bind_mode, BIO_do_accept - accept BIO
|
||||||
BIO *BIO_new_accept(char *host_port);
|
BIO *BIO_new_accept(char *host_port);
|
||||||
|
|
||||||
long BIO_set_nbio_accept(BIO *b, int n);
|
long BIO_set_nbio_accept(BIO *b, int n);
|
||||||
|
long BIO_set_tfo_accept(BIO *b, int n);
|
||||||
long BIO_set_accept_bios(BIO *b, char *bio);
|
long BIO_set_accept_bios(BIO *b, char *bio);
|
||||||
|
|
||||||
char *BIO_get_peer_name(BIO *b);
|
char *BIO_get_peer_name(BIO *b);
|
||||||
|
@ -87,6 +88,11 @@ B<host_port>.
|
||||||
BIO_set_nbio_accept() sets the accept socket to blocking mode
|
BIO_set_nbio_accept() sets the accept socket to blocking mode
|
||||||
(the default) if B<n> is 0 or non blocking mode if B<n> is 1.
|
(the default) if B<n> is 0 or non blocking mode if B<n> is 1.
|
||||||
|
|
||||||
|
BIO_set_tfo_accept() enables TCP Fast Open on the accept socket
|
||||||
|
if B<n> is 1 or disables TCP Fast Open if B<n> is 0 (the default).
|
||||||
|
Setting the value to 1 is equivalent to setting B<BIO_SOCK_TFO>
|
||||||
|
in BIO_set_bind_mode().
|
||||||
|
|
||||||
BIO_set_accept_bios() can be used to set a chain of BIOs which
|
BIO_set_accept_bios() can be used to set a chain of BIOs which
|
||||||
will be duplicated and prepended to the chain when an incoming
|
will be duplicated and prepended to the chain when an incoming
|
||||||
connection is received. This is useful if, for example, a
|
connection is received. This is useful if, for example, a
|
||||||
|
@ -107,7 +113,9 @@ B<BIO_BIND_REUSEADDR> is set then other sockets can bind to the
|
||||||
same port. If B<BIO_BIND_REUSEADDR_IF_UNUSED> is set then and
|
same port. If B<BIO_BIND_REUSEADDR_IF_UNUSED> is set then and
|
||||||
attempt is first made to use BIO_BIN_NORMAL, if this fails
|
attempt is first made to use BIO_BIN_NORMAL, if this fails
|
||||||
and the port is not in use then a second attempt is made
|
and the port is not in use then a second attempt is made
|
||||||
using B<BIO_BIND_REUSEADDR>.
|
using B<BIO_BIND_REUSEADDR>. If B<BIO_SOCK_TFO> is set, then
|
||||||
|
the socket will be configured to accept TCP Fast Open
|
||||||
|
connections.
|
||||||
|
|
||||||
BIO_do_accept() serves two functions. When it is first
|
BIO_do_accept() serves two functions. When it is first
|
||||||
called, after the accept BIO has been setup, it will attempt
|
called, after the accept BIO has been setup, it will attempt
|
||||||
|
@ -230,6 +238,10 @@ down each and finally closes both down.
|
||||||
BIO_free(cbio);
|
BIO_free(cbio);
|
||||||
BIO_free(cbio2);
|
BIO_free(cbio2);
|
||||||
|
|
||||||
|
=head1 HISTORY
|
||||||
|
|
||||||
|
BIO_set_tfo_accept() was added in OpenSSL 3.1.
|
||||||
|
|
||||||
=head1 COPYRIGHT
|
=head1 COPYRIGHT
|
||||||
|
|
||||||
Copyright 2000-2021 The OpenSSL Project Authors. All Rights Reserved.
|
Copyright 2000-2021 The OpenSSL Project Authors. All Rights Reserved.
|
||||||
|
|
|
@ -36,7 +36,6 @@ BIO and one or more filter BIOs. Data read from or written to the
|
||||||
first BIO then traverses the chain to the end (normally a source/sink
|
first BIO then traverses the chain to the end (normally a source/sink
|
||||||
BIO).
|
BIO).
|
||||||
|
|
||||||
|
|
||||||
Some BIOs (such as memory BIOs) can be used immediately after calling
|
Some BIOs (such as memory BIOs) can be used immediately after calling
|
||||||
BIO_new(). Others (such as file BIOs) need some additional initialization,
|
BIO_new(). Others (such as file BIOs) need some additional initialization,
|
||||||
and frequently a utility function exists to create and initialize such BIOs.
|
and frequently a utility function exists to create and initialize such BIOs.
|
||||||
|
@ -52,6 +51,29 @@ pointer to a BIO_METHOD. There is a naming convention for such functions:
|
||||||
a source/sink BIO typically starts with I<BIO_s_> and
|
a source/sink BIO typically starts with I<BIO_s_> and
|
||||||
a filter BIO with I<BIO_f_>.
|
a filter BIO with I<BIO_f_>.
|
||||||
|
|
||||||
|
=head2 TCP Fast Open
|
||||||
|
|
||||||
|
TCP Fast Open (RFC7413), abbreviated "TFO", is supported by the BIO
|
||||||
|
interface since OpenSSL 3.1. TFO is supported in the following operating systems:
|
||||||
|
|
||||||
|
=over 4
|
||||||
|
|
||||||
|
=item * Linux kernel 3.13 and later, where TFO is enabled by default.
|
||||||
|
|
||||||
|
=item * Linux kernel 4.11 and later, using TCP_FASTOPEN_CONNECT.
|
||||||
|
|
||||||
|
=item * FreeBSD 10.3 to 11.4, supports server TFO only.
|
||||||
|
|
||||||
|
=item * FreeBSD 12.0 and later, supports both client and server TFO.
|
||||||
|
|
||||||
|
=item * macOS 10.14 and later.
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
Each operating system has a slightly different API for TFO. Please
|
||||||
|
refer to the operating systems' API documentation when using
|
||||||
|
sockets directly.
|
||||||
|
|
||||||
=head1 EXAMPLES
|
=head1 EXAMPLES
|
||||||
|
|
||||||
Create a memory BIO:
|
Create a memory BIO:
|
||||||
|
@ -65,7 +87,9 @@ L<BIO_f_base64(3)>, L<BIO_f_buffer(3)>,
|
||||||
L<BIO_f_cipher(3)>, L<BIO_f_md(3)>,
|
L<BIO_f_cipher(3)>, L<BIO_f_md(3)>,
|
||||||
L<BIO_f_null(3)>, L<BIO_f_ssl(3)>,
|
L<BIO_f_null(3)>, L<BIO_f_ssl(3)>,
|
||||||
L<BIO_f_readbuffer(3)>,
|
L<BIO_f_readbuffer(3)>,
|
||||||
L<BIO_find_type(3)>, L<BIO_new(3)>,
|
L<BIO_find_type(3)>,
|
||||||
|
L<BIO_get_conn_mode(3)>,
|
||||||
|
L<BIO_new(3)>,
|
||||||
L<BIO_new_bio_pair(3)>,
|
L<BIO_new_bio_pair(3)>,
|
||||||
L<BIO_push(3)>, L<BIO_read_ex(3)>,
|
L<BIO_push(3)>, L<BIO_read_ex(3)>,
|
||||||
L<BIO_s_accept(3)>, L<BIO_s_bio(3)>,
|
L<BIO_s_accept(3)>, L<BIO_s_bio(3)>,
|
||||||
|
@ -73,6 +97,9 @@ L<BIO_s_connect(3)>, L<BIO_s_fd(3)>,
|
||||||
L<BIO_s_file(3)>, L<BIO_s_mem(3)>,
|
L<BIO_s_file(3)>, L<BIO_s_mem(3)>,
|
||||||
L<BIO_s_null(3)>, L<BIO_s_socket(3)>,
|
L<BIO_s_null(3)>, L<BIO_s_socket(3)>,
|
||||||
L<BIO_set_callback(3)>,
|
L<BIO_set_callback(3)>,
|
||||||
|
L<BIO_set_conn_mode(3)>,
|
||||||
|
L<BIO_set_tfo(3)>,
|
||||||
|
L<BIO_set_tfo_accept(3)>,
|
||||||
L<BIO_should_retry(3)>
|
L<BIO_should_retry(3)>
|
||||||
|
|
||||||
=head1 COPYRIGHT
|
=head1 COPYRIGHT
|
||||||
|
@ -85,4 +112,3 @@ in the file LICENSE in the source distribution or at
|
||||||
L<https://www.openssl.org/source/license.html>.
|
L<https://www.openssl.org/source/license.html>.
|
||||||
|
|
||||||
=cut
|
=cut
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,151 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2022 The OpenSSL Project Authors. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Contains definitions for simplifying the use of TCP Fast Open
|
||||||
|
* (RFC7413) in OpenSSL socket BIOs.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* If a supported OS is added here, update test/bio_tfo_test.c */
|
||||||
|
#if defined(TCP_FASTOPEN) && !defined(OPENSSL_NO_TFO)
|
||||||
|
|
||||||
|
# if defined(OPENSSL_SYS_MACOSX) || defined(__FreeBSD__)
|
||||||
|
# include <sys/sysctl.h>
|
||||||
|
# endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* OSSL_TFO_SYSCTL is used to determine if TFO is supported by
|
||||||
|
* this kernel, and if supported, if it is enabled. This is more of
|
||||||
|
* a problem on FreeBSD 10.3 ~ 11.4, where TCP_FASTOPEN was defined,
|
||||||
|
* but not enabled by default in the kernel, and only for the server.
|
||||||
|
* Linux does not have sysctlbyname(), and the closest equivalent
|
||||||
|
* is to go into the /proc filesystem, but I'm not sure it's
|
||||||
|
* worthwhile.
|
||||||
|
*
|
||||||
|
* On MacOS and Linux:
|
||||||
|
* These operating systems use a single parameter to control TFO.
|
||||||
|
* The OSSL_TFO_CLIENT_FLAG and OSSL_TFO_SERVER_FLAGS are used to
|
||||||
|
* determine if TFO is enabled for the client and server respectively.
|
||||||
|
*
|
||||||
|
* OSSL_TFO_CLIENT_FLAG = 1 = client TFO enabled
|
||||||
|
* OSSL_TFO_SERVER_FLAG = 2 = server TFO enabled
|
||||||
|
*
|
||||||
|
* Such that:
|
||||||
|
* 0 = TFO disabled
|
||||||
|
* 3 = server and client TFO enabled
|
||||||
|
*
|
||||||
|
* macOS 10.14 and later support TFO.
|
||||||
|
* Linux kernel 3.6 added support for client TFO.
|
||||||
|
* Linux kernel 3.7 added support for server TFO.
|
||||||
|
* Linux kernel 3.13 enabled TFO by default.
|
||||||
|
* Linux kernel 4.11 added the TCP_FASTOPEN_CONNECT option.
|
||||||
|
*
|
||||||
|
* On FreeBSD:
|
||||||
|
* FreeBSD 10.3 ~ 11.4 uses a single sysctl for server enable.
|
||||||
|
* FreeBSD 12.0 and later uses separate sysctls for server and
|
||||||
|
* client enable.
|
||||||
|
*
|
||||||
|
* Some options are purposely NOT defined per-platform
|
||||||
|
*
|
||||||
|
* OSSL_TFO_SYSCTL
|
||||||
|
* Defined as a sysctlbyname() option to to determine if
|
||||||
|
* TFO is enabled in the kernel (macOS, FreeBSD)
|
||||||
|
*
|
||||||
|
* OSSL_TFO_SERVER_SOCKOPT
|
||||||
|
* Defined to indicate the socket option used to enable
|
||||||
|
* TFO on a server socket (all)
|
||||||
|
*
|
||||||
|
* OSSL_TFO_SERVER_SOCKOPT_VALUE
|
||||||
|
* Value to be used with OSSL_TFO_SERVER_SOCKOPT
|
||||||
|
*
|
||||||
|
* OSSL_TFO_CONNECTX
|
||||||
|
* Use the connectx() function to make a client connection
|
||||||
|
* (macOS)
|
||||||
|
*
|
||||||
|
* OSSL_TFO_CLIENT_SOCKOPT
|
||||||
|
* Defined to indicate the socket option used to enable
|
||||||
|
* TFO on a client socket (FreeBSD, Linux 4.14 and later)
|
||||||
|
*
|
||||||
|
* OSSL_TFO_SENDTO
|
||||||
|
* Defined to indicate the sendto() message type to
|
||||||
|
* be used to initiate a TFO connection (FreeBSD,
|
||||||
|
* Linux pre-4.14)
|
||||||
|
*
|
||||||
|
* OSSL_TFO_DO_NOT_CONNECT
|
||||||
|
* Defined to skip calling conect() when creating a
|
||||||
|
* client socket (macOS, FreeBSD, Linux pre-4.14)
|
||||||
|
*/
|
||||||
|
|
||||||
|
# if defined(OPENSSL_SYS_WINDOWS)
|
||||||
|
/*
|
||||||
|
* NO WINDOWS SUPPORT
|
||||||
|
*
|
||||||
|
* But this is is what would be used on the server:
|
||||||
|
*
|
||||||
|
* define OSSL_TFO_SERVER_SOCKOPT TCP_FASTOPEN
|
||||||
|
* define OSSL_TFO_SERVER_SOCKOPT_VALUE 1
|
||||||
|
*
|
||||||
|
* Still have to figure out client support
|
||||||
|
*/
|
||||||
|
# undef TCP_FASTOPEN
|
||||||
|
# endif
|
||||||
|
|
||||||
|
/* NO VMS SUPPORT */
|
||||||
|
# if defined(OPENSSL_SYS_VMS)
|
||||||
|
# undef TCP_FASTOPEN
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# if defined(OPENSSL_SYS_MACOSX)
|
||||||
|
# define OSSL_TFO_SYSCTL "net.inet.tcp.fastopen"
|
||||||
|
# define OSSL_TFO_SERVER_SOCKOPT TCP_FASTOPEN
|
||||||
|
# define OSSL_TFO_SERVER_SOCKOPT_VALUE 1
|
||||||
|
# define OSSL_TFO_CONNECTX 1
|
||||||
|
# define OSSL_TFO_DO_NOT_CONNECT 1
|
||||||
|
# define OSSL_TFO_CLIENT_FLAG 1
|
||||||
|
# define OSSL_TFO_SERVER_FLAG 2
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# if defined(__FreeBSD__)
|
||||||
|
# if defined(TCP_FASTOPEN_PSK_LEN)
|
||||||
|
/* As of 12.0 these are the SYSCTLs */
|
||||||
|
# define OSSL_TFO_SYSCTL_SERVER "net.inet.tcp.fastopen.server_enable"
|
||||||
|
# define OSSL_TFO_SYSCTL_CLIENT "net.inet.tcp.fastopen.client_enable"
|
||||||
|
# define OSSL_TFO_SERVER_SOCKOPT TCP_FASTOPEN
|
||||||
|
# define OSSL_TFO_SERVER_SOCKOPT_VALUE MAX_LISTEN
|
||||||
|
# define OSSL_TFO_CLIENT_SOCKOPT TCP_FASTOPEN
|
||||||
|
# define OSSL_TFO_DO_NOT_CONNECT 1
|
||||||
|
# define OSSL_TFO_SENDTO 0
|
||||||
|
/* These are the same because the sysctl are client/server-specific */
|
||||||
|
# define OSSL_TFO_CLIENT_FLAG 1
|
||||||
|
# define OSSL_TFO_SERVER_FLAG 1
|
||||||
|
# else
|
||||||
|
/* 10.3 through 11.4 SYSCTL - ONLY SERVER SUPPORT */
|
||||||
|
# define OSSL_TFO_SYSCTL "net.inet.tcp.fastopen.enabled"
|
||||||
|
# define OSSL_TFO_SERVER_SOCKOPT TCP_FASTOPEN
|
||||||
|
# define OSSL_TFO_SERVER_SOCKOPT_VALUE MAX_LISTEN
|
||||||
|
# define OSSL_TFO_SERVER_FLAG 1
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# if defined(OPENSSL_SYS_LINUX)
|
||||||
|
/* OSSL_TFO_PROC not used, but of interest */
|
||||||
|
# define OSSL_TFO_PROC "/proc/sys/net/ipv4/tcp_fastopen"
|
||||||
|
# define OSSL_TFO_SERVER_SOCKOPT TCP_FASTOPEN
|
||||||
|
# define OSSL_TFO_SERVER_SOCKOPT_VALUE MAX_LISTEN
|
||||||
|
# if defined(TCP_FASTOPEN_CONNECT)
|
||||||
|
# define OSSL_TFO_CLIENT_SOCKOPT TCP_FASTOPEN_CONNECT
|
||||||
|
# else
|
||||||
|
# define OSSL_TFO_SENDTO MSG_FASTOPEN
|
||||||
|
# define OSSL_TFO_DO_NOT_CONNECT 1
|
||||||
|
# endif
|
||||||
|
# define OSSL_TFO_CLIENT_FLAG 1
|
||||||
|
# define OSSL_TFO_SERVER_FLAG 2
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -405,10 +405,13 @@ struct bio_dgram_sctp_prinfo {
|
||||||
|
|
||||||
# define BIO_C_SET_CONNECT_MODE 155
|
# define BIO_C_SET_CONNECT_MODE 155
|
||||||
|
|
||||||
|
# define BIO_C_SET_TFO 156 /* like BIO_C_SET_NBIO */
|
||||||
|
|
||||||
# define BIO_set_app_data(s,arg) BIO_set_ex_data(s,0,arg)
|
# define BIO_set_app_data(s,arg) BIO_set_ex_data(s,0,arg)
|
||||||
# define BIO_get_app_data(s) BIO_get_ex_data(s,0)
|
# define BIO_get_app_data(s) BIO_get_ex_data(s,0)
|
||||||
|
|
||||||
# define BIO_set_nbio(b,n) BIO_ctrl(b,BIO_C_SET_NBIO,(n),NULL)
|
# define BIO_set_nbio(b,n) BIO_ctrl(b,BIO_C_SET_NBIO,(n),NULL)
|
||||||
|
# define BIO_set_tfo(b,n) BIO_ctrl(b,BIO_C_SET_TFO,(n),NULL)
|
||||||
|
|
||||||
# ifndef OPENSSL_NO_SOCK
|
# ifndef OPENSSL_NO_SOCK
|
||||||
/* IP families we support, for BIO_s_connect() and BIO_s_accept() */
|
/* IP families we support, for BIO_s_connect() and BIO_s_accept() */
|
||||||
|
@ -429,6 +432,7 @@ struct bio_dgram_sctp_prinfo {
|
||||||
# define BIO_get_conn_port(b) ((const char *)BIO_ptr_ctrl(b,BIO_C_GET_CONNECT,1))
|
# define BIO_get_conn_port(b) ((const char *)BIO_ptr_ctrl(b,BIO_C_GET_CONNECT,1))
|
||||||
# define BIO_get_conn_address(b) ((const BIO_ADDR *)BIO_ptr_ctrl(b,BIO_C_GET_CONNECT,2))
|
# define BIO_get_conn_address(b) ((const BIO_ADDR *)BIO_ptr_ctrl(b,BIO_C_GET_CONNECT,2))
|
||||||
# define BIO_get_conn_ip_family(b) BIO_ctrl(b,BIO_C_GET_CONNECT,3,NULL)
|
# define BIO_get_conn_ip_family(b) BIO_ctrl(b,BIO_C_GET_CONNECT,3,NULL)
|
||||||
|
# define BIO_get_conn_mode(b) BIO_ctrl(b,BIO_C_GET_CONNECT,4,NULL)
|
||||||
# define BIO_set_conn_mode(b,n) BIO_ctrl(b,BIO_C_SET_CONNECT_MODE,(n),NULL)
|
# define BIO_set_conn_mode(b,n) BIO_ctrl(b,BIO_C_SET_CONNECT_MODE,(n),NULL)
|
||||||
|
|
||||||
/* BIO_s_accept() */
|
/* BIO_s_accept() */
|
||||||
|
@ -446,6 +450,7 @@ struct bio_dgram_sctp_prinfo {
|
||||||
(char *)(bio))
|
(char *)(bio))
|
||||||
# define BIO_set_accept_ip_family(b,f) BIO_int_ctrl(b,BIO_C_SET_ACCEPT,4,f)
|
# define BIO_set_accept_ip_family(b,f) BIO_int_ctrl(b,BIO_C_SET_ACCEPT,4,f)
|
||||||
# define BIO_get_accept_ip_family(b) BIO_ctrl(b,BIO_C_GET_ACCEPT,4,NULL)
|
# define BIO_get_accept_ip_family(b) BIO_ctrl(b,BIO_C_GET_ACCEPT,4,NULL)
|
||||||
|
# define BIO_set_tfo_accept(b,n) BIO_ctrl(b,BIO_C_SET_ACCEPT,5,(n)?(void *)"a":NULL)
|
||||||
|
|
||||||
/* Aliases kept for backward compatibility */
|
/* Aliases kept for backward compatibility */
|
||||||
# define BIO_BIND_NORMAL 0
|
# define BIO_BIND_NORMAL 0
|
||||||
|
@ -703,6 +708,7 @@ int BIO_hex_string(BIO *out, int indent, int width, const void *data,
|
||||||
|
|
||||||
# ifndef OPENSSL_NO_SOCK
|
# ifndef OPENSSL_NO_SOCK
|
||||||
BIO_ADDR *BIO_ADDR_new(void);
|
BIO_ADDR *BIO_ADDR_new(void);
|
||||||
|
BIO_ADDR *BIO_ADDR_dup(const BIO_ADDR *ap);
|
||||||
int BIO_ADDR_rawmake(BIO_ADDR *ap, int family,
|
int BIO_ADDR_rawmake(BIO_ADDR *ap, int family,
|
||||||
const void *where, size_t wherelen, unsigned short port);
|
const void *where, size_t wherelen, unsigned short port);
|
||||||
void BIO_ADDR_free(BIO_ADDR *);
|
void BIO_ADDR_free(BIO_ADDR *);
|
||||||
|
@ -765,6 +771,7 @@ int BIO_sock_info(int sock,
|
||||||
# define BIO_SOCK_KEEPALIVE 0x04
|
# define BIO_SOCK_KEEPALIVE 0x04
|
||||||
# define BIO_SOCK_NONBLOCK 0x08
|
# define BIO_SOCK_NONBLOCK 0x08
|
||||||
# define BIO_SOCK_NODELAY 0x10
|
# define BIO_SOCK_NODELAY 0x10
|
||||||
|
# define BIO_SOCK_TFO 0x20
|
||||||
|
|
||||||
int BIO_socket(int domain, int socktype, int protocol, int options);
|
int BIO_socket(int domain, int socktype, int protocol, int options);
|
||||||
int BIO_connect(int sock, const BIO_ADDR *addr, int options);
|
int BIO_connect(int sock, const BIO_ADDR *addr, int options);
|
||||||
|
|
|
@ -45,6 +45,8 @@
|
||||||
# define BIO_R_NO_PORT_DEFINED 113
|
# define BIO_R_NO_PORT_DEFINED 113
|
||||||
# define BIO_R_NO_SUCH_FILE 128
|
# define BIO_R_NO_SUCH_FILE 128
|
||||||
# define BIO_R_NULL_PARAMETER 115 /* unused */
|
# define BIO_R_NULL_PARAMETER 115 /* unused */
|
||||||
|
# define BIO_R_TFO_DISABLED 106
|
||||||
|
# define BIO_R_TFO_NO_KERNEL_SUPPORT 108
|
||||||
# define BIO_R_TRANSFER_ERROR 104
|
# define BIO_R_TRANSFER_ERROR 104
|
||||||
# define BIO_R_TRANSFER_TIMEOUT 105
|
# define BIO_R_TRANSFER_TIMEOUT 105
|
||||||
# define BIO_R_UNABLE_TO_BIND_SOCKET 117
|
# define BIO_R_UNABLE_TO_BIND_SOCKET 117
|
||||||
|
@ -53,6 +55,7 @@
|
||||||
# define BIO_R_UNABLE_TO_LISTEN_SOCKET 119
|
# define BIO_R_UNABLE_TO_LISTEN_SOCKET 119
|
||||||
# define BIO_R_UNABLE_TO_NODELAY 138
|
# define BIO_R_UNABLE_TO_NODELAY 138
|
||||||
# define BIO_R_UNABLE_TO_REUSEADDR 139
|
# define BIO_R_UNABLE_TO_REUSEADDR 139
|
||||||
|
# define BIO_R_UNABLE_TO_TFO 109
|
||||||
# define BIO_R_UNAVAILABLE_IP_FAMILY 145
|
# define BIO_R_UNAVAILABLE_IP_FAMILY 145
|
||||||
# define BIO_R_UNINITIALIZED 120
|
# define BIO_R_UNINITIALIZED 120
|
||||||
# define BIO_R_UNKNOWN_INFO_TYPE 140
|
# define BIO_R_UNKNOWN_INFO_TYPE 140
|
||||||
|
|
|
@ -0,0 +1,418 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2022 The OpenSSL Project Authors. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <openssl/bio.h>
|
||||||
|
#include "internal/e_os.h"
|
||||||
|
#include "internal/sockets.h"
|
||||||
|
#include "internal/bio_tfo.h"
|
||||||
|
#include "testutil.h"
|
||||||
|
|
||||||
|
/* If OS support is added in crypto/bio/bio_tfo.h, add it here */
|
||||||
|
#if defined(OPENSSL_SYS_LINUX)
|
||||||
|
# define GOOD_OS 1
|
||||||
|
#elif defined(__FreeBSD__)
|
||||||
|
# define GOOD_OS 1
|
||||||
|
#elif defined(OPENSSL_SYS_MACOSX)
|
||||||
|
# define GOOD_OS 1
|
||||||
|
#else
|
||||||
|
# ifdef GOOD_OS
|
||||||
|
# undef GOOD_OS
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(OPENSSL_NO_TFO) && defined(GOOD_OS)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This test is to ensure that if TCP Fast Open is configured, that socket
|
||||||
|
* connections will still work. These tests are able to detect if TCP Fast
|
||||||
|
* Open works, but the tests will pass as long as the socket connects.
|
||||||
|
*
|
||||||
|
* The first test function tests the socket interface as implemented as BIOs.
|
||||||
|
*
|
||||||
|
* The second test functions tests the socket interface as implemented as fds.
|
||||||
|
*
|
||||||
|
* The tests are run 5 times. The first time is without TFO.
|
||||||
|
* The second test will create the TCP fast open cookie,
|
||||||
|
* this can be seen in `ip tcp_metrics` and in /proc/net/netstat/ on Linux.
|
||||||
|
* e.g. on Linux 4.15.0-135-generic:
|
||||||
|
* $ grep '^TcpExt:' /proc/net/netstat | cut -d ' ' -f 84-90 | column -t
|
||||||
|
* The third attempt will use the cookie and actually do TCP fast open.
|
||||||
|
* The 4th time is client-TFO only, the 5th time is server-TFO only.
|
||||||
|
*/
|
||||||
|
|
||||||
|
# define SOCKET_DATA "FooBar"
|
||||||
|
# define SOCKET_DATA_LEN sizeof(SOCKET_DATA)
|
||||||
|
|
||||||
|
static int test_bio_tfo(int idx)
|
||||||
|
{
|
||||||
|
BIO *cbio = NULL;
|
||||||
|
BIO *abio = NULL;
|
||||||
|
BIO *sbio = NULL;
|
||||||
|
int ret = 0;
|
||||||
|
int sockerr = 0;
|
||||||
|
const char *port;
|
||||||
|
int server_tfo = 0;
|
||||||
|
int client_tfo = 0;
|
||||||
|
size_t bytes;
|
||||||
|
char read_buffer[20];
|
||||||
|
|
||||||
|
switch (idx) {
|
||||||
|
default:
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
case 2:
|
||||||
|
server_tfo = 1;
|
||||||
|
client_tfo = 1;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
client_tfo = 1;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
server_tfo = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ACCEPT SOCKET */
|
||||||
|
if (!TEST_ptr(abio = BIO_new_accept("localhost:0"))
|
||||||
|
|| !TEST_true(BIO_set_nbio_accept(abio, 1))
|
||||||
|
|| !TEST_true(BIO_set_tfo_accept(abio, server_tfo))
|
||||||
|
|| !TEST_int_gt(BIO_do_accept(abio), 0)
|
||||||
|
|| !TEST_ptr(port = BIO_get_accept_port(abio))) {
|
||||||
|
sockerr = get_last_socket_error();
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Note: first BIO_do_accept will basically do the bind/listen */
|
||||||
|
|
||||||
|
/* CLIENT SOCKET */
|
||||||
|
if (!TEST_ptr(cbio = BIO_new_connect("localhost"))
|
||||||
|
|| !TEST_long_gt(BIO_set_conn_port(cbio, port), 0)
|
||||||
|
|| !TEST_long_gt(BIO_set_nbio(cbio, 1), 0)
|
||||||
|
|| !TEST_long_gt(BIO_set_tfo(cbio, client_tfo), 0)) {
|
||||||
|
sockerr = get_last_socket_error();
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIRST ACCEPT: no connection should be established */
|
||||||
|
if (BIO_do_accept(abio) <= 0) {
|
||||||
|
if (!BIO_should_retry(abio)) {
|
||||||
|
sockerr = get_last_socket_error();
|
||||||
|
BIO_printf(bio_err, "Error: failed without EAGAIN\n");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sbio = BIO_pop(abio);
|
||||||
|
BIO_printf(bio_err, "Error: accepted unknown connection\n");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* CONNECT ATTEMPT: different behavior based on TFO support */
|
||||||
|
if (BIO_do_connect(cbio) <= 0) {
|
||||||
|
sockerr = get_last_socket_error();
|
||||||
|
if (sockerr == EOPNOTSUPP) {
|
||||||
|
BIO_printf(bio_err, "Skip: TFO not enabled/supported for client\n");
|
||||||
|
goto success;
|
||||||
|
} else if (sockerr != EINPROGRESS) {
|
||||||
|
BIO_printf(bio_err, "Error: failed without EINPROGRESSn");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* macOS needs some time for this to happen, so put in a select */
|
||||||
|
if (!TEST_int_ge(BIO_wait(abio, time(NULL) + 2, 0), 0)) {
|
||||||
|
sockerr = get_last_socket_error();
|
||||||
|
BIO_printf(bio_err, "Error: socket wait failed\n");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SECOND ACCEPT: if TFO is supported, this will still fail until data is sent */
|
||||||
|
if (BIO_do_accept(abio) <= 0) {
|
||||||
|
if (!BIO_should_retry(abio)) {
|
||||||
|
sockerr = get_last_socket_error();
|
||||||
|
BIO_printf(bio_err, "Error: failed without EAGAIN\n");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (idx == 0)
|
||||||
|
BIO_printf(bio_err, "Success: non-TFO connection accepted without data\n");
|
||||||
|
else if (idx == 1)
|
||||||
|
BIO_printf(bio_err, "Ignore: connection accepted before data, possibly no TFO cookie, or TFO may not be enabled\n");
|
||||||
|
else if (idx == 4)
|
||||||
|
BIO_printf(bio_err, "Success: connection accepted before data, client TFO is disabled\n");
|
||||||
|
else
|
||||||
|
BIO_printf(bio_err, "Warning: connection accepted before data, TFO may not be enabled\n");
|
||||||
|
sbio = BIO_pop(abio);
|
||||||
|
goto success;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SEND DATA: this should establish the actual TFO connection */
|
||||||
|
if (!TEST_true(BIO_write_ex(cbio, SOCKET_DATA, SOCKET_DATA_LEN, &bytes))) {
|
||||||
|
sockerr = get_last_socket_error();
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* macOS needs some time for this to happen, so put in a select */
|
||||||
|
if (!TEST_int_ge(BIO_wait(abio, time(NULL) + 2, 0), 0)) {
|
||||||
|
sockerr = get_last_socket_error();
|
||||||
|
BIO_printf(bio_err, "Error: socket wait failed\n");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FINAL ACCEPT: if TFO is enabled, socket should be accepted at *this* point */
|
||||||
|
if (BIO_do_accept(abio) <= 0) {
|
||||||
|
sockerr = get_last_socket_error();
|
||||||
|
BIO_printf(bio_err, "Error: socket not accepted\n");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
BIO_printf(bio_err, "Success: Server accepted socket after write\n");
|
||||||
|
if (!TEST_ptr(sbio = BIO_pop(abio))
|
||||||
|
|| !TEST_true(BIO_read_ex(sbio, read_buffer, sizeof(read_buffer), &bytes))
|
||||||
|
|| !TEST_size_t_eq(bytes, SOCKET_DATA_LEN)
|
||||||
|
|| !TEST_strn_eq(read_buffer, SOCKET_DATA, SOCKET_DATA_LEN)) {
|
||||||
|
sockerr = get_last_socket_error();
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
success:
|
||||||
|
sockerr = 0;
|
||||||
|
ret = 1;
|
||||||
|
|
||||||
|
err:
|
||||||
|
if (sockerr != 0) {
|
||||||
|
const char *errstr = strerror(sockerr);
|
||||||
|
|
||||||
|
if (errstr != NULL)
|
||||||
|
BIO_printf(bio_err, "last errno: %d=%s\n", sockerr, errstr);
|
||||||
|
}
|
||||||
|
BIO_free(cbio);
|
||||||
|
BIO_free(abio);
|
||||||
|
BIO_free(sbio);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int test_fd_tfo(int idx)
|
||||||
|
{
|
||||||
|
struct sockaddr_storage sstorage;
|
||||||
|
socklen_t slen;
|
||||||
|
struct addrinfo *ai = NULL;
|
||||||
|
struct addrinfo hints;
|
||||||
|
int ret = 0;
|
||||||
|
int cfd = -1; /* client socket */
|
||||||
|
int afd = -1; /* accept socket */
|
||||||
|
int sfd = -1; /* server accepted socket */
|
||||||
|
BIO_ADDR *baddr = NULL;
|
||||||
|
char read_buffer[20];
|
||||||
|
int bytes_read;
|
||||||
|
int server_flags = BIO_SOCK_NONBLOCK;
|
||||||
|
int client_flags = BIO_SOCK_NONBLOCK;
|
||||||
|
int sockerr = 0;
|
||||||
|
unsigned short port;
|
||||||
|
void *addr;
|
||||||
|
size_t addrlen;
|
||||||
|
|
||||||
|
switch (idx) {
|
||||||
|
default:
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
case 2:
|
||||||
|
server_flags |= BIO_SOCK_TFO;
|
||||||
|
client_flags |= BIO_SOCK_TFO;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
client_flags |= BIO_SOCK_TFO;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
server_flags |= BIO_SOCK_TFO;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ADDRESS SETUP */
|
||||||
|
memset(&hints, 0, sizeof(hints));
|
||||||
|
hints.ai_family = AF_UNSPEC;
|
||||||
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
|
if (!TEST_int_eq(getaddrinfo(NULL, "0", &hints, &ai), 0))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
switch (ai->ai_family) {
|
||||||
|
case AF_INET:
|
||||||
|
port = ((struct sockaddr_in *)ai->ai_addr)->sin_port;
|
||||||
|
addr = &((struct sockaddr_in *)ai->ai_addr)->sin_addr;
|
||||||
|
addrlen = sizeof(((struct sockaddr_in *)ai->ai_addr)->sin_addr);
|
||||||
|
BIO_printf(bio_err, "Using IPv4\n");
|
||||||
|
break;
|
||||||
|
case AF_INET6:
|
||||||
|
port = ((struct sockaddr_in6 *)ai->ai_addr)->sin6_port;
|
||||||
|
addr = &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr;
|
||||||
|
addrlen = sizeof(((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr);
|
||||||
|
BIO_printf(bio_err, "Using IPv6\n");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
BIO_printf(bio_err, "Unknown address family %d\n", ai->ai_family);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!TEST_ptr(baddr = BIO_ADDR_new())
|
||||||
|
|| !TEST_true(BIO_ADDR_rawmake(baddr, ai->ai_family, addr, addrlen, port)))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
/* ACCEPT SOCKET */
|
||||||
|
|
||||||
|
if (!TEST_int_ge(afd = BIO_socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol, 0), 0)
|
||||||
|
|| !TEST_true(BIO_listen(afd, baddr, server_flags)))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
/* UPDATE ADDRESS WITH PORT */
|
||||||
|
slen = sizeof(sstorage);
|
||||||
|
if (!TEST_int_ge(getsockname(afd, (struct sockaddr *)&sstorage, &slen), 0))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
switch (sstorage.ss_family) {
|
||||||
|
case AF_INET:
|
||||||
|
port = ((struct sockaddr_in *)&sstorage)->sin_port;
|
||||||
|
addr = &((struct sockaddr_in *)&sstorage)->sin_addr;
|
||||||
|
addrlen = sizeof(((struct sockaddr_in *)&sstorage)->sin_addr);
|
||||||
|
break;
|
||||||
|
case AF_INET6:
|
||||||
|
port = ((struct sockaddr_in6 *)&sstorage)->sin6_port;
|
||||||
|
addr = &((struct sockaddr_in6 *)&sstorage)->sin6_addr;
|
||||||
|
addrlen = sizeof(((struct sockaddr_in6 *)&sstorage)->sin6_addr);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!TEST_true(BIO_ADDR_rawmake(baddr, sstorage.ss_family, addr, addrlen, port)))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
/* CLIENT SOCKET */
|
||||||
|
if (!TEST_int_ge(cfd = BIO_socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol, 0), 0))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
/* FIRST ACCEPT: no connection should be established */
|
||||||
|
sfd = BIO_accept_ex(afd, NULL, 0);
|
||||||
|
if (sfd == -1) {
|
||||||
|
sockerr = get_last_socket_error();
|
||||||
|
/* Note: Windows would hit WSAEWOULDBLOCK */
|
||||||
|
if (sockerr != EAGAIN) {
|
||||||
|
BIO_printf(bio_err, "Error: failed without EAGAIN\n");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
BIO_printf(bio_err, "Error: accepted unknown connection\n");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* CONNECT ATTEMPT: different behavior based on TFO support */
|
||||||
|
if (!BIO_connect(cfd, baddr, client_flags)) {
|
||||||
|
sockerr = get_last_socket_error();
|
||||||
|
if (sockerr == EOPNOTSUPP) {
|
||||||
|
BIO_printf(bio_err, "Skip: TFO not enabled/supported for client\n");
|
||||||
|
goto success;
|
||||||
|
} else {
|
||||||
|
/* Note: Windows would hit WSAEWOULDBLOCK */
|
||||||
|
if (sockerr != EINPROGRESS) {
|
||||||
|
BIO_printf(bio_err, "Error: failed without EINPROGRESS\n");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* macOS needs some time for this to happen, so put in a select */
|
||||||
|
if (!TEST_int_ge(BIO_socket_wait(afd, 1, time(NULL) + 2), 0)) {
|
||||||
|
sockerr = get_last_socket_error();
|
||||||
|
BIO_printf(bio_err, "Error: socket wait failed\n");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SECOND ACCEPT: if TFO is supported, this will still fail until data is sent */
|
||||||
|
sfd = BIO_accept_ex(afd, NULL, 0);
|
||||||
|
if (sfd == -1) {
|
||||||
|
sockerr = get_last_socket_error();
|
||||||
|
/* Note: Windows would hit WSAEWOULDBLOCK */
|
||||||
|
if (sockerr != EAGAIN) {
|
||||||
|
BIO_printf(bio_err, "Error: failed without EAGAIN\n");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (idx == 0)
|
||||||
|
BIO_printf(bio_err, "Success: non-TFO connection accepted without data\n");
|
||||||
|
else if (idx == 1)
|
||||||
|
BIO_printf(bio_err, "Ignore: connection accepted before data, possibly no TFO cookie, or TFO may not be enabled\n");
|
||||||
|
else if (idx == 4)
|
||||||
|
BIO_printf(bio_err, "Success: connection accepted before data, client TFO is disabled\n");
|
||||||
|
else
|
||||||
|
BIO_printf(bio_err, "Warning: connection accepted before data, TFO may not be enabled\n");
|
||||||
|
goto success;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SEND DATA: this should establish the actual TFO connection */
|
||||||
|
#ifdef OSSL_TFO_SENDTO
|
||||||
|
if (!TEST_int_ge(sendto(cfd, SOCKET_DATA, SOCKET_DATA_LEN, OSSL_TFO_SENDTO,
|
||||||
|
(struct sockaddr *)&sstorage, slen), 0)) {
|
||||||
|
sockerr = get_last_socket_error();
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (!TEST_int_ge(writesocket(cfd, SOCKET_DATA, SOCKET_DATA_LEN), 0)) {
|
||||||
|
sockerr = get_last_socket_error();
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* macOS needs some time for this to happen, so put in a select */
|
||||||
|
if (!TEST_int_ge(BIO_socket_wait(afd, 1, time(NULL) + 2), 0)) {
|
||||||
|
sockerr = get_last_socket_error();
|
||||||
|
BIO_printf(bio_err, "Error: socket wait failed\n");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FINAL ACCEPT: if TFO is enabled, socket should be accepted at *this* point */
|
||||||
|
sfd = BIO_accept_ex(afd, NULL, 0);
|
||||||
|
if (sfd == -1) {
|
||||||
|
sockerr = get_last_socket_error();
|
||||||
|
BIO_printf(bio_err, "Error: socket not accepted\n");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
BIO_printf(bio_err, "Success: Server accepted socket after write\n");
|
||||||
|
bytes_read = readsocket(sfd, read_buffer, sizeof(read_buffer));
|
||||||
|
if (!TEST_int_eq(bytes_read, SOCKET_DATA_LEN)
|
||||||
|
|| !TEST_strn_eq(read_buffer, SOCKET_DATA, SOCKET_DATA_LEN)) {
|
||||||
|
sockerr = get_last_socket_error();
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
success:
|
||||||
|
sockerr = 0;
|
||||||
|
ret = 1;
|
||||||
|
|
||||||
|
err:
|
||||||
|
if (sockerr != 0) {
|
||||||
|
const char *errstr = strerror(sockerr);
|
||||||
|
|
||||||
|
if (errstr != NULL)
|
||||||
|
BIO_printf(bio_err, "last errno: %d=%s\n", sockerr, errstr);
|
||||||
|
}
|
||||||
|
BIO_ADDR_free(baddr);
|
||||||
|
BIO_closesocket(cfd);
|
||||||
|
BIO_closesocket(sfd);
|
||||||
|
BIO_closesocket(afd);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int setup_tests(void)
|
||||||
|
{
|
||||||
|
#if !defined(OPENSSL_NO_TFO) && defined(GOOD_OS)
|
||||||
|
ADD_ALL_TESTS(test_bio_tfo, 5);
|
||||||
|
ADD_ALL_TESTS(test_fd_tfo, 5);
|
||||||
|
#endif
|
||||||
|
return 1;
|
||||||
|
}
|
|
@ -62,7 +62,8 @@ IF[{- !$disabled{tests} -}]
|
||||||
context_internal_test aesgcmtest params_test evp_pkey_dparams_test \
|
context_internal_test aesgcmtest params_test evp_pkey_dparams_test \
|
||||||
keymgmt_internal_test hexstr_test provider_status_test defltfips_test \
|
keymgmt_internal_test hexstr_test provider_status_test defltfips_test \
|
||||||
bio_readbuffer_test user_property_test pkcs7_test upcallstest \
|
bio_readbuffer_test user_property_test pkcs7_test upcallstest \
|
||||||
provfetchtest prov_config_test rand_test ca_internals_test
|
provfetchtest prov_config_test rand_test ca_internals_test \
|
||||||
|
bio_tfo_test
|
||||||
|
|
||||||
IF[{- !$disabled{'deprecated-3.0'} -}]
|
IF[{- !$disabled{'deprecated-3.0'} -}]
|
||||||
PROGRAMS{noinst}=enginetest
|
PROGRAMS{noinst}=enginetest
|
||||||
|
@ -370,6 +371,10 @@ IF[{- !$disabled{tests} -}]
|
||||||
INCLUDE[bio_core_test]=../include ../apps/include
|
INCLUDE[bio_core_test]=../include ../apps/include
|
||||||
DEPEND[bio_core_test]=../libcrypto libtestutil.a
|
DEPEND[bio_core_test]=../libcrypto libtestutil.a
|
||||||
|
|
||||||
|
SOURCE[bio_tfo_test]=bio_tfo_test.c
|
||||||
|
INCLUDE[bio_tfo_test]=../include ../apps/include ..
|
||||||
|
DEPEND[bio_tfo_test]=../libcrypto libtestutil.a
|
||||||
|
|
||||||
SOURCE[params_api_test]=params_api_test.c
|
SOURCE[params_api_test]=params_api_test.c
|
||||||
INCLUDE[params_api_test]=../include ../apps/include
|
INCLUDE[params_api_test]=../include ../apps/include
|
||||||
DEPEND[params_api_test]=../libcrypto libtestutil.a
|
DEPEND[params_api_test]=../libcrypto libtestutil.a
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
#! /usr/bin/env perl
|
||||||
|
# Copyright 2016-2021 The OpenSSL Project Authors. All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use OpenSSL::Test;
|
||||||
|
use OpenSSL::Test::Simple;
|
||||||
|
use OpenSSL::Test::Utils;
|
||||||
|
|
||||||
|
setup("test_bio_tfo");
|
||||||
|
|
||||||
|
plan skip_all => "This test requires enable-tfo" if disabled("tfo");
|
||||||
|
|
||||||
|
simple_test("test_bio_tfo", "bio_tfo_test");
|
|
@ -0,0 +1,87 @@
|
||||||
|
#! /usr/bin/env perl
|
||||||
|
# Copyright 2022 The OpenSSL Project Authors. All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use IPC::Open2;
|
||||||
|
use OpenSSL::Test qw/:DEFAULT srctop_file bldtop_file/;
|
||||||
|
use OpenSSL::Test::Utils;
|
||||||
|
|
||||||
|
setup("test_tfo");
|
||||||
|
|
||||||
|
plan skip_all => "test_tfo_cli needs sock enabled" if disabled("sock");
|
||||||
|
plan skip_all => "test_tfo_cli needs tls < 1.3 enabled"
|
||||||
|
if disabled("tls1") && disabled("tls1_1") && disabled("tls1_2");
|
||||||
|
plan skip_all => "test_tfo_cli does not run on Windows nor VMS"
|
||||||
|
if $^O =~ /^(VMS|MSWin32|msys)$/;
|
||||||
|
|
||||||
|
plan tests => 8;
|
||||||
|
|
||||||
|
my $shlib_wrap = bldtop_file("util", "shlib_wrap.sh");
|
||||||
|
my $apps_openssl = bldtop_file("apps", "openssl");
|
||||||
|
my $cert = srctop_file("apps", "server.pem");
|
||||||
|
|
||||||
|
sub run_test {
|
||||||
|
my $tfo = shift;
|
||||||
|
|
||||||
|
my $client_good = ! $tfo;
|
||||||
|
my $server_good = ! $tfo;
|
||||||
|
my $connect_good = 0;
|
||||||
|
my $port = "0";
|
||||||
|
|
||||||
|
# Not using TLSv1.3 allows the test to work with "no-ec"
|
||||||
|
my @s_cmd = ("s_server", "-accept", ":0", "-cert", $cert, "-www", "-no_tls1_3", "-naccept", "1");
|
||||||
|
push @s_cmd, "-tfo" if ($tfo);
|
||||||
|
|
||||||
|
my $spid = open2(my $sout, my $sin, $shlib_wrap, $apps_openssl, @s_cmd);
|
||||||
|
|
||||||
|
# Read until we get the port, TFO is output before the ACCEPT line
|
||||||
|
while (<$sout>) {
|
||||||
|
chomp;
|
||||||
|
$server_good = $tfo if /^Listening for TFO$/;
|
||||||
|
if (/^ACCEPT\s.*:(\d+)$/) {
|
||||||
|
$port = $1;
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
print STDERR "Port: $port\n";
|
||||||
|
print STDERR "Invalid port\n" if ! ok($port);
|
||||||
|
|
||||||
|
# Start up the client
|
||||||
|
my @c_cmd = ("s_client", "-connect", ":$port", "-no_tls1_3");
|
||||||
|
push @c_cmd, "-tfo" if ($tfo);
|
||||||
|
|
||||||
|
my $cpid = open2(my $cout, my $cin, $shlib_wrap, $apps_openssl, @c_cmd);
|
||||||
|
|
||||||
|
# Do the "GET", which will cause the client to finish
|
||||||
|
print $cin "GET /\r\n";
|
||||||
|
|
||||||
|
waitpid($cpid, 0);
|
||||||
|
waitpid($spid, 0);
|
||||||
|
|
||||||
|
# Check the client output
|
||||||
|
while (<$cout>) {
|
||||||
|
chomp;
|
||||||
|
$client_good = $tfo if /^Connecting via TFO$/;
|
||||||
|
$connect_good = 1 if /^Content-type: text/;
|
||||||
|
}
|
||||||
|
|
||||||
|
print STDERR "Client TFO check failed\n" if ! ok($client_good);
|
||||||
|
print STDERR "Server TFO check failed\n" if ! ok($server_good);
|
||||||
|
print STDERR "Connection failed\n" if ! ok($connect_good);
|
||||||
|
}
|
||||||
|
|
||||||
|
for my $tfo (0..1) {
|
||||||
|
SKIP:
|
||||||
|
{
|
||||||
|
skip "TFO not enabled", 4 if disabled("tfo") && $tfo;
|
||||||
|
|
||||||
|
run_test($tfo);
|
||||||
|
}
|
||||||
|
}
|
|
@ -5436,3 +5436,4 @@ BN_signed_native2bn ? 3_1_0 EXIST::FUNCTION:
|
||||||
BN_signed_bn2native ? 3_1_0 EXIST::FUNCTION:
|
BN_signed_bn2native ? 3_1_0 EXIST::FUNCTION:
|
||||||
ASYNC_set_mem_functions ? 3_1_0 EXIST::FUNCTION:
|
ASYNC_set_mem_functions ? 3_1_0 EXIST::FUNCTION:
|
||||||
ASYNC_get_mem_functions ? 3_1_0 EXIST::FUNCTION:
|
ASYNC_get_mem_functions ? 3_1_0 EXIST::FUNCTION:
|
||||||
|
BIO_ADDR_dup ? 3_1_0 EXIST::FUNCTION:SOCK
|
||||||
|
|
|
@ -9,7 +9,6 @@ BIO_get_retry_flags(3)
|
||||||
BIO_CB_return(3)
|
BIO_CB_return(3)
|
||||||
BIO_cb_pre(3)
|
BIO_cb_pre(3)
|
||||||
BIO_cb_post(3)
|
BIO_cb_post(3)
|
||||||
BIO_set_conn_mode(3)
|
|
||||||
BIO_dup_state(3)
|
BIO_dup_state(3)
|
||||||
BIO_buffer_get_num_lines(3)
|
BIO_buffer_get_num_lines(3)
|
||||||
BIO_buffer_peek(3)
|
BIO_buffer_peek(3)
|
||||||
|
|
|
@ -166,6 +166,7 @@ BIO_get_conn_address define
|
||||||
BIO_get_conn_hostname define
|
BIO_get_conn_hostname define
|
||||||
BIO_get_conn_port define
|
BIO_get_conn_port define
|
||||||
BIO_get_conn_ip_family define
|
BIO_get_conn_ip_family define
|
||||||
|
BIO_get_conn_mode define
|
||||||
BIO_get_fd define
|
BIO_get_fd define
|
||||||
BIO_get_fp define
|
BIO_get_fp define
|
||||||
BIO_get_indent define
|
BIO_get_indent define
|
||||||
|
@ -199,6 +200,7 @@ BIO_set_conn_address define
|
||||||
BIO_set_conn_hostname define
|
BIO_set_conn_hostname define
|
||||||
BIO_set_conn_port define
|
BIO_set_conn_port define
|
||||||
BIO_set_conn_ip_family define
|
BIO_set_conn_ip_family define
|
||||||
|
BIO_set_conn_mode define
|
||||||
BIO_set_fd define
|
BIO_set_fd define
|
||||||
BIO_set_fp define
|
BIO_set_fp define
|
||||||
BIO_set_indent define
|
BIO_set_indent define
|
||||||
|
@ -214,6 +216,8 @@ BIO_set_ssl define
|
||||||
BIO_set_ssl_mode define
|
BIO_set_ssl_mode define
|
||||||
BIO_set_ssl_renegotiate_bytes define
|
BIO_set_ssl_renegotiate_bytes define
|
||||||
BIO_set_ssl_renegotiate_timeout define
|
BIO_set_ssl_renegotiate_timeout define
|
||||||
|
BIO_set_tfo define
|
||||||
|
BIO_set_tfo_accept define
|
||||||
BIO_set_write_buf_size define
|
BIO_set_write_buf_size define
|
||||||
BIO_set_write_buffer_size define
|
BIO_set_write_buffer_size define
|
||||||
BIO_should_io_special define
|
BIO_should_io_special define
|
||||||
|
|
Loading…
Reference in New Issue