Fix EC_KEY initialization race.
[openssl.git] / crypto / ecdh / ech_lib.c
index 85fbfc5cacb9f0ed0f36406f69b11ec18d4498d8..0644431b756ab27a1f7b455aeff5588022a26bf6 100644 (file)
 #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;
+const char ECDH_version[]="ECDH" OPENSSL_VERSION_PTEXT;
 
 static const ECDH_METHOD *default_ECDH_method = NULL;
 
+static void *ecdh_data_new(void);
 static void *ecdh_data_dup(void *);
 static void  ecdh_data_free(void *);
 
@@ -89,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);
@@ -103,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
@@ -167,7 +179,7 @@ static ECDH_DATA *ECDH_DATA_new_method(ENGINE *engine)
        return(ret);
        }
 
-void *ecdh_data_new(void)
+static void *ecdh_data_new(void)
        {
        return (void *)ECDH_DATA_new_method(NULL);
        }
@@ -210,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;