diff options
author | Nikita Popov <nikita.ppv@gmail.com> | 2020-10-19 11:09:17 +0200 |
---|---|---|
committer | Nikita Popov <nikita.ppv@gmail.com> | 2020-10-19 11:09:17 +0200 |
commit | 7727a0227669a966221572831a6eb9bdfc9d953a (patch) | |
tree | 0d932f3696e54f0240712fe44473e284596bc985 /ext/openssl | |
parent | 8bc5e23f40e3beaea3055873a00ad3c4ff007a40 (diff) | |
parent | 750a74ed9c8061681dba26ffc779c81b391b7718 (diff) | |
download | php-git-7727a0227669a966221572831a6eb9bdfc9d953a.tar.gz |
Merge branch 'PHP-7.4' into PHP-8.0
* PHP-7.4:
Fix bug #79983: Add support for OCB mode
Diffstat (limited to 'ext/openssl')
-rw-r--r-- | ext/openssl/openssl.c | 33 | ||||
-rw-r--r-- | ext/openssl/tests/cipher_tests.inc | 53 | ||||
-rw-r--r-- | ext/openssl/tests/openssl_decrypt_ocb.phpt | 60 | ||||
-rw-r--r-- | ext/openssl/tests/openssl_encrypt_ocb.phpt | 60 |
4 files changed, 199 insertions, 7 deletions
diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c index b6556c23b5..f4f9dfc42a 100644 --- a/ext/openssl/openssl.c +++ b/ext/openssl/openssl.c @@ -6888,6 +6888,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; @@ -6896,24 +6897,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)); @@ -6998,12 +7016,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 algorithm does not support AEAD"); } else if (!EVP_CIPHER_CTX_ctrl(cipher_ctx, mode->aead_set_tag_flag, tag_len, (unsigned char *) tag)) { diff --git a/ext/openssl/tests/cipher_tests.inc b/ext/openssl/tests/cipher_tests.inc index 779bfa8515..1d4988c5a8 100644 --- a/ext/openssl/tests/cipher_tests.inc +++ b/ext/openssl/tests/cipher_tests.inc @@ -108,7 +108,58 @@ $php_openssl_cipher_tests = array( '01e4a9a4fba43c90ccdcb281d48c7c6f' . 'd62875d2aca417034c34aee5', ), - ) + ), + // First few test vectors from RFC 7253. + 'aes-128-ocb' => array( + array( + 'key' => '000102030405060708090A0B0C0D0E0F', + 'iv' => 'BBAA99887766554433221100', + 'aad' => '', + 'pt' => '', + 'tag' => '785407BFFFC8AD9EDCC5520AC9111EE6', + 'ct' => '', + ), + array( + 'key' => '000102030405060708090A0B0C0D0E0F', + 'iv' => 'BBAA99887766554433221101', + 'aad' => '0001020304050607', + 'pt' => '0001020304050607', + 'tag' => '5725BDA0D3B4EB3A257C9AF1F8F03009', + 'ct' => '6820B3657B6F615A', + ), + array( + 'key' => '000102030405060708090A0B0C0D0E0F', + 'iv' => 'BBAA99887766554433221102', + 'aad' => '0001020304050607', + 'pt' => '', + 'tag' => '81017F8203F081277152FADE694A0A00', + 'ct' => '', + ), + array( + 'key' => '000102030405060708090A0B0C0D0E0F', + 'iv' => 'BBAA99887766554433221103', + 'aad' => '', + 'pt' => '0001020304050607', + 'tag' => '14054CD1F35D82760B2CD00D2F99BFA9', + 'ct' => '45DD69F8F5AAE724', + ), + array( + 'key' => '000102030405060708090A0B0C0D0E0F', + 'iv' => 'BBAA99887766554433221104', + 'aad' => '000102030405060708090A0B0C0D0E0F', + 'pt' => '000102030405060708090A0B0C0D0E0F', + 'tag' => '3AD7A4FF3835B8C5701C1CCEC8FC3358', + 'ct' => '571D535B60B277188BE5147170A9A22C', + ), + array( + 'key' => '0F0E0D0C0B0A09080706050403020100', + 'iv' => 'BBAA9988776655443322110D', + 'aad' => '000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627', + 'pt' => '000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627', + 'tag' => 'D0C515F4D1CDD4FDAC4F02AA', + 'ct' => '1792A4E31E0755FB03E31B22116E6C2DDF9EFD6E33D536F1A0124B0A55BAE884ED93481529C76B6A', + ), + ), ); function openssl_get_cipher_tests($method) diff --git a/ext/openssl/tests/openssl_decrypt_ocb.phpt b/ext/openssl/tests/openssl_decrypt_ocb.phpt new file mode 100644 index 0000000000..cea35501dd --- /dev/null +++ b/ext/openssl/tests/openssl_decrypt_ocb.phpt @@ -0,0 +1,60 @@ +--TEST-- +openssl_decrypt() with OCB cipher algorithm tests +--SKIPIF-- +<?php +if (!extension_loaded("openssl")) + die("skip"); +if (!in_array('aes-128-ocb', openssl_get_cipher_methods())) + die("skip: aes-128-ocb not available"); +?> +--FILE-- +<?php +require_once __DIR__ . "/cipher_tests.inc"; +$method = 'aes-128-ocb'; +$tests = openssl_get_cipher_tests($method); + +foreach ($tests as $idx => $test) { + echo "TEST $idx\n"; + $pt = openssl_decrypt($test['ct'], $method, $test['key'], OPENSSL_RAW_DATA, + $test['iv'], $test['tag'], $test['aad']); + var_dump($test['pt'] === $pt); +} + +// no IV +var_dump(openssl_decrypt($test['ct'], $method, $test['key'], OPENSSL_RAW_DATA, + NULL, $test['tag'], $test['aad'])); + +// IV too long +var_dump(openssl_decrypt($test['ct'], $method, $test['key'], OPENSSL_RAW_DATA, + str_repeat('x', 32), $test['tag'], $test['aad'])); + +// failed because no AAD +var_dump(openssl_decrypt($test['ct'], $method, $test['key'], OPENSSL_RAW_DATA, + $test['iv'], $test['tag'])); + +// failed because wrong tag +var_dump(openssl_decrypt($test['ct'], $method, $test['key'], OPENSSL_RAW_DATA, + $test['iv'], str_repeat('x', 16), $test['aad'])); + +?> +--EXPECTF-- +TEST 0 +bool(true) +TEST 1 +bool(true) +TEST 2 +bool(true) +TEST 3 +bool(true) +TEST 4 +bool(true) +TEST 5 +bool(true) + +Warning: openssl_decrypt(): Setting of IV length for AEAD mode failed in %s on line %d +bool(false) + +Warning: openssl_decrypt(): Setting of IV length for AEAD mode failed in %s on line %d +bool(false) +bool(false) +bool(false) diff --git a/ext/openssl/tests/openssl_encrypt_ocb.phpt b/ext/openssl/tests/openssl_encrypt_ocb.phpt new file mode 100644 index 0000000000..ee35a37ce4 --- /dev/null +++ b/ext/openssl/tests/openssl_encrypt_ocb.phpt @@ -0,0 +1,60 @@ +--TEST-- +openssl_encrypt() with OCB cipher algorithm tests +--SKIPIF-- +<?php +if (!extension_loaded("openssl")) + die("skip"); +if (!in_array('aes-128-ocb', openssl_get_cipher_methods())) + die("skip: aes-128-ocb not available"); +?> +--FILE-- +<?php +require_once __DIR__ . "/cipher_tests.inc"; +$method = 'aes-128-ocb'; +$tests = openssl_get_cipher_tests($method); + +foreach ($tests as $idx => $test) { + echo "TEST $idx\n"; + $ct = openssl_encrypt($test['pt'], $method, $test['key'], OPENSSL_RAW_DATA, + $test['iv'], $tag, $test['aad'], strlen($test['tag'])); + var_dump($test['ct'] === $ct); + var_dump($test['tag'] === $tag); +} + +// Empty IV error +var_dump(openssl_encrypt('data', $method, 'password', 0, NULL, $tag, '')); + +// Failing to retrieve tag (must be at most 16 bytes) +var_dump(openssl_encrypt('data', $method, 'password', 0, str_repeat('x', 12), $tag, '', 20)); + +// Failing when no tag supplied +var_dump(openssl_encrypt('data', $method, 'password', 0, str_repeat('x', 12))); +?> +--EXPECTF-- +TEST 0 +bool(true) +bool(true) +TEST 1 +bool(true) +bool(true) +TEST 2 +bool(true) +bool(true) +TEST 3 +bool(true) +bool(true) +TEST 4 +bool(true) +bool(true) +TEST 5 +bool(true) +bool(true) + +Warning: openssl_encrypt(): Setting of IV length for AEAD mode failed in %s on line %d +bool(false) + +Warning: openssl_encrypt(): Setting tag length for AEAD cipher failed in %s on line %d +bool(false) + +Warning: openssl_encrypt(): A tag should be provided when using AEAD mode in %s on line %d +bool(false) |