Initial incomplete POST overhaul: add support for POST callback to
authorDr. Stephen Henson <steve@openssl.org>
Thu, 14 Apr 2011 11:15:10 +0000 (11:15 +0000)
committerDr. Stephen Henson <steve@openssl.org>
Thu, 14 Apr 2011 11:15:10 +0000 (11:15 +0000)
allow status of POST to be monitored and/or failures induced.

17 files changed:
CHANGES
crypto/dsa/dsa_key.c
crypto/ec/ec_key.c
crypto/evp/evp.h
crypto/rsa/rsa_gen.c
fips/Makefile
fips/aes/fips_aes_selftest.c
fips/des/fips_des_selftest.c
fips/dsa/fips_dsa_selftest.c
fips/ecdsa/fips_ecdsa_selftest.c
fips/fips.c
fips/fips.h
fips/fips_locl.h
fips/fips_post.c [new file with mode: 0644]
fips/fips_test_suite.c
fips/rsa/fips_rsa_selftest.c
fips/sha/fips_sha1_selftest.c

diff --git a/CHANGES b/CHANGES
index 877976c..70d2382 100644 (file)
--- 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.
index fa4fb09..39cf6b7 100644 (file)
@@ -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();
index 1615ec8..1f04894 100644 (file)
@@ -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();
index d51e0d3..b4c8675 100644 (file)
@@ -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)
index 7bef5dd..977e461 100644 (file)
@@ -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 */
index 28df80c..e84a4fb 100644 (file)
@@ -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
index 05f18d1..457dabd 100644 (file)
@@ -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,
index 6ce556e..9eea546 100644 (file)
@@ -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;
index 9646ae9..8d89425 100644 (file)
@@ -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;
index c09f59d..6949480 100644 (file)
@@ -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;
index 9ad1761..a18fd58 100644 (file)
@@ -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
index e308ff4..4bc77f0 100644 (file)
@@ -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)
index 3273ba6..fba8db8 100644 (file)
@@ -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 (file)
index 0000000..1ab156f
--- /dev/null
@@ -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
index 2cfd5ef..e71ab11 100644 (file)
@@ -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);
+                       }
+               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 @@ int main(int argc,char **argv)
 
     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")) {
index d20b753..0f6c5ff 100644 (file)
@@ -239,7 +239,8 @@ int FIPS_selftest_rsa()
        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"))
index 3a4b431..e0f0c12 100644 (file)
@@ -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 @@ void FIPS_corrupt_sha1()
     }
 
 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