Hello,
I have a class EchoClient which essentially wraps mbedtls into a encryption enabled client object thing.
Then in main() I create such objects in a loop and have them send+receive a string. This is to stress it (and for testing thread behavior later on).
So far it does what it should. But after about 1000 iterations I get this segfault:
#7 0x00000000004015f5 in main () at t1792_handshake_segfault_client.cpp:183
#6 0x000000000040185f in EchoClient::echo (this=0x7ffe9eb61c00) at t1792_handshake_segfault_client.cpp:46
#5 0x00007f09179e2870 in mbedtls_ssl_handshake () from /usr/local/lib/libmbedtls.so.12
#4 0x00007f09179e280d in mbedtls_ssl_handshake_step () from /usr/local/lib/libmbedtls.so.12
#3 0x00007f09179d7388 in mbedtls_ssl_handshake_client_step () from /usr/local/lib/libmbedtls.so.12
#2 0x00007f09179d5324 in ssl_parse_server_hello () from /usr/local/lib/libmbedtls.so.12
#1 0x00007f09179e718e in mbedtls_ssl_read_record () from /usr/local/lib/libmbedtls.so.12
#0 0x00007f09179e5dee in mbedtls_ssl_fetch_input () from /usr/local/lib/libmbedtls.so.12
with mbedtls_debug_set_threshold (2)
the last echo (iteration 1021 in this case) it says this:
--> task 1021
ssl_tls.c:8084: 0x7fff9b1abb98: => handshake
ssl_cli.c:3510: 0x7fff9b1abb98: client state: 0
ssl_tls.c:2755: 0x7fff9b1abb98: => flush output
ssl_tls.c:2767: 0x7fff9b1abb98: <= flush output
ssl_cli.c:3510: 0x7fff9b1abb98: client state: 1
ssl_tls.c:2755: 0x7fff9b1abb98: => flush output
ssl_tls.c:2767: 0x7fff9b1abb98: <= flush output
ssl_cli.c:0774: 0x7fff9b1abb98: => write client hello
ssl_tls.c:3184: 0x7fff9b1abb98: => write handshake message
ssl_tls.c:3343: 0x7fff9b1abb98: => write record
ssl_tls.c:2755: 0x7fff9b1abb98: => flush output
ssl_tls.c:2774: 0x7fff9b1abb98: message length: 378, out_left: 378
ssl_tls.c:2779: 0x7fff9b1abb98: ssl->f_send() returned 378 (-0xfffffe86)
ssl_tls.c:2807: 0x7fff9b1abb98: <= flush output
ssl_tls.c:3476: 0x7fff9b1abb98: <= write record
ssl_tls.c:3320: 0x7fff9b1abb98: <= write handshake message
ssl_cli.c:1106: 0x7fff9b1abb98: <= write client hello
ssl_cli.c:3510: 0x7fff9b1abb98: client state: 2
ssl_tls.c:2755: 0x7fff9b1abb98: => flush output
ssl_tls.c:2767: 0x7fff9b1abb98: <= flush output
ssl_cli.c:1499: 0x7fff9b1abb98: => parse server hello
ssl_tls.c:4311: 0x7fff9b1abb98: => read record
ssl_tls.c:2536: 0x7fff9b1abb98: => fetch input
ssl_tls.c:2697: 0x7fff9b1abb98: in_left: 0, nb_want: 5
Segmentation fault (core dumped)
Now I am lost on how to figure what the actual cause is?
Must I check something on the socket before calling mbedtls_ssl_read()
?
Here is the EchoClient:
// g++ -g -Wall -o t1792_handshake_segfault_client -lmbedtls -lmbedcrypto -l mbedx509 t1792_handshake_segfault_client.cpp
#include "mbedtls/config.h"
#include "mbedtls/platform.h"
#include "mbedtls/net_sockets.h"
#include "mbedtls/error.h"
#include "mbedtls/debug.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
#include <string.h>
#define PAYLOAD "echoclientstring\n"
class EchoClient
{
public :
EchoClient () { init(); };
~EchoClient () {
mbedtls_ssl_close_notify(&tlsCtx);
mbedtls_ssl_free (&tlsCtx);
mbedtls_x509_crt_free (&tlsCert);
mbedtls_pk_free (&tlsKey);
mbedtls_ctr_drbg_free (&cryptRNG);
mbedtls_entropy_free (&cryptEntropy);
mbedtls_ssl_config_free (&tlsConf);
}
void echo() {
// --- connect
err = mbedtls_net_connect (&netCtx, "localhost", "12345", MBEDTLS_NET_PROTO_TCP);
if (err != 0 ) {
mbedtls_strerror(err, error_buf, sizeof(error_buf));
mbedtls_printf("Connecting failed: %d - %s\n\n", err, error_buf );
return;
}
// --- handshake
mbedtls_ssl_set_bio (&tlsCtx, (void*)&netCtx,
mbedtls_net_send, mbedtls_net_recv,
mbedtls_net_recv_timeout);
err = mbedtls_ssl_handshake (&tlsCtx);
if (err != 0 ) {
mbedtls_strerror(err, error_buf, sizeof(error_buf));
mbedtls_printf("Handshake failed: %d - %s\n\n", err, error_buf );
return;
}
// --- send
mbedtls_printf( "sending ");
int len = sprintf( (char *) buf, PAYLOAD);
while( (err = mbedtls_ssl_write( &tlsCtx, buf, len )) <= 0 )
{
if( err != MBEDTLS_ERR_SSL_WANT_READ && err != MBEDTLS_ERR_SSL_WANT_WRITE)
{
mbedtls_printf( " ! mbedtls_ssl_write returned %d\n\n", err);
return;
}
}
len = err;
mbedtls_printf( " %d bytes:\n%s\n--\n", len, (char *)buf );
// --- receive
mbedtls_printf( "receiving");
len = sizeof( buf ) - 1;
memset( buf, 0, sizeof( buf ) );
err = mbedtls_ssl_read( &tlsCtx, buf, len );
if( err < 0 ) {
mbedtls_printf( "failed\n ! mbedtls_ssl_read returned %d\n\n", err );
return;
}
if( err == 0 ) {
mbedtls_printf( "\n\nEOF\n\n" );
}
len = err;
mbedtls_printf( " %d bytes:\n%s\n--\n", len, (char *)buf );
if (strcmp ((char *)buf, PAYLOAD) != 0) {
mbedtls_printf( "\nresponse does not match payload: >%s< != >%s<\n\n", (char *)buf, PAYLOAD);
return;
} else {
mbedtls_printf( "echo SUCCESS\n\n");
}
} // echo
protected :
int err = 0;
unsigned char buf[1024];
char error_buf[100];
mbedtls_net_context netCtx = {};
mbedtls_ssl_config tlsConf = {};
mbedtls_ssl_context tlsCtx = {};
mbedtls_x509_crt tlsCert = {};
mbedtls_pk_context tlsKey = {};
mbedtls_entropy_context cryptEntropy = {};
mbedtls_ctr_drbg_context cryptRNG = {};
void init() {
mbedtls_net_init (&netCtx);
mbedtls_ssl_init (&tlsCtx);
mbedtls_x509_crt_init (&tlsCert);
// --- load cert(s)
err = mbedtls_x509_crt_parse_file (&tlsCert, "echoclient.certchain.pem");
if (err != 0 ) {
mbedtls_strerror(err, error_buf, sizeof(error_buf));
mbedtls_printf("Load cert failed: %d - %s\n\n", err, error_buf );
return;
}
mbedtls_pk_init (&tlsKey);
// --- seed number generator
mbedtls_ctr_drbg_init (&cryptRNG);
mbedtls_entropy_init (&cryptEntropy);
const char *pers = "t1792 client";
err = mbedtls_ctr_drbg_seed (&cryptRNG, mbedtls_entropy_func, &cryptEntropy,
(const unsigned char *) pers, strlen(pers) );
if (err != 0 ) {
mbedtls_strerror(err, error_buf, sizeof(error_buf));
mbedtls_printf("Seed RNG failed: %d - %s\n\n", err, error_buf );
return;
}
// --- setup TLS facility
mbedtls_ssl_config_init (&tlsConf);
err = mbedtls_ssl_config_defaults (&tlsConf,
MBEDTLS_SSL_IS_CLIENT,
MBEDTLS_SSL_TRANSPORT_STREAM,
MBEDTLS_SSL_PRESET_DEFAULT);
if (err != 0 ) {
mbedtls_strerror(err, error_buf, sizeof(error_buf));
mbedtls_printf("Setting tlsConf failed: %d - %s\n\n", err, error_buf );
return;
}
mbedtls_ssl_conf_rng (&tlsConf, mbedtls_ctr_drbg_random, &cryptRNG );
mbedtls_debug_set_threshold (2);
mbedtls_ssl_conf_dbg (&tlsConf, my_debug, stdout);
mbedtls_ssl_conf_ca_chain (&tlsConf, tlsCert.next, NULL);
err = mbedtls_ssl_conf_own_cert (&tlsConf, &tlsCert, &tlsKey);
if (err != 0 ) {
mbedtls_strerror(err, error_buf, sizeof(error_buf));
mbedtls_printf("Setting CA Chain failed: %d - %s\n\n", err, error_buf );
return;
}
err = mbedtls_ssl_setup (&tlsCtx, &tlsConf);
if (err != 0 ) {
mbedtls_strerror(err, error_buf, sizeof(error_buf));
mbedtls_printf("SSL setup failed: %d - %s\n\n", err, error_buf );
return;
}
} // init
static void my_debug( void *ctx, int level,
const char *file, int line,
const char *str )
{
((void) level);
mbedtls_fprintf( (FILE *) ctx, "%s:%04d: %s", file, line, str );
fflush( (FILE *) ctx );
}
}; // class EchoClient
int main() {
for(int t=0; t<10000; ++t) {
mbedtls_printf("--> task %i\n", t);
EchoClient e = EchoClient();
e.echo();
}
return MBEDTLS_EXIT_SUCCESS;
}
the echoing server is this:
ncat -l 12345 -k -c 'xargs -n1 echo' --ssl --ssl-cert echo.cert.pem --ssl-key echoserver.key.pem -v
this was done with mbedtls-2.16.2 from git.