@@ -12,32 +12,69 @@ class Connector implements ConnectorInterface
1212{
1313 private $ loop ;
1414 private $ resolver ;
15+ private $ peerNameCtxKey ;
1516
1617 public function __construct (LoopInterface $ loop , Resolver $ resolver )
1718 {
1819 $ this ->loop = $ loop ;
1920 $ this ->resolver = $ resolver ;
21+ $ this ->peerNameCtxKey = PHP_VERSION_ID < 50600 ? 'CN_match ' : 'peer_name ' ;
2022 }
2123
22- public function create ($ host , $ port )
24+ /**
25+ * We need to set various context options related to the expected SSL certificate name here even though we
26+ * don't know whether we are creating an SSL connection or not, for compatibility with PHP<5.6.
27+ *
28+ * We don't specifically enable verify_peer or verify_peer_name here because these may require additional
29+ * options such as specifying a cafile etc, which means the user will need to do this manually.
30+ *
31+ * @param array $contextOpts
32+ * @param string $host
33+ * @return array
34+ */
35+ private function normalizeSSLContextOptions (array $ contextOpts , $ host )
36+ {
37+ // Allow the user to override the certificate peer name with the context option, unless it's a wildcard
38+ if (isset ($ contextOpts ['ssl ' ]['peer_name ' ]) && false === strpos ($ contextOpts ['ssl ' ]['peer_name ' ], '* ' )) {
39+ $ host = $ contextOpts ['ssl ' ]['peer_name ' ];
40+ } else if ($ contextOpts ['ssl ' ]['CN_match ' ] && false === strpos ($ contextOpts ['ssl ' ]['CN_match ' ], '* ' )) {
41+ $ host = $ contextOpts ['ssl ' ]['CN_match ' ];
42+ }
43+
44+ // Make sure that SNI requests the correct certificate name
45+ if (!isset ($ contextOpts ['ssl ' ]['SNI_enabled ' ])
46+ || $ contextOpts ['ssl ' ]['SNI_enabled ' ] && !isset ($ contextOpts ['ssl ' ]['SNI_server_name ' ])) {
47+ $ contextOpts ['ssl ' ]['SNI_enabled ' ] = true ;
48+ $ contextOpts ['ssl ' ]['SNI_server_name ' ] = $ host ;
49+ }
50+
51+ // Make sure PHP verifies the certificate name against the requested name
52+ if (!isset ($ contextOpts ['ssl ' ][$ this ->peerNameCtxKey ])) {
53+ $ contextOpts ['ssl ' ][$ this ->peerNameCtxKey ] = $ host ;
54+ }
55+
56+ // Disable TLS compression by default
57+ if (!isset ($ contextOpts ['ssl ' ]['disable_compression ' ])) {
58+ $ contextOpts ['ssl ' ]['disable_compression ' ] = true ;
59+ }
60+
61+ return $ contextOpts ;
62+ }
63+
64+ public function create ($ host , $ port , array $ contextOpts = [])
2365 {
2466 return $ this
2567 ->resolveHostname ($ host )
26- ->then (function ($ address ) use ($ port , $ host ) {
27- return $ this ->createSocketForAddress ($ address , $ port , $ host );
68+ ->then (function ($ address ) use ($ port , $ host , $ contextOpts ) {
69+ $ contextOpts = $ this ->normalizeSSLContextOptions ($ contextOpts , $ host );
70+ return $ this ->createSocketForAddress ($ address , $ port , $ contextOpts );
2871 });
2972 }
3073
31- public function createSocketForAddress ($ address , $ port , $ hostName = null )
74+ public function createSocketForAddress ($ address , $ port , array $ contextOpts = [] )
3275 {
3376 $ url = $ this ->getSocketUrl ($ address , $ port );
3477
35- $ contextOpts = array ();
36- if ($ hostName !== null ) {
37- $ contextOpts ['ssl ' ]['SNI_enabled ' ] = true ;
38- $ contextOpts ['ssl ' ]['SNI_server_name ' ] = $ hostName ;
39- }
40-
4178 $ flags = STREAM_CLIENT_CONNECT | STREAM_CLIENT_ASYNC_CONNECT ;
4279 $ context = stream_context_create ($ contextOpts );
4380 $ socket = stream_socket_client ($ url , $ errno , $ errstr , 0 , $ flags , $ context );
0 commit comments