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 877976c23acd91526504e20bd52d584668eac0bd..70d2382e16df7bf4c5a8860423ff1d6b916e0007 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 fa4fb09c3196bf223baa532a3116c8f7eee69e89..39cf6b790db2d875b7d8873a4b9c1deb6a39a8ff 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 1615ec8a5a7204b760e2a8beb039bd6e67169635..1f048948e2d0b0ce2d1ecd25b952a6111e66ab5f 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 d51e0d3403da5c492ac4f3b65c143226790421da..b4c86750438f7094f33f1014cac2a86f4fbef70b 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 7bef5dd6bf207feb38e422b9cdeeb602056dd68f..977e461ef065660ea5d58baaba6321326c49b804 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 28df80cab8a50a314bc7533b992172ffe75b7cd0..e84a4fb0441778bdc188c5f4988504cba9894d80 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 05f18d1484e83b98c273a5c1748a824c3b05c47c..457dabda387358165ccd31edf477bf6cc26976ba 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 6ce556e2bd8533590a0828757557b9ce83c0e664..9eea54656015390dc99816cfca028c5a167d44f5 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 9646ae93dae0ef37d4e14bf6973983e0f983de39..8d894256f6c01e23d0f655bf3321fe7f18c90df9 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 c09f59d926a067ddbda1721cb2507ec46238075d..69494806d558d6319633a4ae6bb2f4aa639af918 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 9ad1761f0dc9d8f6fe8911754a1768ec669ab9af..a18fd58f28f1fe777079797dcba37af98259ca2f 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 e308ff44a10c6290a5d8fbb08d04d215196b22ab..4bc77f00d951e608954b92c359283e14f7b7041b 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 3273ba6a83e9fa920d1b2604374f2892ae2b565c..fba8db8b63ddb2d02b2e25285a5a4eb6132960b9 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 2cfd5ef9308c6a0461beb54f5625c50f87eed5c1..e71ab11599b5fa3040bbe82ed943e30dfd958741 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 d20b753a7dafe2f96b7df12fa0efd0b99bafd8d1..0f6c5ff51a333c7bcddce56cf2944706fd641de2 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 3a4b4315c5d772a6d59038a9f71331c81a1ae163..e0f0c12d9ee899322f090553045197ef1296a369 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