Skip to content

Commit 387d48f

Browse files
committed
Fix SSL handling when server does not support TLS
1 parent 6c9f603 commit 387d48f

File tree

2 files changed

+54
-50
lines changed

2 files changed

+54
-50
lines changed

ChangeLog.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@ HTTP protocol support for the XP Framework ChangeLog
33

44
## ?.?.? / ????-??-??
55

6+
## 9.1.4 / 2019-12-24
7+
8+
* Fixed SSL handling when the server does not support TLS, see PR #25
9+
(@patzerr, @thekid).
10+
611
## 9.1.3 / 2019-12-24
712

813
* Fixed HTTP *HEAD* requests when using `ext/curl` - @patzerr, @thekid
Lines changed: 49 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
<?php namespace peer\http;
22

33
use io\IOException;
4-
use peer\SSLSocket;
5-
use peer\TLSSocket;
4+
use peer\CryptoSocket;
5+
use peer\URL;
6+
use util\Objects;
67

78
/**
89
* Transport via SSL sockets
@@ -12,6 +13,23 @@
1213
* @see xp://peer.http.HttpConnection
1314
*/
1415
class SSLSocketHttpTransport extends SocketHttpTransport {
16+
private static $crypto= [
17+
'tls' => STREAM_CRYPTO_METHOD_TLS_CLIENT,
18+
'tlsv10' => STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT,
19+
'tlsv11' => STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT,
20+
'tlsv12' => STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT,
21+
'sslv3' => STREAM_CRYPTO_METHOD_SSLv3_CLIENT,
22+
'sslv23' => STREAM_CRYPTO_METHOD_SSLv23_CLIENT,
23+
'sslv2' => STREAM_CRYPTO_METHOD_SSLv2_CLIENT
24+
];
25+
26+
static function __static() {
27+
28+
// See https://github.com/php/php-src/commit/5c05f5e6d3d31a03c152fe90697bdc3e33193ced, PHP 7.4+
29+
if (defined('STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT')) {
30+
self::$crypto['tlsv13']= STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT;
31+
}
32+
}
1533

1634
/**
1735
* Creates a socket - overridden from parent class
@@ -20,32 +38,16 @@ class SSLSocketHttpTransport extends SocketHttpTransport {
2038
* @param string $arg
2139
* @return peer.Socket
2240
*/
23-
protected function newSocket(\peer\URL $url, $arg) {
24-
if ('tls' === $arg) {
25-
return new TLSSocket($url->getHost(), $url->getPort(443), null);
41+
protected function newSocket(URL $url, $arg) {
42+
$socket= new CryptoSocket($url->getHost(), $url->getPort(443));
43+
if (null === $arg) {
44+
$socket->cryptoImpl= STREAM_CRYPTO_METHOD_ANY_CLIENT;
45+
} else if ('v' === $arg[0]) {
46+
$socket->cryptoImpl= self::$crypto['ssl'.$arg];
2647
} else {
27-
sscanf($arg, 'v%d', $version);
28-
return new SSLSocket($url->getHost(), $url->getPort(443), null, $version);
29-
}
30-
}
31-
32-
/**
33-
* Enable cryptography on a given socket
34-
*
35-
* @param peer.Socket $s
36-
* @param [:int] $methods
37-
* @return void
38-
* @throws io.IOException
39-
*/
40-
protected function enable($s, $methods) {
41-
$handle= $s->getHandle();
42-
foreach ($methods as $name => $method) {
43-
if (stream_socket_enable_crypto($handle, true, $method)) {
44-
$this->cat && $this->cat->debug('@@@ Enabling', $name, 'cryptography');
45-
return;
46-
}
48+
$socket->cryptoImpl= self::$crypto[$arg];
4749
}
48-
throw new IOException('Cannot establish secure connection, tried '.implode(', ', array_keys($methods)));
50+
return $socket;
4951
}
5052

5153
/**
@@ -54,44 +56,41 @@ protected function enable($s, $methods) {
5456
* @param peer.Socket $s Connection to proxy
5557
* @param peer.http.HttpRequest $request
5658
* @param peer.URL $url
59+
* @return void
5760
* @throws io.IOException
5861
*/
5962
protected function proxy($s, $request, $url) {
60-
static $methods= [
61-
'tls://' => STREAM_CRYPTO_METHOD_TLS_CLIENT,
62-
'tlsv10://' => STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT,
63-
'tlsv11://' => STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT,
64-
'tlsv12://' => STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT,
65-
'sslv3://' => STREAM_CRYPTO_METHOD_SSLv3_CLIENT,
66-
'sslv23://' => STREAM_CRYPTO_METHOD_SSLv23_CLIENT,
67-
'sslv2://' => STREAM_CRYPTO_METHOD_SSLv2_CLIENT,
68-
];
69-
7063
$connect= sprintf(
7164
"CONNECT %1\$s:%2\$d HTTP/1.1\r\nHost: %1\$s:%2\$d\r\n\r\n",
7265
$url->getHost(),
7366
$url->getPort(443)
7467
);
7568
$this->cat && $this->cat->info('>>>', substr($connect, 0, strpos($connect, "\r")));
7669
$s->write($connect);
70+
71+
// Verify we are actually talking to a HTTP proxy
7772
$handshake= $s->read();
73+
if (4 !== ($r= sscanf($handshake, "HTTP/%*d.%*d %d %[^\r]", $status, $message))) {
74+
throw new IOException('Proxy did not answer with valid HTTP: '.$handshake);
75+
}
7876

79-
if (4 === ($r= sscanf($handshake, "HTTP/%*d.%*d %d %[^\r]", $status, $message))) {
80-
while ($line= $s->readLine()) { $handshake.= $line."\n"; }
81-
$this->cat && $this->cat->info('<<<', $handshake);
77+
// Verify proxy answers with a 200 status code
78+
while ($line= $s->readLine()) $handshake.= $line."\n";
79+
$this->cat && $this->cat->info('<<<', $handshake);
80+
if (200 !== $status) {
81+
throw new IOException('Cannot connect through proxy: #'.$status.' '.$message);
82+
}
8283

83-
if (200 === $status) {
84-
stream_context_set_option($s->getHandle(), 'ssl', 'peer_name', $url->getHost());
85-
if (isset($methods[$this->socket->_prefix])) {
86-
$this->enable($s, [$this->socket->_prefix => $methods[$this->socket->_prefix]]);
87-
} else {
88-
$this->enable($s, $methods);
89-
}
90-
} else {
91-
throw new IOException('Cannot connect through proxy: #'.$status.' '.$message);
84+
// Enable cryptography
85+
stream_context_set_option($s->getHandle(), 'ssl', 'peer_name', $url->getHost());
86+
if (!stream_socket_enable_crypto($s->getHandle(), true, $this->socket->cryptoImpl)) {
87+
$methods= '';
88+
foreach (self::$crypto as $name => $flag) {
89+
if ($flag === $this->socket->cryptoImpl & $flag) $methods.= ', '.$name;
9290
}
93-
} else {
94-
throw new IOException('Proxy did not answer with valid HTTP: '.$handshake);
91+
throw new IOException('Cannot establish secure connection, tried '.substr($methods, 2));
9592
}
93+
94+
$this->cat && $this->cat->debug('@@@ Enabled cryptography: '.Objects::stringOf(stream_get_meta_data($s->getHandle())['crypto']));
9695
}
9796
}

0 commit comments

Comments
 (0)