diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c index f6284feeb..73a993326 100644 --- a/programs/ssl/ssl_client2.c +++ b/programs/ssl/ssl_client2.c @@ -67,6 +67,7 @@ int main( void ) #include "mbedtls/error.h" #include "mbedtls/debug.h" #include "mbedtls/timing.h" +#include "mbedtls/base64.h" #if defined(MBEDTLS_USE_PSA_CRYPTO) #include "psa/crypto.h" @@ -139,6 +140,7 @@ int main( void ) #define DFL_EXTENDED_MS -1 #define DFL_ETM -1 #define DFL_SERIALIZE 0 +#define DFL_CONTEXT_FILE "" #define DFL_EXTENDED_MS_ENFORCE -1 #define DFL_CA_CALLBACK 0 #define DFL_EAP_TLS 0 @@ -363,9 +365,14 @@ int main( void ) #if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION) #define USAGE_SERIALIZATION \ - " serialize=%%d default: 0 (do not serialize/deserialize)\n" \ - " options: 1 (serialize)\n" \ - " 2 (serialize with re-initialization)\n" + " serialize=%%d default: 0 (do not serialize/deserialize)\n" \ + " options: 1 (serialize)\n" \ + " 2 (serialize with re-initialization)\n" \ + " context_file=%%s The file path to write a serialized connection\n"\ + " in the form of base64 code (serialize option\n" \ + " must be set)\n" \ + " default: \"\" (do nothing)\n" \ + " option: a file path\n" #else #define USAGE_SERIALIZATION "" #endif @@ -516,6 +523,9 @@ struct options * during renegotiation */ const char *cid_val; /* the CID to use for incoming messages */ int serialize; /* serialize/deserialize connection */ + const char *context_file; /* the file to write a serialized connection + * in the form of base64 code (serialize + * option must be set) */ const char *cid_val_renego; /* the CID to use for incoming messages * after renegotiation */ int reproducible; /* make communication reproducible */ @@ -1310,6 +1320,7 @@ int main( int argc, char *argv[] ) opt.etm = DFL_ETM; opt.dgram_packing = DFL_DGRAM_PACKING; opt.serialize = DFL_SERIALIZE; + opt.context_file = DFL_CONTEXT_FILE; opt.eap_tls = DFL_EAP_TLS; opt.reproducible = DFL_REPRODUCIBLE; opt.nss_keylog = DFL_NSS_KEYLOG; @@ -1707,6 +1718,10 @@ int main( int argc, char *argv[] ) if( opt.serialize < 0 || opt.serialize > 2) goto usage; } + else if( strcmp( p, "context_file") == 0 ) + { + opt.context_file = q; + } else if( strcmp( p, "eap_tls" ) == 0 ) { opt.eap_tls = atoi( q ); @@ -3102,10 +3117,60 @@ send_request: mbedtls_printf( " ok\n" ); + /* Save serialized context to the 'opt.context_file' as a base64 code */ + if( 0 < strlen( opt.context_file ) ) + { + FILE *b64_file; + uint8_t *b64_buf; + size_t b64_len; + + mbedtls_printf( " . Save serialized context to a file... " ); + + mbedtls_base64_encode( NULL, 0, &b64_len, context_buf, buf_len ); + + if( ( b64_buf = mbedtls_calloc( 1, b64_len ) ) == NULL ) + { + mbedtls_printf( "failed\n ! Couldn't allocate buffer for " + "the base64 code\n" ); + goto exit; + } + + if( ( ret = mbedtls_base64_encode( b64_buf, b64_len, &b64_len, + context_buf, buf_len ) ) != 0 ) + { + mbedtls_printf( "failed\n ! mbedtls_base64_encode returned " + "-0x%x\n", -ret ); + mbedtls_free( b64_buf ); + goto exit; + } + + if( ( b64_file = fopen( opt.context_file, "w" ) ) == NULL ) + { + mbedtls_printf( "failed\n ! Cannot open '%s' for writing.\n", + opt.context_file ); + mbedtls_free( b64_buf ); + goto exit; + } + + if( b64_len != fwrite( b64_buf, 1, b64_len, b64_file ) ) + { + mbedtls_printf( "failed\n ! fwrite(%ld bytes) failed\n", + (long) b64_len ); + mbedtls_free( b64_buf ); + fclose( b64_file ); + goto exit; + } + + mbedtls_free( b64_buf ); + fclose( b64_file ); + + mbedtls_printf( "ok\n" ); + } + if( opt.serialize == 1 ) { /* nothing to do here, done by context_save() already */ - mbedtls_printf( " . Context has been reset... ok" ); + mbedtls_printf( " . Context has been reset... ok\n" ); } if( opt.serialize == 2 ) diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c index 845881f93..1d03fe283 100644 --- a/programs/ssl/ssl_server2.c +++ b/programs/ssl/ssl_server2.c @@ -63,6 +63,7 @@ int main( void ) #include "mbedtls/error.h" #include "mbedtls/debug.h" #include "mbedtls/timing.h" +#include "mbedtls/base64.h" #if defined(MBEDTLS_USE_PSA_CRYPTO) #include "psa/crypto.h" @@ -172,6 +173,7 @@ int main( void ) #define DFL_EXTENDED_MS -1 #define DFL_ETM -1 #define DFL_SERIALIZE 0 +#define DFL_CONTEXT_FILE "" #define DFL_EXTENDED_MS_ENFORCE -1 #define DFL_CA_CALLBACK 0 #define DFL_EAP_TLS 0 @@ -449,9 +451,14 @@ int main( void ) #if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION) #define USAGE_SERIALIZATION \ - " serialize=%%d default: 0 (do not serialize/deserialize)\n" \ - " options: 1 (serialize)\n" \ - " 2 (serialize with re-initialization)\n" + " serialize=%%d default: 0 (do not serialize/deserialize)\n" \ + " options: 1 (serialize)\n" \ + " 2 (serialize with re-initialization)\n" \ + " context_file=%%s The file path to write a serialized connection\n"\ + " in the form of base64 code (serialize option\n" \ + " must be set)\n" \ + " default: \"\" (do nothing)\n" \ + " option: a file path\n" #else #define USAGE_SERIALIZATION "" #endif @@ -617,6 +624,9 @@ struct options * during renegotiation */ const char *cid_val; /* the CID to use for incoming messages */ int serialize; /* serialize/deserialize connection */ + const char *context_file; /* the file to write a serialized connection + * in the form of base64 code (serialize + * option must be set) */ const char *cid_val_renego; /* the CID to use for incoming messages * after renegotiation */ int reproducible; /* make communication reproducible */ @@ -1984,6 +1994,7 @@ int main( int argc, char *argv[] ) opt.extended_ms = DFL_EXTENDED_MS; opt.etm = DFL_ETM; opt.serialize = DFL_SERIALIZE; + opt.context_file = DFL_CONTEXT_FILE; opt.eap_tls = DFL_EAP_TLS; opt.reproducible = DFL_REPRODUCIBLE; opt.nss_keylog = DFL_NSS_KEYLOG; @@ -2406,6 +2417,10 @@ int main( int argc, char *argv[] ) if( opt.serialize < 0 || opt.serialize > 2) goto usage; } + else if( strcmp( p, "context_file") == 0 ) + { + opt.context_file = q; + } else if( strcmp( p, "eap_tls" ) == 0 ) { opt.eap_tls = atoi( q ); @@ -4102,6 +4117,56 @@ data_exchange: mbedtls_printf( " ok\n" ); + /* Save serialized context to the 'opt.context_file' as a base64 code */ + if( 0 < strlen( opt.context_file ) ) + { + FILE *b64_file; + uint8_t *b64_buf; + size_t b64_len; + + mbedtls_printf( " . Save serialized context to a file... " ); + + mbedtls_base64_encode( NULL, 0, &b64_len, context_buf, buf_len ); + + if( ( b64_buf = mbedtls_calloc( 1, b64_len ) ) == NULL ) + { + mbedtls_printf( "failed\n ! Couldn't allocate buffer for " + "the base64 code\n" ); + goto exit; + } + + if( ( ret = mbedtls_base64_encode( b64_buf, b64_len, &b64_len, + context_buf, buf_len ) ) != 0 ) + { + mbedtls_printf( "failed\n ! mbedtls_base64_encode returned " + "-0x%x\n", -ret ); + mbedtls_free( b64_buf ); + goto exit; + } + + if( ( b64_file = fopen( opt.context_file, "w" ) ) == NULL ) + { + mbedtls_printf( "failed\n ! Cannot open '%s' for writing.\n", + opt.context_file ); + mbedtls_free( b64_buf ); + goto exit; + } + + if( b64_len != fwrite( b64_buf, 1, b64_len, b64_file ) ) + { + mbedtls_printf( "failed\n ! fwrite(%ld bytes) failed\n", + (long) b64_len ); + mbedtls_free( b64_buf ); + fclose( b64_file ); + goto exit; + } + + mbedtls_free( b64_buf ); + fclose( b64_file ); + + mbedtls_printf( "ok\n" ); + } + /* * This simulates a workflow where you have a long-lived server * instance, potentially with a pool of ssl_context objects, and you @@ -4112,7 +4177,7 @@ data_exchange: if( opt.serialize == 1 ) { /* nothing to do here, done by context_save() already */ - mbedtls_printf( " . Context has been reset... ok" ); + mbedtls_printf( " . Context has been reset... ok\n" ); } /* diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh index 924384faa..df3f53b3b 100755 --- a/tests/ssl-opt.sh +++ b/tests/ssl-opt.sh @@ -958,6 +958,8 @@ run_tests_memory_after_hanshake() cleanup() { rm -f $CLI_OUT $SRV_OUT $PXY_OUT $SESSION + rm -f context_srv.txt + rm -f context_cli.txt test -n "${SRV_PID:-}" && kill $SRV_PID >/dev/null 2>&1 test -n "${PXY_PID:-}" && kill $PXY_PID >/dev/null 2>&1 test -n "${CLI_PID:-}" && kill $CLI_PID >/dev/null 2>&1 @@ -1628,6 +1630,16 @@ run_test "Context serialization, re-init, both serialize, with CID" \ -c "Deserializing connection..." \ -s "Deserializing connection..." +requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION +run_test "Saving the serialized context to a file" \ + "$P_SRV dtls=1 serialize=1 context_file=context_srv.txt" \ + "$P_CLI dtls=1 serialize=1 context_file=context_cli.txt" \ + 0 \ + -s "Save serialized context to a file... ok" \ + -c "Save serialized context to a file... ok" +rm -f context_srv.txt +rm -f context_cli.txt + # Tests for DTLS Connection ID extension # So far, the CID API isn't implemented, so we can't