Add support for event-driven IO in ssl_client2 and ssl_server2

This commit is contained in:
Hanno Becker 2017-10-10 15:56:37 +01:00
parent e09ca3d9b6
commit 16970d2912
2 changed files with 429 additions and 58 deletions

View file

@ -70,6 +70,7 @@ int main( void )
#define DFL_REQUEST_SIZE -1
#define DFL_DEBUG_LEVEL 0
#define DFL_NBIO 0
#define DFL_EVENT 0
#define DFL_READ_TIMEOUT 0
#define DFL_MAX_RESEND 0
#define DFL_CA_FILE ""
@ -243,23 +244,25 @@ int main( void )
" server_port=%%d default: 4433\n" \
" request_page=%%s default: \".\"\n" \
" request_size=%%d default: about 34 (basic request)\n" \
" (minimum: 0, max: 16384)\n" \
" debug_level=%%d default: 0 (disabled)\n" \
" nbio=%%d default: 0 (blocking I/O)\n" \
" options: 1 (non-blocking), 2 (added delays)\n" \
" read_timeout=%%d default: 0 ms (no timeout)\n" \
" (minimum: 0, max: 16384)\n" \
" debug_level=%%d default: 0 (disabled)\n" \
" nbio=%%d default: 0 (blocking I/O)\n" \
" options: 1 (non-blocking), 2 (added delays)\n" \
" event=%%d default: 0 (loop)\n" \
" options: 1 (level-triggered, implies nbio=1),\n" \
" read_timeout=%%d default: 0 ms (no timeout)\n" \
" max_resend=%%d default: 0 (no resend on timeout)\n" \
"\n" \
USAGE_DTLS \
"\n" \
" auth_mode=%%s default: (library default: none)\n" \
" auth_mode=%%s default: (library default: none)\n" \
" options: none, optional, required\n" \
USAGE_IO \
"\n" \
USAGE_PSK \
USAGE_ECJPAKE \
"\n" \
" allow_legacy=%%d default: (library default: no)\n" \
" allow_legacy=%%d default: (library default: no)\n" \
USAGE_RENEGO \
" exchanges=%%d default: 1\n" \
" reconnect=%%d default: 0 (disabled)\n" \
@ -299,7 +302,8 @@ struct options
const char *server_port; /* port on which the ssl service runs */
int debug_level; /* level of debugging */
int nbio; /* should I/O be blocking? */
uint32_t read_timeout; /* timeout on mbedtls_ssl_read() in milliseconds */
int event; /* loop or event-driven IO? level or edge triggered? */
uint32_t read_timeout; /* timeout on mbedtls_ssl_read() in milliseconds */
int max_resend; /* DTLS times to resend on read timeout */
const char *request_page; /* page on server to request */
int request_size; /* pad request with header to requested size */
@ -433,6 +437,78 @@ static int ssl_sig_hashes_for_test[] = {
};
#endif /* MBEDTLS_X509_CRT_PARSE_C */
/*
* Wait for an event from the underlying transport or the timer
* (Used in event-driven IO mode).
*/
#if !defined(MBEDTLS_TIMING_C)
void idle( mbedtls_ssl_context *ssl,
mbedtls_net_context *fd,
int idle_reason )
{
#else
void idle( mbedtls_ssl_context *ssl,
mbedtls_net_context *fd,
mbedtls_timing_delay_context *timer,
int idle_reason )
{
#if defined(MBEDTLS_DEBUG_C)
struct mbedtls_timing_hr_time tm;
unsigned long time_elapsed;
#endif
#endif
int poll_type = 0;
if( idle_reason == MBEDTLS_ERR_SSL_WANT_WRITE )
poll_type = MBEDTLS_NET_POLL_WRITE;
else if( idle_reason == MBEDTLS_ERR_SSL_WANT_READ )
poll_type = MBEDTLS_NET_POLL_READ;
#if !defined(MBEDTLS_TIMING_C)
else
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "WARNING: No reason for idling given" ) );
return;
}
#endif
/* One should not idle on the underlying transport
* if data is still pending to be processed. */
if( mbedtls_ssl_check_pending( ssl ) != 0 )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "WARNING: Data still pending, "
"but idling requested!" ) );
}
MBEDTLS_SSL_DEBUG_MSG( 3, ( "idle, waiting for event... " ) );
#if defined(MBEDTLS_TIMING_C) && defined(MBEDTLS_DEBUG_C)
mbedtls_timing_get_timer( &tm, 1 /* restart */ );
#endif
while( 1 )
{
#if defined(MBEDTLS_TIMING_C)
#if defined(MBEDTLS_DEBUG_C)
time_elapsed = mbedtls_timing_get_timer( &tm, 0 );
#endif
if( mbedtls_timing_get_delay( timer ) == 2 )
{
MBEDTLS_SSL_DEBUG_MSG( 3, ( "[%lu ms] timer expired - continue",
time_elapsed ) );
break;
}
#endif
if( poll_type != 0 &&
mbedtls_net_poll( fd, poll_type, 0 ) == poll_type )
{
MBEDTLS_SSL_DEBUG_MSG( 3, ( "[%lu ms] net_context signals data - "
"continue", time_elapsed ) );
break;
}
}
}
int main( int argc, char *argv[] )
{
int ret = 0, len, tail_len, i, written, frags, retry_left;
@ -516,6 +592,7 @@ int main( int argc, char *argv[] )
opt.server_port = DFL_SERVER_PORT;
opt.debug_level = DFL_DEBUG_LEVEL;
opt.nbio = DFL_NBIO;
opt.event = DFL_EVENT;
opt.read_timeout = DFL_READ_TIMEOUT;
opt.max_resend = DFL_MAX_RESEND;
opt.request_page = DFL_REQUEST_PAGE;
@ -589,6 +666,12 @@ int main( int argc, char *argv[] )
if( opt.nbio < 0 || opt.nbio > 2 )
goto usage;
}
else if( strcmp( p, "event" ) == 0 )
{
opt.event = atoi( q );
if( opt.event < 0 || opt.event > 2 )
goto usage;
}
else if( strcmp( p, "read_timeout" ) == 0 )
opt.read_timeout = atoi( q );
else if( strcmp( p, "max_resend" ) == 0 )
@ -858,6 +941,16 @@ int main( int argc, char *argv[] )
goto usage;
}
/* Event-driven IO is incompatible with the above custom
* receive and send functions, as the polling builds on
* refers to the underlying net_context. */
if( opt.event == 1 && opt.nbio != 1 )
{
mbedtls_printf( "Warning: event-driven IO mandates nbio=1"
" - overwrite\n" );
opt.nbio = 1;
}
#if defined(MBEDTLS_DEBUG_C)
mbedtls_debug_set_threshold( opt.debug_level );
#endif
@ -1092,7 +1185,8 @@ int main( int argc, char *argv[] )
#endif
if( ret < 0 )
{
mbedtls_printf( " failed\n ! mbedtls_x509_crt_parse returned -0x%x\n\n", -ret );
mbedtls_printf( " failed\n ! mbedtls_x509_crt_parse "
"returned -0x%x\n\n", -ret );
goto exit;
}
@ -1115,7 +1209,8 @@ int main( int argc, char *argv[] )
else
#endif
#if defined(MBEDTLS_CERTS_C)
ret = mbedtls_x509_crt_parse( &clicert, (const unsigned char *) mbedtls_test_cli_crt,
ret = mbedtls_x509_crt_parse( &clicert,
(const unsigned char *) mbedtls_test_cli_crt,
mbedtls_test_cli_crt_len );
#else
{
@ -1125,7 +1220,8 @@ int main( int argc, char *argv[] )
#endif
if( ret != 0 )
{
mbedtls_printf( " failed\n ! mbedtls_x509_crt_parse returned -0x%x\n\n", -ret );
mbedtls_printf( " failed\n ! mbedtls_x509_crt_parse "
"returned -0x%x\n\n", -ret );
goto exit;
}
@ -1138,7 +1234,8 @@ int main( int argc, char *argv[] )
else
#endif
#if defined(MBEDTLS_CERTS_C)
ret = mbedtls_pk_parse_key( &pkey, (const unsigned char *) mbedtls_test_cli_key,
ret = mbedtls_pk_parse_key( &pkey,
(const unsigned char *) mbedtls_test_cli_key,
mbedtls_test_cli_key_len, NULL, 0 );
#else
{
@ -1148,7 +1245,8 @@ int main( int argc, char *argv[] )
#endif
if( ret != 0 )
{
mbedtls_printf( " failed\n ! mbedtls_pk_parse_key returned -0x%x\n\n", -ret );
mbedtls_printf( " failed\n ! mbedtls_pk_parse_key "
"returned -0x%x\n\n", -ret );
goto exit;
}
@ -1166,11 +1264,13 @@ int main( int argc, char *argv[] )
opt.server_addr, opt.server_port );
fflush( stdout );
if( ( ret = mbedtls_net_connect( &server_fd, opt.server_addr, opt.server_port,
opt.transport == MBEDTLS_SSL_TRANSPORT_STREAM ?
MBEDTLS_NET_PROTO_TCP : MBEDTLS_NET_PROTO_UDP ) ) != 0 )
if( ( ret = mbedtls_net_connect( &server_fd,
opt.server_addr, opt.server_port,
opt.transport == MBEDTLS_SSL_TRANSPORT_STREAM ?
MBEDTLS_NET_PROTO_TCP : MBEDTLS_NET_PROTO_UDP ) ) != 0 )
{
mbedtls_printf( " failed\n ! mbedtls_net_connect returned -0x%x\n\n", -ret );
mbedtls_printf( " failed\n ! mbedtls_net_connect "
"returned -0x%x\n\n", -ret );
goto exit;
}
@ -1180,7 +1280,8 @@ int main( int argc, char *argv[] )
ret = mbedtls_net_set_block( &server_fd );
if( ret != 0 )
{
mbedtls_printf( " failed\n ! net_set_(non)block() returned -0x%x\n\n", -ret );
mbedtls_printf( " failed\n ! net_set_(non)block() "
"returned -0x%x\n\n", -ret );
goto exit;
}
@ -1197,7 +1298,8 @@ int main( int argc, char *argv[] )
opt.transport,
MBEDTLS_SSL_PRESET_DEFAULT ) ) != 0 )
{
mbedtls_printf( " failed\n ! mbedtls_ssl_config_defaults returned -0x%x\n\n", -ret );
mbedtls_printf( " failed\n ! mbedtls_ssl_config_defaults "
"returned -0x%x\n\n", -ret );
goto exit;
}
@ -1220,13 +1322,15 @@ int main( int argc, char *argv[] )
#if defined(MBEDTLS_SSL_PROTO_DTLS)
if( opt.hs_to_min != DFL_HS_TO_MIN || opt.hs_to_max != DFL_HS_TO_MAX )
mbedtls_ssl_conf_handshake_timeout( &conf, opt.hs_to_min, opt.hs_to_max );
mbedtls_ssl_conf_handshake_timeout( &conf, opt.hs_to_min,
opt.hs_to_max );
#endif /* MBEDTLS_SSL_PROTO_DTLS */
#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH)
if( ( ret = mbedtls_ssl_conf_max_frag_len( &conf, opt.mfl_code ) ) != 0 )
{
mbedtls_printf( " failed\n ! mbedtls_ssl_conf_max_frag_len returned %d\n\n", ret );
mbedtls_printf( " failed\n ! mbedtls_ssl_conf_max_frag_len "
"returned %d\n\n", ret );
goto exit;
}
#endif
@ -1249,8 +1353,8 @@ int main( int argc, char *argv[] )
#if defined(MBEDTLS_SSL_CBC_RECORD_SPLITTING)
if( opt.recsplit != DFL_RECSPLIT )
mbedtls_ssl_conf_cbc_record_splitting( &conf, opt.recsplit
? MBEDTLS_SSL_CBC_RECORD_SPLITTING_ENABLED
: MBEDTLS_SSL_CBC_RECORD_SPLITTING_DISABLED );
? MBEDTLS_SSL_CBC_RECORD_SPLITTING_ENABLED
: MBEDTLS_SSL_CBC_RECORD_SPLITTING_DISABLED );
#endif
#if defined(MBEDTLS_DHM_C)
@ -1262,7 +1366,8 @@ int main( int argc, char *argv[] )
if( opt.alpn_string != NULL )
if( ( ret = mbedtls_ssl_conf_alpn_protocols( &conf, alpn_list ) ) != 0 )
{
mbedtls_printf( " failed\n ! mbedtls_ssl_conf_alpn_protocols returned %d\n\n", ret );
mbedtls_printf( " failed\n ! mbedtls_ssl_conf_alpn_protocols "
"returned %d\n\n", ret );
goto exit;
}
#endif
@ -1301,7 +1406,8 @@ int main( int argc, char *argv[] )
{
if( ( ret = mbedtls_ssl_conf_own_cert( &conf, &clicert, &pkey ) ) != 0 )
{
mbedtls_printf( " failed\n ! mbedtls_ssl_conf_own_cert returned %d\n\n", ret );
mbedtls_printf( " failed\n ! mbedtls_ssl_conf_own_cert "
"returned %d\n\n", ret );
goto exit;
}
}
@ -1320,16 +1426,19 @@ int main( int argc, char *argv[] )
(const unsigned char *) opt.psk_identity,
strlen( opt.psk_identity ) ) ) != 0 )
{
mbedtls_printf( " failed\n ! mbedtls_ssl_conf_psk returned %d\n\n", ret );
mbedtls_printf( " failed\n ! mbedtls_ssl_conf_psk "
"returned %d\n\n", ret );
goto exit;
}
#endif
if( opt.min_version != DFL_MIN_VERSION )
mbedtls_ssl_conf_min_version( &conf, MBEDTLS_SSL_MAJOR_VERSION_3, opt.min_version );
mbedtls_ssl_conf_min_version( &conf, MBEDTLS_SSL_MAJOR_VERSION_3,
opt.min_version );
if( opt.max_version != DFL_MAX_VERSION )
mbedtls_ssl_conf_max_version( &conf, MBEDTLS_SSL_MAJOR_VERSION_3, opt.max_version );
mbedtls_ssl_conf_max_version( &conf, MBEDTLS_SSL_MAJOR_VERSION_3,
opt.max_version );
#if defined(MBEDTLS_SSL_FALLBACK_SCSV)
if( opt.fallback != DFL_FALLBACK )
@ -1338,14 +1447,16 @@ int main( int argc, char *argv[] )
if( ( ret = mbedtls_ssl_setup( &ssl, &conf ) ) != 0 )
{
mbedtls_printf( " failed\n ! mbedtls_ssl_setup returned -0x%x\n\n", -ret );
mbedtls_printf( " failed\n ! mbedtls_ssl_setup "
"returned -0x%x\n\n", -ret );
goto exit;
}
#if defined(MBEDTLS_X509_CRT_PARSE_C)
if( ( ret = mbedtls_ssl_set_hostname( &ssl, opt.server_name ) ) != 0 )
{
mbedtls_printf( " failed\n ! mbedtls_ssl_set_hostname returned %d\n\n", ret );
mbedtls_printf( " failed\n ! mbedtls_ssl_set_hostname "
"returned %d\n\n", ret );
goto exit;
}
#endif
@ -1357,7 +1468,8 @@ int main( int argc, char *argv[] )
(const unsigned char *) opt.ecjpake_pw,
strlen( opt.ecjpake_pw ) ) ) != 0 )
{
mbedtls_printf( " failed\n ! mbedtls_ssl_set_hs_ecjpake_password returned %d\n\n", ret );
mbedtls_printf( " failed\n ! mbedtls_ssl_set_hs_ecjpake_password "
"returned %d\n\n", ret );
goto exit;
}
}
@ -1366,7 +1478,8 @@ int main( int argc, char *argv[] )
if( opt.nbio == 2 )
mbedtls_ssl_set_bio( &ssl, &server_fd, my_send, my_recv, NULL );
else
mbedtls_ssl_set_bio( &ssl, &server_fd, mbedtls_net_send, mbedtls_net_recv,
mbedtls_ssl_set_bio( &ssl, &server_fd,
mbedtls_net_send, mbedtls_net_recv,
opt.nbio == 0 ? mbedtls_net_recv_timeout : NULL );
#if defined(MBEDTLS_TIMING_C)
@ -1384,9 +1497,11 @@ int main( int argc, char *argv[] )
while( ( ret = mbedtls_ssl_handshake( &ssl ) ) != 0 )
{
if( ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE )
if( ret != MBEDTLS_ERR_SSL_WANT_READ &&
ret != MBEDTLS_ERR_SSL_WANT_WRITE )
{
mbedtls_printf( " failed\n ! mbedtls_ssl_handshake returned -0x%x\n", -ret );
mbedtls_printf( " failed\n ! mbedtls_ssl_handshake "
"returned -0x%x\n", -ret );
if( ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED )
mbedtls_printf(
" Unable to verify the server's certificate. "
@ -1398,10 +1513,21 @@ int main( int argc, char *argv[] )
mbedtls_printf( "\n" );
goto exit;
}
/* For event-driven IO, wait for socket to become available */
if( opt.event == 1 /* level triggered IO */ )
{
#if defined(MBEDTLS_TIMING_C)
idle( &ssl, &server_fd, &timer, ret );
#else
idle( &ssl, &server_fd, ret );
#endif
}
}
mbedtls_printf( " ok\n [ Protocol is %s ]\n [ Ciphersuite is %s ]\n",
mbedtls_ssl_get_version( &ssl ), mbedtls_ssl_get_ciphersuite( &ssl ) );
mbedtls_ssl_get_version( &ssl ),
mbedtls_ssl_get_ciphersuite( &ssl ) );
if( ( ret = mbedtls_ssl_get_record_expansion( &ssl ) ) >= 0 )
mbedtls_printf( " [ Record expansion is %d ]\n", ret );
@ -1429,7 +1555,8 @@ int main( int argc, char *argv[] )
if( ( ret = mbedtls_ssl_get_session( &ssl, &saved_session ) ) != 0 )
{
mbedtls_printf( " failed\n ! mbedtls_ssl_get_session returned -0x%x\n\n", -ret );
mbedtls_printf( " failed\n ! mbedtls_ssl_get_session "
"returned -0x%x\n\n", -ret );
goto exit;
}
@ -1448,7 +1575,8 @@ int main( int argc, char *argv[] )
mbedtls_printf( " failed\n" );
mbedtls_x509_crt_verify_info( vrfy_buf, sizeof( vrfy_buf ), " ! ", flags );
mbedtls_x509_crt_verify_info( vrfy_buf, sizeof( vrfy_buf ),
" ! ", flags );
mbedtls_printf( "%s\n", vrfy_buf );
}
@ -1478,9 +1606,21 @@ int main( int argc, char *argv[] )
if( ret != MBEDTLS_ERR_SSL_WANT_READ &&
ret != MBEDTLS_ERR_SSL_WANT_WRITE )
{
mbedtls_printf( " failed\n ! mbedtls_ssl_renegotiate returned %d\n\n", ret );
mbedtls_printf( " failed\n ! mbedtls_ssl_renegotiate "
"returned %d\n\n", ret );
goto exit;
}
/* For event-driven IO, wait for socket to become available */
if( opt.event == 1 /* level triggered IO */ )
{
#if defined(MBEDTLS_TIMING_C)
idle( &ssl, &server_fd, &timer, ret );
#else
idle( &ssl, &server_fd, ret );
#endif
}
}
mbedtls_printf( " ok\n" );
}
@ -1524,27 +1664,54 @@ send_request:
{
for( written = 0, frags = 0; written < len; written += ret, frags++ )
{
while( ( ret = mbedtls_ssl_write( &ssl, buf + written, len - written ) )
<= 0 )
while( ( ret = mbedtls_ssl_write( &ssl, buf + written,
len - written ) ) <= 0 )
{
if( ret != MBEDTLS_ERR_SSL_WANT_READ &&
ret != MBEDTLS_ERR_SSL_WANT_WRITE )
{
mbedtls_printf( " failed\n ! mbedtls_ssl_write returned -0x%x\n\n", -ret );
mbedtls_printf( " failed\n ! mbedtls_ssl_write "
"returned -0x%x\n\n", -ret );
goto exit;
}
/* For event-driven IO, wait for socket to become available */
if( opt.event == 1 /* level triggered IO */ )
{
#if defined(MBEDTLS_TIMING_C)
idle( &ssl, &server_fd, &timer, ret );
#else
idle( &ssl, &server_fd, ret );
#endif
}
}
}
}
else /* Not stream, so datagram */
{
do ret = mbedtls_ssl_write( &ssl, buf, len );
while( ret == MBEDTLS_ERR_SSL_WANT_READ ||
ret == MBEDTLS_ERR_SSL_WANT_WRITE );
while( 1 )
{
ret = mbedtls_ssl_write( &ssl, buf, len );
if( ret != MBEDTLS_ERR_SSL_WANT_READ &&
ret != MBEDTLS_ERR_SSL_WANT_WRITE )
break;
/* For event-driven IO, wait for socket to become available */
if( opt.event == 1 /* level triggered IO */ )
{
#if defined(MBEDTLS_TIMING_C)
idle( &ssl, &server_fd, &timer, ret );
#else
idle( &ssl, &server_fd, ret );
#endif
}
}
if( ret < 0 )
{
mbedtls_printf( " failed\n ! mbedtls_ssl_write returned %d\n\n", ret );
mbedtls_printf( " failed\n ! mbedtls_ssl_write "
"returned %d\n\n", ret );
goto exit;
}
@ -1553,7 +1720,8 @@ send_request:
}
buf[written] = '\0';
mbedtls_printf( " %d bytes written in %d fragments\n\n%s\n", written, frags, (char *) buf );
mbedtls_printf( " %d bytes written in %d fragments\n\n%s\n",
written, frags, (char *) buf );
/*
* 7. Read the HTTP response
@ -1574,7 +1742,18 @@ send_request:
if( ret == MBEDTLS_ERR_SSL_WANT_READ ||
ret == MBEDTLS_ERR_SSL_WANT_WRITE )
{
/* For event-driven IO, wait for socket to become available */
if( opt.event == 1 /* level triggered IO */ )
{
#if defined(MBEDTLS_TIMING_C)
idle( &ssl, &server_fd, &timer, ret );
#else
idle( &ssl, &server_fd, ret );
#endif
}
continue;
}
if( ret <= 0 )
{
@ -1616,9 +1795,24 @@ send_request:
len = sizeof( buf ) - 1;
memset( buf, 0, sizeof( buf ) );
do ret = mbedtls_ssl_read( &ssl, buf, len );
while( ret == MBEDTLS_ERR_SSL_WANT_READ ||
ret == MBEDTLS_ERR_SSL_WANT_WRITE );
while( 1 )
{
ret = mbedtls_ssl_read( &ssl, buf, len );
if( ret != MBEDTLS_ERR_SSL_WANT_READ &&
ret != MBEDTLS_ERR_SSL_WANT_WRITE )
break;
/* For event-driven IO, wait for socket to become available */
if( opt.event == 1 /* level triggered IO */ )
{
#if defined(MBEDTLS_TIMING_C)
idle( &ssl, &server_fd, &timer, ret );
#else
idle( &ssl, &server_fd, ret );
#endif
}
}
if( ret <= 0 )
{
@ -1671,6 +1865,16 @@ send_request:
mbedtls_printf( " failed\n ! mbedtls_ssl_handshake returned -0x%x\n\n", -ret );
goto exit;
}
/* For event-driven IO, wait for socket to become available */
if( opt.event == 1 /* level triggered IO */ )
{
#if defined(MBEDTLS_TIMING_C)
idle( &ssl, &server_fd, &timer, ret );
#else
idle( &ssl, &server_fd, ret );
#endif
}
}
mbedtls_printf( " ok\n" );

View file

@ -101,6 +101,7 @@ int main( void )
#define DFL_SERVER_PORT "4433"
#define DFL_DEBUG_LEVEL 0
#define DFL_NBIO 0
#define DFL_EVENT 0
#define DFL_READ_TIMEOUT 0
#define DFL_CA_FILE ""
#define DFL_CA_PATH ""
@ -331,6 +332,8 @@ int main( void )
" debug_level=%%d default: 0 (disabled)\n" \
" nbio=%%d default: 0 (blocking I/O)\n" \
" options: 1 (non-blocking), 2 (added delays)\n" \
" event=%%d default: 0 (loop)\n" \
" options: 1 (level-triggered, implies nbio=1),\n" \
" read_timeout=%%d default: 0 ms (no timeout)\n" \
"\n" \
USAGE_DTLS \
@ -399,6 +402,7 @@ struct options
const char *server_port; /* port on which the ssl service runs */
int debug_level; /* level of debugging */
int nbio; /* should I/O be blocking? */
int event; /* loop or event-driven IO? level or edge triggered? */
uint32_t read_timeout; /* timeout on mbedtls_ssl_read() in milliseconds */
const char *ca_file; /* the file with the CA certificate(s) */
const char *ca_path; /* the path with the CA certificate(s) reside */
@ -837,6 +841,78 @@ static int ssl_sig_hashes_for_test[] = {
};
#endif /* MBEDTLS_X509_CRT_PARSE_C */
/*
* Wait for an event from the underlying transport or the timer
* (Used in event-driven IO mode).
*/
#if !defined(MBEDTLS_TIMING_C)
void idle( mbedtls_ssl_context *ssl,
mbedtls_net_context *fd,
int idle_reason )
{
#else
void idle( mbedtls_ssl_context *ssl,
mbedtls_net_context *fd,
mbedtls_timing_delay_context *timer,
int idle_reason )
{
#if defined(MBEDTLS_DEBUG_C)
struct mbedtls_timing_hr_time tm;
unsigned long time_elapsed;
#endif
#endif
int poll_type = 0;
if( idle_reason == MBEDTLS_ERR_SSL_WANT_WRITE )
poll_type = MBEDTLS_NET_POLL_WRITE;
else if( idle_reason == MBEDTLS_ERR_SSL_WANT_READ )
poll_type = MBEDTLS_NET_POLL_READ;
#if !defined(MBEDTLS_TIMING_C)
else
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "WARNING: No reason for idling given" ) );
return;
}
#endif
/* One should not idle on the underlying transport
* if data is still pending to be processed. */
if( mbedtls_ssl_check_pending( ssl ) != 0 )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "WARNING: Data still pending, "
"but idling requested!" ) );
}
MBEDTLS_SSL_DEBUG_MSG( 3, ( "idle, waiting for event... " ) );
#if defined(MBEDTLS_TIMING_C) && defined(MBEDTLS_DEBUG_C)
mbedtls_timing_get_timer( &tm, 1 /* restart */ );
#endif
while( 1 )
{
#if defined(MBEDTLS_TIMING_C)
#if defined(MBEDTLS_DEBUG_C)
time_elapsed = mbedtls_timing_get_timer( &tm, 0 );
#endif
if( mbedtls_timing_get_delay( timer ) == 2 )
{
MBEDTLS_SSL_DEBUG_MSG( 3, ( "[%lu ms] timer expired - continue",
time_elapsed ) );
break;
}
#endif
if( poll_type != 0 &&
mbedtls_net_poll( fd, poll_type, 0 ) == poll_type )
{
MBEDTLS_SSL_DEBUG_MSG( 3, ( "[%lu ms] net_context signals data - "
"continue", time_elapsed ) );
break;
}
}
}
int main( int argc, char *argv[] )
{
int ret = 0, len, written, frags, exchanges_left;
@ -969,6 +1045,7 @@ int main( int argc, char *argv[] )
opt.server_addr = DFL_SERVER_ADDR;
opt.server_port = DFL_SERVER_PORT;
opt.debug_level = DFL_DEBUG_LEVEL;
opt.event = DFL_EVENT;
opt.nbio = DFL_NBIO;
opt.read_timeout = DFL_READ_TIMEOUT;
opt.ca_file = DFL_CA_FILE;
@ -1047,6 +1124,12 @@ int main( int argc, char *argv[] )
if( opt.nbio < 0 || opt.nbio > 2 )
goto usage;
}
else if( strcmp( p, "event" ) == 0 )
{
opt.event = atoi( q );
if( opt.event < 0 || opt.event > 2 )
goto usage;
}
else if( strcmp( p, "read_timeout" ) == 0 )
opt.read_timeout = atoi( q );
else if( strcmp( p, "ca_file" ) == 0 )
@ -1328,6 +1411,16 @@ int main( int argc, char *argv[] )
goto usage;
}
/* Event-driven IO is incompatible with the above custom
* receive and send functions, as the polling builds on
* refers to the underlying net_context. */
if( opt.event == 1 && opt.nbio != 1 )
{
mbedtls_printf( "Warning: event-driven IO mandates nbio=1"
" - overwrite\n" );
opt.nbio = 1;
}
#if defined(MBEDTLS_DEBUG_C)
mbedtls_debug_set_threshold( opt.debug_level );
#endif
@ -2113,9 +2206,22 @@ handshake:
mbedtls_printf( " . Performing the SSL/TLS handshake..." );
fflush( stdout );
do ret = mbedtls_ssl_handshake( &ssl );
while( ret == MBEDTLS_ERR_SSL_WANT_READ ||
ret == MBEDTLS_ERR_SSL_WANT_WRITE );
while( ( ret = mbedtls_ssl_handshake( &ssl ) ) != 0 )
{
if( ret != MBEDTLS_ERR_SSL_WANT_READ &&
ret != MBEDTLS_ERR_SSL_WANT_WRITE )
break;
/* For event-driven IO, wait for socket to become available */
if( opt.event == 1 /* level triggered IO */ )
{
#if defined(MBEDTLS_TIMING_C)
idle( &ssl, &client_fd, &timer, ret );
#else
idle( &ssl, &client_fd, ret );
#endif
}
}
if( ret == MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED )
{
@ -2221,7 +2327,18 @@ data_exchange:
if( ret == MBEDTLS_ERR_SSL_WANT_READ ||
ret == MBEDTLS_ERR_SSL_WANT_WRITE )
{
if( opt.event == 1 /* level triggered IO */ )
{
#if defined(MBEDTLS_TIMING_C)
idle( &ssl, &client_fd, &timer, ret );
#else
idle( &ssl, &client_fd, ret );
#endif
}
continue;
}
if( ret <= 0 )
{
@ -2309,9 +2426,24 @@ data_exchange:
len = sizeof( buf ) - 1;
memset( buf, 0, sizeof( buf ) );
do ret = mbedtls_ssl_read( &ssl, buf, len );
while( ret == MBEDTLS_ERR_SSL_WANT_READ ||
ret == MBEDTLS_ERR_SSL_WANT_WRITE );
while( 1 )
{
ret = mbedtls_ssl_read( &ssl, buf, len );
if( ret != MBEDTLS_ERR_SSL_WANT_READ &&
ret != MBEDTLS_ERR_SSL_WANT_WRITE )
break;
/* For event-driven IO, wait for socket to become available */
if( opt.event == 1 /* level triggered IO */ )
{
#if defined(MBEDTLS_TIMING_C)
idle( &ssl, &client_fd, &timer, ret );
#else
idle( &ssl, &client_fd, ret );
#endif
}
}
if( ret <= 0 )
{
@ -2352,6 +2484,16 @@ data_exchange:
mbedtls_printf( " failed\n ! mbedtls_ssl_renegotiate returned %d\n\n", ret );
goto reset;
}
/* For event-driven IO, wait for socket to become available */
if( opt.event == 1 /* level triggered IO */ )
{
#if defined(MBEDTLS_TIMING_C)
idle( &ssl, &client_fd, &timer, ret );
#else
idle( &ssl, &client_fd, ret );
#endif
}
}
mbedtls_printf( " ok\n" );
@ -2386,14 +2528,39 @@ data_exchange:
mbedtls_printf( " failed\n ! mbedtls_ssl_write returned %d\n\n", ret );
goto reset;
}
/* For event-driven IO, wait for socket to become available */
if( opt.event == 1 /* level triggered IO */ )
{
#if defined(MBEDTLS_TIMING_C)
idle( &ssl, &client_fd, &timer, ret );
#else
idle( &ssl, &client_fd, ret );
#endif
}
}
}
}
else /* Not stream, so datagram */
{
do ret = mbedtls_ssl_write( &ssl, buf, len );
while( ret == MBEDTLS_ERR_SSL_WANT_READ ||
ret == MBEDTLS_ERR_SSL_WANT_WRITE );
while( 1 )
{
ret = mbedtls_ssl_write( &ssl, buf, len );
if( ret != MBEDTLS_ERR_SSL_WANT_READ &&
ret != MBEDTLS_ERR_SSL_WANT_WRITE )
break;
/* For event-driven IO, wait for socket to become available */
if( opt.event == 1 /* level triggered IO */ )
{
#if defined(MBEDTLS_TIMING_C)
idle( &ssl, &client_fd, &timer, ret );
#else
idle( &ssl, &client_fd, ret );
#endif
}
}
if( ret < 0 )
{