[geary/wip/20-cert-pinning: 2/5] Update Geary.Endpoint API and source
- From: Michael Gratton <mjog src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [geary/wip/20-cert-pinning: 2/5] Update Geary.Endpoint API and source
- Date: Sat, 29 Dec 2018 02:53:39 +0000 (UTC)
commit 5358f845b4b19cbe86895c441d830364169c117c
Author: Michael Gratton <mike vee net>
Date: Thu Dec 27 16:27:26 2018 +1100
Update Geary.Endpoint API and source
Use a generic GSocketConnectable to specify the remote endpoint,
simplify TLS cert management callbacks.
src/client/application/geary-controller.vala | 18 +-
src/client/dialogs/certificate-warning-dialog.vala | 5 +-
src/console/main.vala | 5 +-
src/engine/api/geary-endpoint.vala | 221 +++++++++++----------
src/engine/api/geary-engine.vala | 11 +-
.../imap-engine/imap-engine-generic-account.vala | 12 +-
src/mailer/main.vala | 7 +-
test/engine/api/geary-account-mock.vala | 14 +-
8 files changed, 158 insertions(+), 135 deletions(-)
---
diff --git a/src/client/application/geary-controller.vala b/src/client/application/geary-controller.vala
index dda59ec8..926ea956 100644
--- a/src/client/application/geary-controller.vala
+++ b/src/client/application/geary-controller.vala
@@ -69,10 +69,14 @@ public class GearyController : Geary.BaseObject {
GearyController.untitled_file_name = _("Untitled");
}
- private static void get_gcr_params(Geary.Endpoint endpoint, out Gcr.Certificate cert,
- out string peer) {
- cert = new Gcr.SimpleCertificate(endpoint.untrusted_certificate.certificate.data);
- peer = "%s:%u".printf(endpoint.remote_address.hostname, endpoint.remote_address.port);
+ private static void get_gcr_params(Geary.ServiceInformation service,
+ Geary.Endpoint endpoint,
+ out Gcr.Certificate cert,
+ out string peer) {
+ cert = new Gcr.SimpleCertificate(
+ endpoint.untrusted_certificate.certificate.data
+ );
+ peer = service.host;
}
@@ -681,7 +685,7 @@ public class GearyController : Geary.BaseObject {
// get GCR parameters
Gcr.Certificate cert;
string peer;
- get_gcr_params(endpoint, out cert, out peer);
+ get_gcr_params(service, endpoint, out cert, out peer);
// Geary allows for user to auto-revoke all questionable server certificates without
// digging around in a keyring/pk manager
@@ -733,8 +737,8 @@ public class GearyController : Geary.BaseObject {
// get GCR parameters for pinning
Gcr.Certificate cert;
string peer;
- get_gcr_params(endpoint, out cert, out peer);
-
+ get_gcr_params(service, endpoint, out cert, out peer);
+
// pinning the certificate creates an exception for the next time a connection
// is attempted
debug("Pinning certificate for %s...", peer);
diff --git a/src/client/dialogs/certificate-warning-dialog.vala
b/src/client/dialogs/certificate-warning-dialog.vala
index f8e49f31..e29ec9a8 100644
--- a/src/client/dialogs/certificate-warning-dialog.vala
+++ b/src/client/dialogs/certificate-warning-dialog.vala
@@ -36,7 +36,7 @@ public class CertificateWarningDialog {
title_label.label = _("Untrusted Connection: %s").printf(account.display_name);
top_label.label = _("The identity of the %s mail server at %s:%u could not be verified.").printf(
- service.protocol.to_value(), endpoint.remote_address.hostname, endpoint.remote_address.port);
+ service.protocol.to_value(), service.host, service.port);
warnings_label.label = generate_warning_list(
endpoint.tls_validation_warnings
@@ -61,8 +61,7 @@ public class CertificateWarningDialog {
dont_trust_label.label =
"<b>"
+ _("Selecting “Don’t Trust This Server” will cause Geary to stop accessing this account.")
- + "</b> "
- + _("Geary will exit if you have no other open email accounts.");
+ + "</b> ";
}
dont_trust_label.use_markup = true;
diff --git a/src/console/main.vala b/src/console/main.vala
index 6a2bbd61..8a95acbc 100644
--- a/src/console/main.vala
+++ b/src/console/main.vala
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 Software Freedom Conservancy Inc.
+n * Copyright 2016 Software Freedom Conservancy Inc.
*
* This software is licensed under the GNU Lesser General Public License
* (version 2.1 or later). See the COPYING file in this distribution.
@@ -311,8 +311,7 @@ class ImapConsole : Gtk.Window {
cx = new Geary.Imap.ClientConnection(
new Geary.Endpoint(
- args[0],
- Geary.Imap.IMAP_TLS_PORT,
+ new GLib.NetworkAddress(args[0], Geary.Imap.IMAP_TLS_PORT),
method,
IMAP_TIMEOUT_SEC
)
diff --git a/src/engine/api/geary-endpoint.vala b/src/engine/api/geary-endpoint.vala
index fe23146d..b1174c6c 100644
--- a/src/engine/api/geary-endpoint.vala
+++ b/src/engine/api/geary-endpoint.vala
@@ -1,23 +1,78 @@
-/* Copyright 2016 Software Freedom Conservancy Inc.
+/*
+ * Copyright 2016 Software Freedom Conservancy Inc.
+ * Copyright 2018 Michael Gratton <mike vee net>
*
* This software is licensed under the GNU Lesser General Public License
- * (version 2.1 or later). See the COPYING file in this distribution.
+ * (version 2.1 or later). See the COPYING file in this distribution.
*/
/**
- * An Endpoint represents the location of an Internet TCP connection as represented by a host,
- * a port, and flags and other parameters that specify the nature of the connection itself.
+ * Encapsulates network configuration and state for remote service.
*/
-
public class Geary.Endpoint : BaseObject {
+
public const string PROP_TRUST_UNTRUSTED_HOST = "trust-untrusted-host";
- public NetworkAddress remote_address { get; private set; }
+
+ /**
+ * The default TLS certificate database to use when connecting.
+ *
+ * If not null, this will be set as the database on new TLS
+ * connections.
+ */
+ public static GLib.TlsDatabase? default_tls_database = null;
+
+
+ /** Returns {@link GLib.TlsCertificateFlags} as a string. */
+ public static string tls_flag_to_string(GLib.TlsCertificateFlags flag) {
+ // Vala to_string() for Flags enums currently doesn't work --
+ // bummer... Should only be called when a single flag is set,
+ // otherwise returns a string indicating an unknown value
+ switch (flag) {
+ case TlsCertificateFlags.BAD_IDENTITY:
+ return "BAD_IDENTITY";
+
+ case TlsCertificateFlags.EXPIRED:
+ return "EXPIRED";
+
+ case TlsCertificateFlags.GENERIC_ERROR:
+ return "GENERIC_ERROR";
+
+ case TlsCertificateFlags.INSECURE:
+ return "INSECURE";
+
+ case TlsCertificateFlags.NOT_ACTIVATED:
+ return "NOT_ACTIVATED";
+
+ case TlsCertificateFlags.REVOKED:
+ return "REVOKED";
+
+ case TlsCertificateFlags.UNKNOWN_CA:
+ return "UNKNOWN_CA";
+
+ default:
+ return "(unknown=%Xh)".printf(flag);
+ }
+ }
+
+
+ /** Specifies how to connect to the remote endpoint. */
+ public GLib.SocketConnectable remote { get; private set; }
+
+ /** A connectivity manager for this endpoint. */
public ConnectivityManager connectivity { get; private set; }
+
+ /** Timeout for connection attempts, in seconds. */
public uint timeout_sec { get; private set; }
+
+ /** Transport security method to use when connecting. */
public TlsNegotiationMethod tls_method { get; private set; }
- public TlsCertificateFlags tls_validation_flags { get; set; default = TlsCertificateFlags.VALIDATE_ALL; }
+
+ /** Transport security certificate validation requirements. */
+ public TlsCertificateFlags tls_validation_flags {
+ get; set; default = TlsCertificateFlags.VALIDATE_ALL;
+ }
/**
* The maximum number of commands that will be pipelined at once.
@@ -34,12 +89,12 @@ public class Geary.Endpoint : BaseObject {
* @see untrusted_host
*/
public TlsCertificateFlags tls_validation_warnings { get; private set; default = 0; }
-
+
/**
* The TLS certificate for an invalid or untrusted connection.
*/
public TlsCertificate? untrusted_certificate { get; private set; default = null; }
-
+
/**
* When set, indicates the user has acceded to trusting the host even though TLS has reported
* certificate issues.
@@ -51,7 +106,7 @@ public class Geary.Endpoint : BaseObject {
* @see tls_validation_warnings
*/
public Trillian trust_untrusted_host { get; set; default = Trillian.UNKNOWN; }
-
+
/**
* Returns true if (a) no TLS warnings have been detected or (b) user has explicitly acceded
* to ignoring them and continuing the connection.
@@ -72,6 +127,7 @@ public class Geary.Endpoint : BaseObject {
: trust_untrusted_host.is_possible();
}
}
+
private SocketClient? socket_client = null;
/**
@@ -88,16 +144,35 @@ public class Geary.Endpoint : BaseObject {
GLib.TlsConnection cx);
- public Endpoint(string host_specifier,
- uint16 port,
+ public Endpoint(GLib.SocketConnectable remote,
TlsNegotiationMethod method,
uint timeout_sec) {
- this.remote_address = new NetworkAddress(host_specifier, port);
- this.connectivity = new ConnectivityManager(this.remote_address);
+ this.remote = remote;
+ this.connectivity = new ConnectivityManager((NetworkAddress) this.remote);
this.timeout_sec = timeout_sec;
this.tls_method = method;
}
+ public async SocketConnection connect_async(Cancellable? cancellable = null) throws Error {
+ return yield get_socket_client().connect_async(this.remote, cancellable);
+ }
+
+ public async TlsClientConnection starttls_handshake_async(IOStream base_stream,
+ Cancellable? cancellable = null) throws Error {
+ TlsClientConnection tls_cx = TlsClientConnection.new(
+ base_stream, this.remote
+ );
+ prepare_tls_cx(tls_cx);
+
+ yield tls_cx.handshake_async(Priority.DEFAULT, cancellable);
+
+ return tls_cx;
+ }
+
+ public string to_string() {
+ return this.remote.to_string();
+ }
+
private SocketClient get_socket_client() {
if (socket_client != null)
return socket_client;
@@ -111,72 +186,34 @@ public class Geary.Endpoint : BaseObject {
}
socket_client.set_timeout(timeout_sec);
-
- return socket_client;
- }
- public async SocketConnection connect_async(Cancellable? cancellable = null) throws Error {
- return yield get_socket_client().connect_async(remote_address, cancellable);
- }
-
- public async TlsClientConnection starttls_handshake_async(IOStream base_stream,
- Cancellable? cancellable = null) throws Error {
- TlsClientConnection tls_cx = TlsClientConnection.new(base_stream, remote_address);
- prepare_tls_cx(tls_cx, true);
-
- yield tls_cx.handshake_async(Priority.DEFAULT, cancellable);
-
- return tls_cx;
- }
-
- private void on_socket_client_event(SocketClientEvent event, SocketConnectable? connectable,
- IOStream? ios) {
- // get TlsClientConnection to bind signals and set flags prior to handshake
- if (event == SocketClientEvent.TLS_HANDSHAKING)
- prepare_tls_cx((TlsClientConnection) ios, false);
- }
-
- private void prepare_tls_cx(TlsClientConnection tls_cx, bool starttls) {
- tls_cx.set_validation_flags(tls_validation_flags);
-
- // Vala doesn't do delegates in a ternary operator very well
- if (starttls)
- tls_cx.accept_certificate.connect(on_accept_starttls_certificate);
- else
- tls_cx.accept_certificate.connect(on_accept_ssl_certificate);
+ return socket_client;
}
- private bool on_accept_starttls_certificate(GLib.TlsConnection cx,
- GLib.TlsCertificate cert,
- GLib.TlsCertificateFlags flags) {
- return report_tls_warnings(
- TlsNegotiationMethod.START_TLS, cx, cert, flags
- );
- }
+ private void prepare_tls_cx(GLib.TlsClientConnection tls_cx) {
+ tls_cx.server_identity = this.remote;
+ tls_cx.validation_flags = this.tls_validation_flags;
+ if (Endpoint.default_tls_database != null) {
+ tls_cx.set_database(Endpoint.default_tls_database);
+ }
- private bool on_accept_ssl_certificate(GLib.TlsConnection cx,
- GLib.TlsCertificate cert,
- GLib.TlsCertificateFlags flags) {
- return report_tls_warnings(
- TlsNegotiationMethod.TRANSPORT, cx, cert, flags
- );
+ tls_cx.accept_certificate.connect(on_accept_certificate);
}
- private bool report_tls_warnings(TlsNegotiationMethod method,
- GLib.TlsConnection cx,
+ private bool report_tls_warnings(GLib.TlsConnection cx,
GLib.TlsCertificate cert,
GLib.TlsCertificateFlags warnings) {
// TODO: Report or verify flags with user, but for now merely
// log for informational/debugging reasons and accede
message(
"%s TLS warnings connecting to %s: %Xh (%s)",
- method.to_string(), to_string(), warnings,
+ this.tls_method.to_string(), to_string(), warnings,
tls_flags_to_string(warnings)
);
tls_validation_warnings = warnings;
untrusted_certificate = cert;
-
+
// if user has marked this untrusted host as trusted already, accept warnings and move on
if (trust_untrusted_host == Trillian.TRUE)
return true;
@@ -186,7 +223,7 @@ public class Geary.Endpoint : BaseObject {
return false;
}
-
+
private string tls_flags_to_string(TlsCertificateFlags flags) {
StringBuilder builder = new StringBuilder();
for (int pos = 0; pos < sizeof (TlsCertificateFlags) * 8; pos++) {
@@ -194,58 +231,28 @@ public class Geary.Endpoint : BaseObject {
if (flag != 0) {
if (!String.is_empty(builder.str))
builder.append(" | ");
-
+
builder.append(tls_flag_to_string(flag));
}
}
-
+
return !String.is_empty(builder.str) ? builder.str : "(none)";
}
-
- // Vala to_string() for Flags enums currently doesn't work -- bummer...
- // Should only be called when a single flag is set, otherwise returns a string indicating an
- // unknown value
- public string tls_flag_to_string(TlsCertificateFlags flag) {
- switch (flag) {
- case TlsCertificateFlags.BAD_IDENTITY:
- return "BAD_IDENTITY";
-
- case TlsCertificateFlags.EXPIRED:
- return "EXPIRED";
-
- case TlsCertificateFlags.GENERIC_ERROR:
- return "GENERIC_ERROR";
-
- case TlsCertificateFlags.INSECURE:
- return "INSECURE";
-
- case TlsCertificateFlags.NOT_ACTIVATED:
- return "NOT_ACTIVATED";
-
- case TlsCertificateFlags.REVOKED:
- return "REVOKED";
-
- case TlsCertificateFlags.UNKNOWN_CA:
- return "UNKNOWN_CA";
-
- default:
- return "(unknown=%Xh)".printf(flag);
- }
- }
- public bool equal_to(Geary.Endpoint other) {
- if (this == other) {
- return true;
+ private void on_socket_client_event(GLib.SocketClientEvent event,
+ GLib.SocketConnectable? connectable,
+ GLib.IOStream? ios) {
+ // get TlsClientConnection to bind signals and set flags prior
+ // to handshake
+ if (event == SocketClientEvent.TLS_HANDSHAKING) {
+ prepare_tls_cx((TlsClientConnection) ios);
}
-
- return (
- this.remote_address.hostname == other.remote_address.hostname &&
- this.remote_address.port == other.remote_address.port
- );
}
- public string to_string() {
- return "%s/default:%u".printf(remote_address.hostname, remote_address.port);
+ private bool on_accept_certificate(GLib.TlsConnection cx,
+ GLib.TlsCertificate cert,
+ GLib.TlsCertificateFlags flags) {
+ return report_tls_warnings(cx, cert, flags);
}
}
diff --git a/src/engine/api/geary-engine.vala b/src/engine/api/geary-engine.vala
index 66bedf3a..b6e4d4bc 100644
--- a/src/engine/api/geary-engine.vala
+++ b/src/engine/api/geary-engine.vala
@@ -480,10 +480,12 @@ public class Geary.Engine : BaseObject {
private Geary.Endpoint get_shared_endpoint(ServiceProvider provider,
ServiceInformation service) {
- string key = "%s/%s:%u".printf(
- service.protocol.to_value(),
+ // Key includes TLS method since endpoints encapsulate
+ // TLS-specific state
+ string key = "%s:%u/%s".printf(
service.host,
- service.port
+ service.port,
+ service.transport_security.to_value()
);
Endpoint? shared = null;
@@ -497,8 +499,7 @@ public class Geary.Engine : BaseObject {
: Smtp.ClientConnection.DEFAULT_TIMEOUT_SEC;
shared = new Endpoint(
- service.host,
- service.port,
+ new NetworkAddress(service.host, service.port),
service.transport_security,
timeout
);
diff --git a/src/engine/imap-engine/imap-engine-generic-account.vala
b/src/engine/imap-engine/imap-engine-generic-account.vala
index 2bde62d3..5402e9af 100644
--- a/src/engine/imap-engine/imap-engine-generic-account.vala
+++ b/src/engine/imap-engine/imap-engine-generic-account.vala
@@ -492,12 +492,14 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.Account {
throws GLib.Error {
check_open();
- // TODO: we should probably not use someone else's FQDN in something
- // that's supposed to be globally unique...
+ // XXX work out what our public IP adddress is somehow and use
+ // that in preference to the sender's domain
+ string domain = composed.sender != null
+ ? composed.sender.domain
+ : this.information.primary_mailbox.domain;
Geary.RFC822.Message rfc822 = new Geary.RFC822.Message.from_composed_email(
- composed, GMime.utils_generate_message_id(
- this.smtp.remote.remote_address.hostname
- ));
+ composed, GMime.utils_generate_message_id(domain)
+ );
yield this.smtp.queue_email(rfc822, cancellable);
}
diff --git a/src/mailer/main.vala b/src/mailer/main.vala
index 6344a6f9..a3528604 100644
--- a/src/mailer/main.vala
+++ b/src/mailer/main.vala
@@ -140,8 +140,7 @@ int main(string[] args) {
if (arg_gmail) {
endpoint = new Geary.Endpoint(
- "smtp.gmail.com",
- Geary.Smtp.SUBMISSION_PORT,
+ new GLib.NetworkAddress("smtp.gmail.com", Geary.Smtp.SUBMISSION_PORT),
Geary.TlsNegotiationMethod.START_TLS,
SMTP_TIMEOUT_SEC
);
@@ -151,7 +150,9 @@ int main(string[] args) {
method = Geary.TlsNegotiationMethod.START_TLS;
}
endpoint = new Geary.Endpoint(
- arg_hostname, (uint16) arg_port, method, SMTP_TIMEOUT_SEC
+ new GLib.NetworkAddress(arg_hostname, (uint16) arg_port),
+ method,
+ SMTP_TIMEOUT_SEC
);
}
diff --git a/test/engine/api/geary-account-mock.vala b/test/engine/api/geary-account-mock.vala
index 8c978f5f..b50fd206 100644
--- a/test/engine/api/geary-account-mock.vala
+++ b/test/engine/api/geary-account-mock.vala
@@ -74,12 +74,22 @@ public class Geary.MockAccount : Account, MockObject {
this._incoming = new MockClientService(
config,
config.incoming,
- new Endpoint(config.incoming.host, config.incoming.port, 0, 0)
+ new Endpoint(
+ new GLib.NetworkAddress(
+ config.incoming.host, config.incoming.port
+ ),
+ 0, 0
+ )
);
this._outgoing = new MockClientService(
config,
config.outgoing,
- new Endpoint(config.outgoing.host, config.outgoing.port, 0, 0)
+ new Endpoint(
+ new GLib.NetworkAddress(
+ config.outgoing.host, config.outgoing.port
+ ),
+ 0, 0
+ )
);
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]