diff options
author | Ruslan N. Marchenko <me@ruff.mobi> | 2020-09-05 13:19:55 +0200 |
---|---|---|
committer | Ruslan N. Marchenko <me@ruff.mobi> | 2020-09-23 20:31:10 +0200 |
commit | ce00127c0202ec1b66edc1bde6e349030059d0b8 (patch) | |
tree | 595c4f9bd1b4b8756df00947fd50ac90fbd73f02 | |
parent | 67edd727512749faa0bcb4c5202cd4146c0e389e (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.c | 66 | ||||
-rw-r--r-- | wocky/wocky-auth-registry.h | 18 | ||||
-rw-r--r-- | wocky/wocky-sasl-scram.c | 82 |
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); |