allow status of POST to be monitored and/or failures induced.
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.
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();
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();
#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)
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 */
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
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,
/* 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;
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;
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;
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 };
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);
{
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)))
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)
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
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
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);
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)
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
--- /dev/null
+/* ====================================================================
+ * 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
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)
{
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")) {
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"))
#include <openssl/sha.h>
#ifdef OPENSSL_FIPS
-static char test[][60]=
+static unsigned char test[][60]=
{
"",
"abc",
}
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