Move minimal EVP_CIPHER implementation into FIPS library. Not used by

any FIPS applications yet.
This commit is contained in:
Dr. Stephen Henson 2007-07-01 00:07:25 +00:00
parent 899f528c1a
commit 49fa74385d
11 changed files with 97 additions and 284 deletions

View file

@ -4,6 +4,10 @@
Changes between 0.9.8e and 0.9.8f-fips [xx XXX xxxx]
*) Move EVP cipher code into enc_min.c to support a minimal implementation
for use by FIPS applications.
[Steve Henson]
*) Add algorithm config module. Currently just handles setting FIPS mode.
[Steve Henson]

View file

@ -298,6 +298,7 @@ FIPS_EX_OBJ= ../crypto/aes/aes_cbc.o \
../crypto/dsa/dsa_vrf.o \
../crypto/err/err.o \
../crypto/evp/digest.o \
../crypto/evp/enc_min.o \
../crypto/evp/p_sign.o \
../crypto/evp/p_verify.o \
../crypto/mem_clr.o \

View file

@ -21,7 +21,7 @@ LIB=$(TOP)/libcrypto.a
LIBSRC= encode.c digest.c dig_eng.c evp_enc.c evp_key.c evp_acnf.c evp_cnf.c \
e_des.c e_bf.c e_idea.c e_des3.c e_camellia.c\
e_rc4.c e_aes.c names.c e_seed.c \
e_xcbc_d.c e_rc2.c e_cast.c e_rc5.c \
e_xcbc_d.c e_rc2.c e_cast.c e_rc5.c enc_min.c \
m_null.c m_md2.c m_md4.c m_md5.c m_sha.c m_sha1.c \
m_dss.c m_dss1.c m_mdc2.c m_ripemd.c m_ecdsa.c\
p_open.c p_seal.c p_sign.c p_verify.c p_lib.c p_enc.c p_dec.c \
@ -33,7 +33,7 @@ LIBSRC= encode.c digest.c dig_eng.c evp_enc.c evp_key.c evp_acnf.c evp_cnf.c \
LIBOBJ= encode.o digest.o dig_eng.o evp_enc.o evp_key.o evp_acnf.o evp_cnf.o \
e_des.o e_bf.o e_idea.o e_des3.o e_camellia.o\
e_rc4.o e_aes.o names.o e_seed.o \
e_xcbc_d.o e_rc2.o e_cast.o e_rc5.o \
e_xcbc_d.o e_rc2.o e_cast.o e_rc5.o enc_min.o \
m_null.o m_md2.o m_md4.o m_md5.o m_sha.o m_sha1.o \
m_dss.o m_dss1.o m_mdc2.o m_ripemd.o m_ecdsa.o\
p_open.o p_seal.o p_sign.o p_verify.o p_lib.o p_enc.o p_dec.o \

View file

@ -122,9 +122,9 @@
#ifdef OPENSSL_FIPS
static int do_evp_md_engine_full(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl)
static int do_evp_md_engine_full(EVP_MD_CTX *ctx, const EVP_MD **ptype, ENGINE *impl)
{
if (type)
if (*ptype)
{
/* Ensure an ENGINE left lying around from last time is cleared
* (the previous check attempted to avoid this if the same
@ -141,11 +141,11 @@ static int do_evp_md_engine_full(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *im
}
else
/* Ask if an ENGINE is reserved for this job */
impl = ENGINE_get_digest_engine(type->type);
impl = ENGINE_get_digest_engine((*ptype)->type);
if(impl)
{
/* There's an ENGINE for this job ... (apparently) */
const EVP_MD *d = ENGINE_get_digest(impl, type->type);
const EVP_MD *d = ENGINE_get_digest(impl, (*ptype)->type);
if(!d)
{
/* Same comment from evp_enc.c */
@ -153,7 +153,7 @@ static int do_evp_md_engine_full(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *im
return 0;
}
/* We'll use the ENGINE's private digest definition */
type = d;
*ptype = d;
/* Store the ENGINE functional reference so we know
* 'type' came from an ENGINE and we need to release
* it when done. */

View file

@ -171,11 +171,13 @@ static const EVP_MD bad_md =
#endif
#ifndef OPENSSL_NO_ENGINE
#ifdef OPENSSL_FIPS
static int do_engine_null(ENGINE *impl) { return 0;}
static int do_evp_md_engine_null(EVP_MD_CTX *ctx,
const EVP_MD *type, ENGINE *impl)
const EVP_MD **ptype, ENGINE *impl)
{ return 1; }
static int (*do_engine_init)(ENGINE *impl)
@ -185,14 +187,14 @@ static int (*do_engine_finish)(ENGINE *impl)
= do_engine_null;
static int (*do_evp_md_engine)
(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl)
(EVP_MD_CTX *ctx, const EVP_MD **ptype, ENGINE *impl)
= do_evp_md_engine_null;
void int_EVP_MD_set_engine_callbacks(
int (*eng_md_init)(ENGINE *impl),
int (*eng_md_fin)(ENGINE *impl),
int (*eng_md_evp)
(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl))
(EVP_MD_CTX *ctx, const EVP_MD **ptype, ENGINE *impl))
{
do_engine_init = eng_md_init;
do_engine_finish = eng_md_fin;
@ -204,9 +206,9 @@ void int_EVP_MD_set_engine_callbacks(
#define do_engine_init ENGINE_init
#define do_engine_finish ENGINE_finish
static int do_evp_md_engine(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl)
static int do_evp_md_engine(EVP_MD_CTX *ctx, const EVP_MD **ptype, ENGINE *impl)
{
if (type)
if (*ptype)
{
/* Ensure an ENGINE left lying around from last time is cleared
* (the previous check attempted to avoid this if the same
@ -223,11 +225,11 @@ static int do_evp_md_engine(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl)
}
else
/* Ask if an ENGINE is reserved for this job */
impl = ENGINE_get_digest_engine(type->type);
impl = ENGINE_get_digest_engine((*ptype)->type);
if(impl)
{
/* There's an ENGINE for this job ... (apparently) */
const EVP_MD *d = ENGINE_get_digest(impl, type->type);
const EVP_MD *d = ENGINE_get_digest(impl, (*ptype)->type);
if(!d)
{
/* Same comment from evp_enc.c */
@ -235,7 +237,7 @@ static int do_evp_md_engine(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl)
return 0;
}
/* We'll use the ENGINE's private digest definition */
type = d;
*ptype = d;
/* Store the ENGINE functional reference so we know
* 'type' came from an ENGINE and we need to release
* it when done. */
@ -255,6 +257,8 @@ static int do_evp_md_engine(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl)
#endif
#endif
int EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl)
{
M_EVP_MD_CTX_clear_flags(ctx,EVP_MD_CTX_FLAG_CLEANED);
@ -266,7 +270,7 @@ int EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl)
if (ctx->engine && ctx->digest && (!type ||
(type && (type->type == ctx->digest->type))))
goto skip_to_init;
if (!do_evp_md_engine(ctx, type, impl))
if (!do_evp_md_engine(ctx, &type, impl))
return 0;
#endif
if (ctx->digest != type)

View file

@ -929,8 +929,13 @@ void int_EVP_MD_set_engine_callbacks(
int (*eng_md_init)(ENGINE *impl),
int (*eng_md_fin)(ENGINE *impl),
int (*eng_md_evp)
(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl));
(EVP_MD_CTX *ctx, const EVP_MD **ptype, ENGINE *impl));
void int_EVP_MD_init_engine_callbacks(void);
void int_EVP_CIPHER_set_engine_callbacks(
int (*eng_ciph_fin)(ENGINE *impl),
int (*eng_ciph_evp)
(EVP_CIPHER_CTX *ctx, const EVP_CIPHER **pciph, ENGINE *impl));
void int_EVP_CIPHER_init_engine_callbacks(void);
#endif
#endif

View file

@ -68,12 +68,6 @@
const char EVP_version[]="EVP" OPENSSL_VERSION_PTEXT;
void EVP_CIPHER_CTX_init(EVP_CIPHER_CTX *ctx)
{
memset(ctx,0,sizeof(EVP_CIPHER_CTX));
/* ctx->cipher=NULL; */
}
EVP_CIPHER_CTX *EVP_CIPHER_CTX_new(void)
{
EVP_CIPHER_CTX *ctx=OPENSSL_malloc(sizeof *ctx);
@ -90,204 +84,6 @@ int EVP_CipherInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
return EVP_CipherInit_ex(ctx,cipher,NULL,key,iv,enc);
}
#ifdef OPENSSL_FIPS
/* The purpose of these is to trap programs that attempt to use non FIPS
* algorithms in FIPS mode and ignore the errors.
*/
int bad_init(EVP_CIPHER_CTX *ctx, const unsigned char *key,
const unsigned char *iv, int enc)
{ FIPS_ERROR_IGNORED("Cipher init"); return 0;}
int bad_do_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
const unsigned char *in, unsigned int inl)
{ FIPS_ERROR_IGNORED("Cipher update"); return 0;}
/* NB: no cleanup because it is allowed after failed init */
int bad_set_asn1(EVP_CIPHER_CTX *ctx, ASN1_TYPE *typ)
{ FIPS_ERROR_IGNORED("Cipher set_asn1"); return 0;}
int bad_get_asn1(EVP_CIPHER_CTX *ctx, ASN1_TYPE *typ)
{ FIPS_ERROR_IGNORED("Cipher get_asn1"); return 0;}
int bad_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr)
{ FIPS_ERROR_IGNORED("Cipher ctrl"); return 0;}
static const EVP_CIPHER bad_cipher =
{
0,
0,
0,
0,
0,
bad_init,
bad_do_cipher,
NULL,
0,
bad_set_asn1,
bad_get_asn1,
bad_ctrl,
NULL
};
#endif
int EVP_CipherInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, ENGINE *impl,
const unsigned char *key, const unsigned char *iv, int enc)
{
if (enc == -1)
enc = ctx->encrypt;
else
{
if (enc)
enc = 1;
ctx->encrypt = enc;
}
#ifndef OPENSSL_NO_ENGINE
/* Whether it's nice or not, "Inits" can be used on "Final"'d contexts
* so this context may already have an ENGINE! Try to avoid releasing
* the previous handle, re-querying for an ENGINE, and having a
* reinitialisation, when it may all be unecessary. */
if (ctx->engine && ctx->cipher && (!cipher ||
(cipher && (cipher->nid == ctx->cipher->nid))))
goto skip_to_init;
#endif
if (cipher)
{
/* Ensure a context left lying around from last time is cleared
* (the previous check attempted to avoid this if the same
* ENGINE and EVP_CIPHER could be used). */
EVP_CIPHER_CTX_cleanup(ctx);
/* Restore encrypt field: it is zeroed by cleanup */
ctx->encrypt = enc;
#ifndef OPENSSL_NO_ENGINE
if(impl)
{
if (!ENGINE_init(impl))
{
EVPerr(EVP_F_EVP_CIPHERINIT_EX, EVP_R_INITIALIZATION_ERROR);
return 0;
}
}
else
/* Ask if an ENGINE is reserved for this job */
impl = ENGINE_get_cipher_engine(cipher->nid);
if(impl)
{
/* There's an ENGINE for this job ... (apparently) */
const EVP_CIPHER *c = ENGINE_get_cipher(impl, cipher->nid);
if(!c)
{
/* One positive side-effect of US's export
* control history, is that we should at least
* be able to avoid using US mispellings of
* "initialisation"? */
EVPerr(EVP_F_EVP_CIPHERINIT_EX, EVP_R_INITIALIZATION_ERROR);
return 0;
}
/* We'll use the ENGINE's private cipher definition */
cipher = c;
/* Store the ENGINE functional reference so we know
* 'cipher' came from an ENGINE and we need to release
* it when done. */
ctx->engine = impl;
}
else
ctx->engine = NULL;
#endif
ctx->cipher=cipher;
if (ctx->cipher->ctx_size)
{
ctx->cipher_data=OPENSSL_malloc(ctx->cipher->ctx_size);
if (!ctx->cipher_data)
{
EVPerr(EVP_F_EVP_CIPHERINIT_EX, ERR_R_MALLOC_FAILURE);
return 0;
}
}
else
{
ctx->cipher_data = NULL;
}
ctx->key_len = cipher->key_len;
ctx->flags = 0;
if(ctx->cipher->flags & EVP_CIPH_CTRL_INIT)
{
if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_INIT, 0, NULL))
{
EVPerr(EVP_F_EVP_CIPHERINIT_EX, EVP_R_INITIALIZATION_ERROR);
return 0;
}
}
}
else if(!ctx->cipher)
{
EVPerr(EVP_F_EVP_CIPHERINIT_EX, EVP_R_NO_CIPHER_SET);
return 0;
}
#ifndef OPENSSL_NO_ENGINE
skip_to_init:
#endif
/* we assume block size is a power of 2 in *cryptUpdate */
OPENSSL_assert(ctx->cipher->block_size == 1
|| ctx->cipher->block_size == 8
|| ctx->cipher->block_size == 16);
if(!(EVP_CIPHER_CTX_flags(ctx) & EVP_CIPH_CUSTOM_IV)) {
switch(EVP_CIPHER_CTX_mode(ctx)) {
case EVP_CIPH_STREAM_CIPHER:
case EVP_CIPH_ECB_MODE:
break;
case EVP_CIPH_CFB_MODE:
case EVP_CIPH_OFB_MODE:
ctx->num = 0;
case EVP_CIPH_CBC_MODE:
OPENSSL_assert(EVP_CIPHER_CTX_iv_length(ctx) <=
(int)sizeof(ctx->iv));
if(iv) memcpy(ctx->oiv, iv, EVP_CIPHER_CTX_iv_length(ctx));
memcpy(ctx->iv, ctx->oiv, EVP_CIPHER_CTX_iv_length(ctx));
break;
default:
return 0;
break;
}
}
#ifdef OPENSSL_FIPS
/* After 'key' is set no further parameters changes are permissible.
* So only check for non FIPS enabling at this point.
*/
if (key && FIPS_mode())
{
if (!(ctx->cipher->flags & EVP_CIPH_FLAG_FIPS)
& !(ctx->flags & EVP_CIPH_FLAG_NON_FIPS_ALLOW))
{
EVPerr(EVP_F_EVP_CIPHERINIT, EVP_R_DISABLED_FOR_FIPS);
ERR_add_error_data(2, "cipher=",
EVP_CIPHER_name(ctx->cipher));
ctx->cipher = &bad_cipher;
return 0;
}
}
#endif
if(key || (ctx->cipher->flags & EVP_CIPH_ALWAYS_CALL_INIT)) {
if(!ctx->cipher->init(ctx,key,iv,enc)) return 0;
}
ctx->buf_len=0;
ctx->final_used=0;
ctx->block_mask=ctx->cipher->block_size-1;
return 1;
}
int EVP_CipherUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl,
const unsigned char *in, int inl)
{
@ -548,28 +344,6 @@ void EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *ctx)
}
}
int EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX *c)
{
if (c->cipher != NULL)
{
if(c->cipher->cleanup && !c->cipher->cleanup(c))
return 0;
/* Cleanse cipher context data */
if (c->cipher_data)
OPENSSL_cleanse(c->cipher_data, c->cipher->ctx_size);
}
if (c->cipher_data)
OPENSSL_free(c->cipher_data);
#ifndef OPENSSL_NO_ENGINE
if (c->engine)
/* The EVP_CIPHER we used belongs to an ENGINE, release the
* functional reference we held for this reason. */
ENGINE_finish(c->engine);
#endif
memset(c,0,sizeof(EVP_CIPHER_CTX));
return 1;
}
int EVP_CIPHER_CTX_set_key_length(EVP_CIPHER_CTX *c, int keylen)
{
if(c->cipher->flags & EVP_CIPH_CUSTOM_KEY_LENGTH)
@ -591,27 +365,6 @@ int EVP_CIPHER_CTX_set_padding(EVP_CIPHER_CTX *ctx, int pad)
return 1;
}
int EVP_CIPHER_CTX_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr)
{
int ret;
if(!ctx->cipher) {
EVPerr(EVP_F_EVP_CIPHER_CTX_CTRL, EVP_R_NO_CIPHER_SET);
return 0;
}
if(!ctx->cipher->ctrl) {
EVPerr(EVP_F_EVP_CIPHER_CTX_CTRL, EVP_R_CTRL_NOT_IMPLEMENTED);
return 0;
}
ret = ctx->cipher->ctrl(ctx, type, arg, ptr);
if(ret == -1) {
EVPerr(EVP_F_EVP_CIPHER_CTX_CTRL, EVP_R_CTRL_OPERATION_NOT_IMPLEMENTED);
return 0;
}
return ret;
}
int EVP_CIPHER_CTX_rand_key(EVP_CIPHER_CTX *ctx, unsigned char *key)
{
if (ctx->cipher->flags & EVP_CIPH_RAND_KEY)
@ -621,3 +374,54 @@ int EVP_CIPHER_CTX_rand_key(EVP_CIPHER_CTX *ctx, unsigned char *key)
return 1;
}
#ifndef OPENSSL_NO_ENGINE
#ifdef OPENSSL_FIPS
static int do_evp_enc_engine_full(EVP_CIPHER_CTX *ctx, const EVP_CIPHER **pcipher, ENGINE *impl)
{
if(impl)
{
if (!ENGINE_init(impl))
{
EVPerr(EVP_F_EVP_CIPHERINIT_EX, EVP_R_INITIALIZATION_ERROR);
return 0;
}
}
else
/* Ask if an ENGINE is reserved for this job */
impl = ENGINE_get_cipher_engine((*pcipher)->nid);
if(impl)
{
/* There's an ENGINE for this job ... (apparently) */
const EVP_CIPHER *c = ENGINE_get_cipher(impl, (*pcipher)->nid);
if(!c)
{
/* One positive side-effect of US's export
* control history, is that we should at least
* be able to avoid using US mispellings of
* "initialisation"? */
EVPerr(EVP_F_EVP_CIPHERINIT_EX, EVP_R_INITIALIZATION_ERROR);
return 0;
}
/* We'll use the ENGINE's private cipher definition */
*pcipher = c;
/* Store the ENGINE functional reference so we know
* 'cipher' came from an ENGINE and we need to release
* it when done. */
ctx->engine = impl;
}
else
ctx->engine = NULL;
return 1;
}
void int_EVP_CIPHER_init_engine_callbacks(void)
{
int_EVP_CIPHER_set_engine_callbacks(
ENGINE_finish, do_evp_enc_engine_full);
}
#endif
#endif

View file

@ -178,11 +178,6 @@ int EVP_CIPHER_CTX_block_size(const EVP_CIPHER_CTX *ctx)
return ctx->cipher->block_size;
}
int EVP_Cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, const unsigned char *in, unsigned int inl)
{
return ctx->cipher->do_cipher(ctx,out,in,inl);
}
const EVP_CIPHER *EVP_CIPHER_CTX_cipher(const EVP_CIPHER_CTX *ctx)
{
return ctx->cipher;
@ -193,11 +188,6 @@ unsigned long EVP_CIPHER_flags(const EVP_CIPHER *cipher)
return cipher->flags;
}
unsigned long EVP_CIPHER_CTX_flags(const EVP_CIPHER_CTX *ctx)
{
return ctx->cipher->flags;
}
void *EVP_CIPHER_CTX_get_app_data(const EVP_CIPHER_CTX *ctx)
{
return ctx->app_data;
@ -213,11 +203,6 @@ int EVP_CIPHER_iv_length(const EVP_CIPHER *cipher)
return cipher->iv_len;
}
int EVP_CIPHER_CTX_iv_length(const EVP_CIPHER_CTX *ctx)
{
return ctx->cipher->iv_len;
}
int EVP_CIPHER_key_length(const EVP_CIPHER *cipher)
{
return cipher->key_len;
@ -228,11 +213,6 @@ int EVP_CIPHER_CTX_key_length(const EVP_CIPHER_CTX *ctx)
return ctx->key_len;
}
int EVP_CIPHER_nid(const EVP_CIPHER *cipher)
{
return cipher->nid;
}
int EVP_CIPHER_CTX_nid(const EVP_CIPHER_CTX *ctx)
{
return ctx->cipher->nid;

View file

@ -75,6 +75,7 @@ void OPENSSL_init(void)
#endif
#ifdef OPENSSL_ENGINE
int_EVP_MD_init_engine_callbacks();
int_EVP_CIPHER_init_engine_callbacks();
int_RAND_init_engine_callbacks();
#endif
done = 1;

View file

@ -134,6 +134,19 @@ int FIPS_selftest_failed(void)
return ret;
}
/* Selftest failure fatal exit routine. This will be called
* during *any* cryptographic operation. It has the minimum
* overhead possible to avoid too big a performance hit.
*/
void FIPS_selftest_check(void)
{
if (fips_selftest_fail)
{
OpenSSLDie(__FILE__,__LINE__, "FATAL FIPS SELFTEST FAILURE");
}
}
int FIPS_selftest()
{

View file

@ -63,6 +63,7 @@ int FIPS_mode_set(int onoff);
int FIPS_mode(void);
const void *FIPS_rand_check(void);
int FIPS_selftest_failed(void);
void FIPS_selftest_check(void);
void FIPS_corrupt_sha1(void);
int FIPS_selftest_sha1(void);
void FIPS_corrupt_aes(void);