mirror of
https://github.com/openssl/openssl.git
synced 2024-11-21 01:15:20 +08:00
[feat] SSL RTT in both client and server statem. SSL_get_handshake_rtt makes it available
Reviewed-by: Tomas Mraz <tomas@openssl.org> Reviewed-by: David von Oheimb <david.von.oheimb@siemens.com> (Merged from https://github.com/openssl/openssl/pull/20248)
This commit is contained in:
parent
fc570b2605
commit
cee0628e0d
@ -25,6 +25,13 @@ OpenSSL 3.2
|
||||
|
||||
### Changes between 3.1 and 3.2 [xx XXX xxxx]
|
||||
|
||||
* TLS round-trip time calculation was added by a Brigham Young University
|
||||
Capstone team partnering with Sandia National Laboratories. A new function
|
||||
in ssl_lib titled SSL_get_handshake_rtt will calculate and retrieve this
|
||||
value.
|
||||
|
||||
*Jairus Christensen*
|
||||
|
||||
* Added the "-quic" option to s_client to enable connectivity to QUIC servers.
|
||||
QUIC requires the use of ALPN, so this must be specified via the "-alpn"
|
||||
option. Use of the "advanced" s_client command command via the "-adv" option
|
||||
|
@ -2551,6 +2551,10 @@ DEPEND[html/man3/SSL_get_fd.html]=man3/SSL_get_fd.pod
|
||||
GENERATE[html/man3/SSL_get_fd.html]=man3/SSL_get_fd.pod
|
||||
DEPEND[man/man3/SSL_get_fd.3]=man3/SSL_get_fd.pod
|
||||
GENERATE[man/man3/SSL_get_fd.3]=man3/SSL_get_fd.pod
|
||||
DEPEND[html/man3/SSL_get_handshake_rtt.html]=man3/SSL_get_handshake_rtt.pod
|
||||
GENERATE[html/man3/SSL_get_handshake_rtt.html]=man3/SSL_get_handshake_rtt.pod
|
||||
DEPEND[man/man3/SSL_get_handshake_rtt.3]=man3/SSL_get_handshake_rtt.pod
|
||||
GENERATE[man/man3/SSL_get_handshake_rtt.3]=man3/SSL_get_handshake_rtt.pod
|
||||
DEPEND[html/man3/SSL_get_peer_cert_chain.html]=man3/SSL_get_peer_cert_chain.pod
|
||||
GENERATE[html/man3/SSL_get_peer_cert_chain.html]=man3/SSL_get_peer_cert_chain.pod
|
||||
DEPEND[man/man3/SSL_get_peer_cert_chain.3]=man3/SSL_get_peer_cert_chain.pod
|
||||
@ -3533,6 +3537,7 @@ html/man3/SSL_get_error.html \
|
||||
html/man3/SSL_get_event_timeout.html \
|
||||
html/man3/SSL_get_extms_support.html \
|
||||
html/man3/SSL_get_fd.html \
|
||||
html/man3/SSL_get_handshake_rtt.html \
|
||||
html/man3/SSL_get_peer_cert_chain.html \
|
||||
html/man3/SSL_get_peer_certificate.html \
|
||||
html/man3/SSL_get_peer_signature_nid.html \
|
||||
@ -4169,6 +4174,7 @@ man/man3/SSL_get_error.3 \
|
||||
man/man3/SSL_get_event_timeout.3 \
|
||||
man/man3/SSL_get_extms_support.3 \
|
||||
man/man3/SSL_get_fd.3 \
|
||||
man/man3/SSL_get_handshake_rtt.3 \
|
||||
man/man3/SSL_get_peer_cert_chain.3 \
|
||||
man/man3/SSL_get_peer_certificate.3 \
|
||||
man/man3/SSL_get_peer_signature_nid.3 \
|
||||
|
57
doc/man3/SSL_get_handshake_rtt.pod
Normal file
57
doc/man3/SSL_get_handshake_rtt.pod
Normal file
@ -0,0 +1,57 @@
|
||||
=pod
|
||||
|
||||
=head1 NAME
|
||||
|
||||
SSL_get_handshake_rtt
|
||||
- get round trip time for SSL Handshake
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
int SSL_get_handshake_rtt(const SSL *s, uint64_t *rtt);
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
SSL_get_handshake_rtt() retrieves the round-trip time (RTT) for I<ssl>.
|
||||
|
||||
This metric is represented in microseconds (us) as a uint64_t data type.
|
||||
|
||||
=head1 NOTES
|
||||
|
||||
This metric is created by taking two timestamps during the handshake and
|
||||
providing the difference between these two times.
|
||||
|
||||
When acting as the server, one timestamp is taken when the server is finished
|
||||
writing to the client. This is during the ServerFinished in TLS 1.3 and
|
||||
ServerHelloDone in TLS 1.2. The other timestamp is taken when the server is
|
||||
done reading the client's response. This is after the client has responded
|
||||
with ClientFinished.
|
||||
|
||||
When acting as the client, one timestamp is taken when the client is finished
|
||||
writing the ClientHello and early data (if any). The other is taken when
|
||||
client is done reading the server's response. This is after ServerFinished in
|
||||
TLS 1.3 and after ServerHelloDone in TLS 1.2.
|
||||
|
||||
In addition to network propagation delay and network stack overhead, this
|
||||
metric includes processing time on both endpoints, as this is based on TLS
|
||||
protocol-level messages and the TLS protocol is not designed to measure
|
||||
network timings. In some cases the processing time can be significant,
|
||||
especially when the processing includes asymmetric cryptographic operations.
|
||||
|
||||
=head1 RETURN VALUES
|
||||
|
||||
Returns 1 if the TLS handshake RTT is successfully retrieved.
|
||||
Returns 0 if the TLS handshake RTT cannot be determined yet.
|
||||
Returns -1 if, while retrieving the TLS handshake RTT, an error occurs.
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
Copyright 2023 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
|
||||
L<https://www.openssl.org/source/license.html>.
|
||||
|
||||
=cut
|
@ -1948,6 +1948,7 @@ __owur int SSL_get_early_data_status(const SSL *s);
|
||||
|
||||
__owur int SSL_get_error(const SSL *s, int ret_code);
|
||||
__owur const char *SSL_get_version(const SSL *s);
|
||||
__owur int SSL_get_handshake_rtt(const SSL *s, uint64_t *rtt);
|
||||
|
||||
/* This sets the 'default' SSL version that SSL_new() will create */
|
||||
# ifndef OPENSSL_NO_DEPRECATED_3_0
|
||||
|
@ -4747,6 +4747,21 @@ const char *SSL_get_version(const SSL *s)
|
||||
return ssl_protocol_to_string(sc->version);
|
||||
}
|
||||
|
||||
__owur int SSL_get_handshake_rtt(const SSL *s, uint64_t *rtt)
|
||||
{
|
||||
const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL(s);
|
||||
|
||||
if (sc == NULL)
|
||||
return -1;
|
||||
if (sc->ts_msg_write.t <= 0 || sc->ts_msg_read.t <= 0)
|
||||
return 0; /* data not (yet) available */
|
||||
if (sc->ts_msg_read.t < sc->ts_msg_write.t)
|
||||
return -1;
|
||||
|
||||
*rtt = ossl_time2us(ossl_time_subtract(sc->ts_msg_read, sc->ts_msg_write));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dup_ca_names(STACK_OF(X509_NAME) **dst, STACK_OF(X509_NAME) *src)
|
||||
{
|
||||
STACK_OF(X509_NAME) *sk;
|
||||
|
@ -1249,6 +1249,9 @@ struct ssl_connection_st {
|
||||
int quiet_shutdown;
|
||||
/* we have shut things down, 0x01 sent, 0x02 for received */
|
||||
int shutdown;
|
||||
/* Timestamps used to calculate the handshake RTT */
|
||||
OSSL_TIME ts_msg_write;
|
||||
OSSL_TIME ts_msg_read;
|
||||
/* where we are */
|
||||
OSSL_STATEM statem;
|
||||
SSL_EARLY_DATA_STATE early_data_state;
|
||||
|
@ -484,6 +484,8 @@ static WRITE_TRAN ossl_statem_client13_write_transition(SSL_CONNECTION *s)
|
||||
st->hand_state = TLS_ST_CW_COMP_CERT;
|
||||
else
|
||||
st->hand_state = TLS_ST_CW_CERT;
|
||||
|
||||
s->ts_msg_read = ossl_time_now();
|
||||
return WRITE_TRAN_CONTINUE;
|
||||
|
||||
case TLS_ST_PENDING_EARLY_DATA_END:
|
||||
@ -584,6 +586,7 @@ WRITE_TRAN ossl_statem_client_write_transition(SSL_CONNECTION *s)
|
||||
* No transition at the end of writing because we don't know what
|
||||
* we will be sent
|
||||
*/
|
||||
s->ts_msg_write = ossl_time_now();
|
||||
return WRITE_TRAN_FINISHED;
|
||||
|
||||
case TLS_ST_CR_SRVR_HELLO:
|
||||
@ -600,6 +603,7 @@ WRITE_TRAN ossl_statem_client_write_transition(SSL_CONNECTION *s)
|
||||
return WRITE_TRAN_CONTINUE;
|
||||
|
||||
case TLS_ST_EARLY_DATA:
|
||||
s->ts_msg_write = ossl_time_now();
|
||||
return WRITE_TRAN_FINISHED;
|
||||
|
||||
case DTLS_ST_CR_HELLO_VERIFY_REQUEST:
|
||||
@ -607,6 +611,7 @@ WRITE_TRAN ossl_statem_client_write_transition(SSL_CONNECTION *s)
|
||||
return WRITE_TRAN_CONTINUE;
|
||||
|
||||
case TLS_ST_CR_SRVR_DONE:
|
||||
s->ts_msg_read = ossl_time_now();
|
||||
if (s->s3.tmp.cert_req)
|
||||
st->hand_state = TLS_ST_CW_CERT;
|
||||
else
|
||||
|
@ -547,12 +547,14 @@ static WRITE_TRAN ossl_statem_server13_write_transition(SSL_CONNECTION *s)
|
||||
|
||||
case TLS_ST_SW_FINISHED:
|
||||
st->hand_state = TLS_ST_EARLY_DATA;
|
||||
s->ts_msg_write = ossl_time_now();
|
||||
return WRITE_TRAN_CONTINUE;
|
||||
|
||||
case TLS_ST_EARLY_DATA:
|
||||
return WRITE_TRAN_FINISHED;
|
||||
|
||||
case TLS_ST_SR_FINISHED:
|
||||
s->ts_msg_read = ossl_time_now();
|
||||
/*
|
||||
* Technically we have finished the handshake at this point, but we're
|
||||
* going to remain "in_init" for now and write out any session tickets
|
||||
@ -702,9 +704,11 @@ WRITE_TRAN ossl_statem_server_write_transition(SSL_CONNECTION *s)
|
||||
return WRITE_TRAN_CONTINUE;
|
||||
|
||||
case TLS_ST_SW_SRVR_DONE:
|
||||
s->ts_msg_write = ossl_time_now();
|
||||
return WRITE_TRAN_FINISHED;
|
||||
|
||||
case TLS_ST_SR_FINISHED:
|
||||
s->ts_msg_read = ossl_time_now();
|
||||
if (s->hit) {
|
||||
st->hand_state = TLS_ST_OK;
|
||||
return WRITE_TRAN_CONTINUE;
|
||||
|
@ -50,7 +50,7 @@ IF[{- !$disabled{tests} -}]
|
||||
dtlsv1listentest ct_test threadstest afalgtest d2i_test \
|
||||
ssl_test_ctx_test ssl_test x509aux cipherlist_test asynciotest \
|
||||
bio_callback_test bio_memleak_test bio_core_test bio_dgram_test param_build_test \
|
||||
bioprinttest sslapitest dtlstest sslcorrupttest \
|
||||
bioprinttest sslapitest ssl_handshake_rtt_test dtlstest sslcorrupttest \
|
||||
bio_enc_test pkey_meth_test pkey_meth_kdf_test evp_kdf_test uitest \
|
||||
cipherbytes_test threadstest_fips threadpool_test \
|
||||
asn1_encode_test asn1_decode_test asn1_string_table_test \
|
||||
@ -494,6 +494,10 @@ IF[{- !$disabled{tests} -}]
|
||||
INCLUDE[sslapitest]=../include ../apps/include ..
|
||||
DEPEND[sslapitest]=../libcrypto ../libssl libtestutil.a
|
||||
|
||||
SOURCE[ssl_handshake_rtt_test]=ssl_handshake_rtt_test.c helpers/ssltestlib.c
|
||||
INCLUDE[ssl_handshake_rtt_test]=../include ../apps/include ..
|
||||
DEPEND[ssl_handshake_rtt_test]=../libcrypto.a ../libssl.a libtestutil.a
|
||||
|
||||
SOURCE[rpktest]=rpktest.c helpers/ssltestlib.c
|
||||
INCLUDE[rpktest]=../include ../apps/include ..
|
||||
DEPEND[rpktest]=../libcrypto ../libssl libtestutil.a
|
||||
|
@ -33,7 +33,7 @@ my $provconfnew = bldtop_file("test", "temp.cnf");
|
||||
plan skip_all => "No TLS/SSL protocols are supported by this OpenSSL build"
|
||||
if alldisabled(grep { $_ ne "ssl3" } available_protocols("tls"));
|
||||
|
||||
plan tests => 3;
|
||||
plan tests => 4;
|
||||
|
||||
(undef, my $tmpfilename) = tempfile();
|
||||
|
||||
@ -140,4 +140,6 @@ SKIP: {
|
||||
unlink $provconfnew;
|
||||
}
|
||||
|
||||
ok(run(test(["ssl_handshake_rtt_test"])),"running ssl_handshake_rtt_test");
|
||||
|
||||
unlink $tmpfilename;
|
||||
|
138
test/ssl_handshake_rtt_test.c
Normal file
138
test/ssl_handshake_rtt_test.c
Normal file
@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright 2023 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
|
||||
*/
|
||||
|
||||
/*
|
||||
* We need access to the deprecated low level HMAC APIs for legacy purposes
|
||||
* when the deprecated calls are not hidden
|
||||
*/
|
||||
#ifndef OPENSSL_NO_DEPRECATED_3_0
|
||||
# define OPENSSL_SUPPRESS_DEPRECATED
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <openssl/opensslconf.h>
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/engine.h>
|
||||
|
||||
#include "helpers/ssltestlib.h"
|
||||
#include "testutil.h"
|
||||
#include "testutil/output.h"
|
||||
#include "internal/ktls.h"
|
||||
#include "../ssl/ssl_local.h"
|
||||
#include "../ssl/statem/statem_local.h"
|
||||
|
||||
static OSSL_LIB_CTX *libctx = NULL;
|
||||
static char *cert = NULL;
|
||||
static char *privkey = NULL;
|
||||
|
||||
/*
|
||||
* Test 0: Clientside handshake RTT (TLSv1.2)
|
||||
* Test 1: Serverside handshake RTT (TLSv1.2)
|
||||
* Test 2: Clientside handshake RTT (TLSv1.3)
|
||||
* Test 3: Serverside handshake RTT (TLSv1.3)
|
||||
* Test 4: Clientside handshake RTT with Early Data (TLSv1.3)
|
||||
*/
|
||||
static int test_handshake_rtt(int tst)
|
||||
{
|
||||
SSL_CTX *cctx = NULL, *sctx = NULL;
|
||||
SSL *clientssl = NULL, *serverssl = NULL;
|
||||
int testresult = 0;
|
||||
SSL_CONNECTION *s = NULL;
|
||||
OSSL_STATEM *st = NULL;
|
||||
uint64_t rtt;
|
||||
|
||||
#ifdef OPENSSL_NO_TLS1_2
|
||||
if (tst <= 1)
|
||||
return 1;
|
||||
#endif
|
||||
#ifdef OSSL_NO_USABLE_TLS1_3
|
||||
if (tst >= 2)
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
if (!TEST_true(create_ssl_ctx_pair(libctx, TLS_server_method(),
|
||||
TLS_client_method(),
|
||||
TLS1_VERSION,
|
||||
(tst <= 1) ? TLS1_2_VERSION
|
||||
: TLS1_3_VERSION,
|
||||
&sctx, &cctx, cert, privkey))
|
||||
|| !TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl,
|
||||
NULL, NULL)))
|
||||
goto end;
|
||||
|
||||
s = SSL_CONNECTION_FROM_SSL(tst % 2 == 0 ? clientssl : serverssl);
|
||||
if (!TEST_ptr(s) || !TEST_ptr(st = &s->statem))
|
||||
return 0;
|
||||
|
||||
/* implicitly set handshake rtt with a delay */
|
||||
switch (tst) {
|
||||
case 0:
|
||||
st->hand_state = TLS_ST_CW_CLNT_HELLO;
|
||||
ossl_statem_client_write_transition(s);
|
||||
OSSL_sleep(1);
|
||||
st->hand_state = TLS_ST_CR_SRVR_DONE;
|
||||
ossl_statem_client_write_transition(s);
|
||||
break;
|
||||
case 1:
|
||||
st->hand_state = TLS_ST_SW_SRVR_DONE;
|
||||
ossl_statem_server_write_transition(s);
|
||||
OSSL_sleep(1);
|
||||
st->hand_state = TLS_ST_SR_FINISHED;
|
||||
ossl_statem_server_write_transition(s);
|
||||
break;
|
||||
case 2:
|
||||
st->hand_state = TLS_ST_CW_CLNT_HELLO;
|
||||
ossl_statem_client_write_transition(s);
|
||||
OSSL_sleep(1);
|
||||
st->hand_state = TLS_ST_CR_SRVR_DONE;
|
||||
ossl_statem_client_write_transition(s);
|
||||
break;
|
||||
case 3:
|
||||
st->hand_state = TLS_ST_SW_SRVR_DONE;
|
||||
ossl_statem_server_write_transition(s);
|
||||
OSSL_sleep(1);
|
||||
st->hand_state = TLS_ST_SR_FINISHED;
|
||||
ossl_statem_server_write_transition(s);
|
||||
break;
|
||||
case 4:
|
||||
st->hand_state = TLS_ST_EARLY_DATA;
|
||||
ossl_statem_client_write_transition(s);
|
||||
OSSL_sleep(1);
|
||||
st->hand_state = TLS_ST_CR_SRVR_DONE;
|
||||
ossl_statem_client_write_transition(s);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!TEST_int_gt(SSL_get_handshake_rtt(SSL_CONNECTION_GET_SSL(s), &rtt), 0))
|
||||
goto end;
|
||||
/* 1 millisec is the absolute minimum it could be given the delay */
|
||||
if (!TEST_uint64_t_ge(rtt, 1000))
|
||||
goto end;
|
||||
|
||||
testresult = 1;
|
||||
|
||||
end:
|
||||
SSL_free(serverssl);
|
||||
SSL_free(clientssl);
|
||||
SSL_CTX_free(sctx);
|
||||
SSL_CTX_free(cctx);
|
||||
|
||||
return testresult;
|
||||
}
|
||||
|
||||
int setup_tests(void)
|
||||
{
|
||||
ADD_ALL_TESTS(test_handshake_rtt, 5);
|
||||
|
||||
return 1;
|
||||
}
|
@ -558,6 +558,7 @@ SSL_add_expected_rpk ? 3_2_0 EXIST::FUNCTION:
|
||||
d2i_SSL_SESSION_ex ? 3_2_0 EXIST::FUNCTION:
|
||||
SSL_is_tls ? 3_2_0 EXIST::FUNCTION:
|
||||
SSL_is_quic ? 3_2_0 EXIST::FUNCTION:
|
||||
SSL_get_handshake_rtt ? 3_2_0 EXIST::FUNCTION:
|
||||
SSL_new_stream ? 3_2_0 EXIST::FUNCTION:
|
||||
SSL_get0_connection ? 3_2_0 EXIST::FUNCTION:
|
||||
SSL_is_connection ? 3_2_0 EXIST::FUNCTION:
|
||||
|
Loading…
Reference in New Issue
Block a user