diff options
-rw-r--r-- | libempathy/empathy-server-tls-handler.c | 41 | ||||
-rw-r--r-- | libempathy/empathy-tls-verifier.c | 38 | ||||
-rw-r--r-- | libempathy/empathy-tls-verifier.h | 3 | ||||
-rw-r--r-- | src/empathy-auth-client.c | 6 |
4 files changed, 81 insertions, 7 deletions
diff --git a/libempathy/empathy-server-tls-handler.c b/libempathy/empathy-server-tls-handler.c index 6cf3290c5..540bb35fa 100644 --- a/libempathy/empathy-server-tls-handler.c +++ b/libempathy/empathy-server-tls-handler.c @@ -35,6 +35,7 @@ enum { PROP_CHANNEL = 1, PROP_TLS_CERTIFICATE, PROP_HOSTNAME, + PROP_REFERENCE_IDENTITIES, LAST_PROPERTY, }; @@ -43,6 +44,7 @@ typedef struct { EmpathyTLSCertificate *certificate; gchar *hostname; + gchar **reference_identities; GSimpleAsyncResult *async_init_res; } EmpathyServerTLSHandlerPriv; @@ -99,9 +101,11 @@ tls_handler_init_async (GAsyncInitable *initable, GHashTable *properties; const gchar *cert_object_path; const gchar *hostname; + const gchar * const *identities; const gchar *bus_name; TpDBusDaemon *dbus; GError *error = NULL; + gchar *default_identities[2]; EmpathyServerTLSHandler *self = EMPATHY_SERVER_TLS_HANDLER (initable); EmpathyServerTLSHandlerPriv *priv = GET_PRIV (self); @@ -117,6 +121,30 @@ tls_handler_init_async (GAsyncInitable *initable, DEBUG ("Received hostname: %s", hostname); + identities = tp_asv_get_strv (properties, + EMP_IFACE_CHANNEL_TYPE_SERVER_TLS_CONNECTION ".ReferenceIdentities"); + + /* + * If the channel doesn't implement the ReferenceIdentities parameter + * then fallback to the hostname. + */ + if (!identities) + { + default_identities[0] = (gchar*)hostname; + default_identities[1] = NULL; + identities = (const gchar**)default_identities; + } + else + { +#ifdef ENABLE_DEBUG + gchar *output = g_strjoinv (", ", (gchar**)identities); + DEBUG ("Received reference identities: %s", output); + g_free (output); +#endif /* ENABLE_DEBUG */ + } + + priv->reference_identities = g_strdupv ((gchar**)identities); + cert_object_path = tp_asv_get_object_path (properties, EMP_IFACE_CHANNEL_TYPE_SERVER_TLS_CONNECTION ".ServerCertificate"); bus_name = tp_proxy_get_bus_name (TP_PROXY (priv->channel)); @@ -162,6 +190,7 @@ empathy_server_tls_handler_finalize (GObject *object) tp_clear_object (&priv->channel); tp_clear_object (&priv->certificate); + g_strfreev (priv->reference_identities); g_free (priv->hostname); G_OBJECT_CLASS (empathy_server_tls_handler_parent_class)->finalize (object); @@ -186,6 +215,9 @@ empathy_server_tls_handler_get_property (GObject *object, case PROP_HOSTNAME: g_value_set_string (value, priv->hostname); break; + case PROP_REFERENCE_IDENTITIES: + g_value_set_boxed (value, priv->reference_identities); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; @@ -236,10 +268,17 @@ empathy_server_tls_handler_class_init (EmpathyServerTLSHandlerClass *klass) g_object_class_install_property (oclass, PROP_TLS_CERTIFICATE, pspec); pspec = g_param_spec_string ("hostname", "The hostname", - "The hostname which should be certified by the server certificate.", + "The hostname the user is expecting to connect to.", NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (oclass, PROP_HOSTNAME, pspec); + + pspec = g_param_spec_boxed ("reference-identities", "Reference Identities", + "The server certificate should certify one of these identities", + G_TYPE_STRV, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (oclass, PROP_REFERENCE_IDENTITIES, pspec); + } static void diff --git a/libempathy/empathy-tls-verifier.c b/libempathy/empathy-tls-verifier.c index 2f98d9364..e0fa130bf 100644 --- a/libempathy/empathy-tls-verifier.c +++ b/libempathy/empathy-tls-verifier.c @@ -42,6 +42,7 @@ G_DEFINE_TYPE (EmpathyTLSVerifier, empathy_tls_verifier, enum { PROP_TLS_CERTIFICATE = 1, PROP_HOSTNAME, + PROP_REFERENCE_IDENTITIES, LAST_PROPERTY, }; @@ -49,6 +50,7 @@ enum { typedef struct { EmpathyTLSCertificate *certificate; gchar *hostname; + gchar **reference_identities; GSimpleAsyncResult *verify_result; GHashTable *details; @@ -255,6 +257,8 @@ perform_verification (EmpathyTLSVerifier *self, guint n_list, n_anchors; guint verify_output; gint res; + gchar **i; + gboolean matched; EmpathyTLSVerifierPriv *priv = GET_PRIV (self); DEBUG ("Performing verification"); @@ -295,8 +299,18 @@ perform_verification (EmpathyTLSVerifier *self, goto out; } - /* now check if the certificate matches the hostname. */ - if (gnutls_x509_crt_check_hostname (list[0], priv->hostname) == 0) + /* now check if the certificate matches one of the reference identities. */ + for (i = priv->reference_identities, matched = FALSE; i && *i; ++i) + { + const gchar *identity = *i; + if (gnutls_x509_crt_check_hostname (list[0], identity) == 1) + { + matched = TRUE; + break; + } + } + + if (!matched) { gchar *certified_hostname; @@ -362,6 +376,9 @@ empathy_tls_verifier_get_property (GObject *object, case PROP_HOSTNAME: g_value_set_string (value, priv->hostname); break; + case PROP_REFERENCE_IDENTITIES: + g_value_set_boxed (value, priv->reference_identities); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; @@ -384,6 +401,9 @@ empathy_tls_verifier_set_property (GObject *object, case PROP_HOSTNAME: priv->hostname = g_value_dup_string (value); break; + case PROP_REFERENCE_IDENTITIES: + priv->reference_identities = g_value_dup_boxed (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; @@ -414,6 +434,7 @@ empathy_tls_verifier_finalize (GObject *object) tp_clear_boxed (G_TYPE_HASH_TABLE, &priv->details); g_free (priv->hostname); + g_strfreev (priv->reference_identities); G_OBJECT_CLASS (empathy_tls_verifier_parent_class)->finalize (object); } @@ -448,22 +469,31 @@ empathy_tls_verifier_class_init (EmpathyTLSVerifierClass *klass) g_object_class_install_property (oclass, PROP_TLS_CERTIFICATE, pspec); pspec = g_param_spec_string ("hostname", "The hostname", - "The hostname which should be certified by the certificate.", + "The hostname which is certified by the certificate.", NULL, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (oclass, PROP_HOSTNAME, pspec); + + pspec = g_param_spec_boxed ("reference-identities", + "The reference identities", + "The certificate should certify one of these identities.", + G_TYPE_STRV, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (oclass, PROP_REFERENCE_IDENTITIES, pspec); } EmpathyTLSVerifier * empathy_tls_verifier_new (EmpathyTLSCertificate *certificate, - const gchar *hostname) + const gchar *hostname, const gchar **reference_identities) { g_assert (EMPATHY_IS_TLS_CERTIFICATE (certificate)); g_assert (hostname != NULL); + g_assert (reference_identities != NULL); return g_object_new (EMPATHY_TYPE_TLS_VERIFIER, "certificate", certificate, "hostname", hostname, + "reference-identities", reference_identities, NULL); } diff --git a/libempathy/empathy-tls-verifier.h b/libempathy/empathy-tls-verifier.h index e333bc81e..436149336 100644 --- a/libempathy/empathy-tls-verifier.h +++ b/libempathy/empathy-tls-verifier.h @@ -62,7 +62,8 @@ GType empathy_tls_verifier_get_type (void); EmpathyTLSVerifier * empathy_tls_verifier_new ( EmpathyTLSCertificate *certificate, - const gchar *hostname); + const gchar *hostname, + const gchar **reference_identities); void empathy_tls_verifier_verify_async (EmpathyTLSVerifier *self, GAsyncReadyCallback callback, diff --git a/src/empathy-auth-client.c b/src/empathy-auth-client.c index df2003495..56c977072 100644 --- a/src/empathy-auth-client.c +++ b/src/empathy-auth-client.c @@ -197,6 +197,7 @@ auth_factory_new_tls_handler_cb (EmpathyAuthFactory *factory, { EmpathyTLSCertificate *certificate = NULL; gchar *hostname = NULL; + gchar **reference_identities = NULL; EmpathyTLSVerifier *verifier; DEBUG ("New TLS server handler received from the factory"); @@ -204,15 +205,18 @@ auth_factory_new_tls_handler_cb (EmpathyAuthFactory *factory, g_object_get (handler, "certificate", &certificate, "hostname", &hostname, + "reference-identities", &reference_identities, NULL); - verifier = empathy_tls_verifier_new (certificate, hostname); + verifier = empathy_tls_verifier_new (certificate, hostname, + (const gchar**)reference_identities); empathy_tls_verifier_verify_async (verifier, verifier_verify_cb, NULL); g_object_unref (verifier); g_object_unref (certificate); g_free (hostname); + g_strfreev (reference_identities); } static void |