a1fb602
diff -up openssl-1.0.2a/crypto/fips/fips.c.fips-ctor openssl-1.0.2a/crypto/fips/fips.c
a1fb602
--- openssl-1.0.2a/crypto/fips/fips.c.fips-ctor	2015-04-21 17:42:18.702765856 +0200
a1fb602
+++ openssl-1.0.2a/crypto/fips/fips.c	2015-04-21 17:42:18.742766794 +0200
a1fb602
@@ -60,6 +60,8 @@
a1fb602
 #include <dlfcn.h>
a1fb602
 #include <stdio.h>
a1fb602
 #include <stdlib.h>
a1fb602
+#include <unistd.h>
a1fb602
+#include <errno.h>
a1fb602
 #include "fips_locl.h"
a1fb602
 
a1fb602
 #ifdef OPENSSL_FIPS
a1fb602
@@ -201,7 +203,9 @@ static char *bin2hex(void *buf, size_t l
a1fb602
 }
a1fb602
 
a1fb602
 # define HMAC_PREFIX "."
a1fb602
-# define HMAC_SUFFIX ".hmac"
a1fb602
+# ifndef HMAC_SUFFIX
a1fb602
+#  define HMAC_SUFFIX ".hmac"
a1fb602
+# endif
a1fb602
 # define READ_BUFFER_LENGTH 16384
a1fb602
 
a1fb602
 static char *make_hmac_path(const char *origpath)
a1fb602
@@ -279,20 +283,14 @@ static int compute_file_hmac(const char
a1fb602
     return rv;
a1fb602
 }
a1fb602
 
a1fb602
-static int FIPSCHECK_verify(const char *libname, const char *symbolname)
a1fb602
+static int FIPSCHECK_verify(const char *path)
a1fb602
 {
a1fb602
-    char path[PATH_MAX + 1];
a1fb602
-    int rv;
a1fb602
+    int rv = 0;
a1fb602
     FILE *hf;
a1fb602
     char *hmacpath, *p;
a1fb602
     char *hmac = NULL;
a1fb602
     size_t n;
a1fb602
 
a1fb602
-    rv = get_library_path(libname, symbolname, path, sizeof(path));
a1fb602
-
a1fb602
-    if (rv < 0)
a1fb602
-        return 0;
a1fb602
-
a1fb602
     hmacpath = make_hmac_path(path);
a1fb602
     if (hmacpath == NULL)
a1fb602
         return 0;
a1fb602
@@ -343,6 +341,51 @@ static int FIPSCHECK_verify(const char *
a1fb602
     return 1;
a1fb602
 }
a1fb602
 
a1fb602
+static int verify_checksums(void)
a1fb602
+{
a1fb602
+    int rv;
a1fb602
+    char path[PATH_MAX + 1];
a1fb602
+    char *p;
a1fb602
+
a1fb602
+    /* we need to avoid dlopening libssl, assume both libcrypto and libssl
a1fb602
+       are in the same directory */
a1fb602
+
a1fb602
+    rv = get_library_path("libcrypto.so." SHLIB_VERSION_NUMBER,
a1fb602
+                          "FIPS_mode_set", path, sizeof(path));
a1fb602
+    if (rv < 0)
a1fb602
+        return 0;
a1fb602
+
a1fb602
+    rv = FIPSCHECK_verify(path);
a1fb602
+    if (!rv)
a1fb602
+        return 0;
a1fb602
+
a1fb602
+    /* replace libcrypto with libssl */
a1fb602
+    while ((p = strstr(path, "libcrypto.so")) != NULL) {
a1fb602
+        p = stpcpy(p, "libssl");
a1fb602
+        memmove(p, p + 3, strlen(p + 2));
a1fb602
+    }
a1fb602
+
a1fb602
+    rv = FIPSCHECK_verify(path);
a1fb602
+    if (!rv)
a1fb602
+        return 0;
a1fb602
+    return 1;
a1fb602
+}
a1fb602
+
a1fb602
+# ifndef FIPS_MODULE_PATH
a1fb602
+#  define FIPS_MODULE_PATH "/etc/system-fips"
a1fb602
+# endif
a1fb602
+
a1fb602
+int FIPS_module_installed(void)
a1fb602
+{
a1fb602
+    int rv;
a1fb602
+    rv = access(FIPS_MODULE_PATH, F_OK);
a1fb602
+    if (rv < 0 && errno != ENOENT)
a1fb602
+        rv = 0;
a1fb602
+
a1fb602
+    /* Installed == true */
a1fb602
+    return !rv;
a1fb602
+}
a1fb602
+
a1fb602
 int FIPS_module_mode_set(int onoff, const char *auth)
a1fb602
 {
a1fb602
     int ret = 0;
a1fb602
@@ -380,17 +423,7 @@ int FIPS_module_mode_set(int onoff, cons
a1fb602
         }
a1fb602
 # endif
a1fb602
 
a1fb602
-        if (!FIPSCHECK_verify
a1fb602
-            ("libcrypto.so." SHLIB_VERSION_NUMBER, "FIPS_mode_set")) {
a1fb602
-            FIPSerr(FIPS_F_FIPS_MODULE_MODE_SET,
a1fb602
-                    FIPS_R_FINGERPRINT_DOES_NOT_MATCH);
a1fb602
-            fips_selftest_fail = 1;
a1fb602
-            ret = 0;
a1fb602
-            goto end;
a1fb602
-        }
a1fb602
-
a1fb602
-        if (!FIPSCHECK_verify
a1fb602
-            ("libssl.so." SHLIB_VERSION_NUMBER, "SSL_CTX_new")) {
a1fb602
+        if (!verify_checksums()) {
a1fb602
             FIPSerr(FIPS_F_FIPS_MODULE_MODE_SET,
a1fb602
                     FIPS_R_FINGERPRINT_DOES_NOT_MATCH);
a1fb602
             fips_selftest_fail = 1;
a1fb602
diff -up openssl-1.0.2a/crypto/fips/fips.h.fips-ctor openssl-1.0.2a/crypto/fips/fips.h
a1fb602
--- openssl-1.0.2a/crypto/fips/fips.h.fips-ctor	2015-04-21 17:42:18.739766724 +0200
a1fb602
+++ openssl-1.0.2a/crypto/fips/fips.h	2015-04-21 17:42:18.743766818 +0200
a1fb602
@@ -74,6 +74,7 @@ extern "C" {
a1fb602
 
a1fb602
     int FIPS_module_mode_set(int onoff, const char *auth);
a1fb602
     int FIPS_module_mode(void);
a1fb602
+    int FIPS_module_installed(void);
a1fb602
     const void *FIPS_rand_check(void);
a1fb602
     int FIPS_selftest(void);
a1fb602
     int FIPS_selftest_failed(void);
a1fb602
diff -up openssl-1.0.2a/crypto/o_init.c.fips-ctor openssl-1.0.2a/crypto/o_init.c
a1fb602
--- openssl-1.0.2a/crypto/o_init.c.fips-ctor	2015-04-21 17:42:18.732766559 +0200
a1fb602
+++ openssl-1.0.2a/crypto/o_init.c	2015-04-21 17:45:02.662613173 +0200
a1fb602
@@ -74,6 +74,9 @@ static void init_fips_mode(void)
a1fb602
     char buf[2] = "0";
a1fb602
     int fd;
a1fb602
 
a1fb602
+    /* Ensure the selftests always run */
a1fb602
+    FIPS_mode_set(1);
a1fb602
+
a1fb602
     if (secure_getenv("OPENSSL_FORCE_FIPS_MODE") != NULL) {
a1fb602
         buf[0] = '1';
a1fb602
     } else if ((fd = open(FIPS_MODE_SWITCH_FILE, O_RDONLY)) >= 0) {
a1fb602
@@ -85,8 +88,12 @@ static void init_fips_mode(void)
a1fb602
      * otherwise..
a1fb602
      */
a1fb602
 
a1fb602
-    if (buf[0] == '1') {
a1fb602
-        FIPS_mode_set(1);
a1fb602
+    if (buf[0] != '1') {
a1fb602
+        /* drop down to non-FIPS mode if it is not requested */
a1fb602
+        FIPS_mode_set(0);
a1fb602
+    } else {
a1fb602
+        /* abort if selftest failed */
a1fb602
+        FIPS_selftest_check();
a1fb602
     }
a1fb602
 }
a1fb602
 #endif
a1fb602
@@ -96,13 +103,16 @@ static void init_fips_mode(void)
a1fb602
  * sets FIPS callbacks
a1fb602
  */
a1fb602
 
a1fb602
-void OPENSSL_init_library(void)
a1fb602
+void __attribute__ ((constructor)) OPENSSL_init_library(void)
a1fb602
 {
a1fb602
     static int done = 0;
a1fb602
     if (done)
a1fb602
         return;
a1fb602
     done = 1;
a1fb602
 #ifdef OPENSSL_FIPS
a1fb602
+    if (!FIPS_module_installed()) {
a1fb602
+        return;
a1fb602
+    }
a1fb602
     RAND_init_fips();
a1fb602
     init_fips_mode();
a1fb602
     if (!FIPS_mode()) {