int entropy_add_source( entropy_context *ctx, f_source_ptr f_source, void *p_source, size_t threshold ) { int index, ret = 0; #if defined(POLARSSL_THREADING_C) if( ( ret = polarssl_mutex_lock( &ctx->mutex ) ) != 0 ) return( ret ); #endif index = ctx->source_count; if( index >= ENTROPY_MAX_SOURCES ) { ret = POLARSSL_ERR_ENTROPY_MAX_SOURCES; goto exit; } ctx->source[index].f_source = f_source; ctx->source[index].p_source = p_source; ctx->source[index].threshold = threshold; ctx->source_count++; exit: #if defined(POLARSSL_THREADING_C) if( polarssl_mutex_unlock( &ctx->mutex ) != 0 ) return( POLARSSL_ERR_THREADING_MUTEX_ERROR ); #endif return( ret ); }
static void my_mutexed_debug( void *ctx, int level, const char *str ) { polarssl_mutex_lock( &debug_mutex ); if( level < DEBUG_LEVEL ) { polarssl_fprintf( (FILE *) ctx, "%s", str ); fflush( (FILE *) ctx ); } polarssl_mutex_unlock( &debug_mutex ); }
/* * Generate or update blinding values, see section 10 of: * KOCHER, Paul C. Timing attacks on implementations of Diffie-Hellman, RSA, * DSS, and other systems. In : Advances in Cryptology—CRYPTO’96. Springer * Berlin Heidelberg, 1996. p. 104-113. */ static int rsa_prepare_blinding( rsa_context *ctx, mpi *Vi, mpi *Vf, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) { int ret, count = 0; #if defined(POLARSSL_THREADING_C) polarssl_mutex_lock( &ctx->mutex ); #endif if( ctx->Vf.p != NULL ) { /* We already have blinding values, just update them by squaring */ MPI_CHK( mpi_mul_mpi( &ctx->Vi, &ctx->Vi, &ctx->Vi ) ); MPI_CHK( mpi_mod_mpi( &ctx->Vi, &ctx->Vi, &ctx->N ) ); MPI_CHK( mpi_mul_mpi( &ctx->Vf, &ctx->Vf, &ctx->Vf ) ); MPI_CHK( mpi_mod_mpi( &ctx->Vf, &ctx->Vf, &ctx->N ) ); goto done; } /* Unblinding value: Vf = random number, invertible mod N */ do { if( count++ > 10 ) return( POLARSSL_ERR_RSA_RNG_FAILED ); MPI_CHK( mpi_fill_random( &ctx->Vf, ctx->len - 1, f_rng, p_rng ) ); MPI_CHK( mpi_gcd( &ctx->Vi, &ctx->Vf, &ctx->N ) ); } while( mpi_cmp_int( &ctx->Vi, 1 ) != 0 ); /* Blinding value: Vi = Vf^(-e) mod N */ MPI_CHK( mpi_inv_mod( &ctx->Vi, &ctx->Vf, &ctx->N ) ); MPI_CHK( mpi_exp_mod( &ctx->Vi, &ctx->Vi, &ctx->E, &ctx->N, &ctx->RN ) ); done: if( Vi != &ctx->Vi ) { MPI_CHK( mpi_copy( Vi, &ctx->Vi ) ); MPI_CHK( mpi_copy( Vf, &ctx->Vf ) ); } cleanup: #if defined(POLARSSL_THREADING_C) polarssl_mutex_unlock( &ctx->mutex ); #endif return( ret ); }
/* * Thread-safe wrapper for entropy_gather_internal() */ int entropy_gather( entropy_context *ctx ) { int ret; #if defined(POLARSSL_THREADING_C) if( ( ret = polarssl_mutex_lock( &ctx->mutex ) ) != 0 ) return( ret ); #endif ret = entropy_gather_internal( ctx ); #if defined(POLARSSL_THREADING_C) if( polarssl_mutex_unlock( &ctx->mutex ) != 0 ) return( POLARSSL_ERR_THREADING_MUTEX_ERROR ); #endif return( ret ); }
int entropy_update_manual( entropy_context *ctx, const unsigned char *data, size_t len ) { int ret; #if defined(POLARSSL_THREADING_C) if( ( ret = polarssl_mutex_lock( &ctx->mutex ) ) != 0 ) return( ret ); #endif ret = entropy_update( ctx, ENTROPY_SOURCE_MANUAL, data, len ); #if defined(POLARSSL_THREADING_C) if( polarssl_mutex_unlock( &ctx->mutex ) != 0 ) return( POLARSSL_ERR_THREADING_MUTEX_ERROR ); #endif return( ret ); }
/* * Do an RSA public key operation */ int rsa_public( rsa_context *ctx, const unsigned char *input, unsigned char *output ) { int ret; size_t olen; mpi T; mpi_init( &T ); MPI_CHK( mpi_read_binary( &T, input, ctx->len ) ); if( mpi_cmp_mpi( &T, &ctx->N ) >= 0 ) { mpi_free( &T ); return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); } #if defined(POLARSSL_THREADING_C) polarssl_mutex_lock( &ctx->mutex ); #endif olen = ctx->len; MPI_CHK( mpi_exp_mod( &T, &T, &ctx->E, &ctx->N, &ctx->RN ) ); MPI_CHK( mpi_write_binary( &T, output, olen ) ); cleanup: #if defined(POLARSSL_THREADING_C) polarssl_mutex_unlock( &ctx->mutex ); #endif mpi_free( &T ); if( ret != 0 ) return( POLARSSL_ERR_RSA_PUBLIC_FAILED + ret ); return( 0 ); }
int entropy_func( void *data, unsigned char *output, size_t len ) { int ret, count = 0, i, reached; entropy_context *ctx = (entropy_context *) data; unsigned char buf[ENTROPY_BLOCK_SIZE]; if( len > ENTROPY_BLOCK_SIZE ) return( POLARSSL_ERR_ENTROPY_SOURCE_FAILED ); #if defined(POLARSSL_THREADING_C) if( ( ret = polarssl_mutex_lock( &ctx->mutex ) ) != 0 ) return( ret ); #endif /* * Always gather extra entropy before a call */ do { if( count++ > ENTROPY_MAX_LOOP ) { ret = POLARSSL_ERR_ENTROPY_SOURCE_FAILED; goto exit; } if( ( ret = entropy_gather_internal( ctx ) ) != 0 ) goto exit; reached = 0; for( i = 0; i < ctx->source_count; i++ ) if( ctx->source[i].size >= ctx->source[i].threshold ) reached++; } while( reached != ctx->source_count ); memset( buf, 0, ENTROPY_BLOCK_SIZE ); #if defined(POLARSSL_ENTROPY_SHA512_ACCUMULATOR) sha512_finish( &ctx->accumulator, buf ); /* * Reset accumulator and counters and recycle existing entropy */ memset( &ctx->accumulator, 0, sizeof( sha512_context ) ); sha512_starts( &ctx->accumulator, 0 ); sha512_update( &ctx->accumulator, buf, ENTROPY_BLOCK_SIZE ); /* * Perform second SHA-512 on entropy */ sha512( buf, ENTROPY_BLOCK_SIZE, buf, 0 ); #else /* POLARSSL_ENTROPY_SHA512_ACCUMULATOR */ sha256_finish( &ctx->accumulator, buf ); /* * Reset accumulator and counters and recycle existing entropy */ memset( &ctx->accumulator, 0, sizeof( sha256_context ) ); sha256_starts( &ctx->accumulator, 0 ); sha256_update( &ctx->accumulator, buf, ENTROPY_BLOCK_SIZE ); /* * Perform second SHA-256 on entropy */ sha256( buf, ENTROPY_BLOCK_SIZE, buf, 0 ); #endif /* POLARSSL_ENTROPY_SHA512_ACCUMULATOR */ for( i = 0; i < ctx->source_count; i++ ) ctx->source[i].size = 0; memcpy( output, buf, len ); ret = 0; exit: #if defined(POLARSSL_THREADING_C) if( polarssl_mutex_unlock( &ctx->mutex ) != 0 ) return( POLARSSL_ERR_THREADING_MUTEX_ERROR ); #endif return( ret ); }
int ssl_cache_get( void *data, ssl_session *session ) { int ret = 1; #if defined(POLARSSL_HAVE_TIME) time_t t = time( NULL ); #endif ssl_cache_context *cache = (ssl_cache_context *) data; ssl_cache_entry *cur, *entry; #if defined(POLARSSL_THREADING_C) if( polarssl_mutex_lock( &cache->mutex ) != 0 ) return( 1 ); #endif cur = cache->chain; entry = NULL; while( cur != NULL ) { entry = cur; cur = cur->next; #if defined(POLARSSL_HAVE_TIME) if( cache->timeout != 0 && (int) ( t - entry->timestamp ) > cache->timeout ) continue; #endif if( session->ciphersuite != entry->session.ciphersuite || session->compression != entry->session.compression || session->length != entry->session.length ) continue; if( memcmp( session->id, entry->session.id, entry->session.length ) != 0 ) continue; memcpy( session->master, entry->session.master, 48 ); session->verify_result = entry->session.verify_result; #if defined(POLARSSL_X509_CRT_PARSE_C) /* * Restore peer certificate (without rest of the original chain) */ if( entry->peer_cert.p != NULL ) { session->peer_cert = (x509_crt *) polarssl_malloc( sizeof(x509_crt) ); if( session->peer_cert == NULL ) { ret = 1; goto exit; } x509_crt_init( session->peer_cert ); if( x509_crt_parse( session->peer_cert, entry->peer_cert.p, entry->peer_cert.len ) != 0 ) { polarssl_free( session->peer_cert ); session->peer_cert = NULL; ret = 1; goto exit; } } #endif /* POLARSSL_X509_CRT_PARSE_C */ ret = 0; goto exit; } exit: #if defined(POLARSSL_THREADING_C) if( polarssl_mutex_unlock( &cache->mutex ) != 0 ) ret = 1; #endif return( ret ); }
int ssl_cache_set( void *data, const ssl_session *session ) { int ret = 1; #if defined(POLARSSL_HAVE_TIME) time_t t = time( NULL ), oldest = 0; ssl_cache_entry *old = NULL; #endif ssl_cache_context *cache = (ssl_cache_context *) data; ssl_cache_entry *cur, *prv; int count = 0; #if defined(POLARSSL_THREADING_C) if( ( ret = polarssl_mutex_lock( &cache->mutex ) ) != 0 ) return( ret ); #endif cur = cache->chain; prv = NULL; while( cur != NULL ) { count++; #if defined(POLARSSL_HAVE_TIME) if( cache->timeout != 0 && (int) ( t - cur->timestamp ) > cache->timeout ) { cur->timestamp = t; break; /* expired, reuse this slot, update timestamp */ } #endif if( memcmp( session->id, cur->session.id, cur->session.length ) == 0 ) break; /* client reconnected, keep timestamp for session id */ #if defined(POLARSSL_HAVE_TIME) if( oldest == 0 || cur->timestamp < oldest ) { oldest = cur->timestamp; old = cur; } #endif prv = cur; cur = cur->next; } if( cur == NULL ) { #if defined(POLARSSL_HAVE_TIME) /* * Reuse oldest entry if max_entries reached */ if( count >= cache->max_entries ) { if( old == NULL ) { ret = 1; goto exit; } cur = old; } #else /* POLARSSL_HAVE_TIME */ /* * Reuse first entry in chain if max_entries reached, * but move to last place */ if( count >= cache->max_entries ) { if( cache->chain == NULL ) { ret = 1; goto exit; } cur = cache->chain; cache->chain = cur->next; cur->next = NULL; prv->next = cur; } #endif /* POLARSSL_HAVE_TIME */ else { /* * max_entries not reached, create new entry */ cur = (ssl_cache_entry *) polarssl_malloc( sizeof(ssl_cache_entry) ); if( cur == NULL ) { ret = 1; goto exit; } memset( cur, 0, sizeof(ssl_cache_entry) ); if( prv == NULL ) cache->chain = cur; else prv->next = cur; } #if defined(POLARSSL_HAVE_TIME) cur->timestamp = t; #endif } memcpy( &cur->session, session, sizeof( ssl_session ) ); #if defined(POLARSSL_X509_CRT_PARSE_C) /* * If we're reusing an entry, free its certificate first */ if( cur->peer_cert.p != NULL ) { polarssl_free( cur->peer_cert.p ); memset( &cur->peer_cert, 0, sizeof(x509_buf) ); } /* * Store peer certificate */ if( session->peer_cert != NULL ) { cur->peer_cert.p = (unsigned char *) polarssl_malloc( session->peer_cert->raw.len ); if( cur->peer_cert.p == NULL ) { ret = 1; goto exit; } memcpy( cur->peer_cert.p, session->peer_cert->raw.p, session->peer_cert->raw.len ); cur->peer_cert.len = session->peer_cert->raw.len; cur->session.peer_cert = NULL; } #endif /* POLARSSL_X509_CRT_PARSE_C */ ret = 0; exit: #if defined(POLARSSL_THREADING_C) if( polarssl_mutex_unlock( &cache->mutex ) != 0 ) ret = 1; #endif return( ret ); }
/* * Do an RSA private key operation */ int rsa_private( rsa_context *ctx, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, const unsigned char *input, unsigned char *output ) { int ret; size_t olen; mpi T, T1, T2; mpi *Vi, *Vf; /* * When using the Chinese Remainder Theorem, we use blinding values. * Without threading, we just read them directly from the context, * otherwise we make a local copy in order to reduce locking contention. */ #if defined(POLARSSL_THREADING_C) mpi Vi_copy, Vf_copy; mpi_init( &Vi_copy ); mpi_init( &Vf_copy ); Vi = &Vi_copy; Vf = &Vf_copy; #else Vi = &ctx->Vi; Vf = &ctx->Vf; #endif mpi_init( &T ); mpi_init( &T1 ); mpi_init( &T2 ); MPI_CHK( mpi_read_binary( &T, input, ctx->len ) ); if( mpi_cmp_mpi( &T, &ctx->N ) >= 0 ) { mpi_free( &T ); return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); } if( f_rng != NULL ) { /* * Blinding * T = T * Vi mod N */ MPI_CHK( rsa_prepare_blinding( ctx, Vi, Vf, f_rng, p_rng ) ); MPI_CHK( mpi_mul_mpi( &T, &T, Vi ) ); MPI_CHK( mpi_mod_mpi( &T, &T, &ctx->N ) ); } #if defined(POLARSSL_THREADING_C) polarssl_mutex_lock( &ctx->mutex ); #endif #if defined(POLARSSL_RSA_NO_CRT) MPI_CHK( mpi_exp_mod( &T, &T, &ctx->D, &ctx->N, &ctx->RN ) ); #else /* * faster decryption using the CRT * * T1 = input ^ dP mod P * T2 = input ^ dQ mod Q */ MPI_CHK( mpi_exp_mod( &T1, &T, &ctx->DP, &ctx->P, &ctx->RP ) ); MPI_CHK( mpi_exp_mod( &T2, &T, &ctx->DQ, &ctx->Q, &ctx->RQ ) ); /* * T = (T1 - T2) * (Q^-1 mod P) mod P */ MPI_CHK( mpi_sub_mpi( &T, &T1, &T2 ) ); MPI_CHK( mpi_mul_mpi( &T1, &T, &ctx->QP ) ); MPI_CHK( mpi_mod_mpi( &T, &T1, &ctx->P ) ); /* * T = T2 + T * Q */ MPI_CHK( mpi_mul_mpi( &T1, &T, &ctx->Q ) ); MPI_CHK( mpi_add_mpi( &T, &T2, &T1 ) ); #endif /* POLARSSL_RSA_NO_CRT */ if( f_rng != NULL ) { /* * Unblind * T = T * Vf mod N */ MPI_CHK( mpi_mul_mpi( &T, &T, Vf ) ); MPI_CHK( mpi_mod_mpi( &T, &T, &ctx->N ) ); } olen = ctx->len; MPI_CHK( mpi_write_binary( &T, output, olen ) ); cleanup: #if defined(POLARSSL_THREADING_C) polarssl_mutex_unlock( &ctx->mutex ); mpi_free( &Vi_copy ); mpi_free( &Vf_copy ); #endif mpi_free( &T ); mpi_free( &T1 ); mpi_free( &T2 ); if( ret != 0 ) return( POLARSSL_ERR_RSA_PRIVATE_FAILED + ret ); return( 0 ); }
int x509_crt_parse_path( x509_crt *chain, const char *path ) { int ret = 0; #if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) int w_ret; WCHAR szDir[MAX_PATH]; char filename[MAX_PATH]; char *p; int len = (int) strlen( path ); WIN32_FIND_DATAW file_data; HANDLE hFind; if( len > MAX_PATH - 3 ) return( POLARSSL_ERR_X509_BAD_INPUT_DATA ); memset( szDir, 0, sizeof(szDir) ); memset( filename, 0, MAX_PATH ); memcpy( filename, path, len ); filename[len++] = '\\'; p = filename + len; filename[len++] = '*'; w_ret = MultiByteToWideChar( CP_ACP, 0, filename, len, szDir, MAX_PATH - 3 ); hFind = FindFirstFileW( szDir, &file_data ); if (hFind == INVALID_HANDLE_VALUE) return( POLARSSL_ERR_X509_FILE_IO_ERROR ); len = MAX_PATH - len; do { memset( p, 0, len ); if( file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) continue; w_ret = WideCharToMultiByte( CP_ACP, 0, file_data.cFileName, lstrlenW(file_data.cFileName), p, len - 1, NULL, NULL ); w_ret = x509_crt_parse_file( chain, filename ); if( w_ret < 0 ) ret++; else ret += w_ret; } while( FindNextFileW( hFind, &file_data ) != 0 ); if (GetLastError() != ERROR_NO_MORE_FILES) ret = POLARSSL_ERR_X509_FILE_IO_ERROR; FindClose( hFind ); #else /* _WIN32 */ int t_ret; struct stat sb; struct dirent *entry; char entry_name[255]; DIR *dir = opendir( path ); if( dir == NULL) return( POLARSSL_ERR_X509_FILE_IO_ERROR ); #if defined(POLARSSL_THREADING_PTHREAD) if( ( ret = polarssl_mutex_lock( &readdir_mutex ) ) != 0 ) return( ret ); #endif while( ( entry = readdir( dir ) ) != NULL ) { snprintf( entry_name, sizeof entry_name, "%s/%s", path, entry->d_name ); if( stat( entry_name, &sb ) == -1 ) { closedir( dir ); ret = POLARSSL_ERR_X509_FILE_IO_ERROR; goto cleanup; } if( !S_ISREG( sb.st_mode ) ) continue; // Ignore parse errors // t_ret = x509_crt_parse_file( chain, entry_name ); if( t_ret < 0 ) ret++; else ret += t_ret; } closedir( dir ); cleanup: #if defined(POLARSSL_THREADING_PTHREAD) if( polarssl_mutex_unlock( &readdir_mutex ) != 0 ) ret = POLARSSL_ERR_THREADING_MUTEX_ERROR; #endif #endif /* _WIN32 */ return( ret ); }