ZF-5524: Zend_Http_Client_Adapter_Proxy doesn't support SSL Client Certificate
Description
Although Zend_Http_Client_Adapter_Socket fully support SSL Client certificate authentication, Zend_Http_Client_Adapter_Proxy doesn't.
in the write() method of Zend_Http_Client_Adapter_Proxy, there is a call to method connectHandshake() if protocol is HTTPS.
This method tries to send a CONNECT query to the proxy server and then, if ok, switch to crypto with PHP function stream_socket_enable_crypto().
This fails if the remote server requires a SSL client certificate to be presented.
The stream_socket_enable_crypto() function is not well documented but it seems that an additional parameter allows to pass the context of another socket (including a local cert) to the function.
In the connecHandshake() method, I changed the code here:
$success = false;
foreach($modes as $mode) {
$success = stream_socket_enable_crypto($this->socket, true, $mode);
if ($success) break;
}
to:
$context = stream_context_create();
if (! stream_context_set_option($context, 'ssl', 'local_cert', 'path/to/my/local_cert')) {
die ('unable to set SSL cert');
}
$socket = stream_socket_client($host . ':' . $port, $errno,$errstr, (int) $this->config['timeout'], STREAM_CLIENT_CONNECT, $context);
if ($socket === false) {
die('Unable to set socket');
}
$success = false;
foreach($modes as $mode) {
$success = stream_socket_enable_crypto($this->socket, true, $mode, $socket);
if ($success) break;
}
Currently, the apache child dies when processing this patched adapter (Apache 2.2.8 + PHP 5.2.8 on Ubuntu 8.04)
Is it a valid method to achieve what I aim to? If positive, what is going wrong?
Comments
Posted by Shahar Evron (shahar) on 2009-07-23T15:44:01.000+0000
Sorry for taking so long with this :)
Recent improvements to HTTP client allowed me to implement this by reducing most of the code in the connect() method, and simply relying on preset stream context for this task.
This should now not be any different than using the Socket adapter with an SSL certificate - you can also look at the setStreamContext and getStreamContext methods for this, if you need "advanced" stuff like peer certificate validation forcing.
Fixed in CS-17013
Posted by Mikko Koppanen (mkoppanen) on 2009-08-26T04:48:33.000+0000
This change breaks backwards compatibility.
http://framework.zend.com/code/browse/…
At least in our environment there is no tcp:// prefix there as it is not required as far as I understand.
Posted by Mikko Koppanen (mkoppanen) on 2009-08-26T04:56:34.000+0000
Changing the line to:
if (($this->connected_to[0] != "tcp://$host" && $this->connected_to[0] != $host) || $this->connected_to[1] != $port) {
Seems to fix this in our environment.
Posted by Shahar Evron (shahar) on 2009-08-26T05:37:34.000+0000
Reopening following previous comment
Posted by Mikko Koppanen (mkoppanen) on 2009-08-26T06:15:15.000+0000
To actually fix the functionality:
http://pastebin.com/m604f9746
Posted by Mikko Koppanen (mkoppanen) on 2009-11-19T02:05:12.000+0000
I commented that this bug breaks backwards compatibility and it's still present in 1.9.5
Posted by Pádraic Brady (padraic) on 2009-11-19T12:37:00.000+0000
Mikko,
Can you repost the fix you added on pastebin? The paste ID is no longer valid. I'll commit tomorrow once I have a fix I can run tests against.
Posted by Mikko Koppanen (mkoppanen) on 2009-11-19T13:09:59.000+0000
The following code can be used to test the issue:
The whole issue explained briefly:
Zend_Http_Client_Adapter_Proxy calls the parent::connect method setting $secure = false. This means that ssl context is not created for the connection. This is problematic in a scenario where the connection to proxy is over plain but SSL stream using client certs is negotiated inside that connection.
The proposed fix:
The issue can be tested using CA setup mentioned here (http://sial.org/howto/openssl/ca/) and setting up for example apache to require the client certificate to be present. Note that this seems to only affect proxy adapter.
Posted by Pádraic Brady (padraic) on 2010-02-06T09:06:58.000+0000
Fixed in r20946
Posted by Lorenzo Alberton (quipo) on 2010-06-14T08:33:00.000+0000
This issue is not completely fixed in 1.10.5: the
'sslusecontext' => false
entry is missing from the
protected $config = array()
causing a NOTICE (Undefined index sslusecontext) on line 92:
if ($secure || $this->config['sslusecontext']) {
Posted by Marco Kaiser (bate) on 2010-06-16T02:06:14.000+0000
next release should address this issue. There was one line missing in the merge
Posted by Pádraic Brady (padraic) on 2010-06-19T13:12:42.000+0000
Reopen due to misapplied patch
Posted by Pádraic Brady (padraic) on 2010-06-19T13:20:48.000+0000
Missing lines previously committed to release branch by bate.
Note: If an issue is technically not fixed, it is fine to reopen it until properly resolved. Thanks for reporting the missing line!