PHP Websocket client + ssl - php

There is a PHP Websocket client: https://github.com/symbiose/php-websocket-client repository. And it works fine for not-secured connection.
What I need is to connect to a websocket server from php code through secure connection. To implement this task I took the code above and modified it a bit. The connect() method of WebSocketClient now looks like this in my code:
public function connect()
{
$root = $this;
if ($this->getPort() == 443) {
$context = stream_context_create();
stream_context_set_option($context, 'ssl', 'allow_self_signed', true);
stream_context_set_option($context, 'ssl', 'verify_peer', false);
$client = stream_socket_client("tls://{$this->getHost()}:{$this->getPort()}", $errno, $errstr, 30, STREAM_CLIENT_CONNECT, $context);
} else {
$client = stream_socket_client("tcp://{$this->getHost()}:{$this->getPort()}", $errno, $errstr);
}
if (!$client) {
throw new RuntimeException('Cannot connect to socket ([#'.$errno.'] '.$errstr.')');
}
$this->setSocket(new Connection($client, $this->getLoop()));
$this->getSocket()->on('data', function ($data) use ($root) {
$data = $root->parseIncomingRaw($data);
$root->parseData($data);
});
$this->getSocket()->write($this->createHeader());
return $this;
}
As a result I almost managed to connect to a server. Websocket server saw my connection, replied that everything is ok and wrote it to the log.
But unfortunately, the library doesn't understand, that it has successfully connected to the server.
This "if":
if (base64_encode(pack('H*', sha1($this->key . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'))) === $response['Sec-Websocket-Accept']) {
$this->connected = true;
}
never gets executed. And so I can't establish the connection.
I can also confirm, that if we use 80 port - everything works like a charm.
So if you have any ideas on why this can happen, i"d really really appreciate them. Cause I've already ran out of ideas.
Best regards,
Kostya

Related

Implement MQTT client using PHP to connect MQTT broker

I'm new to the PHP world, facing problem while connecting to MQTT.
I'm using the phpMQTT.php library, and I'm using the IP address to connect to the MQTT broker.
I'm trying to publish to MQTT broker, getting error in phpMQTT.php library file
The error is:
stream_socket_client(): unable to connect to tcp://...*:8083 (Connection timed out)
facing problem in below code:
if ($this->cafile) {
$socketContext = stream_context_create(["ssl" => [
"verify_peer_name" => true,
"cafile" => $this->cafile
]]);
$this->socket = stream_socket_client("tls://" . $this->address . ":" . $this->port, $errno, $errstr, 60, STREAM_CLIENT_CONNECT, $socketContext);
} else {
$this->socket = stream_socket_client("tcp://" . $this->address . ":" . $this->port, $errno, $errstr, 60, STREAM_CLIENT_CONNECT);
}
From the phpMQTT.php library
( source at https://github.com/bluerhinos/phpMQTT/blob/master/phpMQTT.php ) ,
you have to set the following details as shown in the source code.
/* sets the broker details */
function broker($address, $port, $clientid, $cafile = NULL){
$this->address = $address;
$this->port = $port;
$this->clientid = $clientid;
$this->cafile = $cafile;
}
If you have a firewall running - do open the port that you are using as well.

PHPSeclib Proxy send username and password as arguments

Im using PHPSECLIB to send a file and a XML to a SFTP server.
In this case the server im trying to reach is outside my work network.
To connect to the internet outside we have a proxy to do that.
What i need to do is configure the proxy of this connection to the one i need.
EDIT --
I have the following code, how can i pass the username and password of my proxy ?
$proxyHost = '******'
$fsock = fsockopen($proxyHost, $proxyPort);
$address = '*****';
$port = '*****';
$request = "CONNECT $address:$port HTTP/1.0\r\nContent-Length: 0\r\n\r\n";
if(fputs($fsock, $request) != strlen($request)) {
exit("premature termination");
}
$response = fgets($fsock);
$sftp = new SFTP($fsock);
.......
Quoting https://github.com/phpseclib/phpseclib/issues/1339#issuecomment-462224179:
With authorization:
$fsock = fsockopen('127.0.0.1', 80, $errno, $errstr, 1);
if (!$fsock) {
echo $errstr; exit;
}
fputs($fsock, "CONNECT website.com:22 HTTP/1.0\r\n");
fputs($fsock, "Proxy-Authorization: Basic " . base64_encode('user:pass') . "\r\n");
fputs($fsock, "\r\n");
while ($line = fgets($fsock, 1024)) {
if ($line == "\r\n") {
break;
}
//echo $line;
}
$ssh = new Net_SSH2($fsock);
$ssh->login('user', 'pass');
echo $ssh->exec('ls -latr');
If that doesn't work then run the script and tell me what the headers you get back are. Digest authentication is more of a PITA then Basic but it's not impossible.
More info on how authorization works with HTTP proxies:
https://www.rfc-editor.org/rfc/rfc7235#section-4.3

client side socket security using ssl in android

I am working on php socket server side using ssl security layer, It is working fine from php client side, now i want to connect my server with android client with ssl security layer. I am not getting any helpful solution which can connect with my php server through android client with ssl Authentication
My PHP server.php side code is given below
<?php
$ip="000.000.00.00"; //Set the TCP IP Address to listen on
$port="****"; //Set the TCP Port to listen on
$pem_passphrase = "password"; //Set a password here
$pem_file = "filename.pem"; //Set a path/filename for the PEM SSL Certificate which will be created.
$forkedSocket;
//The following array of data is needed to generate the SSL Cert
$pem_dn = array(
"countryName" => "IN", //Set your country name
"stateOrProvinceName" => "State", //Set your state or province name
"localityName" => "City", //Set your city name
"organizationName" => "Orgnization", //Set your company name
"organizationalUnitName" => "unit", //Set your department name
"commonName" => "hostname", //Set your full hostname.
"emailAddress" => "email#email.com" //Set your email address
);
//create ssl cert for this scripts life.
echo "Creating SSL Cert\n";
createSSLCert($pem_file, $pem_passphrase, $pem_dn);
//setup and listen to a tcp IP/port, returning the socket stream
echo "Listening to {$ip}:{$port} for connections\n";
$socket = setupTcpStreamServer($pem_file, $pem_passphrase, $ip, $port);
while(true){
//Accept any new connections
$forkedSocket = stream_socket_accept($socket, "-1", $remoteIp);
echo "New connection from $remoteIp\n";
//start SSL on the connection
stream_set_blocking ($forkedSocket, true); // block the connection until SSL is done.
stream_socket_enable_crypto($forkedSocket, true, STREAM_CRYPTO_METHOD_SSLv3_SERVER);
//enter a loop until an exit command is received.
$exit=false;
$i=1;
while($exit==false) {
//Read the command from the client. This will read 8192 bytes of data, If you need to read more you may need to increase this. However some systems will fragment the command over 8192 anyway, so you would instead need to write a loop waiting for the command input to end before proceeding.
$command = fread($forkedSocket, 8192);
echo "f_read success--".$command;
//unblock connection
stream_set_blocking ($forkedSocket, false);
//run a switch on the command to determine what we need to do
switch($command) {
CASE "exit";
$exit=true;
echo "exit command received \n";
fwrite($forkedSocket, "exit.... {$remoteIp}. -- $i finished connection"
);
//close the connection to the client
fclose($forkedSocket);
break;
default ;
//write back to the client a response.
fwrite($forkedSocket, "Hello {$remoteIp}. This is our $i command run!".$command );
$i++;
if($i==25){
$exit=true;
}
echo "command received \n";
break;
}
}
}
function createSSLCert($pem_file, $pem_passphrase, $pem_dn) {
//create ssl cert for this scripts life.
//Create private key
$privkey = openssl_pkey_new();
//Create and sign CSR
$cert = openssl_csr_new($pem_dn, $privkey);
$cert = openssl_csr_sign($cert, null, $privkey, 365);
//Generate PEM file
$pem = array();
openssl_x509_export($cert, $pem[0]);
openssl_pkey_export($privkey, $pem[1], $pem_passphrase);
$pem = implode($pem);
//Save PEM file
file_put_contents($pem_file, $pem);
chmod($pem_file, 0600);
}
function setupTcpStreamServer($pem_file, $pem_passphrase, $ip, $port) {
//setup and listen to a tcp IP/port, returning the socket stream
//create a stream context for our SSL settings
$context = stream_context_create();
//Setup the SSL Options
stream_context_set_option($context, 'ssl', 'local_cert', $pem_file); // Our SSL Cert in PEM format
stream_context_set_option($context, 'ssl', 'passphrase', $pem_passphrase); // Private key Password
stream_context_set_option($context, 'ssl', 'allow_self_signed', true);
stream_context_set_option($context, 'ssl', 'verify_peer', false);
//create a stream socket on IP:Port
$socket = stream_socket_server("tcp://{$ip}:{$port}", $errno, $errstr, STREAM_SERVER_BIND|STREAM_SERVER_LISTEN, $context);
stream_socket_enable_crypto($socket, false);
return $socket;
}
?>
and My Android CLient side code is
SocketFactory sf = SSLSocketFactory.getDefault();
SSLSocket socket = null;
// socket = (SSLSocket)
socket = (SSLSocket) sf.createSocket("000.000.00.00", 0000);
socket.addHandshakeCompletedListener(new HandshakeCompletedListener() {
#Override
public void handshakeCompleted(HandshakeCompletedEvent event) {
Log.e("logMessage", "handshake completed...");
}
});
if (socket.getEnableSessionCreation()) {
HostnameVerifier hv = HttpsURLConnection.getDefaultHostnameVerifier();
SSLSession s = socket.getSession();
if (!hv.verify("000.000.00.00", s)) {
Log.e("logMessage", "Failed....");
// throw new SSLHandshakeException("Expected mail.google.com, found " + s.getPeerPrincipal());
throw new SSLHandshakeException("Expected 000.000.00.00, found " + s.getPeerPrincipal());
} else {
//Toast.makeText(context, "verified", Toast.LENGTH_SHORT).show();
Log.e("logMessage", "verified...");
}
}else
{
Log.e("logMessage", "socket.getEnableSessionCreation() -- failed...");
}
// At this point SSLSocket performed certificate verification and
// we have performed hostname verification, so it is safe to proceed.
socket.close();
} catch (IOException e) {
e.printStackTrace();
}

APNS with Google App Engine and PHP SSL error

I am trying to send iOS push notifications from a PHP App Engine backend but I am receiving the following errors. I am not sure if there is a problem with the certificate, the way I'm doing it, or something specific to App Engine. This is my first time sending push notifications to iOS.
Here is my code :
$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'local_cert', 'ck.pem');
$fp = stream_socket_client(
'ssl://gateway.sandbox.push.apple.com:2195', $err,
$errstr, 60, STREAM_CLIENT_CONNECT|STREAM_CLIENT_PERSISTENT, $ctx);
if (!$fp)
{
//Handle Error
}
$body['aps'] = array(
'alert' => $data["message"],
'sound' => 'default',
);
$body["postID"] = $data["postID"];
$body["groupID"] = $data["groupID"];
$body["type"] = $data["type"];
$payload = json_encode($body);
foreach ($registrationIds as $registrationID)
{
$deviceToken = $registrationID;
$msg = chr(0) . pack('n', 32) . pack('H*', $deviceToken) . pack('n', strlen($payload)) . $payload;
$result = fwrite($fp, $msg, strlen($msg));
}
fclose($fp);
Here is the error I get :
PHP Warning: stream_socket_client(): SSL operation failed with code 1. OpenSSL
Error messages: error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake
failure in fakefile.php
I have no idea what the cause is. Thanks in Advance
UPDATE :
That is no longer the error I get. Now I get this :
PHP Warning: stream_socket_client(): unable to connect to ssl://gateway.sandbox.push.apple.com:2195 (Unknown error)
May be your port 2195 and 2196 are closed from server side that are blocking push notifications.
In stream_context_set_option you did not include the full path to the ck.pem file . After giving the full path there was no error.
Following is code may help to solve your problem.
$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'local_cert', '/Users/Development/Dev/ck.pem');
Following code for checking port is enable for Push notification.
<?php
chkServer('gateway.sandbox.push.apple.com', 2195);
//chkServer('gateway.push.apple.com',2195);
function chkServer($host, $port)
{
$hostip = #gethostbyname($host);
if ($hostip == $host) {
echo "Server is down or does not exist";
} else {
if (!$x = #fsockopen($hostip, $port, $errno, $errstr, 5)) {
echo "Port $port is closed.";
} else {
echo "Port $port is open.";
if ($x) {
#fclose($x);
}
}
}
}
?>
Happy coding.

APNS not sending response nor sending push notification

Apple's docs say that:
"If you send a notification and APNs finds the notification malformed or otherwise unintelligible, it returns an error-response packet prior to disconnecting. (If there is no error, APNs doesn’t return anything.) Figure 5-3 depicts the format of the error-response packet."
This leads me to believe that the only reason that APNS would not send something back is if what I sent them was in the correct format. However when I try to fread for their response I get a string of 0 length and when unpacked becomes null, which I assume means nothing has been written back to me.
I the stream was opened by stream_socket_client() and did not return false or throw an exception. I know that my fwrite successfully wrote 154 bytes to that stream as well. Why would there be no response from Apple?
Here is the code for connecting to APNS:
function openConnection() {
$streamContext = stream_context_create();
stream_context_set_option($streamContext, 'ssl', 'local_cert', $this->APNS_CERT);
stream_context_set_option($streamContext, 'ssl', 'passphrase', $this->Password);
$apns = stream_socket_client('ssl://' . $this -> APNS_HOST . ':' . $this -> APNS_PORT, $error, $errorString, 60, STREAM_CLIENT_CONNECT, $streamContext);
return $apns;
}
Then, in the next method after calling openConnection:
//open the connection to use with apple.
$apns = $this->openConnection();
$alert = $message['alert'];
$badge = $message['badge'];
$deviceToken = $message['deviceToken'];
$payload['aps'] = array(
'alert' => $message['alert'],
'badge' => $message['badge'],
'sound' => $message['sound']
);
if ($message['extraPayload'] != null) {
$payload['acme'] = $message['extraPayload'];
}
$encodedString = json_encode($payload);
//create message
$apnsMessage = chr(1) . pack("N", $message['identifier']) . pack("N", $message['expire']) . pack("n", 32) . pack('H*', str_replace(' ', '', $message['deviceToken'])) . pack("n",strlen($encodedString)) . $encodedString;
$write = fwrite($apns, $apnsMessage);
echo $write;
//the echo was just to see if it wrote.
if (!$apns) {
socket_close($apns);
fclose($apns);
echo "connection to APNS was lost.";
}
//look for changes. $null=null because some bug doesn't just let you pass null.
$null = null;
$changedStreams = stream_select($streamArray, $null, $null, 0, 1000000);
//check if it is actually false
if ($changedStreams === false) {
//close stream when done.
socket_close($apns);
fclose($apns);
echo "No response from APNs";
} elseif ($changedStreams > 0) {
//then check if what they sent back is an error and grab the error packet
$responseBinary = fread($apns, 6);
var_dump($responseBinary);
//check that it's the right thing
if ($responseBinary != false || strlen($responseBinary) == 6) {
//convert it from it's binary stream state and print.
$response = unpack('Ccommand/Cstatus_code/Nidentifier', $responseBinary);
var_dump($response);
//close stream when done.
socket_close($apns);
fclose($apns);
}
} else {
echo "Apple failed to respond, message was not sent.";
}
The var_dump at the end is NULL.
Edit:
Turns out it was an error with conflicting credentials. It was solved by creating a new pem file.
From that page:
You should regularly connect with the feedback web server and fetch the current list of those devices that have repeatedly reported failed-delivery attempts. Then you should cease sending notifications to the devices associated with those applications. See “The Feedback Service” for more information.
Feedback Service
Access to the feedback service takes place through a binary interface similar to that used for sending push notifications. You access the production feedback service via feedback.push.apple.com, port 2196; you access the sandbox feedback service via feedback.sandbox.push.apple.com, port 2196. As with the binary interface for push notifications, you must use TLS (or SSL) to establish a secured communications channel. The SSL certificate required for these connections is the same one that is provisioned for sending notifications. To establish a trusted provider identity, you should present this certificate to APNs at connection time using peer-to-peer authentication.

Categories