/pidgin/main: a1591cb7c087: Implement manually trusting certific...
Mike Ruprecht
cmaiku at gmail.com
Thu Apr 7 13:36:20 EDT 2016
Changeset: a1591cb7c087ba419885fde81e55584a1f5925d5
Author: Mike Ruprecht <cmaiku at gmail.com>
Date: 2016-03-30 02:28 -0500
Branch: purple-ssl-to-gio
URL: https://hg.pidgin.im/pidgin/main/rev/a1591cb7c087
Description:
Implement manually trusting certificates with TLS helper API
This patch implements manually trusting certificates when using the
TLS helper API (purple_tls_certificate_attach_*). It fixes this
previously broken functionality.
diffstat:
libpurple/tls-certificate.c | 117 ++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 114 insertions(+), 3 deletions(-)
diffs (140 lines):
diff --git a/libpurple/tls-certificate.c b/libpurple/tls-certificate.c
--- a/libpurple/tls-certificate.c
+++ b/libpurple/tls-certificate.c
@@ -193,12 +193,118 @@ purple_tls_certificate_distrust(const gc
return ret;
}
+/* Converts GTlsCertificateFlags to a translated string representation
+ * of the first set error flag in the order checked
+ */
+static const gchar *
+tls_certificate_flags_to_reason(GTlsCertificateFlags flags)
+{
+ if (flags & G_TLS_CERTIFICATE_UNKNOWN_CA) {
+ return _("The certificate is not trusted because no "
+ "certificate that can verify it is "
+ "currently trusted.");
+ } else if (flags & G_TLS_CERTIFICATE_BAD_IDENTITY) {
+ /* Translators: "domain" refers to a DNS domain
+ * (e.g. talk.google.com)
+ */
+ return _("The certificate presented is not issued to "
+ "this domain.");
+ } else if (flags & G_TLS_CERTIFICATE_NOT_ACTIVATED) {
+ return _("The certificate is not valid yet. Check that your "
+ "computer's date and time are accurate.");
+ } else if (flags & G_TLS_CERTIFICATE_EXPIRED) {
+ return _("The certificate has expired and should not be "
+ "considered valid. Check that your "
+ "computer's date and time are accurate.");
+ } else if (flags & G_TLS_CERTIFICATE_REVOKED) {
+ return _("The certificate has been revoked.");
+ } else if (flags & G_TLS_CERTIFICATE_INSECURE) {
+ return _("The certificate's algorithm is considered insecure.");
+ } else {
+ /* Also catches G_TLS_CERTIFICATE_GENERIC_ERROR here */
+ return _("An unknown certificate error occurred.");
+ }
+}
+
+/* Holds data for requesting the user to accept a given certificate */
+typedef struct {
+ gchar *identity;
+ GTlsCertificate *cert;
+} UserCertRequestData;
+
+static void
+user_cert_request_data_free(UserCertRequestData *data)
+{
+ g_return_if_fail(data != NULL);
+
+ g_free(data->identity);
+ g_object_unref(data->cert);
+
+ g_free(data);
+}
+
+static void
+user_cert_request_accept_cb(UserCertRequestData *data)
+{
+ GError *error = NULL;
+
+ g_return_if_fail(data != NULL);
+
+ /* User accepted. Trust this certificate */
+ if(!purple_tls_certificate_trust(data->identity, data->cert, &error)) {
+ purple_debug_error("tls-certificate",
+ "Error trusting certificate '%s': %s",
+ data->identity, error->message);
+ g_clear_error(&error);
+ }
+
+ user_cert_request_data_free(data);
+}
+
+static void
+user_cert_request_deny_cb(UserCertRequestData *data)
+{
+ /* User denied. Free data related to the requst */
+ user_cert_request_data_free(data);
+}
+
+/* Prompts the user to accept the certificate as it failed due to the
+ * passed errors.
+ */
+static void
+request_accept_certificate(const gchar *identity, GTlsCertificate *peer_cert,
+ GTlsCertificateFlags errors)
+{
+ UserCertRequestData *data;
+ gchar *primary;
+
+ g_return_if_fail(identity != NULL && identity[0] != '\0');
+ g_return_if_fail(G_IS_TLS_CERTIFICATE(peer_cert));
+ g_return_if_fail(errors != 0);
+
+ data = g_new(UserCertRequestData, 1);
+ data->identity = g_strdup(identity);
+ data->cert = g_object_ref(peer_cert);
+
+ primary = g_strdup_printf(_("Accept certificate for %s?"), identity);
+ purple_request_certificate(data,
+ _("TLS Certificate Verification"),
+ primary,
+ tls_certificate_flags_to_reason(errors),
+ data->cert,
+ _("Accept"), G_CALLBACK(user_cert_request_accept_cb),
+ _("Reject"), G_CALLBACK(user_cert_request_deny_cb),
+ data);
+ g_free(primary);
+}
+
/* Called when a GTlsConnection (which this handler has been connected to)
* has an error validating its certificate.
* Returns TRUE if the certificate is already trusted, so the connection
* can continue.
* Returns FALSE if the certificate is not trusted, causing the
- * connection's handshake to fail.
+ * connection's handshake to fail, and then prompts the user to accept
+ * the certificate.
*/
static gboolean
accept_certificate_cb(GTlsConnection *conn, GTlsCertificate *peer_cert,
@@ -240,9 +346,14 @@ accept_certificate_cb(GTlsConnection *co
return TRUE;
}
- /* Certificate failed and isn't trusted. Fail certificate */
+ g_clear_object(&trusted_cert);
- g_clear_object(&trusted_cert);
+ /* Certificate failed and isn't trusted.
+ * Fail certificate and prompt user.
+ */
+
+ request_accept_certificate(identity, peer_cert, errors);
+
return FALSE;
}
More information about the Commits
mailing list