File openssl-fips__0300_run_selftests_if_hmac_files_present.diff of Package compat-openssl098.703

diff -rNU 50 ../openssl-0.9.8j-o/crypto/o_init.c ./crypto/o_init.c
--- ../openssl-0.9.8j-o/crypto/o_init.c	2012-07-10 02:06:00.000000000 +0200
+++ ./crypto/o_init.c	2012-07-10 03:01:34.000000000 +0200
@@ -29,96 +29,128 @@
  *
  * 5. Products derived from this software may not be called "OpenSSL"
  *    nor may "OpenSSL" appear in their names without prior written
  *    permission of the OpenSSL Project.
  *
  * 6. Redistributions of any form whatsoever must retain the following
  *    acknowledgment:
  *    "This product includes software developed by the OpenSSL Project
  *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
  *
  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  * OF THE POSSIBILITY OF SUCH DAMAGE.
  * ====================================================================
  *
  * This product includes cryptographic software written by Eric Young
  * (eay@cryptsoft.com).  This product includes software written by Tim
  * Hudson (tjh@cryptsoft.com).
  *
  */
 
 #include <e_os.h>
 #include <openssl/err.h>
 
 #ifdef OPENSSL_FIPS
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <errno.h>
 #include <stdlib.h>
 #include <openssl/fips.h>
 #include <openssl/evp.h>
 #include <openssl/rand.h>
 
 #define FIPS_MODE_SWITCH_FILE "/proc/sys/crypto/fips_enabled"
 
 static void init_fips_mode(void)
 	{
 	char buf[2] = "0";
 	int fd;
-	
+
+	/* Check if we have already been initialized by FIPS_mode_set(1)
+	 * called directly from the app. If this was the case, calling 
+	 * FIPS_mode_set(1) a second time will lead to a failure
+	 * in fips/fips.c:486, so we better avoid that with this mimic
+	 * to switch via kernel cmdline and/or environment without the
+	 * app knowing.
+	 *
+	 * Note that if we are in fips mode already, there is no need to
+	 * run through the self-tests (further down) either.
+	 *
+	 */
+
+	if(FIPS_mode())
+		return;
+
+	/* The following must be without the app knowing. Including the
+	 * forced self-test if the .hmac files are present, marking the
+	 * complete installation of the module.
+	 * 
+	 */
+
 	if (getenv("OPENSSL_FORCE_FIPS_MODE") != NULL)
 		{
 		buf[0] = '1';
 		}
 	else if ((fd = open(FIPS_MODE_SWITCH_FILE, O_RDONLY)) >= 0)
 		{
 		while (read(fd, buf, sizeof(buf)) < 0 && errno == EINTR);
 		close(fd);
 		}
 	/* Failure reading the fips mode switch file means just not
-	 * switching into FIPS mode. We would break too many things
-	 * otherwise. 
+	 * switching into FIPS mode.
+	 * 
+	 * If we don't switch into FIPS mode, we MUST run the self-tests
+	 * anyway, provided that the module is installed completely.
+	 * This will check if the .hmac files for the integrity check
+	 * in fips/fips.c:FIPSCHECK_verify() exist. If so, the selftests
+	 * are executed, if no .hmac files are present, the selftests are
+	 * aborted gracefully.
+	 * 
 	 */
 	
 	if (buf[0] == '1')
 		{
 		FIPS_mode_set(1);
 		}
+	else
+		{
+		FIPS_mode_set(0);
+		}
 	}
 #endif
 
 /* Perform any essential OpenSSL initialization operations.
  * Currently only sets FIPS callbacks
  */
 
 void OPENSSL_init(void)
 	{
 #ifdef OPENSSL_FIPS
 	static int done = 0;
 	if (!done)
 		{
 		int_ERR_lib_init();
 #ifdef CRYPTO_MDEBUG
 		CRYPTO_malloc_debug_init();
 #endif
 		init_fips_mode();
 		int_EVP_MD_init_engine_callbacks();
 		int_EVP_CIPHER_init_engine_callbacks();
 		int_RAND_init_engine_callbacks();
 		done = 1;
 		}
 #endif
 	}
 		
 
diff -rNU 50 ../openssl-0.9.8j-o/fips/fips.c ./fips/fips.c
--- ../openssl-0.9.8j-o/fips/fips.c	2012-07-10 02:06:00.000000000 +0200
+++ ./fips/fips.c	2012-07-10 02:06:21.000000000 +0200
@@ -346,253 +346,304 @@
 static const char hmackey[] = "ppaksykemnsecgtsttplmamstKMEs";
 
 static int
 compute_file_hmac(const char *path, void **buf, size_t *hmaclen)
 {
       FILE *f = NULL;
       int rv = -1;
       unsigned char rbuf[READ_BUFFER_LENGTH];
       size_t len;
       unsigned int hlen;
       HMAC_CTX c;
 
       HMAC_CTX_init(&c);
 
       f = fopen(path, "r");
 
       if (f == NULL) {
               goto end;
       }
 
       HMAC_Init(&c, hmackey, sizeof(hmackey)-1, EVP_sha256());
 
       while ((len=fread(rbuf, 1, sizeof(rbuf), f)) != 0) {
               HMAC_Update(&c, rbuf, len);
       }
 
       len = sizeof(rbuf);
       /* reuse rbuf for hmac */
       HMAC_Final(&c, rbuf, &hlen);
 
       *buf = malloc(hlen);
       if (*buf == NULL) {
               goto end;
       }
 
       *hmaclen = hlen;
 
       memcpy(*buf, rbuf, hlen);
 
       rv = 0;
 end:
       HMAC_CTX_cleanup(&c);
 
       if (f)
               fclose(f);
 
       return rv;
 }
 
 static int
-FIPSCHECK_verify(const char *libname, const char *symbolname)
+FIPSCHECK_verify(const char *libname, const char *symbolname, int check_hmac_file_open_only)
 {
       char path[PATH_MAX+1];
       int rv;
       FILE *hf;
       char *hmacpath, *p;
       char *hmac = NULL;
       size_t n;
       
       rv = get_library_path(libname, symbolname, path, sizeof(path));
 
       if (rv < 0)
               return 0;
 
       hmacpath = make_hmac_path(path);
 
       if ( hmacpath == NULL )
               return 0;
 
       hf = fopen(hmacpath, "r");
       if (hf == NULL) {
               free(hmacpath);
               return 0;
       }
 
+      if (check_hmac_file_open_only == 1) {
+              fclose(hf);
+              free(hmacpath);
+              return 1;
+      }
+
       if (getline(&hmac, &n, hf) > 0) {
               void *buf;
               size_t hmaclen;
               char *hex;
 
               if ((p=strchr(hmac, '\n')) != NULL)
                       *p = '\0';
 
               if (compute_file_hmac(path, &buf, &hmaclen) < 0) {
                       rv = -4;
                       goto end;
               }
 
               if ((hex=bin2hex(buf, hmaclen)) == NULL) {
                       free(buf);
                       rv = -5;
                       goto end;
               }
 
               if (strcmp(hex, hmac) != 0) {
                       rv = -1;
               }
               free(buf);
               free(hex);
       }
 
 end:
       free(hmac);
       free(hmacpath);
       fclose(hf);
 
       if (rv < 0)
               return 0;
 
       /* check successful */
       return 1;       
 }
 
 #endif
 
 
 int FIPS_mode_set(int onoff)
     {
     int fips_set_owning_thread();
     int fips_clear_owning_thread();
     int ret = 0;
 
     fips_w_lock();
     fips_set_started();
     fips_set_owning_thread();
 
     if(onoff)
 	{
 	unsigned char buf[48];
 
 	fips_selftest_fail = 0;
 
 	/* Don't go into FIPS mode twice, just so we can do automagic
 	   seeding */
 	if(FIPS_mode())
 	    {
 	    FIPSerr(FIPS_F_FIPS_MODE_SET,FIPS_R_FIPS_MODE_ALREADY_SET);
 	    fips_selftest_fail = 1;
 	    ret = 0;
 	    goto end;
 	    }
 
 #ifdef OPENSSL_IA32_SSE2
 	if ((OPENSSL_ia32cap & (1<<25|1<<26)) != (1<<25|1<<26))
 	    {
 	    FIPSerr(FIPS_F_FIPS_MODE_SET,FIPS_R_UNSUPPORTED_PLATFORM);
 	    fips_selftest_fail = 1;
 	    ret = 0;
 	    goto end;
 	    }
 #endif
 
-	if(!FIPSCHECK_verify("libcrypto.so.0.9.8","FIPS_mode_set"))
+	if(!FIPSCHECK_verify("libcrypto.so.0.9.8","FIPS_mode_set", 0 ))
 	    {
 	    FIPSerr(FIPS_F_FIPS_MODE_SET,FIPS_R_FINGERPRINT_DOES_NOT_MATCH);
 	    fips_selftest_fail = 1;
 	    ret = 0;
 	    goto end;
 	    }
 
-	if(!FIPSCHECK_verify("libssl.so.0.9.8","SSL_CTX_new"))
+	if(!FIPSCHECK_verify("libssl.so.0.9.8","SSL_CTX_new", 0 ))
 	    {
 	    FIPSerr(FIPS_F_FIPS_MODE_SET,FIPS_R_FINGERPRINT_DOES_NOT_MATCH);
 	    fips_selftest_fail = 1;
 	    ret = 0;
 	    goto end;
 	    }
 
 	/* Perform RNG KAT before seeding */
 	if (!FIPS_selftest_rng())
 	    {
 	    fips_selftest_fail = 1;
 	    ret = 0;
 	    goto end;
 	    }
 
 	/* now switch into FIPS mode */
 	fips_set_rand_check(FIPS_rand_method());
 	RAND_set_rand_method(FIPS_rand_method());
 
 	/* automagically seed PRNG if not already seeded */
 	if(!FIPS_rand_status())
 	    {
 	    RAND_poll();
 	    if (!FIPS_rand_status())
 		{
 		fips_selftest_fail = 1;
 		ret = 0;
 		goto end;
 		}
 	    }
 
 	if(FIPS_selftest())
 	    fips_set_mode(1);
 	else
 	    {
 	    fips_selftest_fail = 1;
 	    ret = 0;
 	    goto end;
 	    }
 	ret = 1;
 	goto end;
-	}
+     } else {
+		/* 
+		 * onoff == 0, we need to do the self-tests.
+		 * 
+		 * check if the .hmac files are there. If not, then abort
+		 * running the self-tests gracefully.
+		 *
+		 */
+		if( FIPSCHECK_verify("libcrypto.so.0.9.8","FIPS_mode_set", 1) &&
+		    FIPSCHECK_verify("libssl.so.0.9.8","SSL_CTX_new", 1) ) {
+
+/* hmac files are present. */
+
+		        if(!FIPSCHECK_verify("libcrypto.so.0.9.8","FIPS_mode_set", 0 ))
+			    {
+                                 FIPSerr(FIPS_F_FIPS_MODE_SET,FIPS_R_FINGERPRINT_DOES_NOT_MATCH);
+                                 fips_selftest_fail = 1;
+                                 ret = 0;
+                                 goto end;
+                            }
+
+                        if(!FIPSCHECK_verify("libssl.so.0.9.8","SSL_CTX_new", 0 ))
+                            {
+                                 FIPSerr(FIPS_F_FIPS_MODE_SET,FIPS_R_FINGERPRINT_DOES_NOT_MATCH);
+                                 fips_selftest_fail = 1;
+                                 ret = 0;
+                                 goto end;
+                            }
+
+                        /* Perform RNG KAT */
+                        if (!FIPS_selftest_rng())
+                            {
+                            fips_selftest_fail = 1;
+                            ret = 0;
+                            goto end;
+                            }
+
+                        if( ! FIPS_selftest())
+			    {
+				fips_selftest_fail = 1;
+				ret = 0;
+				goto end;
+			    }
+    		}
+    } /* onoff == 0 */
+
     fips_set_mode(0);
     fips_selftest_fail = 0;
     ret = 1;
 end:
     fips_clear_owning_thread();
     fips_w_unlock();
     return ret;
     }
 
 void fips_w_lock(void)		{ CRYPTO_w_lock(CRYPTO_LOCK_FIPS); }
 void fips_w_unlock(void)	{ CRYPTO_w_unlock(CRYPTO_LOCK_FIPS); }
 void fips_r_lock(void)		{ CRYPTO_r_lock(CRYPTO_LOCK_FIPS); }
 void fips_r_unlock(void)	{ CRYPTO_r_unlock(CRYPTO_LOCK_FIPS); }
 
 static int fips_started = 0;
 static unsigned long fips_thread = 0;
 
 void fips_set_started(void)
 	{
 	fips_started = 1;
 	}
 
 int fips_is_started(void)
 	{
 	return fips_started;
 	}
 
 int fips_is_owning_thread(void)
 	{
 	int ret = 0;
 
 	if (fips_is_started())
 		{
 		CRYPTO_r_lock(CRYPTO_LOCK_FIPS2);
 		if (fips_thread != 0 && fips_thread == CRYPTO_thread_id())
 			ret = 1;
 		CRYPTO_r_unlock(CRYPTO_LOCK_FIPS2);
 		}
 	return ret;
 	}
 
 int fips_set_owning_thread(void)
 	{
 	int ret = 0;
 
 	if (fips_is_started())
 		{
 		CRYPTO_w_lock(CRYPTO_LOCK_FIPS2);
 		if (fips_thread == 0)
 			{