summaryrefslogtreecommitdiffstats
path: root/crypto/evp/digest.c
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/evp/digest.c')
-rw-r--r--crypto/evp/digest.c154
1 files changed, 130 insertions, 24 deletions
diff --git a/crypto/evp/digest.c b/crypto/evp/digest.c
index 762e6d3..3bc2d12 100644
--- a/crypto/evp/digest.c
+++ b/crypto/evp/digest.c
@@ -116,6 +116,7 @@
#ifndef OPENSSL_NO_ENGINE
#include <openssl/engine.h>
#endif
+#include "evp_locl.h"
void EVP_MD_CTX_init(EVP_MD_CTX *ctx)
{
@@ -137,18 +138,77 @@ int EVP_DigestInit(EVP_MD_CTX *ctx, const EVP_MD *type)
return EVP_DigestInit_ex(ctx, type, NULL);
}
-int EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl)
+#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.
+ */
+
+static int bad_init(EVP_MD_CTX *ctx)
+ { FIPS_ERROR_IGNORED("Digest init"); return 0;}
+
+static int bad_update(EVP_MD_CTX *ctx,const void *data,size_t count)
+ { FIPS_ERROR_IGNORED("Digest update"); return 0;}
+
+static int bad_final(EVP_MD_CTX *ctx,unsigned char *md)
+ { FIPS_ERROR_IGNORED("Digest Final"); return 0;}
+
+static const EVP_MD bad_md =
{
- EVP_MD_CTX_clear_flags(ctx,EVP_MD_CTX_FLAG_CLEANED);
+ 0,
+ 0,
+ 0,
+ 0,
+ bad_init,
+ bad_update,
+ bad_final,
+ NULL,
+ NULL,
+ NULL,
+ 0,
+ {0,0,0,0},
+ };
+
+#endif
+
#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->digest && (!type ||
- (type && (type->type == ctx->digest->type))))
- goto skip_to_init;
- if (type)
+
+#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 **ptype, ENGINE *impl)
+ { return 1; }
+
+static int (*do_engine_init)(ENGINE *impl)
+ = do_engine_null;
+
+static int (*do_engine_finish)(ENGINE *impl)
+ = do_engine_null;
+
+static int (*do_evp_md_engine)
+ (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 **ptype, ENGINE *impl))
+ {
+ do_engine_init = eng_md_init;
+ do_engine_finish = eng_md_fin;
+ do_evp_md_engine = eng_md_evp;
+ }
+
+#else
+
+#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 **ptype, ENGINE *impl)
+ {
+ if (*ptype)
{
/* Ensure an ENGINE left lying around from last time is cleared
* (the previous check attempted to avoid this if the same
@@ -159,25 +219,25 @@ int EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl)
{
if (!ENGINE_init(impl))
{
- EVPerr(EVP_F_EVP_DIGESTINIT_EX,EVP_R_INITIALIZATION_ERROR);
+ EVPerr(EVP_F_DO_EVP_MD_ENGINE,EVP_R_INITIALIZATION_ERROR);
return 0;
}
}
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 */
- EVPerr(EVP_F_EVP_DIGESTINIT_EX,EVP_R_INITIALIZATION_ERROR);
+ EVPerr(EVP_F_DO_EVP_MD_ENGINE,EVP_R_INITIALIZATION_ERROR);
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. */
@@ -189,12 +249,52 @@ int EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl)
else
if(!ctx->digest)
{
- EVPerr(EVP_F_EVP_DIGESTINIT_EX,EVP_R_NO_DIGEST_SET);
+ EVPerr(EVP_F_DO_EVP_MD_ENGINE,EVP_R_NO_DIGEST_SET);
return 0;
}
+ return 1;
+ }
+
+#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);
+#ifdef OPENSSL_FIPS
+ if(FIPS_selftest_failed())
+ {
+ FIPSerr(FIPS_F_EVP_DIGESTINIT_EX,FIPS_R_FIPS_SELFTEST_FAILED);
+ ctx->digest = &bad_md;
+ return 0;
+ }
+#endif
+#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->digest && (!type ||
+ (type && (type->type == ctx->digest->type))))
+ goto skip_to_init;
+ if (!do_evp_md_engine(ctx, &type, impl))
+ return 0;
#endif
if (ctx->digest != type)
{
+#ifdef OPENSSL_FIPS
+ if (FIPS_mode())
+ {
+ if (!(type->flags & EVP_MD_FLAG_FIPS)
+ && !(ctx->flags & EVP_MD_CTX_FLAG_NON_FIPS_ALLOW))
+ {
+ EVPerr(EVP_F_EVP_DIGESTINIT_EX, EVP_R_DISABLED_FOR_FIPS);
+ ctx->digest = &bad_md;
+ return 0;
+ }
+ }
+#endif
if (ctx->digest && ctx->digest->ctx_size)
OPENSSL_free(ctx->md_data);
ctx->digest=type;
@@ -202,7 +302,7 @@ int EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl)
ctx->md_data=OPENSSL_malloc(type->ctx_size);
}
#ifndef OPENSSL_NO_ENGINE
-skip_to_init:
+ skip_to_init:
#endif
return ctx->digest->init(ctx);
}
@@ -210,6 +310,9 @@ skip_to_init:
int EVP_DigestUpdate(EVP_MD_CTX *ctx, const void *data,
size_t count)
{
+#ifdef OPENSSL_FIPS
+ FIPS_selftest_check();
+#endif
return ctx->digest->update(ctx,data,count);
}
@@ -226,6 +329,9 @@ int EVP_DigestFinal(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *size)
int EVP_DigestFinal_ex(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *size)
{
int ret;
+#ifdef OPENSSL_FIPS
+ FIPS_selftest_check();
+#endif
OPENSSL_assert(ctx->digest->md_size <= EVP_MAX_MD_SIZE);
ret=ctx->digest->final(ctx,md);
@@ -234,7 +340,7 @@ int EVP_DigestFinal_ex(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *size)
if (ctx->digest->cleanup)
{
ctx->digest->cleanup(ctx);
- EVP_MD_CTX_set_flags(ctx,EVP_MD_CTX_FLAG_CLEANED);
+ M_EVP_MD_CTX_set_flags(ctx,EVP_MD_CTX_FLAG_CLEANED);
}
memset(ctx->md_data,0,ctx->digest->ctx_size);
return ret;
@@ -256,7 +362,7 @@ int EVP_MD_CTX_copy_ex(EVP_MD_CTX *out, const EVP_MD_CTX *in)
}
#ifndef OPENSSL_NO_ENGINE
/* Make sure it's safe to copy a digest context using an ENGINE */
- if (in->engine && !ENGINE_init(in->engine))
+ if (in->engine && !do_engine_init(in->engine))
{
EVPerr(EVP_F_EVP_MD_CTX_COPY_EX,ERR_R_ENGINE_LIB);
return 0;
@@ -266,7 +372,7 @@ int EVP_MD_CTX_copy_ex(EVP_MD_CTX *out, const EVP_MD_CTX *in)
if (out->digest == in->digest)
{
tmp_buf = out->md_data;
- EVP_MD_CTX_set_flags(out,EVP_MD_CTX_FLAG_REUSE);
+ M_EVP_MD_CTX_set_flags(out,EVP_MD_CTX_FLAG_REUSE);
}
else tmp_buf = NULL;
EVP_MD_CTX_cleanup(out);
@@ -292,7 +398,7 @@ int EVP_Digest(const void *data, size_t count,
int ret;
EVP_MD_CTX_init(&ctx);
- EVP_MD_CTX_set_flags(&ctx,EVP_MD_CTX_FLAG_ONESHOT);
+ M_EVP_MD_CTX_set_flags(&ctx,EVP_MD_CTX_FLAG_ONESHOT);
ret=EVP_DigestInit_ex(&ctx, type, impl)
&& EVP_DigestUpdate(&ctx, data, count)
&& EVP_DigestFinal_ex(&ctx, md, size);
@@ -314,10 +420,10 @@ int EVP_MD_CTX_cleanup(EVP_MD_CTX *ctx)
* because sometimes only copies of the context are ever finalised.
*/
if (ctx->digest && ctx->digest->cleanup
- && !EVP_MD_CTX_test_flags(ctx,EVP_MD_CTX_FLAG_CLEANED))
+ && !M_EVP_MD_CTX_test_flags(ctx,EVP_MD_CTX_FLAG_CLEANED))
ctx->digest->cleanup(ctx);
if (ctx->digest && ctx->digest->ctx_size && ctx->md_data
- && !EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_REUSE))
+ && !M_EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_REUSE))
{
OPENSSL_cleanse(ctx->md_data,ctx->digest->ctx_size);
OPENSSL_free(ctx->md_data);
@@ -326,7 +432,7 @@ int EVP_MD_CTX_cleanup(EVP_MD_CTX *ctx)
if(ctx->engine)
/* The EVP_MD we used belongs to an ENGINE, release the
* functional reference we held for this reason. */
- ENGINE_finish(ctx->engine);
+ do_engine_finish(ctx->engine);
#endif
memset(ctx,'\0',sizeof *ctx);
OpenPOWER on IntegriCloud