@ -44,12 +44,15 @@ struct provider_store_st; /* Forward declaration */
struct ossl_provider_st {
/* Flag bits */
unsigned int flag_initialized : 1 ;
unsigned int flag_activated : 1 ;
unsigned int flag_fallback : 1 ; /* Can be used as fallback */
unsigned int flag_activated_as_fallback : 1 ;
/* OpenSSL library side data */
CRYPTO_REF_COUNT refcnt ;
CRYPTO_RWLOCK * refcnt_lock ; /* For the ref counter */
CRYPTO_REF_COUNT activatecnt ;
CRYPTO_RWLOCK * activatecnt_lock ; /* For the activate counter */
char * name ;
char * path ;
DSO * module ;
@ -110,20 +113,15 @@ struct provider_store_st {
} ;
/*
* provider_deactivate_free ( ) is a wrapper around ossl_provider_free ( )
* that also makes sure that activated fallback providers are deactivated .
* This is simply done by freeing them an extra time , to compensate for the
* refcount that provider_activate_fallbacks ( ) gives them .
* provider_deactivate_free ( ) is a wrapper around ossl_provider_deactivate ( )
* and ossl_provider_free ( ) , called as needed .
* Since this is only called when the provider store is being emptied , we
* don ' t need to care about any lock .
*/
static void provider_deactivate_free ( OSSL_PROVIDER * prov )
{
int extra_free = ( prov - > flag_initialized
& & prov - > flag_activated_as_fallback ) ;
if ( extra_free )
ossl_provider_free ( prov ) ;
if ( prov - > flag_activated )
ossl_provider_deactivate ( prov ) ;
ossl_provider_free ( prov ) ;
}
@ -251,6 +249,7 @@ static OSSL_PROVIDER *provider_new(const char *name,
if ( ( prov = OPENSSL_zalloc ( sizeof ( * prov ) ) ) = = NULL
# ifndef HAVE_ATOMICS
| | ( prov - > refcnt_lock = CRYPTO_THREAD_lock_new ( ) ) = = NULL
| | ( prov - > activatecnt_lock = CRYPTO_THREAD_lock_new ( ) ) = = NULL
# endif
| | ! ossl_provider_up_ref ( prov ) /* +1 One reference to be returned */
| | ( prov - > name = OPENSSL_strdup ( name ) ) = = NULL ) {
@ -337,38 +336,35 @@ void ossl_provider_free(OSSL_PROVIDER *prov)
CRYPTO_DOWN_REF ( & prov - > refcnt , & ref , prov - > refcnt_lock ) ;
/*
* When the refcount drops below two , the store is the only
* possible reference , or it has already been taken away from
* the store ( this may happen if a provider was activated
* because it ' s a fallback , but isn ' t currently used )
* When that happens , the provider is inactivated .
* When the refcount drops to zero , we clean up the provider .
* Note that this also does teardown , which may seem late ,
* considering that init happens on first activation . However ,
* there may be other structures hanging on to the provider after
* the last deactivation and may therefore need full access to the
* provider ' s services . Therefore , we deinit late .
*/
if ( ref < 2 & & prov - > flag_initialized ) {
if ( ref = = 0 ) {
if ( prov - > flag_initialized ) {
# ifndef FIPS_MODULE
ossl_init_thread_deregister ( prov ) ;
ossl_init_thread_deregister ( prov ) ;
# endif
if ( prov - > teardown ! = NULL )
prov - > teardown ( prov - > provctx ) ;
if ( prov - > teardown ! = NULL )
prov - > teardown ( prov - > provctx ) ;
# ifndef OPENSSL_NO_ERR
# ifndef FIPS_MODULE
if ( prov - > error_strings ! = NULL ) {
ERR_unload_strings ( prov - > error_lib , prov - > error_strings ) ;
OPENSSL_free ( prov - > error_strings ) ;
prov - > error_strings = NULL ;
}
if ( prov - > error_strings ! = NULL ) {
ERR_unload_strings ( prov - > error_lib , prov - > error_strings ) ;
OPENSSL_free ( prov - > error_strings ) ;
prov - > error_strings = NULL ;
}
# endif
# endif
OPENSSL_free ( prov - > operation_bits ) ;
prov - > operation_bits = NULL ;
prov - > operation_bits_sz = 0 ;
prov - > flag_initialized = 0 ;
}
OPENSSL_free ( prov - > operation_bits ) ;
prov - > operation_bits = NULL ;
prov - > operation_bits_sz = 0 ;
prov - > flag_initialized = 0 ;
}
/*
* When the refcount drops to zero , it has been taken out of
* the store . All we have to do here is clean it out .
*/
if ( ref = = 0 ) {
# ifndef FIPS_MODULE
DSO_free ( prov - > module ) ;
# endif
@ -377,6 +373,7 @@ void ossl_provider_free(OSSL_PROVIDER *prov)
sk_INFOPAIR_pop_free ( prov - > parameters , free_infopair ) ;
# ifndef HAVE_ATOMICS
CRYPTO_THREAD_lock_free ( prov - > refcnt_lock ) ;
CRYPTO_THREAD_lock_free ( prov - > activatecnt_lock ) ;
# endif
OPENSSL_free ( prov ) ;
}
@ -460,7 +457,7 @@ int OSSL_PROVIDER_set_default_search_path(OSSL_LIB_CTX *libctx,
* locking . Direct callers must remember to set the store flags when
* appropriate .
*/
static int provider_activate ( OSSL_PROVIDER * prov )
static int provider_init ( OSSL_PROVIDER * prov )
{
const OSSL_DISPATCH * provider_dispatch = NULL ;
void * tmp_provctx = NULL ; /* safety measure */
@ -633,18 +630,60 @@ static int provider_activate(OSSL_PROVIDER *prov)
return 1 ;
}
static int provider_deactivate ( OSSL_PROVIDER * prov )
{
int ref = 0 ;
if ( ! ossl_assert ( prov ! = NULL ) )
return 0 ;
if ( CRYPTO_DOWN_REF ( & prov - > activatecnt , & ref , prov - > activatecnt_lock ) < = 0 )
return 0 ;
if ( ref < 1 )
prov - > flag_activated = 0 ;
/* We don't deinit here, that's done in ossl_provider_free() */
return 1 ;
}
static int provider_activate ( OSSL_PROVIDER * prov )
{
int ref = 0 ;
if ( CRYPTO_UP_REF ( & prov - > activatecnt , & ref , prov - > activatecnt_lock ) < = 0 )
return 0 ;
if ( provider_init ( prov ) ) {
prov - > flag_activated = 1 ;
return 1 ;
}
provider_deactivate ( prov ) ;
return 0 ;
}
int ossl_provider_activate ( OSSL_PROVIDER * prov )
{
if ( prov = = NULL )
return 0 ;
if ( provider_activate ( prov ) ) {
CRYPTO_THREAD_write_lock ( prov - > store - > lock ) ;
prov - > store - > use_fallbacks = 0 ;
CRYPTO_THREAD_unlock ( prov - > store - > lock ) ;
return 1 ;
}
return 0 ;
}
int ossl_provider_deactivate ( OSSL_PROVIDER * prov )
{
if ( prov = = NULL )
return 0 ;
return provider_deactivate ( prov ) ;
}
void * ossl_provider_ctx ( const OSSL_PROVIDER * prov )
{
return prov - > provctx ;
@ -669,7 +708,7 @@ static int provider_forall_loaded(struct provider_store_st *store,
OSSL_PROVIDER * prov =
sk_OSSL_PROVIDER_value ( store - > providers , i ) ;
if ( prov - > flag_initializ ed ) {
if ( prov - > flag_activat ed ) {
if ( found_activated ! = NULL )
* found_activated = 1 ;
if ( ! ( ret = cb ( prov , cbdata ) ) )
@ -695,23 +734,14 @@ static void provider_activate_fallbacks(struct provider_store_st *store)
for ( i = 0 ; i < num_provs ; i + + ) {
OSSL_PROVIDER * prov = sk_OSSL_PROVIDER_value ( store - > providers , i ) ;
/*
* Activated fallback providers get an extra refcount , to
* simulate a regular load .
* Note that we don ' t care if the activation succeeds or not ,
* other than to maintain a correct refcount . If the activation
* doesn ' t succeed , then any future attempt to use the fallback
* provider will fail anyway .
*/
if ( prov - > flag_fallback ) {
if ( ossl_provider_up_ref ( prov ) ) {
if ( ! provider_activate ( prov ) ) {
ossl_provider_free ( prov ) ;
} else {
if ( ossl_provider_up_ref ( prov ) ) {
if ( prov - > flag_fallback ) {
if ( provider_activate ( prov ) ) {
prov - > flag_activated_as_fallback = 1 ;
activated_fallback_count + + ;
}
}
ossl_provider_free ( prov ) ;
}
}
@ -765,7 +795,7 @@ int ossl_provider_available(OSSL_PROVIDER *prov)
provider_activate_fallbacks ( prov - > store ) ;
CRYPTO_THREAD_unlock ( prov - > store - > lock ) ;
return prov - > flag_initializ ed ;
return prov - > flag_activat ed ;
}
return 0 ;
}