summaryrefslogtreecommitdiff
path: root/ext/openssl/openssl.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/openssl/openssl.c')
-rw-r--r--ext/openssl/openssl.c33
1 files changed, 27 insertions, 6 deletions
diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c
index 8489d9bfdd..b18e5f8d99 100644
--- a/ext/openssl/openssl.c
+++ b/ext/openssl/openssl.c
@@ -6483,6 +6483,7 @@ 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;
int aead_get_tag_flag;
int aead_set_tag_flag;
@@ -6491,24 +6492,41 @@ struct php_openssl_cipher_mode {
static void php_openssl_load_cipher_mode(struct php_openssl_cipher_mode *mode, const EVP_CIPHER *cipher_type) /* {{{ */
{
- switch (EVP_CIPHER_mode(cipher_type)) {
-#ifdef EVP_CIPH_GCM_MODE
+ int cipher_mode = EVP_CIPHER_mode(cipher_type);
+ 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;
+ 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;
+ mode->aead_ivlen_flag = EVP_CTRL_AEAD_SET_IVLEN;
+ break;
+#else
+# 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;
break;
-#endif
-#ifdef EVP_CIPH_CCM_MODE
+# endif
+# 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->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));
@@ -6593,12 +6611,15 @@ 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->is_single_run_aead && enc) {
+ if (mode->should_set_tag_length) {
+ /* Explicitly set the tag length even when decrypting,
+ * see https://github.com/openssl/openssl/issues/8331. */
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;
}
- } else if (!enc && tag && tag_len > 0) {
+ }
+ if (!enc && tag && tag_len > 0) {
if (!mode->is_aead) {
php_error_docref(NULL, E_WARNING, "The tag cannot be used because the cipher method does not support AEAD");
} else if (!EVP_CIPHER_CTX_ctrl(cipher_ctx, mode->aead_set_tag_flag, tag_len, (unsigned char *) tag)) {