Commit 75f0bc4f authored by Bodo Möller's avatar Bodo Möller
Browse files

Fix EC_KEY initialization race.

Submitted by: Adam Langley
parent 71a2440e
Loading
Loading
Loading
Loading
+9 −1
Original line number Diff line number Diff line
@@ -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);
+11 −2
Original line number Diff line number Diff line
@@ -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)
+9 −2
Original line number Diff line number Diff line
@@ -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,
		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;
+9 −2
Original line number Diff line number Diff line
@@ -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,
		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;