Skip to content

Instantly share code, notes, and snippets.

@danielealbano
Created August 1, 2023 11:18
Show Gist options
  • Save danielealbano/d78aeb131074c8071b17a5b70e3bb537 to your computer and use it in GitHub Desktop.
Save danielealbano/d78aeb131074c8071b17a5b70e3bb537 to your computer and use it in GitHub Desktop.
openssl vs mbedtls handshake performances
// Compile with
// gcc -O3 -o mbedtls-server-test mbedtls-server-test.c -lmbedtls -lmbedx509 -lmbedcrypto
// mbedtls from Ubuntu 22.10
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#else
#include <stdio.h>
#include <stdlib.h>
#define mbedtls_time time
#define mbedtls_time_t time_t
#define mbedtls_fprintf fprintf
#define mbedtls_printf printf
#define mbedtls_exit exit
#define MBEDTLS_EXIT_SUCCESS EXIT_SUCCESS
#define MBEDTLS_EXIT_FAILURE EXIT_FAILURE
#endif
#include <stdlib.h>
#include <string.h>
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/certs.h"
#include "mbedtls/x509.h"
#include "mbedtls/ssl.h"
#include "mbedtls/net_sockets.h"
#include "mbedtls/error.h"
#include "mbedtls/debug.h"
static char *HTTP_RESPONSE = "HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n<h2>Hello world!</h2>\r\n";
static size_t HTTP_RESPONSE_LENGTH;
int main( void ) {
HTTP_RESPONSE_LENGTH = strlen(HTTP_RESPONSE);
int ret, len;
mbedtls_net_context listen_fd, client_fd;
unsigned char buf[1024];
const char *pers = "ssl_server";
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
mbedtls_ssl_context ssl;
mbedtls_ssl_config conf;
mbedtls_x509_crt srvcert;
mbedtls_pk_context pkey;
mbedtls_net_init( &listen_fd );
mbedtls_net_init( &client_fd );
mbedtls_ssl_init( &ssl );
mbedtls_ssl_config_init( &conf );
mbedtls_x509_crt_init( &srvcert );
mbedtls_pk_init( &pkey );
mbedtls_entropy_init( &entropy );
mbedtls_ctr_drbg_init( &ctr_drbg );
ret = mbedtls_x509_crt_parse_file(&srvcert, "cert.pem");
if( ret != 0 )
{
mbedtls_printf( "mbedtls_x509_crt_parse returned %d\n\n", ret );
goto exit;
}
ret = mbedtls_pk_parse_keyfile( &pkey, "cert.key", NULL);
if( ret != 0 )
{
mbedtls_printf( "mbedtls_pk_parse_key returned %d\n\n", ret );
goto exit;
}
if( ( ret = mbedtls_net_bind( &listen_fd, NULL, "12345", MBEDTLS_NET_PROTO_TCP ) ) != 0 )
{
mbedtls_printf( "mbedtls_net_bind returned %d\n\n", ret );
goto exit;
}
if( ( ret = mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func, &entropy,
(const unsigned char *) pers,
strlen( pers ) ) ) != 0 )
{
mbedtls_printf( "mbedtls_ctr_drbg_seed returned %d\n", ret );
goto exit;
}
if( ( ret = mbedtls_ssl_config_defaults( &conf,
MBEDTLS_SSL_IS_SERVER,
MBEDTLS_SSL_TRANSPORT_STREAM,
MBEDTLS_SSL_PRESET_DEFAULT ) ) != 0 )
{
mbedtls_printf( "mbedtls_ssl_config_defaults returned %d\n\n", ret );
goto exit;
}
// Set mbedtls min and max version to TLS 1.2
mbedtls_ssl_conf_min_version( &conf, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3 );
mbedtls_ssl_conf_max_version( &conf, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3 );
// Set the mbed curve to Curve25519
const mbedtls_ecp_group_id curve_info[2] = { MBEDTLS_ECP_DP_CURVE25519, 0 };
mbedtls_ssl_conf_curves( &conf, curve_info );
// Set the cipher to ECDHE-RSA-AES256-GCM-SHA384,2048,256
const int ciphersuites[2] = { MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, 0 };
mbedtls_ssl_conf_ciphersuites( &conf, ciphersuites );
mbedtls_ssl_conf_rng( &conf, mbedtls_ctr_drbg_random, &ctr_drbg );
mbedtls_ssl_conf_ca_chain( &conf, srvcert.next, NULL );
if( ( ret = mbedtls_ssl_conf_own_cert( &conf, &srvcert, &pkey ) ) != 0 )
{
mbedtls_printf( "mbedtls_ssl_conf_own_cert returned %d\n\n", ret );
goto exit;
}
if( ( ret = mbedtls_ssl_setup( &ssl, &conf ) ) != 0 )
{
mbedtls_printf( "mbedtls_ssl_setup returned %d\n\n", ret );
goto exit;
}
reset:
if( ret != 0 )
{
char error_buf[100];
mbedtls_strerror( ret, error_buf, 100 );
mbedtls_printf("Last error was: %d - %s\n\n", ret, error_buf );
}
mbedtls_net_free( &client_fd );
mbedtls_ssl_session_reset( &ssl );
if( ( ret = mbedtls_net_accept( &listen_fd, &client_fd,
NULL, 0, NULL ) ) != 0 )
{
mbedtls_printf( "mbedtls_net_accept returned %d\n\n", ret );
goto exit;
}
mbedtls_ssl_set_bio( &ssl, &client_fd, mbedtls_net_send, mbedtls_net_recv, NULL );
while( ( ret = mbedtls_ssl_handshake( &ssl ) ) != 0 )
{
if( ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE )
{
mbedtls_printf( "mbedtls_ssl_handshake returned %d\n\n", ret );
goto reset;
}
}
do
{
len = sizeof( buf ) - 1;
memset( buf, 0, sizeof( buf ) );
ret = mbedtls_ssl_read( &ssl, buf, len );
if( ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE )
continue;
if( ret <= 0 )
{
switch( ret )
{
case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY:
mbedtls_printf( "connection was closed gracefully\n" );
break;
case MBEDTLS_ERR_NET_CONN_RESET:
mbedtls_printf( "connection was reset by peer\n" );
break;
default:
mbedtls_printf( "mbedtls_ssl_read returned -0x%x\n", -ret );
break;
}
break;
}
if( ret > 0 )
break;
}
while( 1 );
while( ( ret = mbedtls_ssl_write( &ssl, HTTP_RESPONSE, HTTP_RESPONSE_LENGTH ) ) <= 0 )
{
if( ret == MBEDTLS_ERR_NET_CONN_RESET )
{
goto reset;
}
if( ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE )
{
mbedtls_printf( "mbedtls_ssl_write returned %d\n\n", ret );
goto exit;
}
}
while( ( ret = mbedtls_ssl_close_notify( &ssl ) ) < 0 )
{
if( ret != MBEDTLS_ERR_SSL_WANT_READ &&
ret != MBEDTLS_ERR_SSL_WANT_WRITE )
{
mbedtls_printf( "mbedtls_ssl_close_notify returned %d\n\n", ret );
goto reset;
}
}
ret = 0;
goto reset;
exit:
if( ret != 0 )
{
char error_buf[100];
mbedtls_strerror( ret, error_buf, 100 );
mbedtls_printf("Last error was: %d - %s\n\n", ret, error_buf );
}
mbedtls_net_free( &client_fd );
mbedtls_net_free( &listen_fd );
mbedtls_x509_crt_free( &srvcert );
mbedtls_pk_free( &pkey );
mbedtls_ssl_free( &ssl );
mbedtls_ssl_config_free( &conf );
mbedtls_ctr_drbg_free( &ctr_drbg );
mbedtls_entropy_free( &entropy );
return ret;
}
// mbedtls
$ ab -l -c 1 -t 10 https://localhost:12345/
This is ApacheBench, Version 2.3 <$Revision: 1901567 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking localhost (be patient)
Finished 223 requests
Server Software:
Server Hostname: localhost
Server Port: 12345
SSL/TLS Protocol: TLSv1.2,ECDHE-RSA-AES256-GCM-SHA384,2048,256
Server Temp Key: X25519 253 bits
TLS Server Name: localhost
Document Path: /
Document Length: Variable
Concurrency Level: 1
Time taken for tests: 10.009 seconds
Complete requests: 223
Failed requests: 0
Total transferred: 14941 bytes
HTML transferred: 5129 bytes
Requests per second: 22.28 [#/sec] (mean)
Time per request: 44.884 [ms] (mean)
Time per request: 44.884 [ms] (mean, across all concurrent requests)
Transfer rate: 1.46 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 44 45 1.5 44 52
Processing: 0 0 0.0 0 0
Waiting: 0 0 0.0 0 0
Total: 44 45 1.5 44 52
Percentage of the requests served within a certain time (ms)
50% 44
66% 44
75% 44
80% 44
90% 48
95% 48
98% 48
99% 48
100% 52 (longest request)
// Compile with
// gcc -O3 -o openssl-server-test openssl-server-test.c -lssl -lcrypto
// OpenSSL from Ubuntu 22.10
//SSL-Server.c
#include <errno.h>
#include <unistd.h>
#include <malloc.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <resolv.h>
#include "openssl/ssl.h"
#include "openssl/err.h"
#define FAIL -1
static char *HTTP_RESPONSE = "HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n<h2>Hello world!</h2>\r\n";
static size_t HTTP_RESPONSE_LENGTH;
int OpenListener(int port)
{ int sd;
struct sockaddr_in addr;
sd = socket(PF_INET, SOCK_STREAM, 0);
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = INADDR_ANY;
if ( bind(sd, (struct sockaddr*)&addr, sizeof(addr)) != 0 )
{
perror("can't bind port");
abort();
}
if ( listen(sd, 10) != 0 )
{
perror("Can't configure listening port");
abort();
}
return sd;
}
SSL_CTX* InitServerCTX(void)
{
const SSL_METHOD *method;
SSL_CTX *ctx;
OpenSSL_add_all_algorithms(); /* load & register all cryptos, etc. */
SSL_load_error_strings(); /* load all error messages */
method = TLS_server_method();
ctx = SSL_CTX_new(method); /* create new context from method */
if(ctx == NULL)
{
ERR_print_errors_fp(stderr);
abort();
}
SSL_CTX_set_cipher_list(ctx, "ALL:eNULL");
return ctx;
}
void LoadCertificates(SSL_CTX* ctx, char* CertFile, char* KeyFile)
{
//New lines
if (SSL_CTX_load_verify_locations(ctx, CertFile, KeyFile) != 1)
ERR_print_errors_fp(stderr);
if (SSL_CTX_set_default_verify_paths(ctx) != 1)
ERR_print_errors_fp(stderr);
//End new lines
/* set the local certificate from CertFile */
if (SSL_CTX_use_certificate_file(ctx, CertFile, SSL_FILETYPE_PEM) <= 0)
{
ERR_print_errors_fp(stderr);
abort();
}
/* set the private key from KeyFile (may be the same as CertFile) */
// SSL_CTX_set_default_passwd_cb_userdata(ctx, "12345678");
if (SSL_CTX_use_PrivateKey_file(ctx, KeyFile, SSL_FILETYPE_PEM) <= 0)
{
ERR_print_errors_fp(stderr);
abort();
}
/* verify private key */
if (!SSL_CTX_check_private_key(ctx))
{
fprintf(stderr, "Private key does not match the public certificate\n");
abort();
}
//New lines - Force the client-side have a certificate
//SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
//SSL_CTX_set_verify_depth(ctx, 4);
//End new lines
}
void ShowCerts(SSL* ssl)
{
X509 *cert;
char *line;
cert = SSL_get_peer_certificate(ssl); /* Get certificates (if available) */
if ( cert != NULL )
{
printf("Server certificates:\n");
line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
printf("Subject: %s\n", line);
free(line);
line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
printf("Issuer: %s\n", line);
free(line);
X509_free(cert);
}
else
printf("No certificates.\n");
}
void Servlet(SSL* ssl) /* Serve the connection -- threadable */
{
char buf[1024];
int sd, bytes;
if ( SSL_accept(ssl) == FAIL ) /* do SSL-protocol accept */
ERR_print_errors_fp(stderr);
else
{
bytes = SSL_read(ssl, buf, sizeof(buf)); /* get request */
if ( bytes > 0 )
{
buf[bytes] = 0;
SSL_write(ssl, HTTP_RESPONSE, HTTP_RESPONSE_LENGTH); /* send reply */
}
else
ERR_print_errors_fp(stderr);
}
sd = SSL_get_fd(ssl); /* get socket connection */
SSL_shutdown(ssl); /* shutdown SSL connection */
SSL_free(ssl); /* release SSL state */
close(sd); /* close connection */
}
int main(int argc, char **argv)
{
HTTP_RESPONSE_LENGTH = strlen(HTTP_RESPONSE);
SSL_CTX *ctx;
int server;
char portnum[]="12345";
char CertFile[] = "cert.pem";
char KeyFile[] = "cert.key";
SSL_library_init();
ctx = InitServerCTX(); /* initialize SSL */
LoadCertificates(ctx, CertFile, KeyFile); /* load certs */
server = OpenListener(atoi(portnum)); /* create server socket */
// Set the min version and the max version to TLS 1.2
SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION);
SSL_CTX_set_max_proto_version(ctx, TLS1_2_VERSION);
// Set the cipher to ECDHE-RSA-AES256-GCM-SHA384
SSL_CTX_set_cipher_list(ctx, "ECDHE-RSA-AES256-GCM-SHA384");
// Set the curve to x25519
SSL_CTX_set1_curves_list(ctx, "X25519");
while (1)
{
struct sockaddr_in addr;
socklen_t len = sizeof(addr);
SSL *ssl;
int client = accept(server, (struct sockaddr*)&addr, &len); /* accept connection as usual */
// printf("Connection: %s:%d\n",inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
ssl = SSL_new(ctx); /* get new SSL state with context */
SSL_set_fd(ssl, client); /* set connection socket to SSL state */
Servlet(ssl); /* service connection */
}
close(server); /* close server socket */
SSL_CTX_free(ctx); /* release context */
}
$ ab -l -c 1 -t 10 https://localhost:12345/
This is ApacheBench, Version 2.3 <$Revision: 1901567 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking localhost (be patient)
Completed 5000 requests
Finished 6360 requests
Server Software:
Server Hostname: localhost
Server Port: 12345
SSL/TLS Protocol: TLSv1.2,ECDHE-RSA-AES256-GCM-SHA384,2048,256
Server Temp Key: X25519 253 bits
TLS Server Name: localhost
Document Path: /
Document Length: Variable
Concurrency Level: 1
Time taken for tests: 10.000 seconds
Complete requests: 6360
Failed requests: 0
Total transferred: 426120 bytes
HTML transferred: 146280 bytes
Requests per second: 635.99 [#/sec] (mean)
Time per request: 1.572 [ms] (mean)
Time per request: 1.572 [ms] (mean, across all concurrent requests)
Transfer rate: 41.61 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 1 2 0.1 1 3
Processing: 0 0 0.0 0 0
Waiting: 0 0 0.0 0 0
Total: 2 2 0.1 2 3
ERROR: The median and mean for the initial connection time are more than twice the standard
deviation apart. These results are NOT reliable.
Percentage of the requests served within a certain time (ms)
50% 2
66% 2
75% 2
80% 2
90% 2
95% 2
98% 2
99% 2
100% 3 (longest request)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment