[geary/wip/20-cert-pinning: 3/4] Simplify CertificateManager's db pinned cert management
- From: Michael Gratton <mjog src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [geary/wip/20-cert-pinning: 3/4] Simplify CertificateManager's db pinned cert management
- Date: Thu, 10 Jan 2019 03:45:14 +0000 (UTC)
commit cda0e7f49e6c24b5565587e18d84bd9f8a0b3083
Author: Michael Gratton <mike vee net>
Date: Thu Jan 10 13:52:16 2019 +1100
Simplify CertificateManager's db pinned cert management
Rather than store a list of pinned certs each with a set of idenities,
just use a map of idenities to certs. This simplifies both storage,
lookup, retreival, and will allow pins to be persisted on a per-identity
bassis, allowing a cert to be saved for one host but not saved for
another.
.../application-certficate-manager.vala | 174 +++++++++------------
1 file changed, 75 insertions(+), 99 deletions(-)
---
diff --git a/src/client/application/application-certficate-manager.vala
b/src/client/application/application-certficate-manager.vala
index a1b00533..cb14b137 100644
--- a/src/client/application/application-certficate-manager.vala
+++ b/src/client/application/application-certficate-manager.vala
@@ -112,93 +112,71 @@ public class Application.CertificateManager : GLib.Object {
private class Application.TlsDatabase : GLib.TlsDatabase {
- private class TrustContext {
+ /** A certificate and the identities it is trusted for. */
+ private class TrustContext : Geary.BaseObject {
- private static string to_name(GLib.SocketConnectable id) {
- GLib.NetworkAddress? name = id as GLib.NetworkAddress;
- if (name != null) {
- return name.hostname;
- }
- GLib.NetworkService? service = id as GLib.NetworkService;
- if (service != null) {
- return service.domain;
- }
+ // Perform IO at high priority since UI and network
+ // connections depend on it
+ private const int IO_PRIO = GLib.Priority.HIGH;
+ private const GLib.ChecksumType ID_TYPE = GLib.ChecksumType.SHA384;
+ private const string FILENAME_FORMAT = "%s.pem";
- GLib.InetSocketAddress? inet = id as GLib.InetSocketAddress;
- if (inet != null) {
- return inet.address.to_string();
- }
-
- return id.to_string();
- }
public string id;
- public Gcr.Certificate certificate;
- public Gee.Set<string> pinned_identities = new Gee.HashSet<string>();
+ public GLib.TlsCertificate certificate;
- public TrustContext(Gcr.Certificate certificate) {
- this.id = certificate.get_fingerprint_hex(GLib.ChecksumType.SHA256);
+ public TrustContext(GLib.TlsCertificate certificate) {
+ this.id = GLib.Checksum.compute_for_data(
+ ID_TYPE, certificate.certificate.data
+ );
this.certificate = certificate;
}
- public bool add_identity(GLib.SocketConnectable id) {
- return this.pinned_identities.add(to_name(id));
+ }
+
+
+ private static string to_name(GLib.SocketConnectable id) {
+ GLib.NetworkAddress? name = id as GLib.NetworkAddress;
+ if (name != null) {
+ return name.hostname;
}
- public bool matches_identity(GLib.SocketConnectable id) {
- return this.pinned_identities.contains(to_name(id));
+ GLib.NetworkService? service = id as GLib.NetworkService;
+ if (service != null) {
+ return service.domain;
}
- public GLib.TlsCertificate to_tls_certificate()
- throws GLib.Error {
- //return new GLib.TlsCertificate.from_pem(
- // this.certificate.get_pem_data(), -1
- //);
- warning("Was actually asked to make a TLS cert from a GCR cert");
- throw new GLib.IOError.NOT_SUPPORTED("TODO");
+ GLib.InetSocketAddress? inet = id as GLib.InetSocketAddress;
+ if (inet != null) {
+ return inet.address.to_string();
}
+ return id.to_string();
}
public GLib.TlsDatabase parent { get; private set; }
- private Gee.List<TrustContext> contexts =
- new Gee.ArrayList<TrustContext>();
+ private GLib.File store_dir;
+ private Gee.Map<string,TrustContext> pinned_certs =
+ new Gee.HashMap<string,TrustContext>();
- public TlsDatabase(GLib.TlsDatabase parent) {
+ public TlsDatabase(GLib.TlsDatabase parent, GLib.File store_dir) {
this.parent = parent;
+ this.store_dir = store_dir;
}
-
public void pin_certificate(GLib.TlsCertificate certificate,
- GLib.SocketConnectable identity) {
- Gcr.Certificate gcr = new Gcr.SimpleCertificate(
- certificate.certificate.data
- );
- lock (this.contexts) {
- TrustContext? context = lookup_gcr_unlocked(gcr);
- if (context == null) {
- context = new TrustContext(gcr);
- debug("Adding certificate %s",
- gcr.get_fingerprint_hex(GLib.ChecksumType.SHA1));
- this.contexts.add(context);
- }
- if (context.add_identity(identity)){
- debug("Adding identity %s", identity.to_string());
- }
- }
- }
-
- public void remove_certificate(Gcr.Certificate certificate) {
- lock (this.contexts) {
- TrustContext? context = lookup_gcr_unlocked(certificate);
- if (context != null) {
- this.contexts.remove(context);
- }
+ GLib.SocketConnectable identity,
+ 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);
}
}
@@ -218,7 +196,7 @@ private class Application.TlsDatabase : GLib.TlsDatabase {
throws GLib.Error {
TrustContext? context = lookup_id(handle);
return (context != null)
- ? context.to_tls_certificate()
+ ? context.certificate
: this.parent.lookup_certificate_for_handle(
handle, interaction, flags, cancellable
);
@@ -232,7 +210,7 @@ private class Application.TlsDatabase : GLib.TlsDatabase {
throws GLib.Error {
TrustContext? context = lookup_id(handle);
return (context != null)
- ? context.to_tls_certificate()
+ ? context.certificate
: yield this.parent.lookup_certificate_for_handle_async(
handle, interaction, flags, cancellable
);
@@ -290,21 +268,12 @@ private class Application.TlsDatabase : GLib.TlsDatabase {
GLib.TlsDatabaseVerifyFlags flags,
GLib.Cancellable? cancellable = null)
throws GLib.Error {
- debug("Verifying cert sync: %s: %s",
- purpose,
- identity != null ? identity.to_string() : "[no identity]");
GLib.TlsCertificateFlags ret = this.parent.verify_chain(
chain, purpose, identity, interaction, flags, cancellable
);
- if (should_verify(ret, purpose, identity)) {
- debug("Looking for pinned cert");
- TrustContext? context = lookup_tls_certificate(chain);
- if (context != null) {
- debug("Have trust context with %d ids", context.pinned_identities.size);
- }
- if (context != null && context.matches_identity(identity)) {
- ret = 0;
- }
+ if (should_verify(ret, purpose, identity) &&
+ verify(chain, identity, cancellable)) {
+ ret = 0;
}
return ret;
}
@@ -317,21 +286,12 @@ private class Application.TlsDatabase : GLib.TlsDatabase {
GLib.TlsDatabaseVerifyFlags flags,
GLib.Cancellable? cancellable = null)
throws GLib.Error {
- debug("Verifying cert async: %s: %s",
- purpose,
- identity != null ? identity.to_string() : "[no identity]");
GLib.TlsCertificateFlags ret = yield this.parent.verify_chain_async(
chain, purpose, identity, interaction, flags, cancellable
);
- if (should_verify(ret, purpose, identity)) {
- debug("Looking for pinned cert");
- TrustContext? context = lookup_tls_certificate(chain);
- if (context != null) {
- debug("Have trust context with %d ids", context.pinned_identities.size);
- }
- if (context != null && context.matches_identity(identity)) {
- ret = 0;
- }
+ if (should_verify(ret, purpose, identity) &&
+ yield verify_async(chain, identity, cancellable)) {
+ ret = 0;
}
return ret;
}
@@ -350,27 +310,43 @@ private class Application.TlsDatabase : GLib.TlsDatabase {
);
}
+ private bool verify(GLib.TlsCertificate chain,
+ GLib.SocketConnectable identity,
+ GLib.Cancellable? cancellable)
+ throws GLib.Error {
+ string id = to_name(identity);
+ TrustContext? context = null;
+ lock (this.pinned_certs) {
+ context = this.pinned_certs.get(id);
+ }
+ return (context != null);
+ }
+
+ private async bool verify_async(GLib.TlsCertificate chain,
+ GLib.SocketConnectable identity,
+ GLib.Cancellable? cancellable)
+ throws GLib.Error {
+ bool is_valid = false;
+ yield Geary.Nonblocking.Concurrent.global.schedule_async(() => {
+ is_valid = verify(chain, identity, cancellable);
+ }, cancellable);
+ return is_valid;
+ }
+
private TrustContext? lookup_id(string id) {
- lock (this.contexts) {
- return Geary.traverse(this.contexts).first_matching(
+ lock (this.pinned_certs) {
+ return Geary.traverse(this.pinned_certs.values).first_matching(
(ctx) => ctx.id == id
);
}
}
- private TrustContext? lookup_tls_certificate(GLib.TlsCertificate tls) {
- lock (this.contexts) {
- return lookup_gcr_unlocked(
- new Gcr.SimpleCertificate(tls.certificate.data)
+ private TrustContext? lookup_tls_certificate(GLib.TlsCertificate cert) {
+ lock (this.pinned_certs) {
+ return Geary.traverse(this.pinned_certs.values).first_matching(
+ (ctx) => ctx.certificate.is_same(cert)
);
}
}
- private TrustContext? lookup_gcr_unlocked(Gcr.Certificate cert) {
- debug("Looking for %s", cert.get_fingerprint_hex(GLib.ChecksumType.SHA1));
- return Geary.traverse(this.contexts).first_matching(
- (ctx) => Gcr.Certificate.compare(ctx.certificate, cert) == 0
- );
- }
-
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]