php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #73478 openssl_pkey_new() generates wrong pub/priv keys with Diffie Hellman
Submitted: 2016-11-08 16:53 UTC Modified: 2016-11-15 14:52 UTC
From: enrico at zimuel dot it Assigned: bukka (profile)
Status: Closed Package: OpenSSL related
PHP Version: 7.1.0RC5 OS: Ubuntu 16.04
Private report: No CVE-ID: None
 [2016-11-08 16:53 UTC] enrico at zimuel dot it
Description:
------------
I'm testing the zendframework/zend-crypt library using PHP7.1.0RC5 and I found an issue on  openssl_pkey_new() using the Diffie Hellman key generator. Using the same parameters the output (public and private keys) is different for each execution.   
I tested the test scripts on PHP 7.0.8, 7.0.4, 5.6.20 and it works fine.
I'm using OpenSSL 1.0.2g 1 Mar 2016.

Test script:
---------------
$details = [
  'p' => base64_decode('3Pk6C4g5cuwOGZiaxaLOMQ4dN3F+jZVxu3Yjcxhm5h73Wi4niYsFf5iRwuJ6Y5w/KbYIFFgc07LKOYbSaDcFV31FwuflLcgcehcYduXOp0sUSL/frxiCjv0lGfFOReOCZjSvGUnltTXMgppIO4p2Ij5dSQolfwW9/xby+yLFg6s='),
  'g' => base64_decode('Ag=='),
  'priv_key' => base64_decode('jUdcV++P/m7oUodWiqKqKXZVenHRuj92Ig6Fmzs7QlqVdUc5mNBxmEWjug+ObffanPpOeab/LyXwjNMzevtBz3tW4oROau++9EIMJVVQr8fW9zdYBJcYieC5l4t8nRj5/Uu/Z0G2rWVLBleSi28mqqNEvnUs7uxYxrar69lwQYs=')
];

$opensslKeyResource = openssl_pkey_new(['dh' => $details]);
$data = openssl_pkey_get_details($opensslKeyResource);

printf("Private key:\n%s\n", base64_encode($data['dh']['priv_key']));
printf("Public key:\n%s\n", base64_encode($data['dh']['pub_key']));

Expected result:
----------------
Private key:
jUdcV++P/m7oUodWiqKqKXZVenHRuj92Ig6Fmzs7QlqVdUc5mNBxmEWjug+ObffanPpOeab/LyXwjNMzevtBz3tW4oROau++9EIMJVVQr8fW9zdYBJcYieC5l4t8nRj5/Uu/Z0G2rWVLBleSi28mqqNEvnUs7uxYxrar69lwQYs=
Public key:
0DmJUe9dr02pAtVoGyLHdC+rfBU3mDCelKGPXRDFHofx6mFfN2gcZCmp/ab4ezDXfpIBOatpVdbn2fTNUGo64DtKE2WGTsZCl90RgrGUv8XW/4WDPXeE7g5u7KWHBG/LCE5+XsilE5P5/GIyqr9gsiudTmk+H/hiYZl9Smar9k0=

Actual result:
--------------
The output is different for each execution, for instance this is one:

Private key:
fSv1nExIL8OaVzXIpKCw7YA3w9t5onYM9LR9glI2XEXttltLdfi2/l87iMsOeW+7aeNvGg97DtVC6xbiXmz7UrEyn1sLynauxTGF35xRCL2yCiYdbqcwDpzc2Xj31ggRjhZYTdf8BnM2kIUzTwt733+P0bDB0OhkAz07DvKahz4=
Public key:
S2/Lci8eLGt/ayV3faOJGb6daczG0z55VCoy9eHFhDqy6KHcPiPSnaF/GLyG5bhnlNgLeI9eU/yEIR6A8m+6Crd51A08itmmU2A6dhMtjbT8LYSHCQ1RlBcoasfEahhEltNZFErxl8whVPRXBrwDyZKwCmHu+AJYpoSTQFA6y4I=

Patches

Add a Patch

Pull Requests

Pull requests:

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2016-11-09 18:45 UTC] enrico at zimuel dot it
The error is reported also on Travis CI here:
https://travis-ci.org/ezimuel/zend-crypt/jobs/174568786#L329
 [2016-11-11 11:00 UTC] mhagstrand at gmail dot com
I have put in a pull request to fix this issue.
https://github.com/php/php-src/pull/2197
 [2016-11-13 18:51 UTC] bukka@php.net
-Status: Open +Status: Assigned -Assigned To: +Assigned To: bukka
 [2016-11-13 18:51 UTC] bukka@php.net
I see the issue. However this is no longer allowed in OpenSSL 1.1 - we can't set only priv_key to the DH struct: 

https://github.com/openssl/openssl/blob/e2cefab06a9e1b8d9a21d030754f62dfbb199950/crypto/dh/dh_lib.c#L251

So the question is if we should have support for that only when compiled with OpenSSL 1.0.x (and have a different behaviour between versions) or we should keep it failing and create a BC break but have it consistent between OpenSSL versions.

It means I can add something like this:

------------------------------------------------
diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c
index 528d823..94c50b7 100644
--- a/ext/openssl/openssl.c
+++ b/ext/openssl/openssl.c
@@ -4108,6 +4108,11 @@ zend_bool php_openssl_pkey_init_dh(DH *dh, zval *data)
        if (pub_key) {
                return DH_set0_key(dh, pub_key, priv_key);
        }
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+       if (priv_key) {
+               DH_set0_key(dh, NULL, priv_key);
+       }
+#endif
 
        /* generate key */
        PHP_OPENSSL_RAND_ADD_TIME();
------------------------------------------------

However the test for this bug will work only with 1.0.x and would have to be skipped for 1.1 so not sure if it's a good idea...

Thoughts?
 [2016-11-15 14:52 UTC] enrico at zimuel dot it
If OpenSSL 1.1 doesn't allow to pass only the priv_key, this means we can use the openssl_pkey_new() for Diffie Hellman (dh) only with p (prime) and g (generator) inputs.
 [2016-11-20 20:06 UTC] bukka@php.net
Automatic comment on behalf of bukka
Revision: http://git.php.net/?p=php-src.git;a=commit;h=ce4869f0388e500abf39094ab48ae6769a2ed71f
Log: Fix bug #73478 (openssl_pkey_new() generates wrong pub/priv keys with Diffie Hellman)
 [2016-11-20 20:06 UTC] bukka@php.net
-Status: Assigned +Status: Closed
 [2016-11-20 20:08 UTC] bukka@php.net
Automatic comment on behalf of bukka
Revision: http://git.php.net/?p=php-src.git;a=commit;h=ce4869f0388e500abf39094ab48ae6769a2ed71f
Log: Fix bug #73478 (openssl_pkey_new() generates wrong pub/priv keys with Diffie Hellman)
 [2016-11-30 23:14 UTC] davey@php.net
Automatic comment on behalf of bukka
Revision: http://git.php.net/?p=php-src.git;a=commit;h=ce4869f0388e500abf39094ab48ae6769a2ed71f
Log: Fix bug #73478 (openssl_pkey_new() generates wrong pub/priv keys with Diffie Hellman)
 
PHP Copyright © 2001-2017 The PHP Group
All rights reserved.
Last updated: Sun Nov 19 01:31:42 2017 UTC