[geary/wip/20-cert-pinning: 36/36] Implement loading and saving certs in CertificateManager
- From: Michael Gratton <mjog src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [geary/wip/20-cert-pinning: 36/36] Implement loading and saving certs in CertificateManager
- Date: Thu, 10 Jan 2019 03:01:31 +0000 (UTC)
commit 8e15263660ad78cc8d517725486d6a0f10f0e400
Author: Michael Gratton <mike vee net>
Date: Thu Jan 10 13:58:56 2019 +1100
Implement loading and saving certs in CertificateManager
.../application-certficate-manager.vala | 88 +++++++++++++++++-----
src/client/application/geary-controller.vala | 4 +-
2 files changed, 74 insertions(+), 18 deletions(-)
---
diff --git a/src/client/application/application-certficate-manager.vala
b/src/client/application/application-certficate-manager.vala
index cb14b137..1fb62eb8 100644
--- a/src/client/application/application-certficate-manager.vala
+++ b/src/client/application/application-certficate-manager.vala
@@ -36,9 +36,10 @@ public class Application.CertificateManager : GLib.Object {
/**
* Constructs a new instance, globally installing the pinning database.
*/
- public CertificateManager() {
+ public CertificateManager(GLib.File store_dir) {
this.pinning_database = new TlsDatabase(
- GLib.TlsBackend.get_default().get_default_database()
+ GLib.TlsBackend.get_default().get_default_database(),
+ store_dir
);
Geary.Endpoint.default_tls_database = this.pinning_database;
}
@@ -83,7 +84,7 @@ public class Application.CertificateManager : GLib.Object {
debug("Pinning certificate for %s...", endpoint.remote.to_string());
try {
- yield add_pinned(
+ yield this.pinning_database.pin_certificate(
endpoint.untrusted_certificate,
endpoint.remote,
save,
@@ -94,17 +95,6 @@ public class Application.CertificateManager : GLib.Object {
}
}
- private async void add_pinned(GLib.TlsCertificate cert,
- GLib.SocketConnectable? identity,
- bool save,
- GLib.Cancellable? cancellable)
- throws GLib.Error {
- this.pinning_database.pin_certificate(cert, identity);
- if (save) {
- // XXX
- }
- }
-
}
@@ -134,6 +124,52 @@ private class Application.TlsDatabase : GLib.TlsDatabase {
this.certificate = certificate;
}
+ public TrustContext.lookup(GLib.File dir,
+ string identity,
+ GLib.Cancellable? cancellable)
+ throws GLib.Error {
+ // This isn't async so that we can support both
+ // verify_chain and verify_chain_async with the same call
+ GLib.File storage = dir.get_child(FILENAME_FORMAT.printf(identity));
+ GLib.FileInputStream f_in = storage.read(cancellable);
+ GLib.BufferedInputStream buf = new GLib.BufferedInputStream(f_in);
+ GLib.ByteArray cert_pem = new GLib.ByteArray.sized(buf.buffer_size);
+ bool eof = false;
+ while (!eof) {
+ size_t filled = buf.fill(-1, cancellable);
+ if (filled > 0) {
+ cert_pem.append(buf.peek_buffer());
+ buf.skip(filled, cancellable);
+ } else {
+ eof = true;
+ }
+ }
+ buf.close(cancellable);
+
+ this(new GLib.TlsCertificate.from_pem((string) cert_pem.data, -1));
+ }
+
+ public async void save(GLib.File dir,
+ string identity,
+ GLib.Cancellable? cancellable)
+ throws GLib.Error {
+ yield Geary.Files.make_directory_with_parents(dir, cancellable);
+ GLib.File storage = dir.get_child(FILENAME_FORMAT.printf(identity));
+ GLib.FileOutputStream f_out = yield storage.replace_async(
+ null, false, GLib.FileCreateFlags.NONE, IO_PRIO, cancellable
+ );
+ GLib.BufferedOutputStream buf = new GLib.BufferedOutputStream(f_out);
+
+ size_t written = 0;
+ yield buf.write_all_async(
+ this.certificate.certificate_pem.data,
+ IO_PRIO,
+ cancellable,
+ out written
+ );
+ yield buf.close_async(IO_PRIO, cancellable);
+ }
+
}
@@ -169,15 +205,19 @@ private class Application.TlsDatabase : GLib.TlsDatabase {
this.store_dir = store_dir;
}
- public void pin_certificate(GLib.TlsCertificate certificate,
- GLib.SocketConnectable identity,
- GLib.Cancellable? cancellable = null)
+ public async void pin_certificate(GLib.TlsCertificate certificate,
+ GLib.SocketConnectable identity,
+ bool save,
+ GLib.Cancellable? cancellable = null)
throws GLib.Error {
string id = to_name(identity);
TrustContext context = new TrustContext(certificate);
lock (this.pinned_certs) {
this.pinned_certs.set(id, context);
}
+ if (save) {
+ yield context.save(this.store_dir, to_name(identity), cancellable);
+ }
}
public override string?
@@ -318,6 +358,20 @@ private class Application.TlsDatabase : GLib.TlsDatabase {
TrustContext? context = null;
lock (this.pinned_certs) {
context = this.pinned_certs.get(id);
+ if (context == null) {
+ try {
+ context = new TrustContext.lookup(
+ this.store_dir, id, cancellable
+ );
+ this.pinned_certs.set(id, context);
+ } catch (GLib.IOError.NOT_FOUND err) {
+ // Cert was not found saved, so it not pinned
+ } catch (GLib.Error err) {
+ Geary.ErrorContext err_context = new Geary.ErrorContext(err);
+ debug("Error loading pinned certificate: %s",
+ err_context.format_full_error());
+ }
+ }
}
return (context != null);
}
diff --git a/src/client/application/geary-controller.vala b/src/client/application/geary-controller.vala
index 30d1ef61..1fc61df7 100644
--- a/src/client/application/geary-controller.vala
+++ b/src/client/application/geary-controller.vala
@@ -327,7 +327,9 @@ public class GearyController : Geary.BaseObject {
// Hook up cert, accounts and credentials machinery
- this.certificate_manager = new Application.CertificateManager();
+ this.certificate_manager = new Application.CertificateManager(
+ this.application.get_user_data_directory().get_child("pinned-certs")
+ );
SecretMediator? libsecret = null;
try {
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]