Skip to content

Commit 1359f79

Browse files
committed
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.
1 parent 750a74e commit 1359f79

File tree

1 file changed

+9
-11
lines changed

1 file changed

+9
-11
lines changed

ext/openssl/openssl.c

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6483,8 +6483,9 @@ PHP_FUNCTION(openssl_digest)
64836483
/* Cipher mode info */
64846484
struct php_openssl_cipher_mode {
64856485
zend_bool is_aead;
6486-
zend_bool should_set_tag_length;
64876486
zend_bool is_single_run_aead;
6487+
zend_bool set_tag_length_always;
6488+
zend_bool set_tag_length_when_encrypting;
64886489
int aead_get_tag_flag;
64896490
int aead_set_tag_flag;
64906491
int aead_ivlen_flag;
@@ -6493,14 +6494,17 @@ struct php_openssl_cipher_mode {
64936494
static void php_openssl_load_cipher_mode(struct php_openssl_cipher_mode *mode, const EVP_CIPHER *cipher_type) /* {{{ */
64946495
{
64956496
int cipher_mode = EVP_CIPHER_mode(cipher_type);
6497+
memset(mode, 0, sizeof(struct php_openssl_cipher_mode));
64966498
switch (cipher_mode) {
64976499
#if PHP_OPENSSL_API_VERSION >= 0x10100
64986500
case EVP_CIPH_GCM_MODE:
64996501
case EVP_CIPH_OCB_MODE:
65006502
case EVP_CIPH_CCM_MODE:
65016503
mode->is_aead = 1;
6502-
mode->should_set_tag_length =
6503-
cipher_mode == EVP_CIPH_CCM_MODE || cipher_mode == EVP_CIPH_OCB_MODE;
6504+
/* For OCB mode, explicitly set the tag length even when decrypting,
6505+
* see https://github.com/openssl/openssl/issues/8331. */
6506+
mode->set_tag_length_always = cipher_mode == EVP_CIPH_OCB_MODE;
6507+
mode->set_tag_length_when_encrypting = cipher_mode == EVP_CIPH_CCM_MODE;
65046508
mode->is_single_run_aead = cipher_mode == EVP_CIPH_CCM_MODE;
65056509
mode->aead_get_tag_flag = EVP_CTRL_AEAD_GET_TAG;
65066510
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
65106514
# ifdef EVP_CIPH_GCM_MODE
65116515
case EVP_CIPH_GCM_MODE:
65126516
mode->is_aead = 1;
6513-
mode->should_set_tag_length = 0;
6514-
mode->is_single_run_aead = 0;
65156517
mode->aead_get_tag_flag = EVP_CTRL_GCM_GET_TAG;
65166518
mode->aead_set_tag_flag = EVP_CTRL_GCM_SET_TAG;
65176519
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
65206522
# ifdef EVP_CIPH_CCM_MODE
65216523
case EVP_CIPH_CCM_MODE:
65226524
mode->is_aead = 1;
6523-
mode->should_set_tag_length = 1;
65246525
mode->is_single_run_aead = 1;
6526+
mode->set_tag_length_when_encrypting = 1;
65256527
mode->aead_get_tag_flag = EVP_CTRL_CCM_GET_TAG;
65266528
mode->aead_set_tag_flag = EVP_CTRL_CCM_SET_TAG;
65276529
mode->aead_ivlen_flag = EVP_CTRL_CCM_SET_IVLEN;
65286530
break;
65296531
# endif
65306532
#endif
6531-
default:
6532-
memset(mode, 0, sizeof(struct php_openssl_cipher_mode));
65336533
}
65346534
}
65356535
/* }}} */
@@ -6611,9 +6611,7 @@ static int php_openssl_cipher_init(const EVP_CIPHER *cipher_type,
66116611
if (php_openssl_validate_iv(piv, piv_len, max_iv_len, free_iv, cipher_ctx, mode) == FAILURE) {
66126612
return FAILURE;
66136613
}
6614-
if (mode->should_set_tag_length) {
6615-
/* Explicitly set the tag length even when decrypting,
6616-
* see https://github.com/openssl/openssl/issues/8331. */
6614+
if (mode->set_tag_length_always || (enc && mode->set_tag_length_when_encrypting)) {
66176615
if (!EVP_CIPHER_CTX_ctrl(cipher_ctx, mode->aead_set_tag_flag, tag_len, NULL)) {
66186616
php_error_docref(NULL, E_WARNING, "Setting tag length for AEAD cipher failed");
66196617
return FAILURE;

0 commit comments

Comments
 (0)