Permalink
Browse files

Verify SSL certificates in fsockopen

Proving @mdawaffe wrong one commit at a time.
  • Loading branch information...
rmccue committed Aug 10, 2013
1 parent ab23228 commit 1b4336698f34cbbc56066bf081166068776480a7
Showing with 54 additions and 4 deletions.
  1. +54 −4 library/Requests/Transport/fsockopen.php
@@ -27,6 +27,8 @@ class Requests_Transport_fsockopen implements Requests_Transport {
*/
public $info;
+ protected $connect_error = '';
+
/**
* Perform a request
*
@@ -44,17 +46,48 @@ public function request($url, $headers = array(), $data = array(), $options = ar
$url_parts = parse_url($url);
$host = $url_parts['host'];
+ $context = stream_context_create();
+
+ // HTTPS support
if (isset($url_parts['scheme']) && strtolower($url_parts['scheme']) === 'https') {
- $host = 'ssl://' . $host;
+ $remote_socket = 'ssl://' . $host;
$url_parts['port'] = 443;
+
+ $context_options = array(
+ 'verify_peer' => true,
+ );
+ if (isset($options['verify'])) {
+ if ($options['verify'] === false) {
+ $context_options['verify_peer'] = false;
+ } elseif (is_string($options['verify'])) {
+ $context_options['cafile'] = $options['verify'];
+ }
+ }
+
+ $context = stream_context_create(array('ssl' => $context_options));
}
+ else {
+ $remote_socket = 'tcp://' . $host;
+ }
+
if (!isset($url_parts['port'])) {
$url_parts['port'] = 80;
}
- $fp = @fsockopen($host, $url_parts['port'], $errno, $errstr, $options['timeout']);
+ $remote_socket .= ':' . $url_parts['port'];
+
+ set_error_handler(array($this, 'connect_error_handler'), E_WARNING | E_NOTICE);
+ $fp = stream_socket_client($remote_socket, $errno, $errstr, $options['timeout'], STREAM_CLIENT_CONNECT, $context);
+ restore_error_handler();
+
if (!$fp) {
- throw new Requests_Exception($errstr, 'fsockopenerror');
- return;
+ if ($errno === 0) {
+ // Connection issue
+ throw new Requests_Exception(rtrim($this->connect_error), 'fsockopen.connect_error');
+ }
+ else {
+ throw new Requests_Exception($errstr, 'fsockopenerror');
+ return;
+ }
}
$request_body = '';
@@ -257,6 +290,23 @@ protected static function format_get($url_parts, $data) {
return $get;
}
+ /**
+ * Error handler for stream_socket_client()
+ *
+ * @param int $errno Error number (e.g. E_WARNING)
+ * @param string $errstr Error message
+ */
+ public function connect_error_handler($errno, $errstr) {
+ // Double-check we can handle it
+ if (($errno & E_WARNING) === 0 && ($errno & E_NOTICE) === 0) {
+ // Return false to indicate the default error handler should engage
+ return false;
+ }
+
+ $this->connect_error .= $errstr . "\n";
+ return true;
+ }
+
/**
* Whether this transport is valid
*

5 comments on commit 1b43366

@mdawaffe

This comment has been minimized.

Show comment Hide comment
@mdawaffe

mdawaffe Aug 10, 2013

Check out http://phpsecurity.readthedocs.org/en/latest/Transport-Layer-Security-(HTTPS-SSL-and-TLS).html#php-streams

That mentions we need to check CN_match as well. It also mentions that PHP doesn't support Subject Alternative Names in certs (I don't know how common those are). Maybe SAN verification is possible to do manually with capture_peer_cert. I have no idea :)

Check out http://phpsecurity.readthedocs.org/en/latest/Transport-Layer-Security-(HTTPS-SSL-and-TLS).html#php-streams

That mentions we need to check CN_match as well. It also mentions that PHP doesn't support Subject Alternative Names in certs (I don't know how common those are). Maybe SAN verification is possible to do manually with capture_peer_cert. I have no idea :)

@mdawaffe

This comment has been minimized.

Show comment Hide comment
@mdawaffe

mdawaffe Aug 10, 2013

I'm not familiar with this code's API. My guess is, though, that other transports just pass verify => true/false? This transport, though, will accept false/string to point to a CA bundle. If my guess is correct, it seems a little odd.

I'm not familiar with this code's API. My guess is, though, that other transports just pass verify => true/false? This transport, though, will accept false/string to point to a CA bundle. If my guess is correct, it seems a little odd.

@rmccue

This comment has been minimized.

Show comment Hide comment
@rmccue

rmccue Aug 10, 2013

Owner

Both this transport and cURL accept a boolean or a string to a CA bundle path. This accepts both true and false, but true is handled by the default context option there.

Owner

rmccue replied Aug 10, 2013

Both this transport and cURL accept a boolean or a string to a CA bundle path. This accepts both true and false, but true is handled by the default context option there.

@mdawaffe

This comment has been minimized.

Show comment Hide comment
@mdawaffe

mdawaffe Aug 10, 2013

PS: I love being proven wrong ;)

PS: I love being proven wrong ;)

@rmccue

This comment has been minimized.

Show comment Hide comment
@rmccue

rmccue Aug 10, 2013

Owner
Owner

rmccue replied Aug 10, 2013

Please sign in to comment.