summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikita Popov <nikita.ppv@gmail.com>2020-10-20 10:50:50 +0200
committerNikita Popov <nikita.ppv@gmail.com>2020-10-20 10:50:50 +0200
commit1359f793ee2de31122697fda4ec0503a0d055170 (patch)
treea48a354ba6fdf523fe8749be95b431f7990e3418
parent750a74ed9c8061681dba26ffc779c81b391b7718 (diff)
downloadphp-git-1359f793ee2de31122697fda4ec0503a0d055170.tar.gz
Fix CCM tag length setting for old OpenSSL versions
While OpenSSL 1.1 allows unconditionally setting the CCM tag length even for decryption, some older versions apparently do not. As such, we do need to treat CCM and OCB separately after all.
-rw-r--r--ext/openssl/openssl.c20
1 files changed, 9 insertions, 11 deletions
diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c
index b18e5f8d99..dfb0bd3af2 100644
--- a/ext/openssl/openssl.c
+++ b/ext/openssl/openssl.c
@@ -6483,8 +6483,9 @@ PHP_FUNCTION(openssl_digest)
/* Cipher mode info */
struct php_openssl_cipher_mode {
zend_bool is_aead;
- zend_bool should_set_tag_length;
zend_bool is_single_run_aead;
+ zend_bool set_tag_length_always;
+ zend_bool set_tag_length_when_encrypting;
int aead_get_tag_flag;
int aead_set_tag_flag;
int aead_ivlen_flag;
@@ -6493,14 +6494,17 @@ struct php_openssl_cipher_mode {
static void php_openssl_load_cipher_mode(struct php_openssl_cipher_mode *mode, const EVP_CIPHER *cipher_type) /* {{{ */
{
int cipher_mode = EVP_CIPHER_mode(cipher_type);
+ memset(mode, 0, sizeof(struct php_openssl_cipher_mode));
switch (cipher_mode) {
#if PHP_OPENSSL_API_VERSION >= 0x10100
case EVP_CIPH_GCM_MODE:
case EVP_CIPH_OCB_MODE:
case EVP_CIPH_CCM_MODE:
mode->is_aead = 1;
- mode->should_set_tag_length =
- cipher_mode == EVP_CIPH_CCM_MODE || cipher_mode == EVP_CIPH_OCB_MODE;
+ /* For OCB mode, explicitly set the tag length even when decrypting,
+ * see https://github.com/openssl/openssl/issues/8331. */
+ mode->set_tag_length_always = cipher_mode == EVP_CIPH_OCB_MODE;
+ mode->set_tag_length_when_encrypting = cipher_mode == EVP_CIPH_CCM_MODE;
mode->is_single_run_aead = cipher_mode == EVP_CIPH_CCM_MODE;
mode->aead_get_tag_flag = EVP_CTRL_AEAD_GET_TAG;
mode->aead_set_tag_flag = EVP_CTRL_AEAD_SET_TAG;
@@ -6510,8 +6514,6 @@ static void php_openssl_load_cipher_mode(struct php_openssl_cipher_mode *mode, c
# ifdef EVP_CIPH_GCM_MODE
case EVP_CIPH_GCM_MODE:
mode->is_aead = 1;
- mode->should_set_tag_length = 0;
- mode->is_single_run_aead = 0;
mode->aead_get_tag_flag = EVP_CTRL_GCM_GET_TAG;
mode->aead_set_tag_flag = EVP_CTRL_GCM_SET_TAG;
mode->aead_ivlen_flag = EVP_CTRL_GCM_SET_IVLEN;
@@ -6520,16 +6522,14 @@ static void php_openssl_load_cipher_mode(struct php_openssl_cipher_mode *mode, c
# ifdef EVP_CIPH_CCM_MODE
case EVP_CIPH_CCM_MODE:
mode->is_aead = 1;
- mode->should_set_tag_length = 1;
mode->is_single_run_aead = 1;
+ mode->set_tag_length_when_encrypting = 1;
mode->aead_get_tag_flag = EVP_CTRL_CCM_GET_TAG;
mode->aead_set_tag_flag = EVP_CTRL_CCM_SET_TAG;
mode->aead_ivlen_flag = EVP_CTRL_CCM_SET_IVLEN;
break;
# endif
#endif
- default:
- memset(mode, 0, sizeof(struct php_openssl_cipher_mode));
}
}
/* }}} */
@@ -6611,9 +6611,7 @@ static int php_openssl_cipher_init(const EVP_CIPHER *cipher_type,
if (php_openssl_validate_iv(piv, piv_len, max_iv_len, free_iv, cipher_ctx, mode) == FAILURE) {
return FAILURE;
}
- if (mode->should_set_tag_length) {
- /* Explicitly set the tag length even when decrypting,
- * see https://github.com/openssl/openssl/issues/8331. */
+ if (mode->set_tag_length_always || (enc && mode->set_tag_length_when_encrypting)) {
if (!EVP_CIPHER_CTX_ctrl(cipher_ctx, mode->aead_set_tag_flag, tag_len, NULL)) {
php_error_docref(NULL, E_WARNING, "Setting tag length for AEAD cipher failed");
return FAILURE;