Fix EC_KEY initialization race.
[openssl.git] / crypto / ecdh / ech_lib.c
index e89b1d477287ae47956fd48b02cfb0d1f5e4cbfe..0644431b756ab27a1f7b455aeff5588022a26bf6 100644 (file)
@@ -73,6 +73,9 @@
 #include <openssl/engine.h>
 #endif
 #include <openssl/err.h>
+#ifdef OPENSSL_FIPS
+#include <openssl/fips.h>
+#endif
 
 const char ECDH_version[]="ECDH" OPENSSL_VERSION_PTEXT;
 
@@ -90,13 +93,21 @@ void ECDH_set_default_method(const ECDH_METHOD *meth)
 const ECDH_METHOD *ECDH_get_default_method(void)
        {
        if(!default_ECDH_method) 
+               {
+#ifdef OPENSSL_FIPS
+               if (FIPS_mode())
+                       return FIPS_ecdh_openssl();
+               else
+                       return ECDH_OpenSSL();
+#else
                default_ECDH_method = ECDH_OpenSSL();
+#endif
+               }
        return default_ECDH_method;
        }
 
 int ECDH_set_method(EC_KEY *eckey, const ECDH_METHOD *meth)
        {
-       const ECDH_METHOD *mtmp;
        ECDH_DATA *ecdh;
 
        ecdh = ecdh_check(eckey);
@@ -104,8 +115,8 @@ int ECDH_set_method(EC_KEY *eckey, const ECDH_METHOD *meth)
        if (ecdh == NULL)
                return 0;
 
-        mtmp = ecdh->meth;
 #if 0
+        mtmp = ecdh->meth;
         if (mtmp->finish)
                mtmp->finish(eckey);
 #endif
@@ -211,11 +222,26 @@ 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;
+#ifdef OPENSSL_FIPS
+       if (FIPS_mode() && !(ecdh_data->flags & ECDH_FLAG_FIPS_METHOD)
+                       && !(EC_KEY_get_flags(key) & EC_FLAG_NON_FIPS_ALLOW))
+               {
+               ECDHerr(ECDH_F_ECDH_CHECK, ECDH_R_NON_FIPS_METHOD);
+               return NULL;
+               }
+#endif
        
 
        return ecdh_data;