summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDr. Stephen Henson <steve@openssl.org>2011-04-14 11:15:10 +0000
committerDr. Stephen Henson <steve@openssl.org>2011-04-14 11:15:10 +0000
commitac892b7aa6532e0345e430208335403ead5d2de1 (patch)
tree00f6a544791b74740dbfe115ac6fc7fd4d465de5
parent77394d7e8f2ca8ca01cfe9b002e3df62ae34a23b (diff)
Initial incomplete POST overhaul: add support for POST callback to
allow status of POST to be monitored and/or failures induced.
-rw-r--r--CHANGES5
-rw-r--r--crypto/dsa/dsa_key.c3
-rw-r--r--crypto/ec/ec_key.c3
-rw-r--r--crypto/evp/evp.h1
-rw-r--r--crypto/rsa/rsa_gen.c6
-rw-r--r--fips/Makefile4
-rw-r--r--fips/aes/fips_aes_selftest.c2
-rw-r--r--fips/des/fips_des_selftest.c2
-rw-r--r--fips/dsa/fips_dsa_selftest.c2
-rw-r--r--fips/ecdsa/fips_ecdsa_selftest.c2
-rw-r--r--fips/fips.c206
-rw-r--r--fips/fips.h73
-rw-r--r--fips/fips_locl.h8
-rw-r--r--fips/fips_post.c379
-rw-r--r--fips/fips_test_suite.c197
-rw-r--r--fips/rsa/fips_rsa_selftest.c3
-rw-r--r--fips/sha/fips_sha1_selftest.c31
17 files changed, 681 insertions, 246 deletions
diff --git a/CHANGES b/CHANGES
index 877976c23a..70d2382e16 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 fa4fb09c31..39cf6b790d 100644
--- a/crypto/dsa/dsa_key.c
+++ b/crypto/dsa/dsa_key.c
@@ -85,7 +85,8 @@ static int fips_check_dsa(DSA *dsa)
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 1615ec8a5a..1f048948e2 100644
--- a/crypto/ec/ec_key.c
+++ b/crypto/ec/ec_key.c
@@ -250,7 +250,8 @@ static int fips_check_ec(EC_KEY *key)
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 d51e0d3403..b4c8675043 100644
--- a/crypto/evp/evp.h
+++ b/crypto/evp/evp.h
@@ -460,6 +460,7 @@ typedef int (EVP_PBE_KEYGEN)(EVP_CIPHER_CTX *ctx, const char *pass, int passlen,
#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 7bef5dd6bf..977e461ef0 100644
--- a/crypto/rsa/rsa_gen.c
+++ b/crypto/rsa/rsa_gen.c
@@ -93,11 +93,11 @@ int fips_check_rsa(RSA *rsa)
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 28df80cab8..e84a4fb044 100644
--- a/fips/Makefile
+++ b/fips/Makefile
@@ -41,8 +41,8 @@ GENERAL=Makefile README fips-lib.com install.com
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 05f18d1484..457dabda38 100644
--- a/fips/aes/fips_aes_selftest.c
+++ b/fips/aes/fips_aes_selftest.c
@@ -86,7 +86,7 @@ int FIPS_selftest_aes()
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 6ce556e2bd..9eea546560 100644
--- a/fips/des/fips_des_selftest.c
+++ b/fips/des/fips_des_selftest.c
@@ -115,7 +115,7 @@ int FIPS_selftest_des()
/* 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 9646ae93da..8d894256f6 100644
--- a/fips/dsa/fips_dsa_selftest.c
+++ b/fips/dsa/fips_dsa_selftest.c
@@ -169,7 +169,7 @@ int FIPS_selftest_dsa()
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 c09f59d926..69494806d5 100644
--- a/fips/ecdsa/fips_ecdsa_selftest.c
+++ b/fips/ecdsa/fips_ecdsa_selftest.c
@@ -176,7 +176,7 @@ int FIPS_selftest_ecdsa()
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 9ad1761f0d..a18fd58f28 100644
--- a/fips/fips.c
+++ b/fips/fips.c
@@ -142,20 +142,6 @@ void fips_set_selftest_fail(void)
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 @@ unsigned int FIPS_incore_fingerprint(unsigned char *sig,unsigned int len)
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 @@ int FIPS_check_incore_fingerprint(void)
{
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 @@ int FIPS_check_incore_fingerprint(void)
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 @@ int FIPS_mode_set(int onoff)
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 @@ unsigned char *fips_signature_witness(void)
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 e308ff44a1..4bc77f00d9 100644
--- a/fips/fips.h
+++ b/fips/fips.h
@@ -101,20 +101,6 @@ int FIPS_selftest_cmac(void);
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_set_malloc_callbacks(
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 3273ba6a83..fba8db8b63 100644
--- a/fips/fips_locl.h
+++ b/fips/fips_locl.h
@@ -59,6 +59,14 @@ extern "C" {
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 0000000000..1ab156fb3f
--- /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 2cfd5ef930..e71ab11599 100644
--- a/fips/fips_test_suite.c
+++ b/fips/fips_test_suite.c
@@ -665,6 +665,165 @@ static void test_msg(const char *msg, int result)
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);
+ }
+ id