aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBob Beck <bbe@google.com>2022-08-30 11:28:33 -0600
committerBoringssl LUCI CQ <boringssl-scoped@luci-project-accounts.iam.gserviceaccount.com>2022-09-07 15:56:45 +0000
commit1510e460c646777346bebb9eb060d4c50e093813 (patch)
tree357f19a310e53dd3e0c390b01738b3862cd2855c
parent2e295b91a3c441d32f985bef0dcff5e639f1f448 (diff)
downloadboringssl-1510e460c646777346bebb9eb060d4c50e093813.zip
boringssl-1510e460c646777346bebb9eb060d4c50e093813.tar.gz
boringssl-1510e460c646777346bebb9eb060d4c50e093813.tar.bz2
Add a poisoned field to EVP_CIPHER_CTX.
Poison the EVP_CIPHER_CTX structure on failures, and indicate that it is an error to re-use an EVP_CIPHER_CTX context in another call after a failure. Bug: 494 Change-Id: Ibcdf28b83a2e690f7aab789d908c076d844231c6 Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/54185 Commit-Queue: Bob Beck <bbe@google.com> Reviewed-by: David Benjamin <davidben@google.com>
-rw-r--r--crypto/fipsmodule/cipher/cipher.c42
-rw-r--r--include/openssl/cipher.h3
2 files changed, 44 insertions, 1 deletions
diff --git a/crypto/fipsmodule/cipher/cipher.c b/crypto/fipsmodule/cipher/cipher.c
index a126986..ee45578 100644
--- a/crypto/fipsmodule/cipher/cipher.c
+++ b/crypto/fipsmodule/cipher/cipher.c
@@ -104,6 +104,11 @@ int EVP_CIPHER_CTX_copy(EVP_CIPHER_CTX *out, const EVP_CIPHER_CTX *in) {
return 0;
}
+ if (in->poisoned) {
+ OPENSSL_PUT_ERROR(CIPHER, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ return 0;
+ }
+
EVP_CIPHER_CTX_cleanup(out);
OPENSSL_memcpy(out, in, sizeof(EVP_CIPHER_CTX));
@@ -226,6 +231,9 @@ int EVP_CipherInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
ctx->buf_len = 0;
ctx->final_used = 0;
+ // Clear the poisoned flag to permit re-use of a CTX that previously had a
+ // failed operation.
+ ctx->poisoned = 0;
return 1;
}
@@ -250,6 +258,15 @@ static int block_remainder(const EVP_CIPHER_CTX *ctx, int len) {
int EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len,
const uint8_t *in, int in_len) {
+ if (ctx->poisoned) {
+ OPENSSL_PUT_ERROR(CIPHER, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ return 0;
+ }
+ // If the first call to |cipher| succeeds and the second fails, |ctx| may be
+ // left in an indeterminate state. We set a poison flag on failure to ensure
+ // callers do not continue to use the object in that case.
+ ctx->poisoned = 1;
+
// Ciphers that use blocks may write up to |bl| extra bytes. Ensure the output
// does not overflow |*out_len|.
int bl = ctx->cipher->block_size;
@@ -265,17 +282,23 @@ int EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len,
} else {
*out_len = ret;
}
+ ctx->poisoned = 0;
return 1;
}
if (in_len <= 0) {
*out_len = 0;
- return in_len == 0;
+ if (in_len == 0) {
+ ctx->poisoned = 0;
+ return 1;
+ }
+ return 0;
}
if (ctx->buf_len == 0 && block_remainder(ctx, in_len) == 0) {
if (ctx->cipher->cipher(ctx, out, in, in_len)) {
*out_len = in_len;
+ ctx->poisoned = 0;
return 1;
} else {
*out_len = 0;
@@ -290,6 +313,7 @@ int EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len,
OPENSSL_memcpy(&ctx->buf[i], in, in_len);
ctx->buf_len += in_len;
*out_len = 0;
+ ctx->poisoned = 0;
return 1;
} else {
int j = bl - i;
@@ -319,6 +343,7 @@ int EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len,
OPENSSL_memcpy(ctx->buf, &in[in_len], i);
}
ctx->buf_len = i;
+ ctx->poisoned = 0;
return 1;
}
@@ -326,6 +351,11 @@ int EVP_EncryptFinal_ex(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len) {
int n;
unsigned int i, b, bl;
+ if (ctx->poisoned) {
+ OPENSSL_PUT_ERROR(CIPHER, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ return 0;
+ }
+
if (ctx->cipher->flags & EVP_CIPH_FLAG_CUSTOM_CIPHER) {
// When EVP_CIPH_FLAG_CUSTOM_CIPHER is set, the return value of |cipher| is
// the number of bytes written, or -1 on error. Otherwise the return value
@@ -371,6 +401,11 @@ out:
int EVP_DecryptUpdate(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len,
const uint8_t *in, int in_len) {
+ if (ctx->poisoned) {
+ OPENSSL_PUT_ERROR(CIPHER, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ return 0;
+ }
+
// Ciphers that use blocks may write up to |bl| extra bytes. Ensure the output
// does not overflow |*out_len|.
unsigned int b = ctx->cipher->block_size;
@@ -433,6 +468,11 @@ int EVP_DecryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *out_len) {
unsigned int b;
*out_len = 0;
+ if (ctx->poisoned) {
+ OPENSSL_PUT_ERROR(CIPHER, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ return 0;
+ }
+
if (ctx->cipher->flags & EVP_CIPH_FLAG_CUSTOM_CIPHER) {
i = ctx->cipher->cipher(ctx, out, NULL, 0);
if (i < 0) {
diff --git a/include/openssl/cipher.h b/include/openssl/cipher.h
index 380d25d..ba4b698 100644
--- a/include/openssl/cipher.h
+++ b/include/openssl/cipher.h
@@ -587,6 +587,9 @@ struct evp_cipher_ctx_st {
int final_used;
uint8_t final[EVP_MAX_BLOCK_LENGTH]; // possible final block
+
+ // Has this structure been rendered unusable by a failure.
+ int poisoned;
} /* EVP_CIPHER_CTX */;
typedef struct evp_cipher_info_st {