/* * Non-public function wrapped by ctr_crbg_init(). Necessary to allow NIST * tests to succeed (which require known length fixed entropy) */ int ctr_drbg_init_entropy_len( 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[CTR_DRBG_KEYSIZE]; memset( ctx, 0, sizeof(ctr_drbg_context) ); memset( key, 0, CTR_DRBG_KEYSIZE ); ctx->f_entropy = f_entropy; ctx->p_entropy = p_entropy; ctx->entropy_len = entropy_len; ctx->reseed_interval = CTR_DRBG_RESEED_INTERVAL; /* * Initialize with an empty key */ aes_setkey_enc( &ctx->aes_ctx, key, CTR_DRBG_KEYBITS ); if( ( ret = ctr_drbg_reseed( ctx, custom, len ) ) != 0 ) return( ret ); return( 0 ); }
int rand_ctx_reseed() { ctr_drbg_context *cd_ctx = rand_ctx_get(); entropy_context *ec = cd_ctx->p_entropy; ASSERT(NULL != ec); if (!entropy_gather_blocking(ec)) return 0; if (0 != ctr_drbg_reseed(cd_ctx, NULL, 0)) return 0; return 1; }
/* Push new entropy into the CTR_DRBG instance in ctx, combining * it with the entropy already there. On success, 0 is returned. If * the callback returns a non-zero value, that value is returned. * Other errors return -1. */ static int fips_drbg_reseed(struct fips_drbg_ctx_s *ctx) { uint8_t entropy_pool[Q_HW_DRBG_BLOCK_BYTES]; int rv; enum ctr_drbg_status_t init_rv; if (ctx == NULL) return FIPS140_PRNG_ERR; if (!ctx->fips_drbg_started) { rv = (*ctx->get_entropy_callback)(ctx->get_entropy_callback_ctx, ctx->prev_hw_drbg_block ); if (rv != 0) return FIPS140_PRNG_ERR; ctx->fips_drbg_started = 1; } rv = (*ctx->get_entropy_callback)(ctx->get_entropy_callback_ctx, entropy_pool ); if (rv != 0) { memset(entropy_pool, 0, Q_HW_DRBG_BLOCK_BYTES); return FIPS140_PRNG_ERR; } if (!memcmp(entropy_pool, ctx->prev_hw_drbg_block, Q_HW_DRBG_BLOCK_BYTES)) { memset(entropy_pool, 0, Q_HW_DRBG_BLOCK_BYTES); return FIPS140_PRNG_ERR; } else memcpy(ctx->prev_hw_drbg_block, entropy_pool, Q_HW_DRBG_BLOCK_BYTES); init_rv = ctr_drbg_reseed(&ctx->ctr_drbg_ctx, entropy_pool, 8*MSM_ENTROPY_BUFFER_SIZE); /* Zeroize the buffer for security. */ memset(entropy_pool, 0, Q_HW_DRBG_BLOCK_BYTES); return (init_rv == CTR_DRBG_SUCCESS ? FIPS140_PRNG_OK : FIPS140_PRNG_ERR); }
/* * Checkup routine */ int ctr_drbg_self_test( int verbose ) { ctr_drbg_context ctx; unsigned char buf[16]; /* * Based on a NIST CTR_DRBG test vector (PR = True) */ if( verbose != 0 ) polarssl_printf( " CTR_DRBG (PR = TRUE) : " ); test_offset = 0; CHK( ctr_drbg_init_entropy_len( &ctx, ctr_drbg_self_test_entropy, entropy_source_pr, nonce_pers_pr, 16, 32 ) ); ctr_drbg_set_prediction_resistance( &ctx, CTR_DRBG_PR_ON ); CHK( ctr_drbg_random( &ctx, buf, CTR_DRBG_BLOCKSIZE ) ); CHK( ctr_drbg_random( &ctx, buf, CTR_DRBG_BLOCKSIZE ) ); CHK( memcmp( buf, result_pr, CTR_DRBG_BLOCKSIZE ) ); if( verbose != 0 ) polarssl_printf( "passed\n" ); /* * Based on a NIST CTR_DRBG test vector (PR = FALSE) */ if( verbose != 0 ) polarssl_printf( " CTR_DRBG (PR = FALSE): " ); test_offset = 0; CHK( ctr_drbg_init_entropy_len( &ctx, ctr_drbg_self_test_entropy, entropy_source_nopr, nonce_pers_nopr, 16, 32 ) ); CHK( ctr_drbg_random( &ctx, buf, 16 ) ); CHK( ctr_drbg_reseed( &ctx, NULL, 0 ) ); CHK( ctr_drbg_random( &ctx, buf, 16 ) ); CHK( memcmp( buf, result_nopr, 16 ) ); if( verbose != 0 ) polarssl_printf( "passed\n" ); if( verbose != 0 ) polarssl_printf( "\n" ); return( 0 ); }
int 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; ctr_drbg_context *ctx = (ctr_drbg_context *) p_rng; unsigned char add_input[CTR_DRBG_SEEDLEN]; unsigned char *p = output; unsigned char tmp[CTR_DRBG_BLOCKSIZE]; int i; size_t use_len; if( output_len > CTR_DRBG_MAX_REQUEST ) return( POLARSSL_ERR_CTR_DRBG_REQUEST_TOO_BIG ); if( add_len > CTR_DRBG_MAX_INPUT ) return( POLARSSL_ERR_CTR_DRBG_INPUT_TOO_BIG ); memset( add_input, 0, CTR_DRBG_SEEDLEN ); if( ctx->reseed_counter > ctx->reseed_interval || ctx->prediction_resistance ) { if( ( ret = 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 = CTR_DRBG_BLOCKSIZE; i > 0; i-- ) if( ++ctx->counter[i - 1] != 0 ) break; /* * Crypt counter block */ aes_crypt_ecb( &ctx->aes_ctx, AES_ENCRYPT, ctx->counter, tmp ); use_len = (output_len > CTR_DRBG_BLOCKSIZE ) ? 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( int argc, char *argv[] ) { int ret, len, cnt = 0, pid; int listen_fd; int client_fd; unsigned char buf[1024]; const char *pers = "ssl_fork_server"; entropy_context entropy; ctr_drbg_context ctr_drbg; ssl_context ssl; x509_cert srvcert; rsa_context rsa; ((void) argc); ((void) argv); signal( SIGCHLD, SIG_IGN ); /* * 0. Initial seeding of the RNG */ printf( "\n . Initial seeding of the random generator..." ); fflush( stdout ); entropy_init( &entropy ); if( ( ret = ctr_drbg_init( &ctr_drbg, entropy_func, &entropy, (const unsigned char *) pers, strlen( pers ) ) ) != 0 ) { printf( " failed\n ! ctr_drbg_init returned %d\n", ret ); goto exit; } printf( " ok\n" ); /* * 1. Load the certificates and private RSA key */ printf( " . Loading the server cert. and key..." ); fflush( stdout ); memset( &srvcert, 0, sizeof( x509_cert ) ); /* * This demonstration program uses embedded test certificates. * Instead, you may want to use x509parse_crtfile() to read the * server and CA certificates, as well as x509parse_keyfile(). */ ret = x509parse_crt( &srvcert, (const unsigned char *) test_srv_crt, strlen( test_srv_crt ) ); if( ret != 0 ) { printf( " failed\n ! x509parse_crt returned %d\n\n", ret ); goto exit; } ret = x509parse_crt( &srvcert, (const unsigned char *) test_ca_crt, strlen( test_ca_crt ) ); if( ret != 0 ) { printf( " failed\n ! x509parse_crt returned %d\n\n", ret ); goto exit; } rsa_init( &rsa, RSA_PKCS_V15, 0 ); ret = x509parse_key( &rsa, (const unsigned char *) test_srv_key, strlen( test_srv_key ), NULL, 0 ); if( ret != 0 ) { printf( " failed\n ! x509parse_key returned %d\n\n", ret ); goto exit; } printf( " ok\n" ); /* * 2. Setup the listening TCP socket */ printf( " . Bind on https://localhost:4433/ ..." ); fflush( stdout ); if( ( ret = net_bind( &listen_fd, NULL, 4433 ) ) != 0 ) { printf( " failed\n ! net_bind returned %d\n\n", ret ); goto exit; } printf( " ok\n" ); while( 1 ) { /* * 3. Wait until a client connects */ client_fd = -1; memset( &ssl, 0, sizeof( ssl ) ); printf( " . Waiting for a remote connection ..." ); fflush( stdout ); if( ( ret = net_accept( listen_fd, &client_fd, NULL ) ) != 0 ) { printf( " failed\n ! net_accept returned %d\n\n", ret ); goto exit; } printf( " ok\n" ); /* * 3.5. Forking server thread */ pid = fork(); printf( " . Forking to handle connection ..." ); fflush( stdout ); if( pid < 0 ) { printf(" failed\n ! fork returned %d\n\n", pid ); goto exit; } printf( " ok\n" ); if( pid != 0 ) { if( ( ret = ctr_drbg_reseed( &ctr_drbg, (const unsigned char *) "parent", 6 ) ) != 0 ) { printf( " failed\n ! ctr_drbg_reseed returned %d\n", ret ); goto exit; } close( client_fd ); continue; } close( listen_fd ); /* * 4. Setup stuff */ printf( " . Setting up the SSL data...." ); fflush( stdout ); if( ( ret = ctr_drbg_reseed( &ctr_drbg, (const unsigned char *) "child", 5 ) ) != 0 ) { printf( " failed\n ! ctr_drbg_reseed returned %d\n", ret ); goto exit; } if( ( ret = ssl_init( &ssl ) ) != 0 ) { printf( " failed\n ! ssl_init returned %d\n\n", ret ); goto exit; } printf( " ok\n" ); ssl_set_endpoint( &ssl, SSL_IS_SERVER ); ssl_set_authmode( &ssl, SSL_VERIFY_NONE ); ssl_set_rng( &ssl, ctr_drbg_random, &ctr_drbg ); ssl_set_dbg( &ssl, my_debug, stdout ); ssl_set_bio( &ssl, net_recv, &client_fd, net_send, &client_fd ); ssl_set_ca_chain( &ssl, srvcert.next, NULL, NULL ); ssl_set_own_cert( &ssl, &srvcert, &rsa ); /* * 5. Handshake */ printf( " . Performing the SSL/TLS handshake..." ); fflush( stdout ); while( ( ret = ssl_handshake( &ssl ) ) != 0 ) { if( ret != POLARSSL_ERR_NET_WANT_READ && ret != POLARSSL_ERR_NET_WANT_WRITE ) { printf( " failed\n ! ssl_handshake returned %d\n\n", ret ); goto exit; } } printf( " ok\n" ); /* * 6. Read the HTTP Request */ printf( " < Read from client:" ); fflush( stdout ); do { len = sizeof( buf ) - 1; memset( buf, 0, sizeof( buf ) ); ret = ssl_read( &ssl, buf, len ); if( ret == POLARSSL_ERR_NET_WANT_READ || ret == POLARSSL_ERR_NET_WANT_WRITE ) continue; if( ret <= 0 ) { switch( ret ) { case POLARSSL_ERR_SSL_PEER_CLOSE_NOTIFY: printf( " connection was closed gracefully\n" ); break; case POLARSSL_ERR_NET_CONN_RESET: printf( " connection was reset by peer\n" ); break; default: printf( " ssl_read returned %d\n", ret ); break; } break; } len = ret; printf( " %d bytes read\n\n%s", len, (char *) buf ); } while( 0 ); /* * 7. Write the 200 Response */ printf( " > Write to client:" ); fflush( stdout ); len = sprintf( (char *) buf, HTTP_RESPONSE, ssl_get_ciphersuite( &ssl ) ); while( cnt < 100 ) { while( ( ret = ssl_write( &ssl, buf, len ) ) <= 0 ) { if( ret == POLARSSL_ERR_NET_CONN_RESET ) { printf( " failed\n ! peer closed the connection\n\n" ); goto exit; } if( ret != POLARSSL_ERR_NET_WANT_READ && ret != POLARSSL_ERR_NET_WANT_WRITE ) { printf( " failed\n ! ssl_write returned %d\n\n", ret ); goto exit; } } len = ret; printf( " %d bytes written\n\n%s\n", len, (char *) buf ); m_sleep( 1000 ); } ssl_close_notify( &ssl ); goto exit; } exit: net_close( client_fd ); x509_free( &srvcert ); rsa_free( &rsa ); ssl_free( &ssl ); #if defined(_WIN32) printf( " Press Enter to exit this program.\n" ); fflush( stdout ); getchar(); #endif return( ret ); }