Skip to content

Commit

Permalink
Allow certificates from unknown CAs from .onion domains
Browse files Browse the repository at this point in the history
It's barely possible for .onion servers to provide a non-self-signed cert. But that's fine because encryption is provided independently though TOR.

see #958
  • Loading branch information
fiaxh committed Dec 31, 2020
1 parent 99e98ac commit 81a5505
Show file tree
Hide file tree
Showing 8 changed files with 57 additions and 17 deletions.
14 changes: 13 additions & 1 deletion libdino/src/service/connection_manager.vala
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,9 @@ public class ConnectionManager : Object {
connection_directly_retry[account] = false;

change_connection_state(account, ConnectionState.CONNECTING);
stream_result = yield Xmpp.establish_stream(account.bare_jid, module_manager.get_modules(account, resource), log_options);
stream_result = yield Xmpp.establish_stream(account.bare_jid, module_manager.get_modules(account, resource), log_options,
(_, peer_cert, errors) => { return on_invalid_certificate(account.domainpart, peer_cert, errors); }
);
connections[account].stream = stream_result.stream;

connection_ongoing[account] = false;
Expand Down Expand Up @@ -368,6 +370,16 @@ public class ConnectionManager : Object {
connection_errors[account] = error;
connection_error(account, error);
}

public static bool on_invalid_certificate(string domain, TlsCertificate peer_cert, TlsCertificateFlags errors) {
if (domain.has_suffix(".onion") && errors == TlsCertificateFlags.UNKNOWN_CA) {
// It's barely possible for .onion servers to provide a non-self-signed cert.
// But that's fine because encryption is provided independently though TOR.
warning("Accepting TLS certificate from unknown CA from .onion address %s", domain);
return true;
}
return false;
}
}

}
16 changes: 12 additions & 4 deletions libdino/src/service/registration.vala
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ public class Register : StreamInteractionModule, Object{
list.add(new Iq.Module());
list.add(new Sasl.Module(account.bare_jid.to_string(), account.password));

XmppStreamResult stream_result = yield Xmpp.establish_stream(account.bare_jid.domain_jid, list, Application.print_xmpp);
XmppStreamResult stream_result = yield Xmpp.establish_stream(account.bare_jid.domain_jid, list, Application.print_xmpp,
(_, peer_cert, errors) => { return ConnectionManager.on_invalid_certificate(account.domainpart, peer_cert, errors); }
);

if (stream_result.stream == null) {
if (stream_result.tls_errors != null) {
Expand Down Expand Up @@ -80,7 +82,9 @@ public class Register : StreamInteractionModule, Object{
Gee.List<XmppStreamModule> list = new ArrayList<XmppStreamModule>();
list.add(new Iq.Module());

XmppStreamResult stream_result = yield Xmpp.establish_stream(jid.domain_jid, list, Application.print_xmpp);
XmppStreamResult stream_result = yield Xmpp.establish_stream(jid.domain_jid, list, Application.print_xmpp,
(_, peer_cert, errors) => { return ConnectionManager.on_invalid_certificate(jid.domainpart, peer_cert, errors); }
);

if (stream_result.stream == null) {
if (stream_result.io_error != null) {
Expand Down Expand Up @@ -125,7 +129,9 @@ public class Register : StreamInteractionModule, Object{
list.add(new Iq.Module());
list.add(new Xep.InBandRegistration.Module());

XmppStreamResult stream_result = yield Xmpp.establish_stream(jid.domain_jid, list, Application.print_xmpp);
XmppStreamResult stream_result = yield Xmpp.establish_stream(jid.domain_jid, list, Application.print_xmpp,
(_, peer_cert, errors) => { return ConnectionManager.on_invalid_certificate(jid.domainpart, peer_cert, errors); }
);

if (stream_result.stream == null) {
return null;
Expand Down Expand Up @@ -169,7 +175,9 @@ public class Register : StreamInteractionModule, Object{
list.add(new Iq.Module());
list.add(new Xep.InBandRegistration.Module());

XmppStreamResult stream_result = yield Xmpp.establish_stream(jid.domain_jid, list, Application.print_xmpp);
XmppStreamResult stream_result = yield Xmpp.establish_stream(jid.domain_jid, list, Application.print_xmpp,
(_, peer_cert, errors) => { return ConnectionManager.on_invalid_certificate(jid.domainpart, peer_cert, errors); }
);

if (stream_result.stream == null) {
return null;
Expand Down
11 changes: 7 additions & 4 deletions xmpp-vala/src/core/direct_tls_xmpp_stream.vala
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ public class Xmpp.DirectTlsXmppStream : TlsXmppStream {

string host;
uint16 port;
TlsXmppStream.OnInvalidCert on_invalid_cert_outer;

public DirectTlsXmppStream(Jid remote, string host, uint16 port) {
this.remote_name = remote;
public DirectTlsXmppStream(Jid remote_name, string host, uint16 port, TlsXmppStream.OnInvalidCert on_invalid_cert) {
base(remote_name);
this.host = host;
this.port = port;
this.on_invalid_cert_outer = on_invalid_cert;
}

public override async void connect() throws IOStreamError {
Expand All @@ -15,10 +17,11 @@ public class Xmpp.DirectTlsXmppStream : TlsXmppStream {
debug("Connecting to %s %i (tls)", host, port);
IOStream? io_stream = yield client.connect_to_host_async(host, port);
TlsConnection tls_connection = TlsClientConnection.new(io_stream, new NetworkAddress(remote_name.to_string(), port));
#if ALPN_SUPPORT
#if ALPN_SUPPORT
tls_connection.set_advertised_protocols(new string[]{"xmpp-client"});
#endif
#endif
tls_connection.accept_certificate.connect(on_invalid_certificate);
tls_connection.accept_certificate.connect(on_invalid_cert_outer);
reset_stream(tls_connection);

yield setup();
Expand Down
4 changes: 4 additions & 0 deletions xmpp-vala/src/core/io_xmpp_stream.vala
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ public abstract class Xmpp.IoXmppStream : XmppStream {

internal WriteNodeFunc? write_obj = null;

protected IoXmppStream(Jid remote_name) {
base(remote_name);
}

public override async void disconnect() throws IOStreamError, XmlError, IOError {
disconnected = true;
if (writer == null || reader == null || stream == null) {
Expand Down
7 changes: 5 additions & 2 deletions xmpp-vala/src/core/starttls_xmpp_stream.vala
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ public class Xmpp.StartTlsXmppStream : TlsXmppStream {

string host;
uint16 port;
TlsXmppStream.OnInvalidCert on_invalid_cert_outer;

public StartTlsXmppStream(Jid remote, string host, uint16 port) {
this.remote_name = remote;
public StartTlsXmppStream(Jid remote, string host, uint16 port, TlsXmppStream.OnInvalidCert on_invalid_cert) {
base(remote);
this.host = host;
this.port = port;
this.on_invalid_cert_outer = on_invalid_cert;
}

public override async void connect() throws IOStreamError {
Expand Down Expand Up @@ -40,6 +42,7 @@ public class Xmpp.StartTlsXmppStream : TlsXmppStream {
reset_stream(conn);

conn.accept_certificate.connect(on_invalid_certificate);
conn.accept_certificate.connect(on_invalid_cert_outer);
} catch (Error e) {
stderr.printf("Failed to start TLS: %s\n", e.message);
}
Expand Down
8 changes: 4 additions & 4 deletions xmpp-vala/src/core/stream_connect.vala
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ namespace Xmpp {
}

public class XmppStreamResult {
public XmppStream? stream { get; set; }
public TlsXmppStream? stream { get; set; }
public TlsCertificateFlags? tls_errors { get; set; }
public IOStreamError? io_error { get; set; }
}

public async XmppStreamResult establish_stream(Jid bare_jid, Gee.List<XmppStreamModule> modules, string? log_options) {
public async XmppStreamResult establish_stream(Jid bare_jid, Gee.List<XmppStreamModule> modules, string? log_options, TlsXmppStream.OnInvalidCert on_invalid_cert) {
Jid remote = bare_jid.domain_jid;

//Lookup xmpp-client and xmpps-client SRV records
Expand Down Expand Up @@ -58,9 +58,9 @@ namespace Xmpp {
foreach (SrvTargetInfo target in targets) {
try {
if (target.service == "xmpp-client") {
stream = new StartTlsXmppStream(remote, target.host, target.port);
stream = new StartTlsXmppStream(remote, target.host, target.port, on_invalid_cert);
} else {
stream = new DirectTlsXmppStream(remote, target.host, target.port);
stream = new DirectTlsXmppStream(remote, target.host, target.port, on_invalid_cert);
}
stream.log = new XmppLog(bare_jid.to_string(), log_options);

Expand Down
8 changes: 7 additions & 1 deletion xmpp-vala/src/core/tls_xmpp_stream.vala
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@ public abstract class Xmpp.TlsXmppStream : IoXmppStream {

public TlsCertificateFlags? errors;

public delegate bool OnInvalidCert(GLib.TlsConnection conn, GLib.TlsCertificate peer_cert, GLib.TlsCertificateFlags errors);

protected TlsXmppStream(Jid remote_name) {
base(remote_name);
}

protected bool on_invalid_certificate(TlsCertificate peer_cert, TlsCertificateFlags errors) {
this.errors = errors;

Expand All @@ -13,7 +19,7 @@ public abstract class Xmpp.TlsXmppStream : IoXmppStream {
error_str += @"$(f), ";
}
}
warning(@"Tls Certificate Errors: $(error_str)");
warning(@"[%p, %s] Tls Certificate Errors: %s", this, this.remote_name, error_str);
return false;
}
}
6 changes: 5 additions & 1 deletion xmpp-vala/src/core/xmpp_stream.vala
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,18 @@ public abstract class Xmpp.XmppStream {
protected bool setup_needed = false;
protected bool disconnected = false;

protected XmppStream(Jid remote_name) {
this.remote_name = remote_name;
}

public abstract async void connect() throws IOStreamError;

public abstract async void disconnect() throws IOStreamError, XmlError, IOError;

public abstract async StanzaNode read() throws IOStreamError;

[Version (deprecated = true, deprecated_since = "0.1", replacement = "write_async")]
public abstract void write(StanzaNode node);
public abstract void write(StanzaNode node);

public abstract async void write_async(StanzaNode node) throws IOStreamError;

Expand Down

0 comments on commit 81a5505

Please sign in to comment.