Fix EC_KEY initialization race.
[openssl.git] / crypto / ecdsa / ecs_lib.c
index 8a6d4ad45d2a05b4b1e5f39326ceb2138c0bbc60..814a6bf40465ab7acc83797bcf9735a0b544543c 100644 (file)
 #endif
 #include <openssl/err.h>
 #include <openssl/bn.h>
+#ifdef OPENSSL_FIPS
+#include <openssl/fips.h>
+#endif
 
-const char *ECDSA_version="ECDSA" OPENSSL_VERSION_PTEXT;
+const char ECDSA_version[]="ECDSA" OPENSSL_VERSION_PTEXT;
 
 static const ECDSA_METHOD *default_ECDSA_method = NULL;
 
+static void *ecdsa_data_new(void);
 static void *ecdsa_data_dup(void *);
 static void  ecdsa_data_free(void *);
 
@@ -76,13 +80,21 @@ void ECDSA_set_default_method(const ECDSA_METHOD *meth)
 const ECDSA_METHOD *ECDSA_get_default_method(void)
 {
        if(!default_ECDSA_method) 
+               {
+#ifdef OPENSSL_FIPS
+               if (FIPS_mode())
+                       return FIPS_ecdsa_openssl();
+               else
+                       return ECDSA_OpenSSL();
+#else
                default_ECDSA_method = ECDSA_OpenSSL();
+#endif
+               }
        return default_ECDSA_method;
 }
 
 int ECDSA_set_method(EC_KEY *eckey, const ECDSA_METHOD *meth)
 {
-        const ECDSA_METHOD *mtmp;
        ECDSA_DATA *ecdsa;
 
        ecdsa = ecdsa_check(eckey);
@@ -90,7 +102,6 @@ int ECDSA_set_method(EC_KEY *eckey, const ECDSA_METHOD *meth)
        if (ecdsa == NULL)
                return 0;
 
-        mtmp = ecdsa->meth;
 #ifndef OPENSSL_NO_ENGINE
        if (ecdsa->engine)
        {
@@ -147,7 +158,7 @@ static ECDSA_DATA *ECDSA_DATA_new_method(ENGINE *engine)
        return(ret);
 }
 
-void *ecdsa_data_new(void)
+static void *ecdsa_data_new(void)
 {
        return (void *)ECDSA_DATA_new_method(NULL);
 }
@@ -189,12 +200,26 @@ 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;
-       
+#ifdef OPENSSL_FIPS
+       if (FIPS_mode() && !(ecdsa_data->flags & ECDSA_FLAG_FIPS_METHOD)
+                       && !(EC_KEY_get_flags(key) & EC_FLAG_NON_FIPS_ALLOW))
+               {
+               ECDSAerr(ECDSA_F_ECDSA_CHECK, ECDSA_R_NON_FIPS_METHOD);
+               return NULL;
+               }
+#endif
 
        return ecdsa_data;
 }
@@ -205,10 +230,14 @@ int ECDSA_size(const EC_KEY *r)
        ASN1_INTEGER bs;
        BIGNUM  *order=NULL;
        unsigned char buf[4];
-       const EC_GROUP *group = EC_KEY_get0_group(r);
+       const EC_GROUP *group;
 
-       if (r == NULL || group == NULL)
+       if (r == NULL)
                return 0;
+       group = EC_KEY_get0_group(r);
+       if (group == NULL)
+               return 0;
+
        if ((order = BN_new()) == NULL) return 0;
        if (!EC_GROUP_get_order(group,order,NULL))
        {