diff options
author | Ruslan N. Marchenko <me@ruff.mobi> | 2020-09-05 14:33:53 +0200 |
---|---|---|
committer | Ruslan N. Marchenko <me@ruff.mobi> | 2020-09-25 19:29:50 +0200 |
commit | 1438c5d1c23ceac605e0aec19ab550dea59c0e0b (patch) | |
tree | 7a7a8d89a717b90187b62b8a5522a15ab1e69fe1 | |
parent | a02438ad6aec28c3d9fe16eac5fad83fdd3fb585 (diff) |
Add support for GIO-TLS channel binding API and simple fallback
* Set default biding type to tls-unique - if it's not supported by
GIO (Glib or Glib-networking) will just keep binding in disabled state.
* Add ability to override default binding type via env var
WOCKY_CHANNEL_BINDING_TYPE - accepts enum nicks: disabled, none,
tls-unique, tls-server-end-point.
* Add plain simple (and by default disabled) fallback to
tls-server-end-point. To enable set the ENV var above to corresponding
value.
* Since we cannot be sure the certificate digest is correct (sha256)
we rather use DISABLED versus NONE in fallback mode.
-rw-r--r-- | wocky/wocky-auth-registry.h | 4 | ||||
-rw-r--r-- | wocky/wocky-sasl-auth.c | 117 |
2 files changed, 120 insertions, 1 deletions
diff --git a/wocky/wocky-auth-registry.h b/wocky/wocky-auth-registry.h index 61cb171..433d408 100644 --- a/wocky/wocky-auth-registry.h +++ b/wocky/wocky-auth-registry.h @@ -75,6 +75,7 @@ typedef enum * @WOCKY_TLS_BINDING_NONE : binding is not supported by the server * @WOCKY_TLS_BINDING_TLS_UNIQUE : tls-unique binding type * @WOCKY_TLS_BINDING_TLS_SERVER_END_POINT : tls-server-end-point type + * @WOCKY_TLS_BINDING_TLS_EXPORTER : tls-exporter type * * Possible TLS Channel Binding states */ @@ -83,7 +84,8 @@ typedef enum WOCKY_TLS_BINDING_DISABLED, WOCKY_TLS_BINDING_NONE, WOCKY_TLS_BINDING_TLS_UNIQUE, - WOCKY_TLS_BINDING_TLS_SERVER_END_POINT + WOCKY_TLS_BINDING_TLS_SERVER_END_POINT, + WOCKY_TLS_BINDING_INVALID_TYPE } WockyTLSBindingType; /** diff --git a/wocky/wocky-sasl-auth.c b/wocky/wocky-sasl-auth.c index 31da74d..84c166f 100644 --- a/wocky/wocky-sasl-auth.c +++ b/wocky/wocky-sasl-auth.c @@ -137,11 +137,25 @@ wocky_sasl_auth_get_property (GObject *object, } } +static WockyTLSBindingType default_cb_type = WOCKY_TLS_BINDING_TLS_UNIQUE; + static void wocky_sasl_auth_class_init (WockySaslAuthClass *wocky_sasl_auth_class) { GObjectClass *object_class = G_OBJECT_CLASS (wocky_sasl_auth_class); GParamSpec *spec; + /* Initialize default binding type once */ + const gchar *cb_str = g_getenv ("WOCKY_CHANNEL_BINDING_TYPE"); + + if (cb_str != NULL) + { + GEnumClass *gec = g_type_class_ref (WOCKY_TYPE_TLS_BINDING_TYPE); + GEnumValue *gev = g_enum_get_value_by_nick (gec, cb_str); + + if (gev) + default_cb_type = gev->value; + g_type_class_unref (gec); + } object_class->set_property = wocky_sasl_auth_set_property; object_class->get_property = wocky_sasl_auth_get_property; @@ -657,6 +671,95 @@ wocky_sasl_auth_start_cb (GObject *source_object, g_object_unref (stanza); } +/** + * wocky_tls_get_cb_data: + * @conn: a #WockyXmppConnection wrapping WockyTLSSession aka GTlsConnection + * @type: a #WockyTLSBindingType to return bidning data + */ +static gchar * +wocky_tls_get_cb_data (WockyXmppConnection *conn, WockyTLSBindingType type) +{ + GIOStream *ios = NULL; + GTlsConnection *tc = NULL; + gchar *cb_data = NULL; + int g_tls_cb_t = type; + + g_assert (conn != NULL); + g_object_get (conn, "base-stream", &ios, NULL); + g_return_val_if_fail (ios != NULL, NULL); + tc = G_TLS_CONNECTION (ios); + g_object_unref (ios); + +#if GLIB_VERSION_CUR_STABLE >= G_ENCODE_VERSION(2,66) + switch (type) + { + case WOCKY_TLS_BINDING_TLS_UNIQUE: + g_tls_cb_t = G_TLS_CHANNEL_BINDING_TLS_UNIQUE; + break; + case WOCKY_TLS_BINDING_TLS_SERVER_END_POINT: + g_tls_cb_t = G_TLS_CHANNEL_BINDING_TLS_SERVER_END_POINT; + break; + default: + DEBUG ("TLS channel binding is disabled or not supported[%d]", type); + return NULL; + } + + if (g_tls_connection_get_channel_binding_data (tc, + (GTlsChannelBindingType)g_tls_cb_t, NULL, NULL)) + { + GByteArray *cb = g_byte_array_new (); + GError *err = NULL; + + if (g_tls_connection_get_channel_binding_data (tc, + (GTlsChannelBindingType)g_tls_cb_t, cb, &err)) + { + DEBUG ("Got %d bytes of cb data", cb->len); + cb_data = g_base64_encode (cb->data, cb->len); + } + else + { + DEBUG ("Failed to get binding data: %s", err->message); + g_clear_error (&err); + } + g_byte_array_unref (cb); + } +#else + /* The only thing we can do here is to generate SHA256 certificate digest + * and throw it to the server. 0.01% probability the server accepts it. + * Which is why default is tls-unique which this implementation does not + * support and therefore we skip SCRAM-*-PLUS versions by default. + * If you know your server supports tls-server-end-point and uses SHA256 + * certificate signature algorithm - feel free to enable it via ENV + * variable WOCKY_CHANNEL_BINDING_TYPE=tls-server-end-point */ + if (g_tls_cb_t == WOCKY_TLS_BINDING_TLS_SERVER_END_POINT) + { + GTlsCertificate *ps = g_tls_connection_get_peer_certificate (tc); + + if (ps != NULL) + { + GByteArray *der = NULL; + GChecksum *cs = g_checksum_new (G_CHECKSUM_SHA256); + guint8 sha[32]; // 32 bytes, 64 hex, 44 b64 + gsize sl = 32; + + g_object_get (ps, "certificate", &der, NULL); + g_assert (der != NULL); + + g_checksum_update (cs, der->data, der->len); + g_checksum_get_digest (cs, sha, &sl); + cb_data = g_base64_encode (sha, sl); + + g_checksum_free (cs); + g_byte_array_unref (der); + } + } +#endif /* GLIB_VERSION_CUR_STABLE >= 2.66 */ + else + DEBUG ("Requested binding type[%d] is not supported", type); + return cb_data; +} + + /* Initiate sasl auth. features should contain the stream features stanza as * receiver from the server */ void @@ -690,6 +793,20 @@ wocky_sasl_auth_authenticate_async (WockySaslAuth *sasl, goto out; } + if (is_secure) + { + WockyTLSBindingType cb_type = default_cb_type; + gchar *cb_data = wocky_tls_get_cb_data (priv->connection, cb_type); + if (cb_data != NULL) + { + DEBUG ("Using TLS Channel Binding Data: %s", cb_data); + g_object_set (priv->auth_registry, + "tls-binding-type", cb_type, + "tls-binding-data", cb_data, + NULL); + g_free (cb_data); + } + } priv->task = g_task_new (G_OBJECT (sasl), cancellable, callback, user_data); |