- Edited
Hello!
Using godot v4.3, I am trying to use TLS to implement secure authentication in game server, so both client and server are mine. Handling TCP connections provided by the StreamPeerTCP (connect_to_host
on client side and TCPServer::take_connection
on server side) in StreamPeerTLS
leads to an error TLS handshake error: -27648
, sometimes only in client, sometimes only on server and sometime on both.
I'm using self-signed certificate (and private key so on) generated by Godot. I read that error -27648
is something about certificate, but server has this error too, so I don't think that's the problem, but I tried to generate certificate using openssl, but the error remains. Also TLSOptions::client_unsafe
gave no results.
Below you can find my test code. I tried to implement server which just makes client message to_upper
and send it back.
Client side code:
extends Node
var _peer : StreamPeerTLS
var _last_status : StreamPeerTLS.Status
var _status_strings : Dictionary = {
StreamPeerTLS.STATUS_DISCONNECTED : "STATUS_DISCONNECTED",
StreamPeerTLS.STATUS_HANDSHAKING : "StreamPeerTLS.STATUS_HANDSHAKING",
StreamPeerTLS.STATUS_CONNECTED : "StreamPeerTLS.STATUS_CONNECTED",
StreamPeerTLS.STATUS_ERROR : "StreamPeerTLS.STATUS_ERROR",
StreamPeerTLS.STATUS_ERROR_HOSTNAME_MISMATCH : "StreamPeerTLS.STATUS_ERROR_HOSTNAME_MISMATCH"
}
func _ready() -> void:
var tcp_peer : StreamPeerTCP = StreamPeerTCP.new()
var err : Error = tcp_peer.connect_to_host("localhost", 7070)
if err != OK:
printerr("conenct: %s" % error_string(err))
return get_tree().quit(0)
var tls_options : TLSOptions = TLSOptions.client(load("res://server/game.crt"))
_peer = StreamPeerTLS.new()
err = _peer.connect_to_stream(tcp_peer, "localhost", tls_options)
if err != OK:
printerr("tls sonnect_to_stream: %s" % error_string(err))
get_tree().quit.call_deferred(1)
return
_last_status = _peer.get_status()
print("Peer created. Status is %s" % _status_strings[_last_status])
func _process(delta: float) -> void:
_peer.poll()
if _peer.get_status() != _last_status:
print("Peer status changed to %s" % _status_strings[_last_status])
_last_status = _peer.get_status()
if _peer.get_status() == StreamPeerTLS.STATUS_CONNECTED:
var data : PackedByteArray = _peer.get_data(_peer.get_available_bytes())
var str : String = data.get_string_from_ascii()
%ServerResponseLabel.append_text(str)
func _on_server_msg_edit_text_submitted(new_text: String) -> void:
if _peer.get_status() == StreamPeerTLS.STATUS_CONNECTED:
_peer.put_data(new_text.to_ascii_buffer())
else:
printerr("Not connected")
%ServerMsgEdit.clear()
Server code:
extends Node
var _tcp_server : TCPServer
var _tls_optinos : TLSOptions
var _connected_peers : Array[StreamPeerTLS] = []
var _status_strings : Dictionary = {
StreamPeerTLS.STATUS_DISCONNECTED : "STATUS_DISCONNECTED",
StreamPeerTLS.STATUS_HANDSHAKING : "StreamPeerTLS.STATUS_HANDSHAKING",
StreamPeerTLS.STATUS_CONNECTED : "StreamPeerTLS.STATUS_CONNECTED",
StreamPeerTLS.STATUS_ERROR : "StreamPeerTLS.STATUS_ERROR",
StreamPeerTLS.STATUS_ERROR_HOSTNAME_MISMATCH : "StreamPeerTLS.STATUS_ERROR_HOSTNAME_MISMATCH"
}
func _ready() -> void:
_tcp_server = TCPServer.new()
if _tcp_server.listen(7070) != OK:
printerr("listen")
return get_tree().quit(1)
_tls_optinos = TLSOptions.server(
load("res://server/game-private.key"), load("res://server/game.crt")
)
func _process(delta: float) -> void:
if _tcp_server.is_connection_available():
var connection : StreamPeerTCP = _tcp_server.take_connection()
var tls_peer : StreamPeerTLS = StreamPeerTLS.new()
if tls_peer.accept_stream(connection, _tls_optinos) != OK:
printerr("Error accepting peer %s:%d" % [connection.get_connected_host(), connection.get_connected_port()])
else:
var id : int = randi()
print("Peer %s:%d accepted with id = %d" % [connection.get_connected_host(), connection.get_connected_port(), id])
print("%d status is: %s" % [id, _status_strings[tls_peer.get_status()]])
tls_peer.set_meta("id", id)
_connected_peers.append(tls_peer)
for i:StreamPeerTLS in _connected_peers:
if i.get_status() != StreamPeerTLS.STATUS_CONNECTED and i.get_status() != StreamPeerTLS.STATUS_HANDSHAKING:
_connected_peers.erase.call_deferred(i)
continue
i.poll()
if not i.has_meta("last_status") or i.get_status() != i.get_meta("last_status"):
print("peer %d changed status to %s" % [i.get_meta("id"), _status_strings[i.get_status()]])
i.set_meta("last_status", i.get_status())
if i.get_status() == StreamPeerTLS.STATUS_CONNECTED:
var bytes : PackedByteArray = i.get_data(i.get_available_bytes())
var str : String = bytes.get_string_from_ascii()
%ClientsMessagesLabel.append_text(str)
str.to_upper()
i.put_data(str.to_ascii_buffer())
And generating crypto stuff:
extends Node
func _ready() -> void:
# don't forget to disable multi instanse before running this scene
var crypto : Crypto = Crypto.new()
var key : CryptoKey = crypto.generate_rsa(2048)
var cert : X509Certificate = crypto.generate_self_signed_certificate(key,
"CN=localhost,O=A Game Company,C=IT"
)
key.save("res://server/game-private.key")
cert.save("res://server/game.crt")
print("Generated")
Error:
(same on client and server)
Praying for help. You can find test project in attachments (its pretty simple, so comments isn't necessary). Thanks!
P. S. Also I tried to use different CN's, like localhost
, default myserver
, localhost:7070
. Error remains.