summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuslan N. Marchenko <me@ruff.mobi>2020-09-05 13:19:55 +0200
committerRuslan N. Marchenko <me@ruff.mobi>2020-09-23 20:31:10 +0200
commitce00127c0202ec1b66edc1bde6e349030059d0b8 (patch)
tree595c4f9bd1b4b8756df00947fd50ac90fbd73f02
parent67edd727512749faa0bcb4c5202cd4146c0e389e (diff)
Initial SASL-SCRAM-SHA-1-PLUS implementation: enable gs2_flags
* Set default biding type to disabled - binding data and type should be set by auth handler from available at TLS layer * When binding type is disabled gs2_flags is set to 'n' which preserves existing functionality
-rw-r--r--wocky/wocky-auth-registry.c66
-rw-r--r--wocky/wocky-auth-registry.h18
-rw-r--r--wocky/wocky-sasl-scram.c82
3 files changed, 163 insertions, 3 deletions
diff --git a/wocky/wocky-auth-registry.c b/wocky/wocky-auth-registry.c
index 4e3f483..7bba2ea 100644
--- a/wocky/wocky-auth-registry.c
+++ b/wocky/wocky-auth-registry.c
@@ -17,10 +17,18 @@
#include "wocky-debug-internal.h"
+enum
+{
+ PROP_CB_TYPE = 1,
+ PROP_CB_DATA,
+};
+
/* private structure */
struct _WockyAuthRegistryPrivate
{
gboolean dispose_has_run;
+ WockyTLSBindingType cb_type;
+ gchar *cb_data;
WockyAuthHandler *handler;
GSList *handlers;
@@ -87,8 +95,19 @@ wocky_auth_registry_get_property (GObject *object,
GValue *value,
GParamSpec *pspec)
{
+ WockyAuthRegistry *self = WOCKY_AUTH_REGISTRY (object);
+ WockyAuthRegistryPrivate *priv = self->priv;
+
switch (property_id)
{
+ case PROP_CB_TYPE:
+ g_value_set_enum (value, priv->cb_type);
+ break;
+
+ case PROP_CB_DATA:
+ g_value_set_string (value, priv->cb_data);
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
@@ -100,8 +119,20 @@ wocky_auth_registry_set_property (GObject *object,
const GValue *value,
GParamSpec *pspec)
{
+ WockyAuthRegistry *self = WOCKY_AUTH_REGISTRY (object);
+ WockyAuthRegistryPrivate *priv = self->priv;
+
switch (property_id)
{
+ case PROP_CB_TYPE:
+ priv->cb_type = g_value_get_enum (value);
+ break;
+
+ case PROP_CB_DATA:
+ g_free (priv->cb_data);
+ priv->cb_data = g_value_dup_string (value);
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
@@ -118,6 +149,7 @@ wocky_auth_registry_dispose (GObject *object)
priv->dispose_has_run = TRUE;
+ g_free (priv->cb_data);
/* release any references held by the object here */
if (priv->handler != NULL)
{
@@ -147,6 +179,17 @@ wocky_auth_registry_class_init (WockyAuthRegistryClass *klass)
object_class->constructed = wocky_auth_registry_constructed;
object_class->get_property = wocky_auth_registry_get_property;
object_class->set_property = wocky_auth_registry_set_property;
+ g_object_class_install_property (object_class, PROP_CB_TYPE,
+ g_param_spec_enum ("tls-binding-type", "tls channel binding type",
+ "The type of the TLS Channel Binding to use in SASL negotiation",
+ WOCKY_TYPE_TLS_BINDING_TYPE, WOCKY_TLS_BINDING_DISABLED,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (object_class, PROP_CB_DATA,
+ g_param_spec_string ("tls-binding-data", "tls channel binding data",
+ "Base64 encoded TLS Channel binding data for the set type", NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+
object_class->dispose = wocky_auth_registry_dispose;
object_class->finalize = wocky_auth_registry_finalize;
@@ -244,6 +287,26 @@ wocky_auth_registry_select_handler (WockyAuthRegistry *self,
}
}
+ /* FIXME: should we skip PLUS if cb is disabled? Works with Prosody */
+ if (wocky_auth_registry_has_mechanism (mechanisms,
+ WOCKY_AUTH_MECH_SASL_SCRAM_SHA_1_PLUS))
+ {
+ if (out_handler != NULL)
+ {
+ /* XXX: check for username and password here? */
+ DEBUG ("Choosing SCRAM-SHA-1-PLUS as auth mechanism");
+ *out_handler = WOCKY_AUTH_HANDLER (wocky_sasl_scram_new (
+ server, username, password));
+ WOCKY_AUTH_HANDLER_GET_IFACE (*out_handler)->mechanism =
+ WOCKY_AUTH_MECH_SASL_SCRAM_SHA_1_PLUS;
+ g_object_set (G_OBJECT (*out_handler),
+ "cb-type", priv->cb_type,
+ "cb-data", priv->cb_data,
+ NULL);
+ }
+ return TRUE;
+ }
+
if (wocky_auth_registry_has_mechanism (mechanisms,
WOCKY_AUTH_MECH_SASL_SCRAM_SHA_1))
{
@@ -253,6 +316,9 @@ wocky_auth_registry_select_handler (WockyAuthRegistry *self,
DEBUG ("Choosing SCRAM-SHA-1 as auth mechanism");
*out_handler = WOCKY_AUTH_HANDLER (wocky_sasl_scram_new (
server, username, password));
+ g_object_set (G_OBJECT (*out_handler),
+ "cb-type", MIN (priv->cb_type, WOCKY_TLS_BINDING_NONE),
+ NULL);
}
return TRUE;
}
diff --git a/wocky/wocky-auth-registry.h b/wocky/wocky-auth-registry.h
index f5e3f45..84fbb51 100644
--- a/wocky/wocky-auth-registry.h
+++ b/wocky/wocky-auth-registry.h
@@ -59,6 +59,24 @@ typedef enum
#define WOCKY_AUTH_MECH_SASL_DIGEST_MD5 "DIGEST-MD5"
#define WOCKY_AUTH_MECH_SASL_PLAIN "PLAIN"
#define WOCKY_AUTH_MECH_SASL_SCRAM_SHA_1 "SCRAM-SHA-1"
+#define WOCKY_AUTH_MECH_SASL_SCRAM_SHA_1_PLUS "SCRAM-SHA-1-PLUS"
+
+/**
+ * WockyTLSBindingType
+ * @WOCKY_TLS_BINDING_DISABLED : binding is not supported by the client
+ * @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
+ *
+ * Possible TLS Channel Binding states
+ */
+typedef enum
+{
+ WOCKY_TLS_BINDING_DISABLED,
+ WOCKY_TLS_BINDING_NONE,
+ WOCKY_TLS_BINDING_TLS_UNIQUE,
+ WOCKY_TLS_BINDING_TLS_SERVER_END_POINT
+} WockyTLSBindingType;
/**
* WockyAuthRegistryStartData:
diff --git a/wocky/wocky-sasl-scram.c b/wocky/wocky-sasl-scram.c
index fe2eddc..7a051fd 100644
--- a/wocky/wocky-sasl-scram.c
+++ b/wocky/wocky-sasl-scram.c
@@ -44,6 +44,8 @@ sasl_handler_iface_init (gpointer g_iface);
enum
{
PROP_SERVER = 1,
+ PROP_CB_TYPE,
+ PROP_CB_DATA,
PROP_USERNAME,
PROP_PASSWORD
};
@@ -51,6 +53,9 @@ enum
struct _WockySaslScramPrivate
{
WockySaslScramState state;
+ WockyTLSBindingType cb_type;
+ const gchar *gs2_flag;
+ gchar *cb_data;
gchar *username;
gchar *password;
gchar *server;
@@ -82,6 +87,14 @@ wocky_sasl_scram_get_property (
switch (property_id)
{
+ case PROP_CB_TYPE:
+ g_value_set_enum (value, priv->cb_type);
+ break;
+
+ case PROP_CB_DATA:
+ g_value_set_string (value, priv->cb_data);
+ break;
+
case PROP_USERNAME:
g_value_set_string (value, priv->username);
break;
@@ -108,6 +121,15 @@ wocky_sasl_scram_set_property (
switch (property_id)
{
+ case PROP_CB_TYPE:
+ priv->cb_type = g_value_get_enum (value);
+ break;
+
+ case PROP_CB_DATA:
+ g_free (priv->cb_data);
+ priv->cb_data = g_value_dup_string (value);
+ break;
+
case PROP_SERVER:
g_free (priv->server);
priv->server = g_value_dup_string (value);
@@ -137,6 +159,7 @@ wocky_sasl_scram_dispose (GObject *object)
g_free (priv->server);
g_free (priv->username);
g_free (priv->password);
+ g_free (priv->cb_data);
g_free (priv->client_nonce);
g_free (priv->nonce);
@@ -163,6 +186,17 @@ wocky_sasl_scram_class_init (
object_class->set_property = wocky_sasl_scram_set_property;
object_class->get_property = wocky_sasl_scram_get_property;
+ g_object_class_install_property (object_class, PROP_CB_TYPE,
+ g_param_spec_enum ("cb-type", "binding type",
+ "The type of the TLS Channel Binding to use in SASL negotiation",
+ WOCKY_TYPE_TLS_BINDING_TYPE, WOCKY_TLS_BINDING_DISABLED,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (object_class, PROP_CB_DATA,
+ g_param_spec_string ("cb-data", "binding data",
+ "Base64 encoded TLS Channel binding data for the set type", NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+
g_object_class_install_property (object_class, PROP_SERVER,
g_param_spec_string ("server", "server",
"The name of the server we're authenticating to", NULL,
@@ -241,14 +275,42 @@ scram_initial_response (WockyAuthHandler *handler,
return FALSE;
}
+ switch (priv->cb_type)
+ {
+ /* no client cb support, make sure we don't stuff cb_data in */
+ case WOCKY_TLS_BINDING_DISABLED:
+ priv->gs2_flag = "n,,";
+ g_free (priv->cb_data);
+ priv->cb_data = NULL;
+ break;
+ /* we support channel binding, let's inform the other side */
+ case WOCKY_TLS_BINDING_NONE:
+ /* no server support, wipe cb data, just in case */
+ priv->gs2_flag = "y,,";
+ g_free (priv->cb_data);
+ priv->cb_data = NULL;
+ break;
+ case WOCKY_TLS_BINDING_TLS_UNIQUE:
+ priv->gs2_flag = "p=tls-unique,,";
+ g_assert (priv->cb_data != NULL);
+ break;
+ case WOCKY_TLS_BINDING_TLS_SERVER_END_POINT:
+ priv->gs2_flag = "p=tls-server-end-point,,";
+ g_assert (priv->cb_data != NULL);
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
g_assert (priv->client_nonce == NULL);
priv->client_nonce = sasl_generate_base64_nonce ();
- priv->client_first_bare = g_strdup_printf ("n,,n=%s,r=%s",
+ priv->client_first_bare = g_strdup_printf ("n=%s,r=%s",
priv->username,
priv->client_nonce);
*response = g_string_new (priv->client_first_bare);
+ g_string_prepend (*response, priv->gs2_flag);
priv->state = WOCKY_SASL_SCRAM_STATE_SERVER_FIRST_MESSAGE;
@@ -400,6 +462,8 @@ scram_handle_server_first_message (WockySaslScram *self,
WockySaslScramPrivate *priv = self->priv;
gchar attr, *value = NULL;
gchar *proof = NULL;
+ GByteArray *cb = NULL;
+ gchar *cb_b64 = NULL;
GString *client_reply;
if (!scram_get_next_attr_value (&message, &attr, &value))
@@ -435,11 +499,23 @@ scram_handle_server_first_message (WockySaslScram *self,
/* We got everything we needed for our response without proof
* base64("n,,") => biws */
client_reply = g_string_new (NULL);
- g_string_append_printf (client_reply, "c=biws,r=%s", priv->nonce);
+ if (priv->cb_data)
+ {
+ gsize len = 0;
+ guchar *buf = g_base64_decode (priv->cb_data, &len);
+ cb = g_byte_array_new_take (buf, len);
+ }
+ else
+ cb = g_byte_array_new ();
+ cb = g_byte_array_prepend (cb, (const guint8 *)priv->gs2_flag, strlen (priv->gs2_flag));
+ cb_b64 = g_base64_encode (cb->data, cb->len);
+ g_byte_array_unref (cb);
+ g_string_append_printf (client_reply, "c=%s,r=%s", cb_b64, priv->nonce);
+ g_free (cb_b64);
/* So we can make the auth message */
priv->auth_message = g_strdup_printf ("%s,%s,%s",
- priv->client_first_bare + 3,
+ priv->client_first_bare,
priv->server_first_bare,
client_reply->str);