/* * Non-public function wrapped by mbedtls_ctr_drbg_seed(). Necessary to allow * NIST tests to succeed (which require known length fixed entropy) */ int mbedtls_ctr_drbg_seed_entropy_len( mbedtls_ctr_drbg_context *ctx, int (*f_entropy)(void *, unsigned char *, size_t), void *p_entropy, const unsigned char *custom, size_t len, size_t entropy_len ) { int ret; unsigned char key[MBEDTLS_CTR_DRBG_KEYSIZE]; memset( key, 0, MBEDTLS_CTR_DRBG_KEYSIZE ); mbedtls_aes_init( &ctx->aes_ctx ); ctx->f_entropy = f_entropy; ctx->p_entropy = p_entropy; ctx->entropy_len = entropy_len; ctx->reseed_interval = MBEDTLS_CTR_DRBG_RESEED_INTERVAL; /* * Initialize with an empty key */ mbedtls_aes_setkey_enc( &ctx->aes_ctx, key, MBEDTLS_CTR_DRBG_KEYBITS ); if( ( ret = mbedtls_ctr_drbg_reseed( ctx, custom, len ) ) != 0 ) return( ret ); return( 0 ); }
/* * Checkup routine */ int mbedtls_ctr_drbg_self_test( int verbose ) { mbedtls_ctr_drbg_context ctx; unsigned char buf[16]; mbedtls_ctr_drbg_init( &ctx ); /* * Based on a NIST CTR_DRBG test vector (PR = True) */ if( verbose != 0 ) mbedtls_printf( " CTR_DRBG (PR = TRUE) : " ); test_offset = 0; CHK( mbedtls_ctr_drbg_seed_entropy_len( &ctx, ctr_drbg_self_test_entropy, (void *) entropy_source_pr, nonce_pers_pr, 16, 32 ) ); mbedtls_ctr_drbg_set_prediction_resistance( &ctx, MBEDTLS_CTR_DRBG_PR_ON ); CHK( mbedtls_ctr_drbg_random( &ctx, buf, MBEDTLS_CTR_DRBG_BLOCKSIZE ) ); CHK( mbedtls_ctr_drbg_random( &ctx, buf, MBEDTLS_CTR_DRBG_BLOCKSIZE ) ); CHK( memcmp( buf, result_pr, MBEDTLS_CTR_DRBG_BLOCKSIZE ) ); mbedtls_ctr_drbg_free( &ctx ); if( verbose != 0 ) mbedtls_printf( "passed\n" ); /* * Based on a NIST CTR_DRBG test vector (PR = FALSE) */ if( verbose != 0 ) mbedtls_printf( " CTR_DRBG (PR = FALSE): " ); mbedtls_ctr_drbg_init( &ctx ); test_offset = 0; CHK( mbedtls_ctr_drbg_seed_entropy_len( &ctx, ctr_drbg_self_test_entropy, (void *) entropy_source_nopr, nonce_pers_nopr, 16, 32 ) ); CHK( mbedtls_ctr_drbg_random( &ctx, buf, 16 ) ); CHK( mbedtls_ctr_drbg_reseed( &ctx, NULL, 0 ) ); CHK( mbedtls_ctr_drbg_random( &ctx, buf, 16 ) ); CHK( memcmp( buf, result_nopr, 16 ) ); mbedtls_ctr_drbg_free( &ctx ); if( verbose != 0 ) mbedtls_printf( "passed\n" ); if( verbose != 0 ) mbedtls_printf( "\n" ); return( 0 ); }
/* Accept incoming TLS connection */ int tls_accept(int *sock, mbedtls_ssl_context *context, mbedtls_ssl_config *config, int timeout) { int result, handshake; struct timeval timer; time_t start_time; mbedtls_ssl_init(context); if (mbedtls_ctr_drbg_reseed(&ctr_drbg, (const unsigned char*)"client thread", 13) != 0) { return -1; } if (mbedtls_ssl_setup(context, config) != 0) { return -1; } mbedtls_ssl_set_bio(context, sock, mbedtls_net_send, mbedtls_net_recv, NULL); timer.tv_sec = timeout; timer.tv_usec = 0; setsockopt(*sock, SOL_SOCKET, SO_RCVTIMEO, (void*)&timer, sizeof(struct timeval)); start_time = time(NULL); result = TLS_HANDSHAKE_OKE; while ((handshake = mbedtls_ssl_handshake(context)) != 0) { if (handshake == MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION) { mbedtls_ssl_free(context); result = TLS_HANDSHAKE_NO_MATCH; break; } if ((handshake != MBEDTLS_ERR_SSL_WANT_READ) && (handshake != MBEDTLS_ERR_SSL_WANT_WRITE)) { mbedtls_ssl_free(context); result = TLS_HANDSHAKE_ERROR; break; } if (time(NULL) - start_time >= timeout) { mbedtls_ssl_free(context); result = TLS_HANDSHAKE_TIMEOUT; break; } } if (result == TLS_HANDSHAKE_OKE) { timer.tv_sec = 0; timer.tv_usec = 0; setsockopt(*sock, SOL_SOCKET, SO_RCVTIMEO, (void*)&timer, sizeof(struct timeval)); } return result; }
/* Connect to remote server via TLS */ int tls_connect(mbedtls_ssl_context *context, int *sock, char *hostname) { if (mbedtls_ctr_drbg_reseed(&ctr_drbg, (const unsigned char*)"Reverse Proxy", 13) != 0) { return -1; } mbedtls_ssl_init(context); if (mbedtls_ssl_setup(context, &client_config) != 0) { return -1; } mbedtls_ssl_set_bio(context, sock, mbedtls_net_send, mbedtls_net_recv, NULL); if (hostname != NULL) { mbedtls_ssl_set_hostname(context, hostname); } if (mbedtls_ssl_handshake(context) != 0) { mbedtls_ssl_free(context); return TLS_HANDSHAKE_ERROR; } return TLS_HANDSHAKE_OKE; }
int mbedtls_ctr_drbg_random_with_add( void *p_rng, unsigned char *output, size_t output_len, const unsigned char *additional, size_t add_len ) { int ret = 0; mbedtls_ctr_drbg_context *ctx = (mbedtls_ctr_drbg_context *) p_rng; unsigned char add_input[MBEDTLS_CTR_DRBG_SEEDLEN]; unsigned char *p = output; unsigned char tmp[MBEDTLS_CTR_DRBG_BLOCKSIZE]; int i; size_t use_len; if( output_len > MBEDTLS_CTR_DRBG_MAX_REQUEST ) return( MBEDTLS_ERR_CTR_DRBG_REQUEST_TOO_BIG ); if( add_len > MBEDTLS_CTR_DRBG_MAX_INPUT ) return( MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG ); memset( add_input, 0, MBEDTLS_CTR_DRBG_SEEDLEN ); if( ctx->reseed_counter > ctx->reseed_interval || ctx->prediction_resistance ) { if( ( ret = mbedtls_ctr_drbg_reseed( ctx, additional, add_len ) ) != 0 ) return( ret ); add_len = 0; } if( add_len > 0 ) { block_cipher_df( add_input, additional, add_len ); ctr_drbg_update_internal( ctx, add_input ); } while( output_len > 0 ) { /* * Increase counter */ for( i = MBEDTLS_CTR_DRBG_BLOCKSIZE; i > 0; i-- ) if( ++ctx->counter[i - 1] != 0 ) break; /* * Crypt counter block */ mbedtls_aes_crypt_ecb( &ctx->aes_ctx, MBEDTLS_AES_ENCRYPT, ctx->counter, tmp ); use_len = ( output_len > MBEDTLS_CTR_DRBG_BLOCKSIZE ) ? MBEDTLS_CTR_DRBG_BLOCKSIZE : output_len; /* * Copy random block to destination */ memcpy( p, tmp, use_len ); p += use_len; output_len -= use_len; } ctr_drbg_update_internal( ctx, add_input ); ctx->reseed_counter++; return( 0 ); }
int main( void ) { int ret, len, cnt = 0, pid; mbedtls_net_context listen_fd, client_fd; unsigned char buf[1024]; const char *pers = "ssl_fork_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_entropy_init( &entropy ); mbedtls_pk_init( &pkey ); mbedtls_x509_crt_init( &srvcert ); mbedtls_ctr_drbg_init( &ctr_drbg ); signal( SIGCHLD, SIG_IGN ); /* * 0. Initial seeding of the RNG */ mbedtls_printf( "\n . Initial seeding of the random generator..." ); fflush( stdout ); 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 %d\n", ret ); goto exit; } mbedtls_printf( " ok\n" ); /* * 1. Load the certificates and private RSA key */ mbedtls_printf( " . Loading the server cert. and key..." ); fflush( stdout ); /* * This demonstration program uses embedded test certificates. * Instead, you may want to use mbedtls_x509_crt_parse_file() to read the * server and CA certificates, as well as mbedtls_pk_parse_keyfile(). */ ret = mbedtls_x509_crt_parse( &srvcert, (const unsigned char *) mbedtls_test_srv_crt, mbedtls_test_srv_crt_len ); if( ret != 0 ) { mbedtls_printf( " failed\n ! mbedtls_x509_crt_parse returned %d\n\n", ret ); goto exit; } ret = mbedtls_x509_crt_parse( &srvcert, (const unsigned char *) mbedtls_test_cas_pem, mbedtls_test_cas_pem_len ); if( ret != 0 ) { mbedtls_printf( " failed\n ! mbedtls_x509_crt_parse returned %d\n\n", ret ); goto exit; } ret = mbedtls_pk_parse_key( &pkey, (const unsigned char *) mbedtls_test_srv_key, mbedtls_test_srv_key_len, NULL, 0 ); if( ret != 0 ) { mbedtls_printf( " failed\n ! mbedtls_pk_parse_key returned %d\n\n", ret ); goto exit; } mbedtls_printf( " ok\n" ); /* * 1b. Prepare SSL configuration */ mbedtls_printf( " . Configuring SSL..." ); fflush( stdout ); if( ( ret = mbedtls_ssl_config_defaults( &conf, MBEDTLS_SSL_IS_SERVER, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT ) ) != 0 ) { mbedtls_printf( " failed\n ! mbedtls_ssl_config_defaults returned %d\n\n", ret ); goto exit; } mbedtls_ssl_conf_rng( &conf, mbedtls_ctr_drbg_random, &ctr_drbg ); mbedtls_ssl_conf_dbg( &conf, my_debug, stdout ); mbedtls_ssl_conf_ca_chain( &conf, srvcert.next, NULL ); if( ( ret = mbedtls_ssl_conf_own_cert( &conf, &srvcert, &pkey ) ) != 0 ) { mbedtls_printf( " failed\n ! mbedtls_ssl_conf_own_cert returned %d\n\n", ret ); goto exit; } mbedtls_printf( " ok\n" ); /* * 2. Setup the listening TCP socket */ mbedtls_printf( " . Bind on https://localhost:4433/ ..." ); fflush( stdout ); if( ( ret = mbedtls_net_bind( &listen_fd, NULL, "4433", MBEDTLS_NET_PROTO_TCP ) ) != 0 ) { mbedtls_printf( " failed\n ! mbedtls_net_bind returned %d\n\n", ret ); goto exit; } mbedtls_printf( " ok\n" ); while( 1 ) { /* * 3. Wait until a client connects */ mbedtls_net_init( &client_fd ); mbedtls_ssl_init( &ssl ); mbedtls_printf( " . Waiting for a remote connection ..." ); fflush( stdout ); if( ( ret = mbedtls_net_accept( &listen_fd, &client_fd, NULL, 0, NULL ) ) != 0 ) { mbedtls_printf( " failed\n ! mbedtls_net_accept returned %d\n\n", ret ); goto exit; } mbedtls_printf( " ok\n" ); /* * 3.5. Forking server thread */ pid = fork(); mbedtls_printf( " . Forking to handle connection ..." ); fflush( stdout ); if( pid < 0 ) { mbedtls_printf(" failed\n ! fork returned %d\n\n", pid ); goto exit; } mbedtls_printf( " ok\n" ); if( pid != 0 ) { if( ( ret = mbedtls_ctr_drbg_reseed( &ctr_drbg, (const unsigned char *) "parent", 6 ) ) != 0 ) { mbedtls_printf( " failed\n ! mbedtls_ctr_drbg_reseed returned %d\n", ret ); goto exit; } mbedtls_net_free( &client_fd ); continue; } mbedtls_net_free( &listen_fd ); /* * 4. Setup stuff */ mbedtls_printf( " . Setting up the SSL data...." ); fflush( stdout ); if( ( ret = mbedtls_ctr_drbg_reseed( &ctr_drbg, (const unsigned char *) "child", 5 ) ) != 0 ) { mbedtls_printf( " failed\n ! mbedtls_ctr_drbg_reseed returned %d\n", ret ); goto exit; } if( ( ret = mbedtls_ssl_setup( &ssl, &conf ) ) != 0 ) { mbedtls_printf( " failed\n ! mbedtls_ssl_setup returned %d\n\n", ret ); goto exit; } mbedtls_ssl_set_bio( &ssl, &client_fd, mbedtls_net_send, mbedtls_net_recv, NULL ); mbedtls_printf( " ok\n" ); /* * 5. Handshake */ mbedtls_printf( " . Performing the SSL/TLS handshake..." ); fflush( stdout ); while( ( ret = mbedtls_ssl_handshake( &ssl ) ) != 0 ) { if( ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE ) { mbedtls_printf( " failed\n ! mbedtls_ssl_handshake returned %d\n\n", ret ); goto exit; } } mbedtls_printf( " ok\n" ); /* * 6. Read the HTTP Request */ mbedtls_printf( " < Read from client:" ); fflush( stdout ); 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 %d\n", ret ); break; } break; } len = ret; mbedtls_printf( " %d bytes read\n\n%s", len, (char *) buf ); if( ret > 0 ) break; } while( 1 ); /* * 7. Write the 200 Response */ mbedtls_printf( " > Write to client:" ); fflush( stdout ); len = sprintf( (char *) buf, HTTP_RESPONSE, mbedtls_ssl_get_ciphersuite( &ssl ) ); while( cnt++ < 100 ) { while( ( ret = mbedtls_ssl_write( &ssl, buf, len ) ) <= 0 ) { if( ret == MBEDTLS_ERR_NET_CONN_RESET ) { mbedtls_printf( " failed\n ! peer closed the connection\n\n" ); goto exit; } 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 exit; } } len = ret; mbedtls_printf( " %d bytes written\n\n%s\n", len, (char *) buf ); mbedtls_net_usleep( 1000000 ); } mbedtls_ssl_close_notify( &ssl ); goto exit; } exit: 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 ); #if defined(_WIN32) mbedtls_printf( " Press Enter to exit this program.\n" ); fflush( stdout ); getchar(); #endif return( ret ); }
void ssh_reseed(void) { mbedtls_ctr_drbg_reseed(&ssh_mbedtls_ctr_drbg, NULL, 0); }