|
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
[2019-09-29 00:12 UTC] perske at uni-muenster dot de
Description: ------------ Though OpenSSL implements much more ciphers, the 6th parameter to openssl_pkcs7_encrypt() ($cryptid) does only allow for very few values: OPENSSL_CIPHER_RC2_40 OPENSSL_CIPHER_RC2_128 OPENSSL_CIPHER_RC2_64 OPENSSL_CIPHER_DES OPENSSL_CIPHER_3DES OPENSSL_CIPHER_AES_128_CBC OPENSSL_CIPHER_AES_192_CBC OPENSSL_CIPHER_AES_256_CBC *All* these values produce weak ciphertexts, either because the cipher itself is weak (RC2) or because the block cipher mode of operation (CBC) allows to attack the ciphertext with the EFAIL CBC/CFB Gadget Attack, see "efail dot de". OpenSSL already offers AES GCM ciphers that are not susceptible to the attack, so please implement: OPENSSL_CIPHER_AES_128_GCM OPENSSL_CIPHER_AES_192_GCM OPENSSL_CIPHER_AES_256_GCM (AES GCM is the cipher recommended in the Security Considerations in the new S/MIME RFC 8551 that was written after EFAIL became known.) Thank you! PatchesPull RequestsHistoryAllCommentsChangesGit/SVN commits
|
|||||||||||||||||||||||||||||||||||||
Copyright © 2001-2025 The PHP GroupAll rights reserved. |
Last updated: Sat Nov 01 05:00:01 2025 UTC |
Thank you for you check-back. I hope this long comment can give more explanations. :-) Regarding the questions whether this qualifies as a security issue: I think it does because openssl_pkcs7_encrypt() is currently producing encrypted data that is no longer secure since EFail. (The security issue is not that ciphers are missing but that the output is vulnerable with every currently available cipher; you cannot even choose a cipher that produces non-vulnerable output. This makes existing e-mail applications that use this function vulnerable, and I am using such applications, for example www.uni-muenster.de/WWUCA/en/howto-setup-php.html#4 . This is why I detected this weakness.) Regarding whether there is an RFC that allows to use the AES GCM ciphers in PKCS#7 / S/MIME: The RFC is RFC8551 chapter 2.7. It does not only allow but even demands ("MUST") that AES GCM must be supported in S/MIME (and so in PKCS#7). Regarding the implementation: Maybe I do not understand every detail of the source code (this is why I do not dare to write a patch myself), but if I look into ext/openssl.c of PHP 7.2.24, trying to understand what the source code does, I see this: How ist the cipher argument evaluated and passed to OpenSSL? PHP Function openssl_pkcs7_encrypt() starts in line 5168, reads in line 5188 the cipher argument into "cipherid", converts it in line 5253 into "cipher" using php_openssl_get_evp_cipher_from_algo(), and passes it in line 5260 to the OpenSSL function PKCS7_encrypt(). What ciphers are known by php_openssl_get_evp_cipher_from_algo()? Function php_openssl_get_evp_cipher_from_algo() starts in line 1361, knows a list of PHP_OPENSSL_CIPHER_XXXXX constants, returns for each constant the result of a corresponding OpenSSL EVP_xxxxx() function. What constants are known and what EVP_xxxxx() functions are available()? This probably depends on the OpenSSL version. But PHP is already using appropriate feature test macros. PHP already knows (see line 1361 ff.): #ifndef OPENSSL_NO_RC2 PHP_OPENSSL_CIPHER_RC2_40 - EVP_rc2_40_cbc() PHP_OPENSSL_CIPHER_RC2_64 - EVP_rc2_64_cbc() PHP_OPENSSL_CIPHER_RC2_128 - EVP_rc2_cbc() #ifndef OPENSSL_NO_DES PHP_OPENSSL_CIPHER_DES - EVP_des_cbc() PHP_OPENSSL_CIPHER_3DES - EVP_des_ede3_cbc() #ifndef OPENSSL_NO_AES PHP_OPENSSL_CIPHER_AES_128_CBC - EVP_aes_128_cbc() PHP_OPENSSL_CIPHER_AES_192_CBC - EVP_aes_192_cbc() PHP_OPENSSL_CIPHER_AES_256_CBC - EVP_aes_256_cbc() If I look into /usr/include/openssl/evp.h (RedHat Enterprise Linux 7, openssl-1.0.2k with fixed backported by RedHat, so your own findings may differ), I see: [...] # ifndef OPENSSL_NO_RC2 const EVP_CIPHER *EVP_rc2_ecb(void); const EVP_CIPHER *EVP_rc2_cbc(void); const EVP_CIPHER *EVP_rc2_40_cbc(void); const EVP_CIPHER *EVP_rc2_64_cbc(void); [...] # ifndef OPENSSL_NO_AES const EVP_CIPHER *EVP_aes_128_ecb(void); const EVP_CIPHER *EVP_aes_128_cbc(void); const EVP_CIPHER *EVP_aes_128_cfb1(void); const EVP_CIPHER *EVP_aes_128_cfb8(void); const EVP_CIPHER *EVP_aes_128_cfb128(void); # define EVP_aes_128_cfb EVP_aes_128_cfb128 const EVP_CIPHER *EVP_aes_128_ofb(void); const EVP_CIPHER *EVP_aes_128_ctr(void); const EVP_CIPHER *EVP_aes_128_ccm(void); const EVP_CIPHER *EVP_aes_128_gcm(void); const EVP_CIPHER *EVP_aes_128_xts(void); const EVP_CIPHER *EVP_aes_128_wrap(void); const EVP_CIPHER *EVP_aes_128_wrap_pad(void); const EVP_CIPHER *EVP_aes_192_ecb(void); const EVP_CIPHER *EVP_aes_192_cbc(void); const EVP_CIPHER *EVP_aes_192_cfb1(void); const EVP_CIPHER *EVP_aes_192_cfb8(void); const EVP_CIPHER *EVP_aes_192_cfb128(void); # define EVP_aes_192_cfb EVP_aes_192_cfb128 const EVP_CIPHER *EVP_aes_192_ofb(void); const EVP_CIPHER *EVP_aes_192_ctr(void); const EVP_CIPHER *EVP_aes_192_ccm(void); const EVP_CIPHER *EVP_aes_192_gcm(void); const EVP_CIPHER *EVP_aes_192_wrap(void); const EVP_CIPHER *EVP_aes_192_wrap_pad(void); const EVP_CIPHER *EVP_aes_256_ecb(void); const EVP_CIPHER *EVP_aes_256_cbc(void); const EVP_CIPHER *EVP_aes_256_cfb1(void); const EVP_CIPHER *EVP_aes_256_cfb8(void); const EVP_CIPHER *EVP_aes_256_cfb128(void); # define EVP_aes_256_cfb EVP_aes_256_cfb128 const EVP_CIPHER *EVP_aes_256_ofb(void); const EVP_CIPHER *EVP_aes_256_ctr(void); const EVP_CIPHER *EVP_aes_256_ccm(void); const EVP_CIPHER *EVP_aes_256_gcm(void); const EVP_CIPHER *EVP_aes_256_xts(void); const EVP_CIPHER *EVP_aes_256_wrap(void); const EVP_CIPHER *EVP_aes_256_wrap_pad(void); [...] If I interpret my findings correctly, it should be a not too difficult task to extend php_openssl_get_evp_cipher_from_algo() so it knows also the existing OpenSSL functions EVP_aes_128_gcm() EVP_aes_192_gcm() EVP_aes_256_gcm() (and possibly further ciphers) You wrote "We just expose what OpenSSL gives us". Nothing more I want. Because of these findings, I dare to ask kindly to expose these AES GCM functions if they are available. (In my eyes my proposed change cannot break any existing application, so it can be done in a minor release (perhaps already in 7.2.25?). And in my eyes it is worth the effort because then an application can again use openssl_pkcs7_encrypt() to create a secure S/MIME encryted e-mail.) Thank you very much! :-)Thank you very much for your comments and your intense look at the problem! Just for completeness, if someone later stumbles across this bug report: Yes, we are talking about PKCS#7. Embedding the output of PKCS#7 encryption into a valid CMS e-mail is done by my calling PHP code and not a feature I request from the PHP function openssl_pkcs7_encrypt(). According to the man pages on openssl.org, PKCS7_encrypt() has this synopsis: » PKCS7 *PKCS7_encrypt(STACK_OF(X509) *certs, BIO *in, const EVP_CIPHER *cipher, int flags); « In the man page of PKCS7_encrypt(), there is only one restriction for the cipher parameter: » The algorithm passed in the cipher parameter must support ASN1 encoding of its parameters. « So according to this man page, passing the the result of EVP_aes_256_gcm() as third argument to PKCS7_encrypt() should be supported. But I didn't see one remark until now: On the man page »EVP_EncryptInit« for EVP_aes_256_gcm() and many similar functions, in the BUGS section, there is another important remark: » The ASN1 code is incomplete (and sometimes inaccurate) it has only been tested for certain common S/MIME ciphers (RC2, DES, triple DES) in CBC mode. « :-( I think it is still a security problem that encrypted S/MIME e-mails created with PHP are no longer secure. But unfortunately this problem cannot be fixed as long as OpenSSL does not support ASN1 for AES-GCM. Both OpenSSL and PHP need to be improved, first OpenSSL, then PHP, to fix it and it makes no sense to improve PHP before OpenSSL. So it is okay to close this bug; maybe it can be reopened when OpenSSL provides the necessary support. Thank you very much!