/*
- * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2023 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
#if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODULE)
|| tmpimpl != NULL
#endif
- || impl != NULL) {
+ || impl != NULL
+ || (cipher != NULL && cipher->origin == EVP_ORIG_METH)
+ || (cipher == NULL && ctx->cipher != NULL
+ && ctx->cipher->origin == EVP_ORIG_METH)) {
if (ctx->cipher == ctx->fetched_cipher)
ctx->cipher = NULL;
EVP_CIPHER_free(ctx->fetched_cipher);
* (legacy code)
*/
if (cipher != NULL && ctx->cipher != NULL) {
+ if (ctx->cipher->cleanup != NULL && !ctx->cipher->cleanup(ctx))
+ return 0;
OPENSSL_clear_free(ctx->cipher_data, ctx->cipher->ctx_size);
ctx->cipher_data = NULL;
}
-
/* Start of non-legacy code below */
/* Ensure a context left lying around from last time is cleared */
#endif
}
- if (cipher->prov != NULL) {
+ if (!ossl_assert(cipher->prov != NULL)) {
+ ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
+ return 0;
+ }
+
+ if (cipher != ctx->fetched_cipher) {
if (!EVP_CIPHER_up_ref((EVP_CIPHER *)cipher)) {
ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
return 0;
}
EVP_CIPHER_free(ctx->fetched_cipher);
+ /* Coverity false positive, the reference counting is confusing it */
+ /* coverity[use_after_free] */
ctx->fetched_cipher = (EVP_CIPHER *)cipher;
}
ctx->cipher = cipher;
return 0;
}
+#ifndef FIPS_MODULE
+ /*
+ * Fix for CVE-2023-5363
+ * Passing in a size as part of the init call takes effect late
+ * so, force such to occur before the initialisation.
+ *
+ * The FIPS provider's internal library context is used in a manner
+ * such that this is not an issue.
+ */
+ if (params != NULL) {
+ OSSL_PARAM param_lens[3] = { OSSL_PARAM_END, OSSL_PARAM_END,
+ OSSL_PARAM_END };
+ OSSL_PARAM *q = param_lens;
+ const OSSL_PARAM *p;
+
+ p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_KEYLEN);
+ if (p != NULL)
+ memcpy(q++, p, sizeof(*q));
+
+ /*
+ * Note that OSSL_CIPHER_PARAM_AEAD_IVLEN is a synonym for
+ * OSSL_CIPHER_PARAM_IVLEN so both are covered here.
+ */
+ p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_IVLEN);
+ if (p != NULL)
+ memcpy(q++, p, sizeof(*q));
+
+ if (q != param_lens) {
+ if (!EVP_CIPHER_CTX_set_params(ctx, param_lens)) {
+ ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_LENGTH);
+ return 0;
+ }
+ }
+ }
+#endif
+
if (enc) {
if (ctx->cipher->einit == NULL) {
ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
ctx->cipher_data = OPENSSL_zalloc(ctx->cipher->ctx_size);
if (ctx->cipher_data == NULL) {
ctx->cipher = NULL;
- ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE);
return 0;
}
} else {
/* Preserve wrap enable flag, zero everything else */
ctx->flags &= EVP_CIPHER_CTX_FLAG_WRAP_ALLOW;
if (ctx->cipher->flags & EVP_CIPH_CTRL_INIT) {
- if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_INIT, 0, NULL)) {
+ if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_INIT, 0, NULL) <= 0) {
ctx->cipher = NULL;
ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
return 0;
case EVP_CIPH_CBC_MODE:
n = EVP_CIPHER_CTX_get_iv_length(ctx);
- if (!ossl_assert(n >= 0 && n <= (int)sizeof(ctx->iv)))
- return 0;
+ if (n < 0 || n > (int)sizeof(ctx->iv)) {
+ ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_IV_LENGTH);
+ return 0;
+ }
if (iv != NULL)
memcpy(ctx->oiv, iv, n);
memcpy(ctx->iv, ctx->oiv, n);
ctx->num = 0;
/* Don't reuse IV for CTR mode */
if (iv != NULL) {
- if ((n = EVP_CIPHER_CTX_get_iv_length(ctx)) <= 0)
+ n = EVP_CIPHER_CTX_get_iv_length(ctx);
+ if (n <= 0 || n > (int)sizeof(ctx->iv)) {
+ ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_IV_LENGTH);
return 0;
+ }
memcpy(ctx->iv, iv, n);
}
break;
size_t soutl, inl_ = (size_t)inl;
int blocksize;
- if (outl != NULL) {
+ if (ossl_likely(outl != NULL)) {
*outl = 0;
} else {
ERR_raise(ERR_LIB_EVP, ERR_R_PASSED_NULL_PARAMETER);
}
/* Prevent accidental use of decryption context when encrypting */
- if (!ctx->encrypt) {
+ if (ossl_unlikely(!ctx->encrypt)) {
ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_OPERATION);
return 0;
}
- if (ctx->cipher == NULL) {
+ if (ossl_unlikely(ctx->cipher == NULL)) {
ERR_raise(ERR_LIB_EVP, EVP_R_NO_CIPHER_SET);
return 0;
}
- if (ctx->cipher->prov == NULL)
+ if (ossl_unlikely(ctx->cipher->prov == NULL))
goto legacy;
blocksize = ctx->cipher->block_size;
- if (ctx->cipher->cupdate == NULL || blocksize < 1) {
+ if (ossl_unlikely(ctx->cipher->cupdate == NULL || blocksize < 1)) {
ERR_raise(ERR_LIB_EVP, EVP_R_UPDATE_ERROR);
return 0;
}
inl_ + (size_t)(blocksize == 1 ? 0 : blocksize),
in, inl_);
- if (ret) {
+ if (ossl_likely(ret)) {
if (soutl > INT_MAX) {
ERR_raise(ERR_LIB_EVP, EVP_R_UPDATE_ERROR);
return 0;
size_t soutl, inl_ = (size_t)inl;
int blocksize;
- if (outl != NULL) {
+ if (ossl_likely(outl != NULL)) {
*outl = 0;
} else {
ERR_raise(ERR_LIB_EVP, ERR_R_PASSED_NULL_PARAMETER);
}
/* Prevent accidental use of encryption context when decrypting */
- if (ctx->encrypt) {
+ if (ossl_unlikely(ctx->encrypt)) {
ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_OPERATION);
return 0;
}
- if (ctx->cipher == NULL) {
+ if (ossl_unlikely(ctx->cipher == NULL)) {
ERR_raise(ERR_LIB_EVP, EVP_R_NO_CIPHER_SET);
return 0;
}
- if (ctx->cipher->prov == NULL)
+ if (ossl_unlikely(ctx->cipher->prov == NULL))
goto legacy;
blocksize = EVP_CIPHER_CTX_get_block_size(ctx);
- if (ctx->cipher->cupdate == NULL || blocksize < 1) {
+ if (ossl_unlikely(ctx->cipher->cupdate == NULL || blocksize < 1)) {
ERR_raise(ERR_LIB_EVP, EVP_R_UPDATE_ERROR);
return 0;
}
inl_ + (size_t)(blocksize == 1 ? 0 : blocksize),
in, inl_);
- if (ret) {
+ if (ossl_likely(ret)) {
if (soutl > INT_MAX) {
ERR_raise(ERR_LIB_EVP, EVP_R_UPDATE_ERROR);
return 0;
switch (type) {
case EVP_CTRL_SET_KEY_LENGTH:
+ if (arg < 0)
+ return 0;
+ if (ctx->key_len == arg)
+ /* Skip calling into provider if unchanged. */
+ return 1;
params[0] = OSSL_PARAM_construct_size_t(OSSL_CIPHER_PARAM_KEYLEN, &sz);
ctx->key_len = -1;
break;
case EVP_CTRL_AEAD_SET_IVLEN:
if (arg < 0)
return 0;
+ if (ctx->iv_len == arg)
+ /* Skip calling into provider if unchanged. */
+ return 1;
params[0] = OSSL_PARAM_construct_size_t(OSSL_CIPHER_PARAM_IVLEN, &sz);
ctx->iv_len = -1;
break;
out->cipher_data = OPENSSL_malloc(in->cipher->ctx_size);
if (out->cipher_data == NULL) {
out->cipher = NULL;
- ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE);
return 0;
}
memcpy(out->cipher_data, in->cipher_data, in->cipher->ctx_size);
{
EVP_CIPHER *cipher = OPENSSL_zalloc(sizeof(EVP_CIPHER));
- if (cipher != NULL) {
- cipher->lock = CRYPTO_THREAD_lock_new();
- if (cipher->lock == NULL) {
- OPENSSL_free(cipher);
- return NULL;
- }
- cipher->refcnt = 1;
+ if (cipher != NULL && !CRYPTO_NEW_REF(&cipher->refcnt, 1)) {
+ OPENSSL_free(cipher);
+ return NULL;
}
return cipher;
}
int fnciphcnt = 0, fnctxcnt = 0;
if ((cipher = evp_cipher_new()) == NULL) {
- ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_EVP, ERR_R_EVP_LIB);
return NULL;
}
int ref = 0;
if (cipher->origin == EVP_ORIG_DYNAMIC)
- CRYPTO_UP_REF(&cipher->refcnt, &ref, cipher->lock);
+ CRYPTO_UP_REF(&cipher->refcnt, &ref);
return 1;
}
{
OPENSSL_free(cipher->type_name);
ossl_provider_free(cipher->prov);
- CRYPTO_THREAD_lock_free(cipher->lock);
+ CRYPTO_FREE_REF(&cipher->refcnt);
OPENSSL_free(cipher);
}
if (cipher == NULL || cipher->origin != EVP_ORIG_DYNAMIC)
return;
- CRYPTO_DOWN_REF(&cipher->refcnt, &i, cipher->lock);
+ CRYPTO_DOWN_REF(&cipher->refcnt, &i);
if (i > 0)
return;
evp_cipher_free_int(cipher);