blob: 2ec5b2cc4a932dc68c63e282913716885a8900f7 [file] [log] [blame]
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
/*
*
* tls_server.c
*
*
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#include <stdio.h>
#define mbedtls_free free
#define mbedtls_calloc calloc
#define mbedtls_fprintf fprintf
#define mbedtls_printf printf
#if !defined(MBEDTLS_ENTROPY_C) || \
!defined(MBEDTLS_SSL_TLS_C) || !defined(MBEDTLS_SSL_SRV_C) || \
!defined(MBEDTLS_NET_C) || !defined(MBEDTLS_CTR_DRBG_C)
int main( void )
{
mbedtls_printf("MBEDTLS_ENTROPY_C and/or "
"MBEDTLS_SSL_TLS_C and/or MBEDTLS_SSL_SRV_C and/or "
"MBEDTLS_NET_C and/or MBEDTLS_CTR_DRBG_C and/or not defined.\n");
return( 0 );
}
#else
#include "mbedtls/net.h"
#include "mbedtls/ssl.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/error.h"
#include "mbedtls/debug.h"
#include "mbedtls/timing.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if !defined(_WIN32)
#include <signal.h>
#endif
#if defined(MBEDTLS_TLS_MILAGRO_CS)
#include "mbedtls/milagro.h"
#endif
#if defined(_WIN32)
#include <windows.h>
#endif
#define DFL_SERVER_ADDR NULL
#define DFL_SERVER_PORT "4444"
#define DFL_DEBUG_LEVEL 1
#define DFL_NBIO 0
#define DFL_FORCE_CIPHER 49329
#define DFL_VERSION_SUITES NULL
#define DFL_EXCHANGES 1
#define DFL_MIN_VERSION MBEDTLS_SSL_MAJOR_VERSION_3
#define DFL_MAX_VERSION MBEDTLS_SSL_MAJOR_VERSION_3
#define DFL_AUTH_MODE -1
#define DFL_MFL_CODE MBEDTLS_SSL_MAX_FRAG_LEN_NONE
#define DFL_TRANSPORT MBEDTLS_SSL_TRANSPORT_STREAM
/* packets (for fragmentation purposes) */
#define HTTP_RESPONSE \
"\n SERVER: Hi Client, yes very well!!!\n\n"
/*
* Size of the basic I/O buffer. Able to hold our default response.
*
* You will need to adapt the mbedtls_ssl_get_bytes_avail() test in ssl-opt.sh
* if you change this value to something outside the range <= 100 or > 500
*/
#define IO_BUF_LEN 200
#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH)
#define USAGE_MAX_FRAG_LEN \
" max_frag_len=%%d default: 16384 (tls default)\n" \
" options: 512, 1024, 2048, 4096\n"
#else
#define USAGE_MAX_FRAG_LEN ""
#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */
#define USAGE \
"\n usage: tls_server param=<>...\n" \
"\n acceptable parameters:\n" \
" server_addr=%%d default: (all interfaces)\n" \
" server_port=%%d default: 4444\n" \
" debug_level=%%d default: 0 (disabled)\n" \
" nbio=%%d default: 0 (blocking I/O)\n" \
" options: 1 (non-blocking), 2 (added delays)\n" \
" force_ciphersuite=<name>" \
" acceptable ciphersuite names:\n" \
" TLS-MILAGRO-CS-WITH-AES-128-GCM-SHA256\n" \
" TLS-MILAGRO-P2P-WITH-AES-128-GCM-SHA256\n" \
"\n" \
"\n" \
" exchanges=%%d default: 1\n" \
"\n" \
USAGE_MAX_FRAG_LEN \
"\n" \
"\n" \
/*
* global options
*/
struct options
{
const char *server_addr; /* address on which the ssl service runs */
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 force_ciphersuite[2]; /* protocol/ciphersuite to use, or all */
const char *version_suites; /* per-version ciphersuites */
int exchanges; /* number of data exchanges */
int min_version; /* minimum protocol version accepted */
int max_version; /* maximum protocol version accepted */
int auth_mode; /* verify mode for connection */
unsigned char mfl_code; /* code for maximum fragment length */
int transport; /* TLS as default (no DTLS) */
} opt;
int read_from_file(const char* path, char* secret, int len_secret){
char hex[len_secret];
int tmp=0;
unsigned int i=0;
FILE* file = fopen(path,"r");
if(!file)
{
printf("Secret file is missing\n");
exit(-1);
}
fscanf(file,"%[^\n]",hex);
fclose(file);
for (i = 0; i < strlen(hex)/2; i++){
sscanf(&hex[i * 2], "%02x", &tmp);
secret[i] = tmp;
}
secret[(strlen(hex)/2)+1] = 0;
return 0;
}
static void my_debug( void *ctx, int level,
const char *file, int line,
const char *str )
{
const char *p, *basename;
/* Extract basename from file */
for( p = basename = file; *p != '\0'; p++ )
if( *p == '/' || *p == '\\' )
basename = p + 1;
mbedtls_fprintf( (FILE *) ctx, "%s:%04d: |%d| %s", basename, line, level, str );
fflush( (FILE *) ctx );
}
/*
* Test recv/send functions that make sure each try returns
* WANT_READ/WANT_WRITE at least once before sucesseding
*/
static int my_recv( void *ctx, unsigned char *buf, size_t len )
{
static int first_try = 1;
int ret;
if( first_try )
{
first_try = 0;
return( MBEDTLS_ERR_SSL_WANT_READ );
}
ret = mbedtls_net_recv( ctx, buf, len );
if( ret != MBEDTLS_ERR_SSL_WANT_READ )
first_try = 1; /* Next call will be a new operation */
return( ret );
}
static int my_send( void *ctx, const unsigned char *buf, size_t len )
{
static int first_try = 1;
int ret;
if( first_try )
{
first_try = 0;
return( MBEDTLS_ERR_SSL_WANT_WRITE );
}
ret = mbedtls_net_send( ctx, buf, len );
if( ret != MBEDTLS_ERR_SSL_WANT_WRITE )
first_try = 1; /* Next call will be a new operation */
return( ret );
}
/*
* Return authmode from string, or -1 on error
*/
static int get_auth_mode( const char *s )
{
if( strcmp( s, "none" ) == 0 )
return( MBEDTLS_SSL_VERIFY_NONE );
if( strcmp( s, "optional" ) == 0 )
return( MBEDTLS_SSL_VERIFY_OPTIONAL );
if( strcmp( s, "required" ) == 0 )
return( MBEDTLS_SSL_VERIFY_REQUIRED );
return( -1 );
}
static mbedtls_net_context listen_fd, client_fd;
/* Interruption handler to ensure clean exit (for valgrind testing) */
#if !defined(_WIN32)
static int received_sigterm = 0;
void term_handler( int sig )
{
((void) sig);
received_sigterm = 1;
mbedtls_net_free( &listen_fd ); /* causes mbedtls_net_accept() to abort */
mbedtls_net_free( &client_fd ); /* causes net_read() to abort */
}
#endif
int main( int argc, char *argv[] )
{
int ret = 0, len, written, frags, exchanges_left;
unsigned char buf[IO_BUF_LEN];
const char *pers = "tls_server";
unsigned char client_ip[16] = { 0 };
size_t cliip_len;
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
mbedtls_ssl_context ssl;
mbedtls_ssl_config conf;
const int *ciphersuites;
char *cs_server_key;
char *p2p_server_key;
const mbedtls_ssl_ciphersuite_t *ciphersuite_info;
int got_milagro_cs_ciphersuite;
int got_milagro_p2p_ciphersuite;
#if defined(MBEDTLS_TLS_MILAGRO_CS)
mbedtls_milagro_cs_context milagro_cs;
#endif
#if defined(MBEDTLS_TLS_MILAGRO_P2P)
mbedtls_milagro_p2p_context milagro_p2p;
#endif
#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C)
unsigned char alloc_buf[100000];
#endif
int i;
char *p, *q;
#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C)
mbedtls_memory_buffer_alloc_init( alloc_buf, sizeof(alloc_buf) );
#endif
/*
* Make sure memory references are valid in case we exit early.
*/
mbedtls_net_init( &client_fd );
mbedtls_net_init( &listen_fd );
mbedtls_ssl_init( &ssl );
mbedtls_ssl_config_init( &conf );
mbedtls_ctr_drbg_init( &ctr_drbg );
#if defined(MBEDTLS_TLS_MILAGRO_CS)
mbedtls_ssl_milagro_cs_init(&milagro_cs );
#endif
#if defined(MBEDTLS_TLS_MILAGRO_P2P)
mbedtls_ssl_milagro_p2p_init(&milagro_p2p);
#endif
#if !defined(_WIN32)
/* Abort cleanly on SIGTERM and SIGINT */
signal( SIGTERM, term_handler );
signal( SIGINT, term_handler );
#endif
if( argc == 0 )
{
usage:
if( ret == 0 )
ret = 1;
mbedtls_printf( USAGE );
mbedtls_printf("\n");
goto exit;
}
opt.server_addr = DFL_SERVER_ADDR;
opt.server_port = DFL_SERVER_PORT;
opt.debug_level = DFL_DEBUG_LEVEL;
opt.nbio = DFL_NBIO;
opt.force_ciphersuite[0]= DFL_FORCE_CIPHER;
opt.version_suites = DFL_VERSION_SUITES;
opt.exchanges = DFL_EXCHANGES;
opt.min_version = DFL_MIN_VERSION;
opt.max_version = DFL_MAX_VERSION;
opt.auth_mode = DFL_AUTH_MODE;
opt.mfl_code = DFL_MFL_CODE;
opt.transport = DFL_TRANSPORT;
for( i = 1; i < argc; i++ )
{
p = argv[i];
if( ( q = strchr( p, '=' ) ) == NULL )
goto usage;
*q++ = '\0';
if( strcmp( p, "server_port" ) == 0 )
opt.server_port = q;
else if( strcmp( p, "server_addr" ) == 0 )
opt.server_addr = q;
else if( strcmp( p, "debug_level" ) == 0 )
{
opt.debug_level = atoi( q );
if( opt.debug_level < 0 || opt.debug_level > 65535 )
goto usage;
}
else if( strcmp( p, "force_ciphersuite" ) == 0 )
{
opt.force_ciphersuite[0] = mbedtls_ssl_get_ciphersuite_id( q );
if( opt.force_ciphersuite[0] == 0 )
{
ret = 2;
goto usage;
}
opt.force_ciphersuite[1] = 0;
}
else if( strcmp( p, "nbio" ) == 0 )
{
opt.nbio = atoi( q );
if( opt.nbio < 0 || opt.nbio > 2 )
goto usage;
}
else if( strcmp( p, "exchanges" ) == 0 )
{
opt.exchanges = atoi( q );
if( opt.exchanges < 0 )
goto usage;
}
else if( strcmp( p, "auth_mode" ) == 0 )
{
if( ( opt.auth_mode = get_auth_mode( q ) ) < 0 )
goto usage;
}
else if( strcmp( p, "max_frag_len" ) == 0 )
{
if( strcmp( q, "512" ) == 0 )
opt.mfl_code = MBEDTLS_SSL_MAX_FRAG_LEN_512;
else if( strcmp( q, "1024" ) == 0 )
opt.mfl_code = MBEDTLS_SSL_MAX_FRAG_LEN_1024;
else if( strcmp( q, "2048" ) == 0 )
opt.mfl_code = MBEDTLS_SSL_MAX_FRAG_LEN_2048;
else if( strcmp( q, "4096" ) == 0 )
opt.mfl_code = MBEDTLS_SSL_MAX_FRAG_LEN_4096;
else
goto usage;
}
else
goto usage;
}
#if defined(MBEDTLS_DEBUG_C)
mbedtls_debug_set_threshold( opt.debug_level );
#endif
/*
* 1. Initialize the RNG and the session data
*/
mbedtls_printf( "\n . Seeding the random number generator..." );
fflush( stdout );
mbedtls_entropy_init( &entropy );
if( ( ret = mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func, &entropy,
(const unsigned char *) pers,
strlen( pers ) ) ) != 0 )
{
mbedtls_printf( " failed\n ! mbedtls_ctr_drbg_seed returned -0x%x\n", -ret );
goto exit;
}
mbedtls_printf( " ok\n" );
/*
* 2. Setup the listening TCP socket
*/
mbedtls_printf( " . Bind on %s://%s:%s/ ...",
opt.transport == MBEDTLS_SSL_TRANSPORT_STREAM ? "tcp" : "udp",
opt.server_addr ? opt.server_addr : "*",
opt.server_port );
fflush( stdout );
if( ( ret = mbedtls_net_bind( &listen_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_bind returned -0x%x\n\n", -ret );
goto exit;
}
mbedtls_printf( " ok\n" );
/*
* 2.1. Setup stuff
*/
mbedtls_printf( " . Setting up the SSL/TLS structure..." );
fflush( stdout );
if( ( ret = mbedtls_ssl_config_defaults( &conf,
MBEDTLS_SSL_IS_SERVER,
opt.transport,
MBEDTLS_SSL_PRESET_DEFAULT ) ) != 0 )
{
mbedtls_printf( " failed\n ! mbedtls_ssl_config_defaults returned -0x%x\n\n", -ret );
goto exit;
}
if( opt.auth_mode != DFL_AUTH_MODE )
mbedtls_ssl_conf_authmode( &conf, opt.auth_mode );
#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 );
goto exit;
};
#endif
mbedtls_ssl_conf_rng( &conf, mbedtls_ctr_drbg_random, &ctr_drbg );
mbedtls_ssl_conf_dbg( &conf, my_debug, stdout );
mbedtls_ssl_conf_ciphersuites( &conf, opt.force_ciphersuite );
if( ( ret = mbedtls_ssl_setup( &ssl, &conf ) ) != 0 )
{
mbedtls_printf( " failed\n ! mbedtls_ssl_setup returned -0x%x\n\n", -ret );
goto exit;
}
if( opt.nbio == 2 )
mbedtls_ssl_set_bio( &ssl, &client_fd, my_send, my_recv, NULL );
else
mbedtls_ssl_set_bio( &ssl, &client_fd, mbedtls_net_send, mbedtls_net_recv,
opt.nbio == 0 ? mbedtls_net_recv_timeout : NULL );
mbedtls_printf( " ok\n" );
reset:
#if !defined(_WIN32)
if( received_sigterm )
{
mbedtls_printf( " interrupted by SIGTERM\n" );
ret = 0;
goto exit;
}
#endif
if( ret == MBEDTLS_ERR_SSL_CLIENT_RECONNECT )
{
mbedtls_printf( " ! Client initiated reconnection from same port\n" );
goto handshake;
}
#ifdef MBEDTLS_ERROR_C
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 );
}
#endif
mbedtls_net_free( &client_fd );
mbedtls_ssl_session_reset( &ssl );
ciphersuites = ssl.conf->ciphersuite_list[ssl.minor_ver];
got_milagro_cs_ciphersuite = 0;
got_milagro_p2p_ciphersuite = 0;
ciphersuite_info = NULL;
for(i = 0; ciphersuites[i] != 0; i++ )
{
ciphersuite_info = mbedtls_ssl_ciphersuite_from_id(ciphersuites[i]);
if (ciphersuite_info->id ==
mbedtls_ssl_get_ciphersuite_id( "TLS-MILAGRO-CS-WITH-AES-128-GCM-SHA256" ) )
{
got_milagro_cs_ciphersuite++;
}
else if(ciphersuite_info->id ==
mbedtls_ssl_get_ciphersuite_id( "TLS-MILAGRO-P2P-WITH-AES-128-GCM-SHA256" ) )
{
got_milagro_p2p_ciphersuite++;
}
}
#if defined(MBEDTLS_TLS_MILAGRO_CS)
if(got_milagro_cs_ciphersuite>0)
{
/*
* 2.5 Setup MILAGRO_CS parameters
*/
printf( " . Setting up MILAGRO_CS parameters..." );
cs_server_key = calloc(4*PFS,sizeof(char));
read_from_file("CSServerKey", cs_server_key, 2*(4*PFS));
mbedtls_ssl_milagro_cs_set_secret(&milagro_cs, cs_server_key, 4*PFS); free(cs_server_key);
if( mbedtls_ssl_milagro_cs_setup_RNG(&milagro_cs, &entropy) != 0)
{
printf("\n\nFailed while setting the RNG in MILAGRO_CS\n");
exit(-1);
}
mbedtls_ssl_set_milagro_cs(ssl.handshake, &milagro_cs);
printf( " ok\n" );
}
#endif /* MBEDTLS_TLS_MILAGRO_CS */
#if defined(MBEDTLS_TLS_MILAGRO_P2P)
if(got_milagro_p2p_ciphersuite>0)
{
/*
* 2.5 Setup MILAGRO_P2P parameters
*/
mbedtls_printf( " . Setting up MILAGRO_P2P parameters..." );
p2p_server_key = calloc(2*PFS+1, sizeof(char));
read_from_file("P2PServerKey", p2p_server_key, 2*(2*PFS+1));
mbedtls_ssl_milagro_p2p_set_key(MBEDTLS_SSL_IS_SERVER, &milagro_p2p, p2p_server_key, 2*PFS+1); free(p2p_server_key);
if (mbedtls_ssl_milagro_p2p_setup_RNG( &milagro_p2p, &entropy) != 0 )
{
printf("\n\nFailed while setting the RNG in MPIN\n");
exit(-1);
}
mbedtls_ssl_milagro_p2p_set_identity(MBEDTLS_SSL_IS_SERVER, &milagro_p2p, (char *)"server.miracl.com");
mbedtls_ssl_set_milagro_p2p(ssl.handshake, &milagro_p2p);
mbedtls_printf( " ok\n" );
}
#endif /* MBEDTLS_TLS_MILAGRO_P2P */
/*
* 3. Wait until a client connects
*/
mbedtls_printf( " . Waiting for a remote connection ..." );
fflush( stdout );
if( ( ret = mbedtls_net_accept( &listen_fd, &client_fd,
client_ip, sizeof( client_ip ), &cliip_len ) ) != 0 )
{
#if !defined(_WIN32)
if( received_sigterm )
{
mbedtls_printf( " interrupted by signal\n" );
ret = 0;
goto exit;
}
#endif
mbedtls_printf( " failed\n ! mbedtls_net_accept returned -0x%x\n\n", -ret );
goto exit;
}
if( opt.nbio > 0 )
ret = mbedtls_net_set_nonblock( &client_fd );
else
ret = mbedtls_net_set_block( &client_fd );
if( ret != 0 )
{
mbedtls_printf( " failed\n ! net_set_(non)block() returned -0x%x\n\n", -ret );
goto exit;
}
mbedtls_printf( " ok\n" );
/*
* 4. Handshake
*/
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 );
if( ret == MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED )
{
mbedtls_printf( " hello verification requested\n" );
ret = 0;
goto reset;
}
else if( ret != 0 )
{
mbedtls_printf( " failed\n ! mbedtls_ssl_handshake returned -0x%x\n\n", -ret );
goto reset;
}
else /* ret == 0 */
{
mbedtls_printf( " ok\n [ Protocol is %s ]\n [ Ciphersuite is %s ]\n",
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 );
else
mbedtls_printf( " [ Record expansion is unknown (compression) ]\n" );
#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH)
mbedtls_printf( " [ Maximum fragment length is %u ]\n",
(unsigned int) mbedtls_ssl_get_max_frag_len( &ssl ) );
#endif
if( opt.exchanges == 0 )
goto close_notify;
exchanges_left = opt.exchanges;
data_exchange:
/*
* 6. Read from client
*/
mbedtls_printf( " < Read from client:" );
fflush( stdout );
do
{
int terminated = 0;
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" );
goto close_notify;
case 0:
case MBEDTLS_ERR_NET_CONN_RESET:
mbedtls_printf( " connection was reset by peer\n" );
ret = MBEDTLS_ERR_NET_CONN_RESET;
goto reset;
default:
mbedtls_printf( " mbedtls_ssl_read returned -0x%x\n", -ret );
goto reset;
}
}
if( mbedtls_ssl_get_bytes_avail( &ssl ) == 0 )
{
len = ret;
buf[len] = '\0';
mbedtls_printf( " %d bytes read\n\n%s\n", len, (char *) buf );
/* End of message should be detected according to the syntax of the
* application protocol (eg HTTP), just use a dummy test here. */
if( buf[len - 1] == '\n' )
terminated = 1;
}
else
{
int extra_len, ori_len;
unsigned char *larger_buf;
ori_len = ret;
extra_len = (int) mbedtls_ssl_get_bytes_avail( &ssl );
larger_buf = mbedtls_calloc( 1, ori_len + extra_len + 1 );
if( larger_buf == NULL )
{
mbedtls_printf( " ! memory allocation failed\n" );
ret = 1;
goto reset;
}
memset( larger_buf, 0, ori_len + extra_len );
memcpy( larger_buf, buf, ori_len );
/* This read should never fail and get the whole cached data */
ret = mbedtls_ssl_read( &ssl, larger_buf + ori_len, extra_len );
if( ret != extra_len ||
mbedtls_ssl_get_bytes_avail( &ssl ) != 0 )
{
mbedtls_printf( " ! mbedtls_ssl_read failed on cached data\n" );
ret = 1;
goto reset;
}
larger_buf[ori_len + extra_len] = '\0';
mbedtls_printf( " %u bytes read (%u + %u)\n\n%s\n",
ori_len + extra_len, ori_len, extra_len,
(char *) larger_buf );
/* End of message should be detected according to the syntax of the
* application protocol (eg HTTP), just use a dummy test here. */
if( larger_buf[ori_len + extra_len - 1] == '\n' )
terminated = 1;
mbedtls_free( larger_buf );
}
if( terminated )
{
break;
}
}
while( 1 );
/*
* 7. Write the response
*/
mbedtls_printf( " > Write to client:" );
fflush( stdout );
len = sprintf( (char *) buf, HTTP_RESPONSE );
for( written = 0, frags = 0; written < len; written += ret, frags++ )
{
while( ( ret = mbedtls_ssl_write( &ssl, buf + written, len - written ) )
<= 0 )
{
if( ret == MBEDTLS_ERR_NET_CONN_RESET )
{
mbedtls_printf( " failed\n ! peer closed the connection\n\n" );
goto reset;
}
if( ret != MBEDTLS_ERR_SSL_WANT_READ &&
ret != MBEDTLS_ERR_SSL_WANT_WRITE )
{
mbedtls_printf( " failed\n ! mbedtls_ssl_write returned %d\n\n", ret );
goto reset;
}
}
}
buf[written] = '\0';
mbedtls_printf( " %d bytes written in %d fragments\n\n%s\n", written, frags, (char *) buf );
/*
* 7b. Continue doing data exchanges?
*/
if( --exchanges_left > 0 )
goto data_exchange;
/*
* 8. Done, cleanly close the connection
*/
close_notify:
mbedtls_printf( " . Closing the connection..." );
/* No error checking, the connection might be closed already */
do ret = mbedtls_ssl_close_notify( &ssl );
while( ret == MBEDTLS_ERR_SSL_WANT_WRITE );
ret = 0;
mbedtls_printf( " done\n" );
goto reset;
/*
* Cleanup and exit
*/
exit:
#ifdef MBEDTLS_ERROR_C
if( ret != 0 )
{
char error_buf[100];
mbedtls_strerror( ret, error_buf, 100 );
mbedtls_printf("Last error was: -0x%X - %s\n\n", -ret, error_buf );
}
#endif
mbedtls_printf( " . Cleaning up..." );
fflush( stdout );
mbedtls_net_free( &client_fd );
mbedtls_net_free( &listen_fd );
mbedtls_ssl_free( &ssl );
mbedtls_ssl_config_free( &conf );
mbedtls_ctr_drbg_free( &ctr_drbg );
mbedtls_entropy_free( &entropy );
#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C)
#if defined(MBEDTLS_MEMORY_DEBUG)
mbedtls_memory_buffer_alloc_status();
#endif
mbedtls_memory_buffer_alloc_free();
#endif
mbedtls_printf( " done.\n" );
#if defined(_WIN32)
mbedtls_printf( " + Press Enter to exit this program.\n" );
fflush( stdout ); getchar();
#endif
// Shell can not handle large exit numbers -> 1 for errors
if( ret < 0 )
ret = 1;
return( ret );
}
#endif /* MBEDTLS_ENTROPY_C && MBEDTLS_SSL_TLS_C &&
MBEDTLS_SSL_SRV_C && MBEDTLS_NET_C &&
MBEDTLS_CTR_DRBG_C */