-
Notifications
You must be signed in to change notification settings - Fork 27
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement TLS Sockets #19
Comments
I think this should be prioritized in mconnect. As of now, the KDE Connect Android app still supports the old crypto for compatibility with distributions that don't yet package modern versions of KDE Connect on the desktop, but we would like to drop support for it at some point. Also, the old encryption is unsafe against replay attacks and weak compared to TLS. |
Makes sense. I hope it will be much easier to implement. From initial investigation I have a feeling that we'll be able to dump openssl as a direct dependency and just stick to Gio. |
I've been playing with this a little bit. It seems like KDE Connect does a bit of a custom handshake which might not be compatible with First the server connects an SSL socket (in response to UDP Identity packet), then the socket opts are set like before (keepalive etc), then the server sends an Identity packet which the client responds to with a handshake (eg.
Hope that helps a bit. |
I haven't had time to learn Vala, but here's my GJS analog to open: function () {
log("DeviceChannel.open()");
this._socket = new Gio.Socket({
family: Gio.SocketFamily.IPV4,
type: Gio.SocketType.STREAM,
protocol: Gio.SocketProtocol.TCP
});
// Setup socket
this._socket.init(null);
this._socket.set_keepalive(true);
this._socket.set_option(6, 4, 10); // TCP_KEEPIDLE
this._socket.set_option(6, 5, 5); // TCP_KEEPINTVL
this._socket.set_option(6, 6, 3); // TCP_KEEPCNT
this._connection = new Gio.TcpConnection({ socket: this._socket });
this._connection.connect_async(
new Gio.InetSocketAddress({
address: this.device.tcpHost,
port: this.device.tcpPort
}),
null,
Lang.bind(this, this.opened) // Lang.bind is Javascript scope B.S.
);
},
opened: function (connection, res) {
log("DeviceChannel.opened()");
try {
if (!connection.connect_finish(res)) {
throw Error("failed to connect");
}
} catch (e) {
log("Error finishing connection: " + e);
this.emit("disconnected");
return;
}
// Send identity packet
let ident = new Packet.IdentityPacket();
ident.fromServer(this.device.manager);
let _out = new Gio.UnixOutputStream({
fd: this._socket.fd,
close_fd: false
});
_out.write(ident.toString() + "\n", null);
_out.close(null);
// TLS
let cert = Gio.TlsCertificate.new_from_files(
"tls/certificate.pem",
"tls/privateKey.pem"
);
// Redefine this._connection to the TLS connection
this._connection = Gio.TlsServerConnection.new(this._connection, cert);
this._connection.validation_flags = 0;
this._connection.authentication_mode = 1;
this._connection.connect("accept-certificate", (conn, peer_cert, flags) => {
if (this.device.paired) {
// If the device is already paired, we can compare the connection
// certificate to the one we have saved to disk
let paired_cert = Gio.TlsCertificate.new_from_file(
"device_config_path/certificate.pem"
);
return (paired_cert.verify(null, peer_cert) === 0);
} else {
// If the device isn't paired, we store the Gio.TlsCertificate in a variable
// and later save it to disk if we accept or send a pair request.
this._peer_cert = peer_cert;
return true;
}
});
this._connection.handshake(null);
// Streams
this._in = new Gio.DataInputStream({
base_stream: this._connection.input_stream,
newline_type: Gio.DataStreamNewlineType.LF
});
this._out = new Gio.DataOutputStream({
base_stream: this._connection.output_stream
});
// There is no Gio.Socket.create_source() in GJS, but you get it
this._monitor = this._in.base_stream.create_source(null);
this._monitor.set_callback(Lang.bind(this, this._io_ready));
this._monitor.attach(null);
} |
Thanks, this looks really helpful. |
I updated the code snippet above, so it now includes certificate verification stuff. Apparently:
So in my test code for pairing (not included above) I just checked if a |
Hey Andy, You got it right :) The idea is to use TOFU (trust on first use), like in SSH or other protocols. If you have any questions feel free to ask here (I'm watching the thread) or on the kdeconnect mailing list (https://mail.kde.org/mailman/listinfo/kdeconnect). Albert |
Hey Albert, Thanks for checking in and glad to hear I got it right (I'm kind of any everything newb), I'll let you know if I have any more questions. |
@albertvaka @andyholmes thanks for your input. Since we're bound to use GLib.TlsConnection anyway I have spent a couple of hours trying to get rid of explicit dependency on openssl and use GnuTLS instead. GnuTLS is a dependency of glib-networking (a package that delivers Gio TlsConnection classes). Well, tough luck, turns out |
That's too bad, I seem to recall a similar comment in the kdeconnect code somewhere, lamenting the need for another dependency. FWIW, on Ubuntu/Debian |
I'm a bit surprised how inconvenient generating self signed certificates with GnuTLS is. I managed to generate the private key with relative ease, but self signed certificate seems to be a whole new level. Makes me a bit envious of the Qt version. It's nice and clean. Once I fixed |
Please share the fixed gnutls.vapi, I know a contributor that wants to fix it and keep it up to date |
@albertvaka any idea what might be causing this?
on |
@bboozzoo This may be caused by |
I'm past that step, mconnect is already connected and identity packet was sent. The error happens when the code starts TLS handshake. KDE connect code does a bit of magic:
I tried setting |
Isn't that represented in gnutls with a priority string ? |
Yes, that's what |
To make things more interesting, my ArchLinux laptop can do TLS handshake just fine:
OpenSUSE Tumbleweed can not 😒 |
I don't anything about TLS, but here is my exact Device Channel code in GJS that works reliably for me: https://gist.github.com/andyholmes/159a6fb628dcc926518d1b129e345f47 I'm on Ubuntu 17.04, GnuTLS 3.5.6-4ubuntu4.2 |
Got it mostly working in Tumbleweed problem is still bugging me though. Thought that maybe it is caused by recent update to GNOME 3.26 in TW, like a regression in |
Cool, I've discovered file transfers can use the same type of connection, minus the identity packet, except downloads need to be wrapped in a Gio.TlsClientConnection. |
Something totally weird that I stumbled upon. First, I compared GnuTLS handshake logs between Arch and Tumbleweed, no luck here. However, when I regenerated the certificate on the Tumbleweed box, the problem was gone. Copying the old certficate/key to Arch setup I was able to reproduce the problem. So, for some unexplained reason, the certificate/key pair generated by openssl is bad or loading this bundle through GnuTLS causes issues. Comparing |
Pushed some changes that introduce direct dependency on GnuTLS for generating certificate and key. Finally after digging through documentation and @desiderantes updated gnutls.vapi file is in |
This should be fairly complete now. Device connection is rather stable, didn't notice anything unusual. What might be useful for the shell integration is that device certificates are accessible through DBus as |
Could be, (current) desktop and android KDE Connect clients present the local and remote SHA fingerprints for verification. Can that be extracted on the backend as well? |
Yes. Do you know if the fingerprint is SHA1 or SHA256? |
The android app says SHA1 |
Pushed a couple of patches:
|
Cool, I've been trying to follow along a bit in GJS just for fun, and just opened this bug here: Bug 788315 - Implement 'fingerprint()' function on Gio.TlsCertificate Must be nice having the full GLib and C libraries available ;) |
The code is now in master, closing this ticket. |
Just reporting so it's on the roadmap. TLS/SSL came with protocolVersion 6 and Android client is kept up to date in Play Store and F-Droid. Here's some relevant links to kdeconnect source:
TLS setup:
https://github.com/KDE/kdeconnect-kde/blob/master/core/backends/lan/lanlinkprovider.cpp#L417-L445
Testing for protocolVersion >= 6 (Android client is v7):
https://github.com/KDE/kdeconnect-kde/blob/master/core/backends/lan/lanlinkprovider.cpp#L254-L278
The text was updated successfully, but these errors were encountered: