Maintain EVP_MD_CTX invariants.
Thanks to Lennart Beringer for pointing that that malloc failures could lead to invalid EVP_MD_CTX states. This change cleans up the code in general so that fallible operations are all performed before mutating objects. Thus failures should leave objects in a valid state. Also, |ctx_size| is never zero and a hash with no context is not sensible, so stop handling that case and simply assert that it doesn't occur. Change-Id: Ia60c3796dcf2f772f55e12e49431af6475f64d52 Reviewed-on: https://boringssl-review.googlesource.com/20544 Reviewed-by: Adam Langley <agl@google.com> Commit-Queue: Adam Langley <agl@google.com>
This commit is contained in:
parent
40b24c8154
commit
6b35262272
@ -90,9 +90,7 @@ EVP_MD_CTX *EVP_MD_CTX_create(void) {
|
||||
}
|
||||
|
||||
int EVP_MD_CTX_cleanup(EVP_MD_CTX *ctx) {
|
||||
if (ctx->digest && ctx->digest->ctx_size && ctx->md_data) {
|
||||
OPENSSL_free(ctx->md_data);
|
||||
}
|
||||
OPENSSL_free(ctx->md_data);
|
||||
|
||||
assert(ctx->pctx == NULL || ctx->pctx_ops != NULL);
|
||||
if (ctx->pctx_ops) {
|
||||
@ -114,17 +112,35 @@ void EVP_MD_CTX_destroy(EVP_MD_CTX *ctx) {
|
||||
}
|
||||
|
||||
int EVP_MD_CTX_copy_ex(EVP_MD_CTX *out, const EVP_MD_CTX *in) {
|
||||
uint8_t *tmp_buf = NULL;
|
||||
|
||||
if (in == NULL || in->digest == NULL) {
|
||||
OPENSSL_PUT_ERROR(DIGEST, DIGEST_R_INPUT_NOT_INITIALIZED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (out->digest == in->digest) {
|
||||
// |md_data| will be the correct size in this case so it's removed from
|
||||
// |out| at this point so that |EVP_MD_CTX_cleanup| doesn't free it and
|
||||
// then it's reused.
|
||||
EVP_PKEY_CTX *pctx = NULL;
|
||||
assert(in->pctx == NULL || in->pctx_ops != NULL);
|
||||
if (in->pctx) {
|
||||
pctx = in->pctx_ops->dup(in->pctx);
|
||||
if (!pctx) {
|
||||
OPENSSL_PUT_ERROR(DIGEST, ERR_R_MALLOC_FAILURE);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *tmp_buf;
|
||||
if (out->digest != in->digest) {
|
||||
assert(in->digest->ctx_size != 0);
|
||||
tmp_buf = OPENSSL_malloc(in->digest->ctx_size);
|
||||
if (tmp_buf == NULL) {
|
||||
if (pctx) {
|
||||
in->pctx_ops->free(pctx);
|
||||
}
|
||||
OPENSSL_PUT_ERROR(DIGEST, ERR_R_MALLOC_FAILURE);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
// |md_data| will be the correct size in this case. It's removed from |out|
|
||||
// so that |EVP_MD_CTX_cleanup| doesn't free it, and then it's reused.
|
||||
tmp_buf = out->md_data;
|
||||
out->md_data = NULL;
|
||||
}
|
||||
@ -132,28 +148,11 @@ int EVP_MD_CTX_copy_ex(EVP_MD_CTX *out, const EVP_MD_CTX *in) {
|
||||
EVP_MD_CTX_cleanup(out);
|
||||
|
||||
out->digest = in->digest;
|
||||
if (in->md_data && in->digest->ctx_size) {
|
||||
if (tmp_buf) {
|
||||
out->md_data = tmp_buf;
|
||||
} else {
|
||||
out->md_data = OPENSSL_malloc(in->digest->ctx_size);
|
||||
if (!out->md_data) {
|
||||
OPENSSL_PUT_ERROR(DIGEST, ERR_R_MALLOC_FAILURE);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
OPENSSL_memcpy(out->md_data, in->md_data, in->digest->ctx_size);
|
||||
}
|
||||
|
||||
assert(in->pctx == NULL || in->pctx_ops != NULL);
|
||||
out->md_data = tmp_buf;
|
||||
OPENSSL_memcpy(out->md_data, in->md_data, in->digest->ctx_size);
|
||||
out->pctx = pctx;
|
||||
out->pctx_ops = in->pctx_ops;
|
||||
if (in->pctx && in->pctx_ops) {
|
||||
out->pctx = in->pctx_ops->dup(in->pctx);
|
||||
if (!out->pctx) {
|
||||
EVP_MD_CTX_cleanup(out);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
assert(out->pctx == NULL || out->pctx_ops != NULL);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -165,18 +164,16 @@ int EVP_MD_CTX_copy(EVP_MD_CTX *out, const EVP_MD_CTX *in) {
|
||||
|
||||
int EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *engine) {
|
||||
if (ctx->digest != type) {
|
||||
if (ctx->digest && ctx->digest->ctx_size > 0) {
|
||||
OPENSSL_free(ctx->md_data);
|
||||
ctx->md_data = NULL;
|
||||
assert(type->ctx_size != 0);
|
||||
uint8_t *md_data = OPENSSL_malloc(type->ctx_size);
|
||||
if (md_data == NULL) {
|
||||
OPENSSL_PUT_ERROR(DIGEST, ERR_R_MALLOC_FAILURE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
OPENSSL_free(ctx->md_data);
|
||||
ctx->md_data = md_data;
|
||||
ctx->digest = type;
|
||||
if (type->ctx_size > 0) {
|
||||
ctx->md_data = OPENSSL_malloc(type->ctx_size);
|
||||
if (ctx->md_data == NULL) {
|
||||
OPENSSL_PUT_ERROR(DIGEST, ERR_R_MALLOC_FAILURE);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert(ctx->pctx == NULL || ctx->pctx_ops != NULL);
|
||||
|
Loading…
Reference in New Issue
Block a user