Initial incomplete POST overhaul: add support for POST callback to
allow status of POST to be monitored and/or failures induced.
diff --git a/CHANGES b/CHANGES
index 877976c..70d2382 100644
--- a/CHANGES
+++ b/CHANGES
@@ -4,6 +4,11 @@
 
  Changes between 1.0.1 and 1.1.0  [xx XXX xxxx]
 
+  *) Initial version of POST overhaul. Add POST callback to allow the status
+     of POST to be monitored and/or failures induced. Modify fips_test_suite
+     to use callback. Always run all selftests even if one fails.
+     [Steve Henson]
+
   *) Provisional XTS support. Note: this does increase the maximum key
      length from 32 to 64 bytes but there should be no binary compatibility
      issues as existing applications will never use XTS mode.
diff --git a/crypto/dsa/dsa_key.c b/crypto/dsa/dsa_key.c
index fa4fb09..39cf6b7 100644
--- a/crypto/dsa/dsa_key.c
+++ b/crypto/dsa/dsa_key.c
@@ -85,7 +85,8 @@
     	pk.type = EVP_PKEY_DSA;
     	pk.pkey.dsa = dsa;
 
-	if (!fips_pkey_signature_test(&pk, tbs, -1, NULL, 0, NULL, 0, NULL))
+	if (!fips_pkey_signature_test(FIPS_TEST_PAIRWISE,
+					&pk, tbs, -1, NULL, 0, NULL, 0, NULL))
 		{
 		FIPSerr(FIPS_F_FIPS_CHECK_DSA,FIPS_R_PAIRWISE_TEST_FAILED);
 		fips_set_selftest_fail();
diff --git a/crypto/ec/ec_key.c b/crypto/ec/ec_key.c
index 1615ec8..1f04894 100644
--- a/crypto/ec/ec_key.c
+++ b/crypto/ec/ec_key.c
@@ -250,7 +250,8 @@
     	pk.type = EVP_PKEY_EC;
     	pk.pkey.ec = key;
 
-	if (!fips_pkey_signature_test(&pk, tbs, -1, NULL, 0, NULL, 0, NULL))
+	if (!fips_pkey_signature_test(FIPS_TEST_PAIRWISE,
+					&pk, tbs, -1, NULL, 0, NULL, 0, NULL))
 		{
 		FIPSerr(FIPS_F_FIPS_CHECK_EC,FIPS_R_PAIRWISE_TEST_FAILED);
 		fips_set_selftest_fail();
diff --git a/crypto/evp/evp.h b/crypto/evp/evp.h
index d51e0d3..b4c8675 100644
--- a/crypto/evp/evp.h
+++ b/crypto/evp/evp.h
@@ -460,6 +460,7 @@
 #define M_EVP_MD_CTX_type(e)		M_EVP_MD_type(M_EVP_MD_CTX_md(e))
 #define M_EVP_MD_CTX_md(e)			((e)->digest)
 
+#define M_EVP_CIPHER_nid(e)		((e)->nid)
 #define M_EVP_CIPHER_CTX_iv_length(e)	((e)->cipher->iv_len)
 #define M_EVP_CIPHER_CTX_flags(e)	((e)->cipher->flags)
 #define M_EVP_CIPHER_CTX_block_size(e)	((e)->cipher->block_size)
diff --git a/crypto/rsa/rsa_gen.c b/crypto/rsa/rsa_gen.c
index 7bef5dd..977e461 100644
--- a/crypto/rsa/rsa_gen.c
+++ b/crypto/rsa/rsa_gen.c
@@ -93,11 +93,11 @@
     	pk.pkey.rsa = rsa;
 
 	/* Perform pairwise consistency signature test */
-	if (!fips_pkey_signature_test(&pk, tbs, -1,
+	if (!fips_pkey_signature_test(FIPS_TEST_PAIRWISE, &pk, tbs, -1,
 			NULL, 0, NULL, RSA_PKCS1_PADDING, NULL)
-		|| !fips_pkey_signature_test(&pk, tbs, -1,
+		|| !fips_pkey_signature_test(FIPS_TEST_PAIRWISE, &pk, tbs, -1,
 			NULL, 0, NULL, RSA_X931_PADDING, NULL)
-		|| !fips_pkey_signature_test(&pk, tbs, -1,
+		|| !fips_pkey_signature_test(FIPS_TEST_PAIRWISE, &pk, tbs, -1,
 			NULL, 0, NULL, RSA_PKCS1_PSS_PADDING, NULL))
 		goto err;
 	/* Now perform pairwise consistency encrypt/decrypt test */
diff --git a/fips/Makefile b/fips/Makefile
index 28df80c..e84a4fb 100644
--- a/fips/Makefile
+++ b/fips/Makefile
@@ -41,8 +41,8 @@
 
 LIB= $(TOP)/libcrypto.a
 SHARED_LIB= $(FIPSCANLIB)$(SHLIB_EXT)
-LIBSRC=fips.c 
-LIBOBJ=fips.o
+LIBSRC=fips.c fips_post.c
+LIBOBJ=fips.o fips_post.o
 
 FIPS_OBJ_LISTS=sha/lib hmac/lib rand/lib des/lib aes/lib dsa/lib rsa/lib \
 		dh/lib utl/lib ecdsa/lib cmac/lib
diff --git a/fips/aes/fips_aes_selftest.c b/fips/aes/fips_aes_selftest.c
index 05f18d1..457dabd 100644
--- a/fips/aes/fips_aes_selftest.c
+++ b/fips/aes/fips_aes_selftest.c
@@ -86,7 +86,7 @@
 
     for(n=0 ; n < 1 ; ++n)
 	{
-	if (fips_cipher_test(&ctx, EVP_aes_128_ecb(),
+	if (fips_cipher_test(FIPS_TEST_CIPHER, &ctx, EVP_aes_128_ecb(),
 				tests[n].key, NULL,
 				tests[n].plaintext,
 				tests[n].ciphertext,
diff --git a/fips/des/fips_des_selftest.c b/fips/des/fips_des_selftest.c
index 6ce556e..9eea546 100644
--- a/fips/des/fips_des_selftest.c
+++ b/fips/des/fips_des_selftest.c
@@ -115,7 +115,7 @@
     /* Encrypt/decrypt with 3DES and compare to known answers */
     for(n=0 ; n < 2 ; ++n)
 	{
-	if (!fips_cipher_test(&ctx, EVP_des_ede3_ecb(),
+	if (!fips_cipher_test(FIPS_TEST_CIPHER, &ctx, EVP_des_ede3_ecb(),
 				tests3[n].key, NULL,
 				tests3[n].plaintext, tests3[n].ciphertext, 8))
 		goto err;
diff --git a/fips/dsa/fips_dsa_selftest.c b/fips/dsa/fips_dsa_selftest.c
index 9646ae9..8d89425 100644
--- a/fips/dsa/fips_dsa_selftest.c
+++ b/fips/dsa/fips_dsa_selftest.c
@@ -169,7 +169,7 @@
 	pk.type = EVP_PKEY_DSA;
 	pk.pkey.dsa = dsa;
 
-	if (!fips_pkey_signature_test(&pk, NULL, 0,
+	if (!fips_pkey_signature_test(FIPS_TEST_SIGNATURE, &pk, NULL, 0,
 					NULL, 0, EVP_sha384(), 0,
 					"DSA SHA384"))
 		goto err;
diff --git a/fips/ecdsa/fips_ecdsa_selftest.c b/fips/ecdsa/fips_ecdsa_selftest.c
index c09f59d..6949480 100644
--- a/fips/ecdsa/fips_ecdsa_selftest.c
+++ b/fips/ecdsa/fips_ecdsa_selftest.c
@@ -176,7 +176,7 @@
 		pk.type = EVP_PKEY_EC;
 		pk.pkey.ec = ec;
 
-		if (!fips_pkey_signature_test(&pk, NULL, 0,
+		if (!fips_pkey_signature_test(FIPS_TEST_SIGNATURE, &pk, NULL, 0,
 						NULL, 0, EVP_sha512(), 0,
 						ecd->name))
 			goto err;
diff --git a/fips/fips.c b/fips/fips.c
index 9ad1761..a18fd58 100644
--- a/fips/fips.c
+++ b/fips/fips.c
@@ -142,20 +142,6 @@
     fips_selftest_fail = 1;
     }
 
-int FIPS_selftest(void)
-    {
-
-    return FIPS_selftest_sha1()
-	&& FIPS_selftest_hmac()
-	&& FIPS_selftest_cmac()
-	&& FIPS_selftest_aes()
-	&& FIPS_selftest_aes_gcm()
-	&& FIPS_selftest_des()
-	&& FIPS_selftest_rsa()
-	&& FIPS_selftest_ecdsa()
-	&& FIPS_selftest_dsa();
-    }
-
 extern const void         *FIPS_text_start(),  *FIPS_text_end();
 extern const unsigned char FIPS_rodata_start[], FIPS_rodata_end[];
 unsigned char              FIPS_signature [20] = { 0 };
@@ -192,6 +178,9 @@
     else
 	HMAC_Update(&c,p3,(size_t)p4-(size_t)p3);
 
+    if (!fips_post_corrupt(FIPS_TEST_INTEGRITY, 0, NULL))
+	HMAC_Update(&c, (unsigned char *)FIPS_hmac_key, 1);
+
     HMAC_Final(&c,sig,&len);
     HMAC_CTX_cleanup(&c);
 
@@ -202,19 +191,23 @@
     {
     unsigned char sig[EVP_MAX_MD_SIZE];
     unsigned int len;
+    int rv = 0;
 #if defined(__sgi) && (defined(__mips) || defined(mips))
     extern int __dso_displacement[];
 #else
     extern int OPENSSL_NONPIC_relocated;
 #endif
 
+    if (!fips_post_started(FIPS_TEST_INTEGRITY, 0, NULL))
+	return 1;
+
     if (FIPS_text_start()==NULL)
 	{
 	FIPSerr(FIPS_F_FIPS_CHECK_INCORE_FINGERPRINT,FIPS_R_UNSUPPORTED_PLATFORM);
-	return 0;
+	goto err;
 	}
 
-    len=FIPS_incore_fingerprint (sig,sizeof(sig));
+    len=FIPS_incore_fingerprint(sig,sizeof(sig));
 
     if (len!=sizeof(FIPS_signature) ||
 	memcmp(FIPS_signature,sig,sizeof(FIPS_signature)))
@@ -230,12 +223,18 @@
 	else
 	    FIPSerr(FIPS_F_FIPS_CHECK_INCORE_FINGERPRINT,FIPS_R_FINGERPRINT_DOES_NOT_MATCH);
 #ifdef OPENSSL_FIPS_DEBUGGER
-    	return 1;
-#else
-	return 0;
+    	rv = 1;
 #endif
+	goto err;
 	}
-    return 1;
+    rv = 1;
+    err:
+    if (rv == 0)
+    	fips_post_failed(FIPS_TEST_INTEGRITY, 0, NULL);
+    else
+	if (!fips_post_success(FIPS_TEST_INTEGRITY, 0, NULL))
+		return 0;
+    return rv;
     }
 
 int FIPS_mode_set(int onoff)
@@ -281,28 +280,6 @@
 	    goto end;
 	    }
 
-	if(!FIPS_check_incore_fingerprint())
-	    {
-	    fips_selftest_fail = 1;
-	    ret = 0;
-	    goto end;
-	    }
-
-	if (!FIPS_selftest_drbg())
-	    {
-	    fips_selftest_fail = 1;
-	    ret = 0;
-	    goto end;
-	    }
-
-	/* Perform RNG KAT before seeding */
-	if (!FIPS_selftest_x931())
-	    {
-	    fips_selftest_fail = 1;
-	    ret = 0;
-	    goto end;
-	    }
-
 	if(FIPS_selftest())
 	    fips_set_mode(1);
 	else
@@ -388,151 +365,6 @@
 	return FIPS_signature;
 	}
 
-/* Generalized public key test routine. Signs and verifies the data
- * supplied in tbs using mesage digest md and setting RSA padding mode
- * pad_mode. If the 'kat' parameter is not NULL it will
- * additionally check the signature matches it: a known answer test
- * The string "fail_str" is used for identification purposes in case
- * of failure.
- */
-
-int fips_pkey_signature_test(EVP_PKEY *pkey,
-			const unsigned char *tbs, size_t tbslen,
-			const unsigned char *kat, size_t katlen,
-			const EVP_MD *digest, int pad_mode,
-			const char *fail_str)
-	{	
-	int ret = 0;
-	unsigned char *sig = NULL;
-	unsigned int siglen;
-	static const unsigned char str1[]="12345678901234567890";
-	DSA_SIG *dsig = NULL;
-	ECDSA_SIG *esig = NULL;
-	EVP_MD_CTX mctx;
-	FIPS_md_ctx_init(&mctx);
-
-
-	if (tbs == NULL)
-		tbs = str1;
-
-	if (pkey->type == EVP_PKEY_RSA)
-		{
-		sig = OPENSSL_malloc(RSA_size(pkey->pkey.rsa));
-		if (!sig)
-			{
-			FIPSerr(FIPS_F_FIPS_PKEY_SIGNATURE_TEST,ERR_R_MALLOC_FAILURE);
-			return 0;
-			}
-		}
-
-	if (tbslen == 0)
-		tbslen = strlen((char *)tbs);
-
-	if (digest == NULL)
-		digest = EVP_sha256();
-
-	if (!FIPS_digestinit(&mctx, digest))
-		goto error;
-	if (!FIPS_digestupdate(&mctx, tbs, tbslen))
-		goto error;
-	if (pkey->type == EVP_PKEY_RSA)
-		{
-		if (!FIPS_rsa_sign_ctx(pkey->pkey.rsa, &mctx,
-					pad_mode, 0, NULL, sig, &siglen))
-			goto error;
-		}
-	else if (pkey->type == EVP_PKEY_DSA)
-		{
-		dsig = FIPS_dsa_sign_ctx(pkey->pkey.dsa, &mctx);
-		if (!dsig)
-			goto error;
-		}
-	else if (pkey->type == EVP_PKEY_EC)
-		{
-		esig = FIPS_ecdsa_sign_ctx(pkey->pkey.ec, &mctx);
-		if (!esig)
-			goto error;
-		}
-
-	if (kat && ((siglen != katlen) || memcmp(kat, sig, katlen)))
-		goto error;
-#if 0
-	{
-	/* Debug code to print out self test KAT discrepancies */
-	unsigned int i;
-	fprintf(stderr, "%s=", fail_str);
-	for (i = 0; i < siglen; i++)
-			fprintf(stderr, "%02X", sig[i]);
-	fprintf(stderr, "\n");
-	goto error;
-	}
-#endif
-	if (!FIPS_digestinit(&mctx, digest))
-		goto error;
-	if (!FIPS_digestupdate(&mctx, tbs, tbslen))
-		goto error;
-	if (pkey->type == EVP_PKEY_RSA)
-		{
-		ret = FIPS_rsa_verify_ctx(pkey->pkey.rsa, &mctx,
-						pad_mode, 0, NULL, sig, siglen);
-		}
-	else if (pkey->type == EVP_PKEY_DSA)
-		{
-		ret = FIPS_dsa_verify_ctx(pkey->pkey.dsa, &mctx, dsig);
-		}
-	else if (pkey->type == EVP_PKEY_EC)
-		{
-		ret = FIPS_ecdsa_verify_ctx(pkey->pkey.ec, &mctx, esig);
-		}
-
-	error:
-	if (dsig != NULL)
-		FIPS_dsa_sig_free(dsig);
-	if (esig != NULL)
-		FIPS_ecdsa_sig_free(esig);
-	if (sig)
-		OPENSSL_free(sig);
-	FIPS_md_ctx_cleanup(&mctx);
-	if (ret != 1)
-		{
-		FIPSerr(FIPS_F_FIPS_PKEY_SIGNATURE_TEST,FIPS_R_TEST_FAILURE);
-		if (fail_str)
-			FIPS_add_error_data(2, "Type=", fail_str);
-		return 0;
-		}
-	return 1;
-	}
-
-/* Generalized symmetric cipher test routine. Encrypt data, verify result
- * against known answer, decrypt and compare with original plaintext.
- */
-
-int fips_cipher_test(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
-			const unsigned char *key,
-			const unsigned char *iv,
-			const unsigned char *plaintext,
-			const unsigned char *ciphertext,
-			int len)
-	{
-	unsigned char pltmp[FIPS_MAX_CIPHER_TEST_SIZE];
-	unsigned char citmp[FIPS_MAX_CIPHER_TEST_SIZE];
-	OPENSSL_assert(len <= FIPS_MAX_CIPHER_TEST_SIZE);
-	memset(pltmp, 0, FIPS_MAX_CIPHER_TEST_SIZE);
-	memset(citmp, 0, FIPS_MAX_CIPHER_TEST_SIZE);
-	if (FIPS_cipherinit(ctx, cipher, key, iv, 1) <= 0)
-		return 0;
-	if (!FIPS_cipher(ctx, citmp, plaintext, len))
-		return 0;
-	if (memcmp(citmp, ciphertext, len))
-		return 0;
-	if (FIPS_cipherinit(ctx, cipher, key, iv, 0) <= 0)
-		return 0;
-	FIPS_cipher(ctx, pltmp, citmp, len);
-	if (memcmp(pltmp, plaintext, len))
-		return 0;
-	return 1;
-	}
-
 #if 0
 /* The purpose of this is to ensure the error code exists and the function
  * name is to keep the error checking script quiet
diff --git a/fips/fips.h b/fips/fips.h
index e308ff4..4bc77f0 100644
--- a/fips/fips.h
+++ b/fips/fips.h
@@ -101,20 +101,6 @@
 unsigned int FIPS_incore_fingerprint(unsigned char *sig,unsigned int len);
 int FIPS_check_incore_fingerprint(void);
 
-int fips_pkey_signature_test(struct evp_pkey_st *pkey,
-			const unsigned char *tbs, size_t tbslen,
-			const unsigned char *kat, size_t katlen,
-			const struct env_md_st *digest, int pad_mode,
-			const char *fail_str);
-
-int fips_cipher_test(struct evp_cipher_ctx_st *ctx,
-			const struct evp_cipher_st *cipher,
-			const unsigned char *key,
-			const unsigned char *iv,
-			const unsigned char *plaintext,
-			const unsigned char *ciphertext,
-			int len);
-
 void fips_set_selftest_fail(void);
 int fips_check_rsa(struct rsa_st *rsa);
 
@@ -129,9 +115,68 @@
 
 void FIPS_get_timevec(unsigned char *buf, unsigned long *pctr);
 
+/* POST callback operation value: */
+/* All tests started */
+#define	FIPS_POST_BEGIN		1
+/* All tests end: result in id */
+#define	FIPS_POST_END		2
+/* One individual test started */
+#define	FIPS_POST_STARTED	3
+/* Individual test success */
+#define	FIPS_POST_SUCCESS	4
+/* Individual test failure */
+#define	FIPS_POST_FAIL		5
+/* Induce failure in test if zero return */
+#define FIPS_POST_CORRUPT	6
+
+/* Test IDs */
+/* HMAC integrity test */
+#define FIPS_TEST_INTEGRITY	1
+/* Digest test */
+#define FIPS_TEST_DIGEST	2
+/* Symmetric cipher test */
+#define FIPS_TEST_CIPHER	3
+/* Public key signature test */
+#define FIPS_TEST_SIGNATURE	4
+/* HMAC test */
+#define FIPS_TEST_HMAC		5
+/* CMAC test */
+#define FIPS_TEST_CMAC		6
+/* GCM test */
+#define FIPS_TEST_GCM		7
+/* CCM test */
+#define FIPS_TEST_CCM		8
+/* XTS test */
+#define FIPS_TEST_XTS		9
+/* X9.31 PRNG */
+#define FIPS_TEST_X931		10
+/* DRNB */
+#define FIPS_TEST_DRBG		11
+/* Keygen pairwise consistency test */
+#define FIPS_TEST_PAIRWISE	12
+/* Continuous PRNG test */
+#define FIPS_TEST_CONTINUOUS	13
+
+void FIPS_post_set_callback(
+	int (*post_cb)(int op, int id, int subid, void *ex));
+
 #define FIPS_ERROR_IGNORED(alg) OpenSSLDie(__FILE__, __LINE__, \
 		alg " previous FIPS forbidden algorithm error ignored");
 
+int fips_pkey_signature_test(int id, struct evp_pkey_st *pkey,
+			const unsigned char *tbs, size_t tbslen,
+			const unsigned char *kat, size_t katlen,
+			const struct env_md_st *digest, int pad_mode,
+			const char *fail_str);
+
+int fips_cipher_test(int id, struct evp_cipher_ctx_st *ctx,
+			const struct evp_cipher_st *cipher,
+			const unsigned char *key,
+			const unsigned char *iv,
+			const unsigned char *plaintext,
+			const unsigned char *ciphertext,
+			int len);
+
 /* Where necessary redirect standard OpenSSL APIs to FIPS versions */
 
 #if defined(OPENSSL_FIPSCANISTER) && defined(OPENSSL_FIPSAPI)
diff --git a/fips/fips_locl.h b/fips/fips_locl.h
index 3273ba6..fba8db8 100644
--- a/fips/fips_locl.h
+++ b/fips/fips_locl.h
@@ -59,6 +59,14 @@
 	if (!key->comp) \
 		goto err
 
+int fips_post_begin(void);
+void fips_post_end(void);
+int fips_post_started(int id, int subid, void *ex);
+int fips_post_success(int id, int subid, void *ex);
+int fips_post_failed(int id, int subid, void *ex);
+int fips_post_corrupt(int id, int subid, void *ex);
+int fips_post_status(void);
+
 #ifdef  __cplusplus
 }
 #endif
diff --git a/fips/fips_post.c b/fips/fips_post.c
new file mode 100644
index 0000000..1ab156f
--- /dev/null
+++ b/fips/fips_post.c
@@ -0,0 +1,379 @@
+/* ====================================================================
+ * Copyright (c) 2011 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core@openssl.org.
+ *
+ * 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.
+ *
+ */
+
+#define OPENSSL_FIPSAPI
+
+#include <openssl/crypto.h>
+#include <openssl/rand.h>
+#include <openssl/fips_rand.h>
+#include <openssl/err.h>
+#include <openssl/bio.h>
+#include <openssl/hmac.h>
+#include <openssl/rsa.h>
+#include <openssl/dsa.h>
+#include <openssl/ecdsa.h>
+#include <string.h>
+#include <limits.h>
+
+#ifdef OPENSSL_FIPS
+
+/* Power on self test (POST) support functions */
+
+#include <openssl/fips.h>
+#include "fips_locl.h"
+
+/* POST notification callback */
+
+int (*fips_post_cb)(int op, int id, int subid, void *ex);
+
+void FIPS_post_set_callback(
+	int (*post_cb)(int op, int id, int subid, void *ex))
+	{
+	fips_post_cb = post_cb;
+	}
+
+/* POST status: i.e. status of all tests */
+#define FIPS_POST_STATUS_NOT_STARTED	0
+#define FIPS_POST_STATUS_OK		1
+#define FIPS_POST_STATUS_RUNNING	2
+#define FIPS_POST_STATUS_FAILED		-1
+static int post_status = 0;
+/* Set to 1 if any test failed */
+static int post_failure = 0;
+
+/* All tests started */
+
+int fips_post_begin(void)
+	{
+	post_failure = 0;
+	post_status = FIPS_POST_STATUS_NOT_STARTED;
+	if (fips_post_cb)
+		if (!fips_post_cb(FIPS_POST_BEGIN, 0, 0, NULL))
+			return 0;
+	post_status = FIPS_POST_STATUS_RUNNING;
+	return 1;
+	}
+
+void fips_post_end(void)
+	{
+	if (post_failure)
+		{
+		post_status = FIPS_POST_STATUS_FAILED;
+		fips_post_cb(FIPS_POST_END, 0, 0, NULL);
+		}
+	else
+		{
+		post_status = FIPS_POST_STATUS_OK;
+		fips_post_cb(FIPS_POST_END, 1, 0, NULL);
+		}
+	}
+
+/* A self test started */
+int fips_post_started(int id, int subid, void *ex)
+	{
+	if (fips_post_cb)
+		return fips_post_cb(FIPS_POST_STARTED, id, subid, ex);
+	return 1;
+	}
+/* A self test passed successfully */
+int fips_post_success(int id, int subid, void *ex)
+	{
+	if (fips_post_cb)
+		return fips_post_cb(FIPS_POST_SUCCESS, id, subid, ex);
+	return 1;
+	}
+/* A self test failed */
+int fips_post_failed(int id, int subid, void *ex)
+	{
+	post_failure = 1;
+	if (fips_post_cb)
+		return fips_post_cb(FIPS_POST_FAIL, id, subid, ex);
+	return 1;
+	}
+/* Indicate if a self test failure should be induced */
+int fips_post_corrupt(int id, int subid, void *ex)
+	{
+	if (fips_post_cb)
+		return fips_post_cb(FIPS_POST_CORRUPT, id, subid, ex);
+	return 1;
+	}
+/* Note: if selftests running return status OK so their operation is
+ * not interrupted. This will only happen while selftests are actually
+ * running so will not interfere with normal operation.
+ */
+int fips_post_status(void)
+	{
+	return post_status > 0 ? 1 : 0;
+	}
+/* Run all selftests */
+int FIPS_selftest(void)
+	{
+	int rv = 1;
+	fips_post_begin();
+	if(!FIPS_check_incore_fingerprint())
+		rv = 0;
+	if (!FIPS_selftest_drbg())
+		rv = 0;
+	if (!FIPS_selftest_x931())
+		rv = 0;
+    	if (!FIPS_selftest_sha1())
+		rv = 0;
+	if (!FIPS_selftest_hmac())
+		rv = 0;
+	if (!FIPS_selftest_cmac())
+		rv = 0;
+	if (!FIPS_selftest_aes())
+		rv = 0;
+	if (!FIPS_selftest_aes_gcm())
+		rv = 0;
+	if (!FIPS_selftest_des())
+		rv = 0;
+	if (!FIPS_selftest_rsa())
+		rv = 0;
+	if (!FIPS_selftest_ecdsa())
+		rv = 0;
+	if (!FIPS_selftest_dsa())
+		rv = 0;
+	fips_post_end();
+	return rv;
+	}
+
+/* Generalized public key test routine. Signs and verifies the data
+ * supplied in tbs using mesage digest md and setting RSA padding mode
+ * pad_mode. If the 'kat' parameter is not NULL it will
+ * additionally check the signature matches it: a known answer test
+ * The string "fail_str" is used for identification purposes in case
+ * of failure. If "pkey" is NULL just perform a message digest check.
+ */
+
+int fips_pkey_signature_test(int id, EVP_PKEY *pkey,
+			const unsigned char *tbs, size_t tbslen,
+			const unsigned char *kat, size_t katlen,
+			const EVP_MD *digest, int pad_mode,
+			const char *fail_str)
+	{	
+	int subid;
+	void *ex = NULL;
+	int ret = 0;
+	unsigned char *sig = NULL;
+	unsigned int siglen;
+	static const unsigned char str1[]="12345678901234567890";
+	DSA_SIG *dsig = NULL;
+	ECDSA_SIG *esig = NULL;
+	EVP_MD_CTX mctx;
+	FIPS_md_ctx_init(&mctx);
+
+	if (tbs == NULL)
+		tbs = str1;
+
+	if (tbslen == 0)
+		tbslen = strlen((char *)tbs);
+
+	if (digest == NULL)
+		digest = EVP_sha256();
+
+	subid = M_EVP_MD_type(digest);
+
+
+	if (!fips_post_started(id, subid, pkey))
+		return 1;
+
+	if (!pkey || pkey->type == EVP_PKEY_RSA)
+		{
+		size_t sigsize;
+		if (!pkey)
+			sigsize = EVP_MAX_MD_SIZE;
+		else
+			sigsize = RSA_size(pkey->pkey.rsa);
+
+		sig = OPENSSL_malloc(sigsize);
+		if (!sig)
+			{
+			FIPSerr(FIPS_F_FIPS_PKEY_SIGNATURE_TEST,ERR_R_MALLOC_FAILURE);
+			goto error;
+			}
+		}
+
+	if (!FIPS_digestinit(&mctx, digest))
+		goto error;
+	if (!FIPS_digestupdate(&mctx, tbs, tbslen))
+		goto error;
+
+	if (!fips_post_corrupt(id, subid, pkey))
+		{
+		if (!FIPS_digestupdate(&mctx, tbs, 1))
+			goto error;
+		}
+
+	if (pkey == NULL)
+		{
+		if (!FIPS_digestfinal(&mctx, sig, &siglen))
+			goto error;
+		}
+	else if (pkey->type == EVP_PKEY_RSA)
+		{
+		if (!FIPS_rsa_sign_ctx(pkey->pkey.rsa, &mctx,
+					pad_mode, 0, NULL, sig, &siglen))
+			goto error;
+		}
+	else if (pkey->type == EVP_PKEY_DSA)
+		{
+		dsig = FIPS_dsa_sign_ctx(pkey->pkey.dsa, &mctx);
+		if (!dsig)
+			goto error;
+		}
+	else if (pkey->type == EVP_PKEY_EC)
+		{
+		esig = FIPS_ecdsa_sign_ctx(pkey->pkey.ec, &mctx);
+		if (!esig)
+			goto error;
+		}
+
+	if (kat && ((siglen != katlen) || memcmp(kat, sig, katlen)))
+		goto error;
+#if 0
+	{
+	/* Debug code to print out self test KAT discrepancies */
+	unsigned int i;
+	fprintf(stderr, "%s=", fail_str);
+	for (i = 0; i < siglen; i++)
+			fprintf(stderr, "%02X", sig[i]);
+	fprintf(stderr, "\n");
+	goto error;
+	}
+#endif
+	/* If just digest test we've finished */
+	if (pkey == NULL)
+		{
+		ret = 1;
+		/* Well actually sucess as we've set ret to 1 */
+		goto error;
+		}
+	if (!FIPS_digestinit(&mctx, digest))
+		goto error;
+	if (!FIPS_digestupdate(&mctx, tbs, tbslen))
+		goto error;
+	if (pkey->type == EVP_PKEY_RSA)
+		{
+		ret = FIPS_rsa_verify_ctx(pkey->pkey.rsa, &mctx,
+						pad_mode, 0, NULL, sig, siglen);
+		}
+	else if (pkey->type == EVP_PKEY_DSA)
+		{
+		ret = FIPS_dsa_verify_ctx(pkey->pkey.dsa, &mctx, dsig);
+		}
+	else if (pkey->type == EVP_PKEY_EC)
+		{
+		ret = FIPS_ecdsa_verify_ctx(pkey->pkey.ec, &mctx, esig);
+		}
+
+	error:
+	if (dsig != NULL)
+		FIPS_dsa_sig_free(dsig);
+	if (esig != NULL)
+		FIPS_ecdsa_sig_free(esig);
+	if (sig)
+		OPENSSL_free(sig);
+	FIPS_md_ctx_cleanup(&mctx);
+	if (ret != 1)
+		{
+		FIPSerr(FIPS_F_FIPS_PKEY_SIGNATURE_TEST,FIPS_R_TEST_FAILURE);
+		if (fail_str)
+			FIPS_add_error_data(2, "Type=", fail_str);
+		fips_post_failed(id, subid, ex);
+		return 0;
+		}
+	return fips_post_success(id, subid, pkey);
+	}
+
+/* Generalized symmetric cipher test routine. Encrypt data, verify result
+ * against known answer, decrypt and compare with original plaintext.
+ */
+
+int fips_cipher_test(int id, EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
+			const unsigned char *key,
+			const unsigned char *iv,
+			const unsigned char *plaintext,
+			const unsigned char *ciphertext,
+			int len)
+	{
+	unsigned char pltmp[FIPS_MAX_CIPHER_TEST_SIZE];
+	unsigned char citmp[FIPS_MAX_CIPHER_TEST_SIZE];
+	int subid = M_EVP_CIPHER_nid(cipher);
+	int rv = 0;
+	OPENSSL_assert(len <= FIPS_MAX_CIPHER_TEST_SIZE);
+	memset(pltmp, 0, FIPS_MAX_CIPHER_TEST_SIZE);
+	memset(citmp, 0, FIPS_MAX_CIPHER_TEST_SIZE);
+
+	if (!fips_post_started(id, subid, NULL))
+		return 1;
+	if (FIPS_cipherinit(ctx, cipher, key, iv, 1) <= 0)
+		goto error;
+	if (!FIPS_cipher(ctx, citmp, plaintext, len))
+		goto error;
+	if (memcmp(citmp, ciphertext, len))
+		goto error;
+	if (!fips_post_corrupt(id, subid, NULL))
+			citmp[0] ^= 0x1;
+	if (FIPS_cipherinit(ctx, cipher, key, iv, 0) <= 0)
+		goto error;
+	FIPS_cipher(ctx, pltmp, citmp, len);
+	if (memcmp(pltmp, plaintext, len))
+		goto error;
+	rv = 1;
+	error:
+	if (rv == 0)
+		{
+		fips_post_failed(id, subid, NULL);
+		return 0;
+		}
+	return fips_post_success(id, subid, NULL);
+	}
+
+#endif
diff --git a/fips/fips_test_suite.c b/fips/fips_test_suite.c
index 2cfd5ef..e71ab11 100644
--- a/fips/fips_test_suite.c
+++ b/fips/fips_test_suite.c
@@ -665,6 +665,165 @@
 	printf("%s...%s\n", msg, result ? "successful" : Fail("Failed!"));
 	}
 
+static const char *post_get_sig(int id)
+	{
+	switch (id)
+		{
+		case EVP_PKEY_RSA:
+		return " (RSA)";
+
+		case EVP_PKEY_DSA:
+		return " (DSA)";
+
+		case EVP_PKEY_EC:
+		return " (ECDSA)";
+
+		default:
+		return " (UNKNOWN)";
+
+		}
+	}
+
+static const char *post_get_cipher(int id)
+	{
+	static char out[128];
+	switch(id)
+		{
+
+		case NID_aes_128_ecb:
+		return " (AES-128-ECB)";
+
+		case NID_des_ede3_ecb:
+		return " (DES-EDE3-ECB)";
+		
+		default:
+		sprintf(out, " (NID=%d)", id);
+		return out;
+
+		}
+	}
+
+static int fail_id = -1;
+static int fail_sub = -1;
+static int fail_key = -1;
+
+static int post_cb(int op, int id, int subid, void *ex)
+	{
+	const char *idstr, *exstr = "";
+	int keytype = -1;
+	switch(id)
+		{
+		case FIPS_TEST_INTEGRITY:
+		idstr = "Integrity";
+		break;
+
+		case FIPS_TEST_DIGEST:
+		idstr = "Digest";
+		if (subid == NID_sha1)
+			exstr = " (SHA1)";
+		break;
+
+		case FIPS_TEST_CIPHER:
+		exstr = post_get_cipher(subid);
+		idstr = "Cipher";
+		break;
+
+		case FIPS_TEST_SIGNATURE:
+		if (ex)
+			{
+			EVP_PKEY *pkey = ex;
+			keytype = pkey->type;
+			exstr = post_get_sig(keytype);
+			}
+		idstr = "Signature";
+		break;
+
+		case FIPS_TEST_HMAC:
+		idstr = "HMAC";
+		break;
+
+		case FIPS_TEST_CMAC:
+		idstr = "HMAC";
+		break;
+
+		case FIPS_TEST_GCM:
+		idstr = "HMAC";
+		break;
+
+		case FIPS_TEST_CCM:
+		idstr = "HMAC";
+		break;
+
+		case FIPS_TEST_XTS:
+		idstr = "HMAC";
+		break;
+
+		case FIPS_TEST_X931:
+		idstr = "X9.31 PRNG";
+		break;
+
+		case FIPS_TEST_DRBG:
+		idstr = "DRBG";
+		break;
+
+		case FIPS_TEST_PAIRWISE:
+		if (ex)
+			{
+			EVP_PKEY *pkey = ex;
+			keytype = pkey->type;
+			exstr = post_get_sig(keytype);
+			}
+		idstr = "Pairwise Consistency";
+		break;
+
+		case FIPS_TEST_CONTINUOUS:
+		idstr = "Continuous PRNG";
+		break;
+
+		default:
+		idstr = "Unknown";
+		break;
+
+		}
+
+	switch(op)
+		{
+		case FIPS_POST_BEGIN:
+		printf("\tPOST started\n");
+		break;
+
+		case FIPS_POST_END:
+		printf("\tPOST %s\n", id ? "Success" : "Failed");
+		break;
+
+		case FIPS_POST_STARTED:
+		printf("\t\t%s%s test started\n", idstr, exstr);
+		break;
+
+		case FIPS_POST_SUCCESS:
+		printf("\t\t%s%s test OK\n", idstr, exstr);
+		break;
+
+		case FIPS_POST_FAIL:
+		printf("\t\t%s%s test FAILED!!\n", idstr, exstr);
+		break;
+
+		case FIPS_POST_CORRUPT:
+		if (fail_id == id
+			&& (fail_key == -1 || fail_key == keytype)
+			&& (fail_sub == -1 || fail_sub == subid))
+			{
+			printf("\t\t%s%s test failure induced\n", idstr, exstr);
+			return 0;
+			}
+		break;
+
+		}
+	return 1;
+	}
+
+
+
 int main(int argc,char **argv)
     {
 
@@ -676,47 +835,51 @@
 
     fips_algtest_init_nofips();
 
+    FIPS_post_set_callback(post_cb);
+
     printf("\tFIPS-mode test application\n\n");
 
     if (argv[1]) {
         /* Corrupted KAT tests */
-        if (!strcmp(argv[1], "aes")) {
-            FIPS_corrupt_aes();
-            printf("AES encryption/decryption with corrupted KAT...\n");
+        if (!strcmp(argv[1], "integrity")) {
+	    fail_id = FIPS_TEST_INTEGRITY;
+        } else if (!strcmp(argv[1], "aes")) {
+	    fail_id = FIPS_TEST_CIPHER;
+	    fail_sub = NID_aes_128_ecb;	
         } else if (!strcmp(argv[1], "aes-gcm")) {
             FIPS_corrupt_aes_gcm();
             printf("AES-GCM encryption/decryption with corrupted KAT...\n");
         } else if (!strcmp(argv[1], "des")) {
-            FIPS_corrupt_des();
-            printf("DES3-ECB encryption/decryption with corrupted KAT...\n");
+	    fail_id = FIPS_TEST_CIPHER;
+	    fail_sub = NID_des_ede3_ecb;	
         } else if (!strcmp(argv[1], "dsa")) {
-            FIPS_corrupt_dsa();
-            printf("DSA key generation and signature validation with corrupted KAT...\n");
+	    fail_id = FIPS_TEST_SIGNATURE;
+	    fail_key = EVP_PKEY_DSA;	
         } else if (!strcmp(argv[1], "ecdsa")) {
-            FIPS_corrupt_ecdsa();
-            printf("ECDSA key generation and signature validation with corrupted KAT...\n");
+	    fail_id = FIPS_TEST_SIGNATURE;
+	    fail_key = EVP_PKEY_EC;	
         } else if (!strcmp(argv[1], "rsa")) {
-            FIPS_corrupt_rsa();
-            printf("RSA key generation and signature validation with corrupted KAT...\n");
+	    fail_id = FIPS_TEST_SIGNATURE;
+	    fail_key = EVP_PKEY_RSA;	
         } else if (!strcmp(argv[1], "rsakey")) {
             printf("RSA key generation and signature validation with corrupted key...\n");
 	    bad_rsa = 1;
 	    no_exit = 1;
         } else if (!strcmp(argv[1], "rsakeygen")) {
-	    do_corrupt_rsa_keygen = 1;
+	    fail_id = FIPS_TEST_PAIRWISE;
+	    fail_key = EVP_PKEY_RSA;
 	    no_exit = 1;
-            printf("RSA key generation and signature validation with corrupted keygen...\n");
         } else if (!strcmp(argv[1], "dsakey")) {
             printf("DSA key generation and signature validation with corrupted key...\n");
 	    bad_dsa = 1;
 	    no_exit = 1;
         } else if (!strcmp(argv[1], "dsakeygen")) {
-	    do_corrupt_dsa_keygen = 1;
+	    fail_id = FIPS_TEST_PAIRWISE;
+	    fail_key = EVP_PKEY_DSA;
 	    no_exit = 1;
-            printf("DSA key generation and signature validation with corrupted keygen...\n");
         } else if (!strcmp(argv[1], "sha1")) {
-            FIPS_corrupt_sha1();
-            printf("SHA-1 hash with corrupted KAT...\n");
+	    fail_id = FIPS_TEST_DIGEST;
+	    fail_sub = NID_sha1;	
 	} else if (!strcmp(argv[1], "drbg")) {
 	    FIPS_corrupt_drbg();
 	} else if (!strcmp(argv[1], "rng")) {
diff --git a/fips/rsa/fips_rsa_selftest.c b/fips/rsa/fips_rsa_selftest.c
index d20b753..0f6c5ff 100644
--- a/fips/rsa/fips_rsa_selftest.c
+++ b/fips/rsa/fips_rsa_selftest.c
@@ -239,7 +239,8 @@
 	pk.type = EVP_PKEY_RSA;
 	pk.pkey.rsa = key;
 
-	if (!fips_pkey_signature_test(&pk, kat_tbs, sizeof(kat_tbs) - 1,
+	if (!fips_pkey_signature_test(FIPS_TEST_SIGNATURE,
+				&pk, kat_tbs, sizeof(kat_tbs) - 1,
 				kat_RSA_PSS_SHA256, sizeof(kat_RSA_PSS_SHA256),
 				EVP_sha256(), RSA_PKCS1_PSS_PADDING,
 				"RSA SHA256 PSS"))
diff --git a/fips/sha/fips_sha1_selftest.c b/fips/sha/fips_sha1_selftest.c
index 3a4b431..e0f0c12 100644
--- a/fips/sha/fips_sha1_selftest.c
+++ b/fips/sha/fips_sha1_selftest.c
@@ -56,7 +56,7 @@
 #include <openssl/sha.h>
 
 #ifdef OPENSSL_FIPS
-static char test[][60]=
+static unsigned char test[][60]=
     {
     "",
     "abc",
@@ -79,21 +79,20 @@
     }
 
 int FIPS_selftest_sha1()
-    {
-    size_t n;
-
-    for(n=0 ; n<sizeof(test)/sizeof(test[0]) ; ++n)
 	{
-	unsigned char md[SHA_DIGEST_LENGTH];
-
-	FIPS_digest(test[n],strlen(test[n]),md, NULL, EVP_sha1());
-	if(memcmp(md,ret[n],sizeof md))
-	    {
-	    FIPSerr(FIPS_F_FIPS_SELFTEST_SHA1,FIPS_R_SELFTEST_FAILED);
-	    return 0;
-	    }
-	}
-    return 1;
-    }
+	int rv = 1;
+	size_t i;
+	
+	for(i=0 ; i <sizeof(test)/sizeof(test[0]) ; i++)
+		{
+		if (!fips_pkey_signature_test(FIPS_TEST_DIGEST, NULL,
+						test[i], 0,
+						ret[i], 20,
+						EVP_sha1(), 0,
+						"SHA1 Digest"))
+			rv = 0;
+	    	}
+    	return rv;
+    	}
 
 #endif