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]
*) 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.

View 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();

View 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();

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_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)

View 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 */

View 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

View 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,

View 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;

View 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;

View 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;

View 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

View 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)

View 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

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!"));
}
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")) {

View 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"))

View 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