Initial incomplete POST overhaul: add support for POST callback to

allow status of POST to be monitored and/or failures induced.
This commit is contained in:
Dr. Stephen Henson 2011-04-14 11:15:10 +00:00
parent 77394d7e8f
commit ac892b7aa6
17 changed files with 681 additions and 246 deletions

View File

@ -4,6 +4,11 @@
Changes between 1.0.1 and 1.1.0 [xx XXX xxxx] 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 *) Provisional XTS support. Note: this does increase the maximum key
length from 32 to 64 bytes but there should be no binary compatibility length from 32 to 64 bytes but there should be no binary compatibility
issues as existing applications will never use XTS mode. issues as existing applications will never use XTS mode.

View File

@ -85,7 +85,8 @@ static int fips_check_dsa(DSA *dsa)
pk.type = EVP_PKEY_DSA; pk.type = EVP_PKEY_DSA;
pk.pkey.dsa = 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); FIPSerr(FIPS_F_FIPS_CHECK_DSA,FIPS_R_PAIRWISE_TEST_FAILED);
fips_set_selftest_fail(); fips_set_selftest_fail();

View File

@ -250,7 +250,8 @@ static int fips_check_ec(EC_KEY *key)
pk.type = EVP_PKEY_EC; pk.type = EVP_PKEY_EC;
pk.pkey.ec = key; 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); FIPSerr(FIPS_F_FIPS_CHECK_EC,FIPS_R_PAIRWISE_TEST_FAILED);
fips_set_selftest_fail(); fips_set_selftest_fail();

View 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_type(e) M_EVP_MD_type(M_EVP_MD_CTX_md(e))
#define M_EVP_MD_CTX_md(e) ((e)->digest) #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_iv_length(e) ((e)->cipher->iv_len)
#define M_EVP_CIPHER_CTX_flags(e) ((e)->cipher->flags) #define M_EVP_CIPHER_CTX_flags(e) ((e)->cipher->flags)
#define M_EVP_CIPHER_CTX_block_size(e) ((e)->cipher->block_size) #define M_EVP_CIPHER_CTX_block_size(e) ((e)->cipher->block_size)

View File

@ -93,11 +93,11 @@ int fips_check_rsa(RSA *rsa)
pk.pkey.rsa = rsa; pk.pkey.rsa = rsa;
/* Perform pairwise consistency signature test */ /* 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) 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) 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)) NULL, 0, NULL, RSA_PKCS1_PSS_PADDING, NULL))
goto err; goto err;
/* Now perform pairwise consistency encrypt/decrypt test */ /* Now perform pairwise consistency encrypt/decrypt test */

View File

@ -41,8 +41,8 @@ GENERAL=Makefile README fips-lib.com install.com
LIB= $(TOP)/libcrypto.a LIB= $(TOP)/libcrypto.a
SHARED_LIB= $(FIPSCANLIB)$(SHLIB_EXT) SHARED_LIB= $(FIPSCANLIB)$(SHLIB_EXT)
LIBSRC=fips.c LIBSRC=fips.c fips_post.c
LIBOBJ=fips.o LIBOBJ=fips.o fips_post.o
FIPS_OBJ_LISTS=sha/lib hmac/lib rand/lib des/lib aes/lib dsa/lib rsa/lib \ 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 dh/lib utl/lib ecdsa/lib cmac/lib

View File

@ -86,7 +86,7 @@ int FIPS_selftest_aes()
for(n=0 ; n < 1 ; ++n) 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].key, NULL,
tests[n].plaintext, tests[n].plaintext,
tests[n].ciphertext, tests[n].ciphertext,

View File

@ -115,7 +115,7 @@ int FIPS_selftest_des()
/* Encrypt/decrypt with 3DES and compare to known answers */ /* Encrypt/decrypt with 3DES and compare to known answers */
for(n=0 ; n < 2 ; ++n) 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].key, NULL,
tests3[n].plaintext, tests3[n].ciphertext, 8)) tests3[n].plaintext, tests3[n].ciphertext, 8))
goto err; goto err;

View File

@ -169,7 +169,7 @@ int FIPS_selftest_dsa()
pk.type = EVP_PKEY_DSA; pk.type = EVP_PKEY_DSA;
pk.pkey.dsa = 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, NULL, 0, EVP_sha384(), 0,
"DSA SHA384")) "DSA SHA384"))
goto err; goto err;

View File

@ -176,7 +176,7 @@ int FIPS_selftest_ecdsa()
pk.type = EVP_PKEY_EC; pk.type = EVP_PKEY_EC;
pk.pkey.ec = 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, NULL, 0, EVP_sha512(), 0,
ecd->name)) ecd->name))
goto err; goto err;

View File

@ -142,20 +142,6 @@ void fips_set_selftest_fail(void)
fips_selftest_fail = 1; 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 void *FIPS_text_start(), *FIPS_text_end();
extern const unsigned char FIPS_rodata_start[], FIPS_rodata_end[]; extern const unsigned char FIPS_rodata_start[], FIPS_rodata_end[];
unsigned char FIPS_signature [20] = { 0 }; unsigned char FIPS_signature [20] = { 0 };
@ -192,6 +178,9 @@ unsigned int FIPS_incore_fingerprint(unsigned char *sig,unsigned int len)
else else
HMAC_Update(&c,p3,(size_t)p4-(size_t)p3); 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_Final(&c,sig,&len);
HMAC_CTX_cleanup(&c); HMAC_CTX_cleanup(&c);
@ -202,19 +191,23 @@ int FIPS_check_incore_fingerprint(void)
{ {
unsigned char sig[EVP_MAX_MD_SIZE]; unsigned char sig[EVP_MAX_MD_SIZE];
unsigned int len; unsigned int len;
int rv = 0;
#if defined(__sgi) && (defined(__mips) || defined(mips)) #if defined(__sgi) && (defined(__mips) || defined(mips))
extern int __dso_displacement[]; extern int __dso_displacement[];
#else #else
extern int OPENSSL_NONPIC_relocated; extern int OPENSSL_NONPIC_relocated;
#endif #endif
if (!fips_post_started(FIPS_TEST_INTEGRITY, 0, NULL))
return 1;
if (FIPS_text_start()==NULL) if (FIPS_text_start()==NULL)
{ {
FIPSerr(FIPS_F_FIPS_CHECK_INCORE_FINGERPRINT,FIPS_R_UNSUPPORTED_PLATFORM); 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) || if (len!=sizeof(FIPS_signature) ||
memcmp(FIPS_signature,sig,sizeof(FIPS_signature))) memcmp(FIPS_signature,sig,sizeof(FIPS_signature)))
@ -230,12 +223,18 @@ int FIPS_check_incore_fingerprint(void)
else else
FIPSerr(FIPS_F_FIPS_CHECK_INCORE_FINGERPRINT,FIPS_R_FINGERPRINT_DOES_NOT_MATCH); FIPSerr(FIPS_F_FIPS_CHECK_INCORE_FINGERPRINT,FIPS_R_FINGERPRINT_DOES_NOT_MATCH);
#ifdef OPENSSL_FIPS_DEBUGGER #ifdef OPENSSL_FIPS_DEBUGGER
return 1; rv = 1;
#else
return 0;
#endif #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) int FIPS_mode_set(int onoff)
@ -281,28 +280,6 @@ int FIPS_mode_set(int onoff)
goto end; 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()) if(FIPS_selftest())
fips_set_mode(1); fips_set_mode(1);
else else
@ -388,151 +365,6 @@ unsigned char *fips_signature_witness(void)
return FIPS_signature; 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 #if 0
/* The purpose of this is to ensure the error code exists and the function /* The purpose of this is to ensure the error code exists and the function
* name is to keep the error checking script quiet * name is to keep the error checking script quiet

View File

@ -101,20 +101,6 @@ int FIPS_selftest_cmac(void);
unsigned int FIPS_incore_fingerprint(unsigned char *sig,unsigned int len); unsigned int FIPS_incore_fingerprint(unsigned char *sig,unsigned int len);
int FIPS_check_incore_fingerprint(void); 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); void fips_set_selftest_fail(void);
int fips_check_rsa(struct rsa_st *rsa); 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); 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__, \ #define FIPS_ERROR_IGNORED(alg) OpenSSLDie(__FILE__, __LINE__, \
alg " previous FIPS forbidden algorithm error ignored"); 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 */ /* Where necessary redirect standard OpenSSL APIs to FIPS versions */
#if defined(OPENSSL_FIPSCANISTER) && defined(OPENSSL_FIPSAPI) #if defined(OPENSSL_FIPSCANISTER) && defined(OPENSSL_FIPSAPI)

View File

@ -59,6 +59,14 @@ extern "C" {
if (!key->comp) \ if (!key->comp) \
goto err 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 #ifdef __cplusplus
} }
#endif #endif

379
fips/fips_post.c Normal file
View File

@ -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

View File

@ -665,6 +665,165 @@ static void test_msg(const char *msg, int result)
printf("%s...%s\n", msg, result ? "successful" : Fail("Failed!")); 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) int main(int argc,char **argv)
{ {
@ -676,47 +835,51 @@ int main(int argc,char **argv)
fips_algtest_init_nofips(); fips_algtest_init_nofips();
FIPS_post_set_callback(post_cb);
printf("\tFIPS-mode test application\n\n"); printf("\tFIPS-mode test application\n\n");
if (argv[1]) { if (argv[1]) {
/* Corrupted KAT tests */ /* Corrupted KAT tests */
if (!strcmp(argv[1], "aes")) { if (!strcmp(argv[1], "integrity")) {
FIPS_corrupt_aes(); fail_id = FIPS_TEST_INTEGRITY;
printf("AES encryption/decryption with corrupted KAT...\n"); } else if (!strcmp(argv[1], "aes")) {
fail_id = FIPS_TEST_CIPHER;
fail_sub = NID_aes_128_ecb;
} else if (!strcmp(argv[1], "aes-gcm")) { } else if (!strcmp(argv[1], "aes-gcm")) {
FIPS_corrupt_aes_gcm(); FIPS_corrupt_aes_gcm();
printf("AES-GCM encryption/decryption with corrupted KAT...\n"); printf("AES-GCM encryption/decryption with corrupted KAT...\n");
} else if (!strcmp(argv[1], "des")) { } else if (!strcmp(argv[1], "des")) {
FIPS_corrupt_des(); fail_id = FIPS_TEST_CIPHER;
printf("DES3-ECB encryption/decryption with corrupted KAT...\n"); fail_sub = NID_des_ede3_ecb;
} else if (!strcmp(argv[1], "dsa")) { } else if (!strcmp(argv[1], "dsa")) {
FIPS_corrupt_dsa(); fail_id = FIPS_TEST_SIGNATURE;
printf("DSA key generation and signature validation with corrupted KAT...\n"); fail_key = EVP_PKEY_DSA;
} else if (!strcmp(argv[1], "ecdsa")) { } else if (!strcmp(argv[1], "ecdsa")) {
FIPS_corrupt_ecdsa(); fail_id = FIPS_TEST_SIGNATURE;
printf("ECDSA key generation and signature validation with corrupted KAT...\n"); fail_key = EVP_PKEY_EC;
} else if (!strcmp(argv[1], "rsa")) { } else if (!strcmp(argv[1], "rsa")) {
FIPS_corrupt_rsa(); fail_id = FIPS_TEST_SIGNATURE;
printf("RSA key generation and signature validation with corrupted KAT...\n"); fail_key = EVP_PKEY_RSA;
} else if (!strcmp(argv[1], "rsakey")) { } else if (!strcmp(argv[1], "rsakey")) {
printf("RSA key generation and signature validation with corrupted key...\n"); printf("RSA key generation and signature validation with corrupted key...\n");
bad_rsa = 1; bad_rsa = 1;
no_exit = 1; no_exit = 1;
} else if (!strcmp(argv[1], "rsakeygen")) { } else if (!strcmp(argv[1], "rsakeygen")) {
do_corrupt_rsa_keygen = 1; fail_id = FIPS_TEST_PAIRWISE;
fail_key = EVP_PKEY_RSA;
no_exit = 1; no_exit = 1;
printf("RSA key generation and signature validation with corrupted keygen...\n");
} else if (!strcmp(argv[1], "dsakey")) { } else if (!strcmp(argv[1], "dsakey")) {
printf("DSA key generation and signature validation with corrupted key...\n"); printf("DSA key generation and signature validation with corrupted key...\n");
bad_dsa = 1; bad_dsa = 1;
no_exit = 1; no_exit = 1;
} else if (!strcmp(argv[1], "dsakeygen")) { } else if (!strcmp(argv[1], "dsakeygen")) {
do_corrupt_dsa_keygen = 1; fail_id = FIPS_TEST_PAIRWISE;
fail_key = EVP_PKEY_DSA;
no_exit = 1; no_exit = 1;
printf("DSA key generation and signature validation with corrupted keygen...\n");
} else if (!strcmp(argv[1], "sha1")) { } else if (!strcmp(argv[1], "sha1")) {
FIPS_corrupt_sha1(); fail_id = FIPS_TEST_DIGEST;
printf("SHA-1 hash with corrupted KAT...\n"); fail_sub = NID_sha1;
} else if (!strcmp(argv[1], "drbg")) { } else if (!strcmp(argv[1], "drbg")) {
FIPS_corrupt_drbg(); FIPS_corrupt_drbg();
} else if (!strcmp(argv[1], "rng")) { } else if (!strcmp(argv[1], "rng")) {

View File

@ -239,7 +239,8 @@ int FIPS_selftest_rsa()
pk.type = EVP_PKEY_RSA; pk.type = EVP_PKEY_RSA;
pk.pkey.rsa = key; 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), kat_RSA_PSS_SHA256, sizeof(kat_RSA_PSS_SHA256),
EVP_sha256(), RSA_PKCS1_PSS_PADDING, EVP_sha256(), RSA_PKCS1_PSS_PADDING,
"RSA SHA256 PSS")) "RSA SHA256 PSS"))

View File

@ -56,7 +56,7 @@
#include <openssl/sha.h> #include <openssl/sha.h>
#ifdef OPENSSL_FIPS #ifdef OPENSSL_FIPS
static char test[][60]= static unsigned char test[][60]=
{ {
"", "",
"abc", "abc",
@ -79,21 +79,20 @@ void FIPS_corrupt_sha1()
} }
int FIPS_selftest_sha1() int FIPS_selftest_sha1()
{
size_t n;
for(n=0 ; n<sizeof(test)/sizeof(test[0]) ; ++n)
{ {
unsigned char md[SHA_DIGEST_LENGTH]; int rv = 1;
size_t i;
FIPS_digest(test[n],strlen(test[n]),md, NULL, EVP_sha1());
if(memcmp(md,ret[n],sizeof md)) for(i=0 ; i <sizeof(test)/sizeof(test[0]) ; i++)
{ {
FIPSerr(FIPS_F_FIPS_SELFTEST_SHA1,FIPS_R_SELFTEST_FAILED); if (!fips_pkey_signature_test(FIPS_TEST_DIGEST, NULL,
return 0; test[i], 0,
} ret[i], 20,
} EVP_sha1(), 0,
return 1; "SHA1 Digest"))
} rv = 0;
}
return rv;
}
#endif #endif