[evolution-data-server] Bug #681962 - Identify server certificates by hostname and fingerprint
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-data-server] Bug #681962 - Identify server certificates by hostname and fingerprint
- Date: Tue, 30 Oct 2012 18:00:14 +0000 (UTC)
commit 0e4713735bb0c51f6fc4808834eb15de25fd5269
Author: Milan Crha <mcrha redhat com>
Date: Tue Oct 30 18:59:40 2012 +0100
Bug #681962 - Identify server certificates by hostname and fingerprint
camel/camel-certdb.c | 102 ++++++++++++++++++++++++++++++++++++------
camel/camel-certdb.h | 4 +-
camel/camel-tcp-stream-ssl.c | 11 ++---
3 files changed, 94 insertions(+), 23 deletions(-)
---
diff --git a/camel/camel-certdb.c b/camel/camel-certdb.c
index 5f19f55..94508fb 100644
--- a/camel/camel-certdb.c
+++ b/camel/camel-certdb.c
@@ -63,14 +63,73 @@ static void cert_set_string (CamelCertDB *certdb, CamelCert *cert, gint string,
G_DEFINE_TYPE (CamelCertDB, camel_certdb, CAMEL_TYPE_OBJECT)
+typedef struct {
+ gchar *hostname;
+ gchar *fingerprint;
+} CamelCertDBKey;
+
+static CamelCertDBKey *
+certdb_key_new (const gchar *hostname,
+ const gchar *fingerprint)
+{
+ CamelCertDBKey *key;
+
+ key = g_new0 (CamelCertDBKey, 1);
+ key->hostname = g_strdup (hostname);
+ key->fingerprint = g_strdup (fingerprint);
+
+ return key;
+}
+
+static void
+certdb_key_free (gpointer ptr)
+{
+ CamelCertDBKey *key = ptr;
+
+ if (!key)
+ return;
+
+ g_free (key->hostname);
+ g_free (key->fingerprint);
+ g_free (key);
+}
+
+static guint
+certdb_key_hash (gconstpointer ptr)
+{
+ const CamelCertDBKey *key = ptr;
+
+ if (!key)
+ return 0;
+
+ /* hash by fingerprint only, but compare by both hostname and fingerprint */
+ return g_str_hash (key->fingerprint);
+}
+
static gboolean
-certdb_str_equal_casecmp (gconstpointer str1,
- gconstpointer str2)
+certdb_key_equal (gconstpointer ptr1,
+ gconstpointer ptr2)
{
- if (!str1 || !str2)
- return str1 == str2;
+ const CamelCertDBKey *key1 = ptr1, *key2 = ptr2;
+ gboolean same_hostname;
+
+ if (!key1 || !key2)
+ return key1 == key2;
+
+ if (!key1->hostname || !key2->hostname)
+ same_hostname = key1->hostname == key2->hostname;
+ else
+ same_hostname = g_ascii_strcasecmp (key1->hostname, key2->hostname) == 0;
- return g_ascii_strcasecmp (str1, str2) == 0;
+ if (same_hostname) {
+ if (!key1->fingerprint || !key2->fingerprint)
+ return key1->fingerprint == key2->fingerprint;
+
+ return g_ascii_strcasecmp (key1->fingerprint, key2->fingerprint) == 0;
+ }
+
+
+ return same_hostname;
}
static void
@@ -137,7 +196,7 @@ camel_certdb_init (CamelCertDB *certdb)
certdb->cert_chunks = NULL;
certdb->certs = g_ptr_array_new ();
- certdb->cert_hash = g_hash_table_new (g_str_hash, certdb_str_equal_casecmp);
+ certdb->cert_hash = g_hash_table_new_full (certdb_key_hash, certdb_key_equal, certdb_key_free, NULL);
certdb->priv->db_lock = g_mutex_new ();
certdb->priv->io_lock = g_mutex_new ();
@@ -451,18 +510,24 @@ camel_certdb_touch (CamelCertDB *certdb)
**/
CamelCert *
camel_certdb_get_host (CamelCertDB *certdb,
- const gchar *hostname)
+ const gchar *hostname,
+ const gchar *fingerprint)
{
CamelCert *cert;
+ CamelCertDBKey *key;
g_return_val_if_fail (CAMEL_IS_CERTDB (certdb), NULL);
camel_certdb_lock (certdb, CAMEL_CERTDB_DB_LOCK);
- cert = g_hash_table_lookup (certdb->cert_hash, hostname);
+ key = certdb_key_new (hostname, fingerprint);
+
+ cert = g_hash_table_lookup (certdb->cert_hash, key);
if (cert)
camel_certdb_cert_ref (certdb, cert);
+ certdb_key_free (key);
+
camel_certdb_unlock (certdb, CAMEL_CERTDB_DB_LOCK);
return cert;
@@ -480,22 +545,26 @@ camel_certdb_put (CamelCertDB *certdb,
CamelCert *cert)
{
CamelCert *old_cert;
+ CamelCertDBKey *key;
g_return_if_fail (CAMEL_IS_CERTDB (certdb));
camel_certdb_lock (certdb, CAMEL_CERTDB_DB_LOCK);
+ key = certdb_key_new (cert->hostname, cert->fingerprint);
+
/* Replace an existing entry with the same hostname. */
- old_cert = g_hash_table_lookup (certdb->cert_hash, cert->hostname);
+ old_cert = g_hash_table_lookup (certdb->cert_hash, key);
if (old_cert) {
- g_hash_table_remove (certdb->cert_hash, cert->hostname);
+ g_hash_table_remove (certdb->cert_hash, key);
g_ptr_array_remove (certdb->certs, old_cert);
camel_certdb_cert_unref (certdb, old_cert);
}
camel_certdb_cert_ref (certdb, cert);
g_ptr_array_add (certdb->certs, cert);
- g_hash_table_insert (certdb->cert_hash, cert->hostname, cert);
+ /* takes ownership of 'key' */
+ g_hash_table_insert (certdb->cert_hash, key, cert);
certdb->flags |= CAMEL_CERTDB_DIRTY;
@@ -511,23 +580,28 @@ camel_certdb_put (CamelCertDB *certdb,
**/
void
camel_certdb_remove_host (CamelCertDB *certdb,
- const gchar *hostname)
+ const gchar *hostname,
+ const gchar *fingerprint)
{
CamelCert *cert;
+ CamelCertDBKey *key;
g_return_if_fail (CAMEL_IS_CERTDB (certdb));
camel_certdb_lock (certdb, CAMEL_CERTDB_DB_LOCK);
- cert = g_hash_table_lookup (certdb->cert_hash, hostname);
+ key = certdb_key_new (hostname, fingerprint);
+ cert = g_hash_table_lookup (certdb->cert_hash, key);
if (cert) {
- g_hash_table_remove (certdb->cert_hash, hostname);
+ g_hash_table_remove (certdb->cert_hash, key);
g_ptr_array_remove (certdb->certs, cert);
camel_certdb_cert_unref (certdb, cert);
certdb->flags |= CAMEL_CERTDB_DIRTY;
}
+ certdb_key_free (key);
+
camel_certdb_unlock (certdb, CAMEL_CERTDB_DB_LOCK);
}
diff --git a/camel/camel-certdb.h b/camel/camel-certdb.h
index f8bc380..8a6edd9 100644
--- a/camel/camel-certdb.h
+++ b/camel/camel-certdb.h
@@ -150,14 +150,14 @@ void camel_certdb_touch (CamelCertDB *certdb);
/* The lookup key was changed from fingerprint to hostname to fix bug 606181. */
/* Get the certificate for the given hostname, if any. */
-CamelCert *camel_certdb_get_host (CamelCertDB *certdb, const gchar *hostname);
+CamelCert *camel_certdb_get_host (CamelCertDB *certdb, const gchar *hostname, const gchar *fingerprint);
/* Store cert for cert->hostname, replacing any existing certificate for the
* same hostname. */
void camel_certdb_put (CamelCertDB *certdb, CamelCert *cert);
/* Remove any user-accepted certificate for the given hostname. */
-void camel_certdb_remove_host (CamelCertDB *certdb, const gchar *hostname);
+void camel_certdb_remove_host (CamelCertDB *certdb, const gchar *hostname, const gchar *fingerprint);
CamelCert *camel_certdb_cert_new (CamelCertDB *certdb);
void camel_certdb_cert_ref (CamelCertDB *certdb, CamelCert *cert);
diff --git a/camel/camel-tcp-stream-ssl.c b/camel/camel-tcp-stream-ssl.c
index da0ccff..d1f1bb7 100644
--- a/camel/camel-tcp-stream-ssl.c
+++ b/camel/camel-tcp-stream-ssl.c
@@ -306,13 +306,10 @@ camel_certdb_nss_cert_get (CamelCertDB *certdb,
gchar *fingerprint;
CamelCert *ccert;
- ccert = camel_certdb_get_host (certdb, hostname);
- if (ccert == NULL)
- return NULL;
-
fingerprint = cert_fingerprint (cert);
- if (strcmp (fingerprint, ccert->fingerprint) != 0) {
- /* The saved certificate is not the one we wanted. */
+
+ ccert = camel_certdb_get_host (certdb, hostname, fingerprint);
+ if (ccert == NULL) {
g_free (fingerprint);
return NULL;
}
@@ -336,7 +333,7 @@ camel_certdb_nss_cert_get (CamelCertDB *certdb,
/* failed to load the certificate, thus remove it from
* the CertDB, thus it can be re-added and properly saved */
- camel_certdb_remove_host (certdb, hostname);
+ camel_certdb_remove_host (certdb, hostname, fingerprint);
camel_certdb_touch (certdb);
g_free (fingerprint);
g_free (filename);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]