I am attempting to create a server and client using PHP Sockets with SSL / TLS. However, when sending data to the server, I receive the following error:
PHP Warning: stream_socket_accept(): SSL_R_NO_SHARED_CIPHER: no suitable shared cipher could be used. This could be because the server is missing an SSL certificate (local_cert context option) in server.php on line 32
I've looked at other examples and tried various changes to no avail. Any help could be much appreciated.
client.php
<?php
$host = '192.168.10.10';
$port = 8080;
$timeout = 30;
$cert = 'assets/cert.pem';
$context = stream_context_create(
[ 'ssl'=> [ 'local_cert'=> $cert, "crypto_method" => STREAM_CRYPTO_METHOD_TLS_CLIENT ] ]
);
stream_context_set_option($context, 'ssl', 'allow_self_signed', true);
stream_context_set_option($context, 'ssl', 'verify_peer', false);
stream_context_set_option($context, 'ssl', 'verify_peer_name', false);
if ($socket = stream_socket_client( 'tls://'.$host.':'.$port, $errno, $errstr, 30, STREAM_CLIENT_CONNECT, $context) ) {
$meta = stream_get_meta_data($socket);
print_r( $meta );
fwrite($socket, "Hello, World!\n");
echo stream_socket_recvfrom($socket,8192);
fclose($socket);
} else {
echo "ERROR: $errno - $errstr\n";
}
server.php
<?php
// Set the ip and port we will listen on
$address = '192.168.10.10';
$port = 8080;
$cert = 'assets/cert.pem';
$context = stream_context_create();
stream_context_set_option($context, 'ssl', 'local_cert', $cert);
stream_context_set_option($context, 'ssl', 'crypto_method', STREAM_CRYPTO_METHOD_TLS_SERVER);
stream_context_set_option($context, 'ssl', 'allow_self_signed', true);
stream_context_set_option($context, 'ssl', 'verify_peer', false);
stream_context_set_option($context, 'ssl', 'verify_peer_name', false);
$server = stream_socket_server('tls://'.$address.':'.$port, $errno, $errstr, STREAM_SERVER_BIND|STREAM_SERVER_LISTEN, $context);
// Display server start time
echo "PHP Socket Server started at " . $address . " " . $port . ", at ". date( 'Y-m-d H:i:s' ) ."\n";
// loop and listen
while (true) {
/* Accept incoming requests and handle them as child processes */
$client = stream_socket_accept($server);
$ip = stream_socket_get_name( $client, true );
echo "New connection from " . $ip;
stream_set_blocking($client, true); // block the connection until SSL is done
stream_socket_enable_crypto($client, true, STREAM_CRYPTO_METHOD_TLS_SERVER);
// Read the input from the client – 1024 bytes
$input = fread($client, 1024);
// unblock connection
stream_set_blocking($client, false);
// Strip all white spaces from input
$output = preg_replace("[ \t\n\r]", "", $input) . "\0";
$new = $input;
// Display Date, IP and Msg received
echo date( 'Y-m-d H:i:s' ) . " | " . $ip . ": \033[0;32m" . $input . "\033[0m" . PHP_EOL;
fclose($client);
}
// Close the master sockets
socket_close($sock);
It turns out that the issue was related to OpenSSL and the transport streams available. The issue was resolved by:
1.0.2k
, to support TLS v1.2)Updating the code to use
tlsv1.2://
as the protocol on both the server and the client, e.g.and
Once the transport stream was updated to TLSv1.2, there was no need for the cipher option, and the scripts successfully negotiated a TLS connection.