John Davidson

ssl - Secure Websockets in php - how to add certificate to script

0 comments
Message:


I'm trying to understand websockets. I have found excelent example on https://phppot.com/php/simple-php-chat-using-websocket/.


But got stuck implementing certificate to use it on wss. The example is based on socket_create() but to socket_set_option() certificate doesnt fit and i din't find how to combine that with stream_context_set_option() or stream_sockte_.... Is socket part of a stream? Am I missing something else.


Sorry not experienced in websockets nor ssl connection... I have googled for almost 2, days and not moved forward... Thank you for anything, that shifts me forward...


how can I combine


define('HOST_NAME',"localhost"); 
define('PORT',"8090");
$null = NULL;

require_once("class.chathandler.php");
$chatHandler = new ChatHandler();

$socketResource = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_set_option($socketResource, SOL_SOCKET, SO_REUSEADDR, 1);
socket_bind($socketResource, 0, PORT);
socket_listen($socketResource);


//with

$opts = array(
'http'=>array(
'local_cert'=>'/usr/local/etc/apache224/ssl.crt/www.mojehra.cz.crt',
'local_pk'=>'/usr/local/etc/apache224/ssl.key/www.mojehra.cz.key'
)
);

$context = stream_context_create($opts);

The full original example is below.


<?php
define('HOST_NAME',"localhost");
define('PORT',"8090");
$null = NULL;

require_once("class.chathandler.php");
$chatHandler = new ChatHandler();

$socketResource = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_set_option($socketResource, SOL_SOCKET, SO_REUSEADDR, 1);
socket_bind($socketResource, 0, PORT);
socket_listen($socketResource);

$clientSocketArray = array($socketResource);
while (true) {
$newSocketArray = $clientSocketArray;
socket_select($newSocketArray, $null, $null, 0, 10);

if (in_array($socketResource, $newSocketArray)) {
$newSocket = socket_accept($socketResource);
$clientSocketArray[] = $newSocket;

$header = socket_read($newSocket, 1024);
$chatHandler->doHandshake($header, $newSocket, HOST_NAME, PORT);

socket_getpeername($newSocket, $client_ip_address);
$connectionACK = $chatHandler->newConnectionACK($client_ip_address);

$chatHandler->send($connectionACK);

$newSocketIndex = array_search($socketResource, $newSocketArray);
unset($newSocketArray[$newSocketIndex]);
}

foreach ($newSocketArray as $newSocketArrayResource) {
while(socket_recv($newSocketArrayResource, $socketData, 1024, 0) >= 1){
$socketMessage = $chatHandler->unseal($socketData);
$messageObj = json_decode($socketMessage);

$chat_box_message = $chatHandler->createChatBoxMessage($messageObj->chat_user, $messageObj->chat_message);
$chatHandler->send($chat_box_message);
break 2;
}

$socketData = @socket_read($newSocketArrayResource, 1024, PHP_NORMAL_READ);
if ($socketData === false) {
socket_getpeername($newSocketArrayResource, $client_ip_address);
$connectionACK = $chatHandler->connectionDisconnectACK($client_ip_address);
$chatHandler->send($connectionACK);
$newSocketIndex = array_search($newSocketArrayResource, $clientSocketArray);
unset($clientSocketArray[$newSocketIndex]);
}
}
}
socket_close($socketResource);
?>

class


<?php
class ChatHandler {
function send($message) {
global $clientSocketArray;
$messageLength = strlen($message);
foreach($clientSocketArray as $clientSocket)
{
@socket_write($clientSocket,$message,$messageLength);
}
return true;
}

function unseal($socketData) {
$length = ord($socketData[1]) & 127;
if($length == 126) {
$masks = substr($socketData, 4, 4);
$data = substr($socketData, 8);
}
elseif($length == 127) {
$masks = substr($socketData, 10, 4);
$data = substr($socketData, 14);
}
else {
$masks = substr($socketData, 2, 4);
$data = substr($socketData, 6);
}
$socketData = "";
for ($i = 0; $i < strlen($data); ++$i) {
$socketData .= $data[$i] ^ $masks[$i%4];
}
return $socketData;
}

function seal($socketData) {
$b1 = 0x80 | (0x1 & 0x0f);
$length = strlen($socketData);

if($length <= 125)
$header = pack('CC', $b1, $length);
elseif($length > 125 && $length < 65536)
$header = pack('CCn', $b1, 126, $length);
elseif($length >= 65536)
$header = pack('CCNN', $b1, 127, $length);
return $header.$socketData;
}

function doHandshake($received_header,$client_socket_resource, $host_name, $port) {
$headers = array();
$lines = preg_split("/\r\n/", $received_header);
foreach($lines as $line)
{
$line = chop($line);
if(preg_match('/\A(\S+): (.*)\z/', $line, $matches))
{
$headers[$matches[1]] = $matches[2];
}
}

$secKey = $headers['Sec-WebSocket-Key'];
$secAccept = base64_encode(pack('H*', sha1($secKey . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')));
$buffer = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n" .
"Upgrade: websocket\r\n" .
"Connection: Upgrade\r\n" .
"WebSocket-Origin: $host_name\r\n" .
"WebSocket-Location: ws://$host_name:$port/demo/shout.php\r\n".
"Sec-WebSocket-Accept:$secAccept\r\n\r\n";
socket_write($client_socket_resource,$buffer,strlen($buffer));
}

function newConnectionACK($client_ip_address) {
$message = 'New client ' . $client_ip_address.' joined';
$messageArray = array('message'=>$message,'message_type'=>'chat-connection-ack');
$ACK = $this->seal(json_encode($messageArray));
return $ACK;
}

function connectionDisconnectACK($client_ip_address) {
$message = 'Client ' . $client_ip_address.' disconnected';
$messageArray = array('message'=>$message,'message_type'=>'chat-connection-ack');
$ACK = $this->seal(json_encode($messageArray));
return $ACK;
}

function createChatBoxMessage($chat_user,$chat_box_message) {
$message = $chat_user . ": <div class='chat-box-message'>" . $chat_box_message . "</div>";
$messageArray = array('message'=>$message,'message_type'=>'chat-box-html');
$chatMessage = $this->seal(json_encode($messageArray));
return $chatMessage;
}
}
?>

The author did not reply.



My Answer:
To add SSL support to your PHP WebSocket server, you need to use the `stream_socket_server` function instead of `socket_create` and `socket_bind`. Here's how you can modify your code to add SSL support:

1. Replace the socket creation and binding code with the following code:

php
$context = stream_context_create([
'ssl' => [
'local_cert' => '/usr/local/etc/apache224/ssl.crt/www.mojehra.cz.crt',
'local_pk' => '/usr/local/etc/apache224/ssl.key/www.mojehra.cz.key',
'verify_peer' => false, // You may need to set this to true if you want to verify the peer
]
]);

$socketResource = stream_socket_server('ssl://'.HOST_NAME.':'.PORT, $errno, $errstr, STREAM_SERVER_BIND|STREAM_SERVER_LISTEN, $context);
if (!$socketResource) {
die("Failed to create SSL socket: $errstr ($errno)");
}


2. Update the WebSocket handshake function to use the SSL context:

php
function doHandshake($received_header, $client_socket_resource, $host_name, $port) {
// Omitting the code for brevity
$buffer = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n" .
"Upgrade: websocket\r\n" .
"Connection: Upgrade\r\n" .
"WebSocket-Origin: $host_name\r\n" .
"WebSocket-Location: wss://$host_name:$port/demo/shout.php\r\n".
"Sec-WebSocket-Accept:$secAccept\r\n\r\n";
stream_socket_sendto($client_socket_resource, $buffer);
}


3. Make sure to update the WebSocket client to connect using `wss://` instead of `ws://` to establish a secure WebSocket connection.

By making these changes, your PHP WebSocket server should now support SSL connections. Remember to adjust the paths to your SSL certificate and key files accordingly.

Rate this post

4 of 5 based on 3086 votes

Comments




© 2024 Hayatsk.info - Personal Blogs Platform. All Rights Reserved.
Create blog  |  Privacy Policy  |  Terms & Conditions  |  Contact Us