Fix EC_KEY initialization race.

Submitted by: Adam Langley
This commit is contained in:
Bodo Möller 2012-10-05 20:51:47 +00:00
parent 71a2440ee5
commit 75f0bc4f44
4 changed files with 38 additions and 7 deletions

View file

@ -321,7 +321,15 @@ void EC_KEY_set_conv_form(EC_KEY *, point_conversion_form_t);
/* functions to set/get method specific data */
void *EC_KEY_get_key_method_data(EC_KEY *,
void *(*dup_func)(void *), void (*free_func)(void *), void (*clear_free_func)(void *));
void EC_KEY_insert_key_method_data(EC_KEY *, void *data,
/** Sets the key method data of an EC_KEY object, if none has yet been set.
* \param key EC_KEY object
* \param data opaque data to install.
* \param dup_func a function that duplicates |data|.
* \param free_func a function that frees |data|.
* \param clear_free_func a function that wipes and frees |data|.
* \return the previously set data pointer, or NULL if |data| was inserted.
*/
void *EC_KEY_insert_key_method_data(EC_KEY *key, void *data,
void *(*dup_func)(void *), void (*free_func)(void *), void (*clear_free_func)(void *));
/* wrapper functions for the underlying EC_GROUP object */
void EC_KEY_set_asn1_flag(EC_KEY *, int);

View file

@ -435,18 +435,27 @@ void EC_KEY_set_conv_form(EC_KEY *key, point_conversion_form_t cform)
void *EC_KEY_get_key_method_data(EC_KEY *key,
void *(*dup_func)(void *), void (*free_func)(void *), void (*clear_free_func)(void *))
{
return EC_EX_DATA_get_data(key->method_data, dup_func, free_func, clear_free_func);
void *ret;
CRYPTO_r_lock(CRYPTO_LOCK_EC);
ret = EC_EX_DATA_get_data(key->method_data, dup_func, free_func, clear_free_func);
CRYPTO_r_unlock(CRYPTO_LOCK_EC);
return ret;
}
void EC_KEY_insert_key_method_data(EC_KEY *key, void *data,
void *EC_KEY_insert_key_method_data(EC_KEY *key, void *data,
void *(*dup_func)(void *), void (*free_func)(void *), void (*clear_free_func)(void *))
{
EC_EXTRA_DATA *ex_data;
CRYPTO_w_lock(CRYPTO_LOCK_EC);
ex_data = EC_EX_DATA_get_data(key->method_data, dup_func, free_func, clear_free_func);
if (ex_data == NULL)
EC_EX_DATA_set_data(&key->method_data, data, dup_func, free_func, clear_free_func);
CRYPTO_w_unlock(CRYPTO_LOCK_EC);
return ex_data;
}
void EC_KEY_set_asn1_flag(EC_KEY *key, int flag)

View file

@ -205,8 +205,15 @@ ECDH_DATA *ecdh_check(EC_KEY *key)
ecdh_data = (ECDH_DATA *)ecdh_data_new();
if (ecdh_data == NULL)
return NULL;
EC_KEY_insert_key_method_data(key, (void *)ecdh_data,
ecdh_data_dup, ecdh_data_free, ecdh_data_free);
data = EC_KEY_insert_key_method_data(key, (void *)ecdh_data,
ecdh_data_dup, ecdh_data_free, ecdh_data_free);
if (data != NULL)
{
/* Another thread raced us to install the key_method
* data and won. */
ecdh_data_free(ecdh_data);
ecdh_data = (ECDH_DATA *)data;
}
}
else
ecdh_data = (ECDH_DATA *)data;

View file

@ -188,8 +188,15 @@ ECDSA_DATA *ecdsa_check(EC_KEY *key)
ecdsa_data = (ECDSA_DATA *)ecdsa_data_new();
if (ecdsa_data == NULL)
return NULL;
EC_KEY_insert_key_method_data(key, (void *)ecdsa_data,
ecdsa_data_dup, ecdsa_data_free, ecdsa_data_free);
data = EC_KEY_insert_key_method_data(key, (void *)ecdsa_data,
ecdsa_data_dup, ecdsa_data_free, ecdsa_data_free);
if (data != NULL)
{
/* Another thread raced us to install the key_method
* data and won. */
ecdsa_data_free(ecdsa_data);
ecdsa_data = (ECDSA_DATA *)data;
}
}
else
ecdsa_data = (ECDSA_DATA *)data;