summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuslan N. Marchenko <me@ruff.mobi>2020-10-04 20:50:33 +0200
committerRuslan N. Marchenko <me@ruff.mobi>2020-10-05 15:40:53 +0200
commitfa4145eb9c300eab9f002675de56e8b9021730a4 (patch)
tree0d20f94f46e269e80dd83f2a5ecfb50311a5f643
parent43ea7cd17b98622b03495c90815266126cb8a89b (diff)
Add SASL SCRAM-SHA*-PLUS tests
-rw-r--r--tests/wocky-connector-test.c52
-rw-r--r--tests/wocky-test-sasl-auth-server.c223
-rw-r--r--tests/wocky-test-sasl-auth-server.h3
-rw-r--r--tests/wocky-test-sasl-auth.c11
4 files changed, 287 insertions, 2 deletions
diff --git a/tests/wocky-connector-test.c b/tests/wocky-connector-test.c
index 08d0267..5e77438 100644
--- a/tests/wocky-connector-test.c
+++ b/tests/wocky-connector-test.c
@@ -938,6 +938,58 @@ test_t tests[] =
{ NULL, 0 } } },
/* ********************************************************************* */
+ /* SASL SCRAM TLS channel binding tests and error conditions */
+#if G_ENCODE_VERSION (GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION) > G_ENCODE_VERSION(2,66)
+ { "/connector/auth/sasl/binding",
+ NOISY,
+ { S_NO_ERROR },
+ { { TLS, "SCRAM-SHA-512-PLUS" },
+ { SERVER_PROBLEM_NO_PROBLEM, CONNECTOR_OK },
+ { "moose", "something" },
+ PORT_XMPP },
+ { "weasel-juice.org", PORT_XMPP, "thud.org", REACHABLE, UNREACHABLE },
+ { TLS_REQUIRED,
+ { "moose@weasel-juice.org", "something", DIGEST, TLS },
+ { NULL, 0 } } },
+
+ { "/connector/auth/sasl/bad-binding-data",
+ NOISY,
+ { S_WOCKY_AUTH_ERROR, WOCKY_AUTH_ERROR_FAILURE, -1 },
+ { { TLS, "SCRAM-SHA-512-PLUS" },
+ { SERVER_PROBLEM_MANGLED_BINDING_DATA, CONNECTOR_OK },
+ { "moose", "something" },
+ PORT_XMPP },
+ { "weasel-juice.org", PORT_XMPP, "thud.org", REACHABLE, UNREACHABLE },
+ { TLS_REQUIRED,
+ { "moose@weasel-juice.org", "something", DIGEST, TLS },
+ { NULL, 0 } } },
+
+ { "/connector/auth/sasl/bad-binding-flag",
+ NOISY,
+ { S_WOCKY_AUTH_ERROR, WOCKY_AUTH_ERROR_FAILURE, -1 },
+ { { TLS, "SCRAM-SHA-512-PLUS" },
+ { SERVER_PROBLEM_MANGLED_BINDING_FLAG, CONNECTOR_OK },
+ { "moose", "something" },
+ PORT_XMPP },
+ { "weasel-juice.org", PORT_XMPP, "thud.org", REACHABLE, UNREACHABLE },
+ { TLS_REQUIRED,
+ { "moose@weasel-juice.org", "something", DIGEST, TLS },
+ { NULL, 0 } } },
+
+ { "/connector/auth/sasl/scrambled-binding",
+ NOISY,
+ { S_WOCKY_AUTH_ERROR, WOCKY_AUTH_ERROR_INVALID_REPLY, -1 },
+ { { TLS, "SCRAM-SHA-512-PLUS" },
+ { SERVER_PROBLEM_SCRAMBLED_BINDING, CONNECTOR_OK },
+ { "moose", "something" },
+ PORT_XMPP },
+ { "weasel-juice.org", PORT_XMPP, "thud.org", REACHABLE, UNREACHABLE },
+ { TLS_REQUIRED,
+ { "moose@weasel-juice.org", "something", DIGEST, TLS },
+ { NULL, 0 } } },
+#endif /* GLIB_VERSION_2_66 */
+
+ /* ********************************************************************* */
/* TLS error conditions */
{ "/connector/problem/tls/refused",
NOISY,
diff --git a/tests/wocky-test-sasl-auth-server.c b/tests/wocky-test-sasl-auth-server.c
index b0f2308..f66736a 100644
--- a/tests/wocky-test-sasl-auth-server.c
+++ b/tests/wocky-test-sasl-auth-server.c
@@ -101,6 +101,7 @@ struct _TestSaslAuthServerPrivate
ServerProblem problem;
GTask *task;
GCancellable *cancellable;
+ WockySaslScram *scram;
};
G_DEFINE_TYPE_WITH_CODE (TestSaslAuthServer, test_sasl_auth_server, G_TYPE_OBJECT,
@@ -398,12 +399,30 @@ success_sent (GObject *source,
{
GError *error = NULL;
gboolean ok;
+ TestSaslAuthServer *tsas = TEST_SASL_AUTH_SERVER (user_data);
+ TestSaslAuthServerPrivate *priv = test_sasl_auth_server_get_instance_private (tsas);
ok = wocky_xmpp_connection_send_stanza_finish (
WOCKY_XMPP_CONNECTION (source), result, &error);
g_assert_no_error (error);
g_assert (ok);
+ if (priv->problem == SERVER_PROBLEM_SCRAMBLED_BINDING && priv->task)
+ {
+ GTask *t = priv->task;
+
+ priv->task = NULL;
+
+ if (priv->cancellable != NULL)
+ g_object_unref (priv->cancellable);
+
+ priv->cancellable = NULL;
+
+ g_task_return_boolean (t, TRUE);
+ g_object_unref (t);
+ return;
+ }
+
wocky_xmpp_connection_reset (WOCKY_XMPP_CONNECTION (source));
wocky_xmpp_connection_recv_open_async (WOCKY_XMPP_CONNECTION (source),
@@ -490,7 +509,9 @@ check_sasl_return (TestSaslAuthServer *self, int ret)
{
case SASL_BADAUTH:
/* Bad password provided */
- g_assert_cmpint (priv->problem, ==, SERVER_PROBLEM_INVALID_PASSWORD);
+ g_assert_true (priv->problem == SERVER_PROBLEM_MANGLED_BINDING_FLAG
+ || priv->problem == SERVER_PROBLEM_MANGLED_BINDING_DATA
+ || priv->problem == SERVER_PROBLEM_INVALID_PASSWORD);
not_authorized (self);
return FALSE;
#if SASL_VERSION_FULL <= 0x02011B
@@ -648,6 +669,51 @@ static gchar * slash_challenge (const gchar *challenge, unsigned *len)
return g_string_free (slashed, FALSE);
}
+typedef struct {
+ TestSaslAuthServer *srv;
+ gchar *challenge;
+ gboolean complete;
+} ScramRes;
+
+static void
+handle_auth_cb (GObject *source,
+ GAsyncResult *result,
+ gpointer data)
+{
+ WockySaslScram *scram = WOCKY_SASL_SCRAM (source);
+ GError *error = NULL;
+ ScramRes *res = data;
+ TestSaslAuthServerPrivate *priv = test_sasl_auth_server_get_instance_private (res->srv);
+ gchar *username = NULL;
+
+ g_object_get (source, "username", &username, NULL);
+ if (priv->problem == SERVER_PROBLEM_INVALID_USERNAME)
+ {
+ g_assert_cmpstr (username, !=, priv->username);
+ }
+ else
+ {
+ g_assert_cmpstr (username, ==, priv->username);
+ g_object_set (source, "password", priv->password, NULL);
+ }
+ g_free (username);
+
+ res->challenge = wocky_sasl_scram_server_start_finish (scram, result, &error);
+
+ if (priv->problem == SERVER_PROBLEM_INVALID_USERNAME)
+ {
+ g_assert_error (error, WOCKY_AUTH_ERROR, WOCKY_AUTH_ERROR_NO_CREDENTIALS);
+ g_assert_null (res->challenge);
+ }
+ else
+ {
+ g_assert_no_error (error);
+ g_assert_nonnull (res->challenge);
+ }
+
+ res->complete = TRUE;
+}
+
static void
handle_auth (TestSaslAuthServer *self, WockyStanza *stanza)
{
@@ -702,6 +768,71 @@ handle_auth (TestSaslAuthServer *self, WockyStanza *stanza)
ret = wocky_strdiff ((gchar *) response, priv->password) ?
SASL_BADAUTH : SASL_OK;
}
+ else if (!wocky_strdiff ("SCRAM-SHA-512-PLUS", priv->selected_mech))
+ {
+ ScramRes res = { self, NULL, FALSE };
+ GIOStream *ios = NULL;
+
+ g_assert_nonnull (priv->conn);
+ g_assert_nonnull (priv->scram);
+
+#if G_ENCODE_VERSION (GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION) > G_ENCODE_VERSION(2,66)
+ g_object_get (G_OBJECT (priv->conn), "base-stream", &ios, NULL);
+ if (G_IS_TLS_CONNECTION (ios))
+ {
+ GError *err = NULL;
+ gchar *cb64 = NULL;
+ GByteArray *cb = g_byte_array_new ();
+
+ if (!g_tls_connection_get_channel_binding_data ((GTlsConnection *) ios,
+ G_TLS_CHANNEL_BINDING_TLS_UNIQUE, cb, &err))
+ {
+ g_error ("Error getting binding data: %s", err->message);
+ g_assert_not_reached ();
+ }
+
+ if (priv->problem == SERVER_PROBLEM_MANGLED_BINDING_DATA)
+ cb->data[0] ^= cb->data[1];
+ else if (priv->problem == SERVER_PROBLEM_MANGLED_BINDING_FLAG
+ || priv->problem == SERVER_PROBLEM_SCRAMBLED_BINDING)
+ {
+ gchar *r;
+ g_assert_true (g_str_has_prefix ((gchar *) response, "p=tls-unique,"));
+ r = g_strdup_printf ("n%s", response + 12);
+ g_free (response);
+ response = (guchar *) r;
+ }
+
+ cb64 = g_base64_encode (cb->data, cb->len);
+ g_byte_array_unref (cb);
+ g_object_set (G_OBJECT (priv->scram),
+ "cb-type", WOCKY_TLS_BINDING_TLS_UNIQUE,
+ "cb-data", cb64,
+ NULL);
+ g_debug ("TLS binding: %s", cb64);
+ g_free (cb64);
+ }
+ else
+ g_debug ("No TLS");
+#else
+ (void)(ios);
+#endif /* GLIB_VERSION_2_66 */
+
+ wocky_sasl_scram_server_start_async (priv->scram, (gchar *) response,
+ handle_auth_cb, priv->cancellable, &res);
+
+ while (!res.complete)
+ g_main_context_iteration (NULL, FALSE);
+
+ if (res.challenge)
+ {
+ ret = 1; /* SASL_CONTINUE */
+ challenge = res.challenge;
+ challenge_len = strlen (challenge);
+ }
+ else
+ ret = SASL_NOUSER;
+ }
else
{
#if HAVE_LIBSASL2
@@ -782,6 +913,52 @@ out:
}
static void
+handle_response_cb (GObject *source,
+ GAsyncResult *result,
+ gpointer data)
+{
+ WockySaslScram *scram = WOCKY_SASL_SCRAM (source);
+ GError *error = NULL;
+ ScramRes *res = data;
+ TestSaslAuthServerPrivate *priv = test_sasl_auth_server_get_instance_private (res->srv);
+
+
+ res->challenge = wocky_sasl_scram_server_step_finish (scram, result, &error);
+
+ if (priv->problem == SERVER_PROBLEM_INVALID_PASSWORD)
+ {
+ g_assert_error (error, WOCKY_AUTH_ERROR, WOCKY_AUTH_ERROR_NOT_AUTHORIZED);
+ g_assert_null (res->challenge);
+ }
+ else if (priv->problem == SERVER_PROBLEM_MANGLED_BINDING_DATA)
+ {
+ g_assert_error (error, WOCKY_AUTH_ERROR, WOCKY_AUTH_ERROR_FAILURE);
+ g_assert_null (res->challenge);
+ }
+ else if (priv->problem == SERVER_PROBLEM_MANGLED_BINDING_FLAG)
+ {
+ g_assert_error (error, WOCKY_AUTH_ERROR, WOCKY_AUTH_ERROR_FAILURE);
+ g_assert_null (res->challenge);
+ }
+ else if (priv->problem == SERVER_PROBLEM_SCRAMBLED_BINDING)
+ {
+ g_assert_error (error, WOCKY_AUTH_ERROR, WOCKY_AUTH_ERROR_NOT_AUTHORIZED);
+ g_assert_null (res->challenge);
+
+ /* Now pretend it didn't happen and provide phony server verification */
+ res->challenge = g_strdup_printf ("v=%s",
+ "QRx7t5sNW98H5eXodJPJKiQKZbEJBb1XKRnK9hb1ON+WU5/D4z/9wBtG1J2OKGt/gHdDzblO7BYbBhHVb6CXtg==");
+ }
+ else
+ {
+ g_assert_no_error (error);
+ g_assert_nonnull (res->challenge);
+ }
+
+ res->complete = TRUE;
+}
+
+static void
handle_response (TestSaslAuthServer *self, WockyStanza *stanza)
{
TestSaslAuthServerPrivate * priv = self->priv;
@@ -806,6 +983,40 @@ handle_response (TestSaslAuthServer *self, WockyStanza *stanza)
&response_len);
}
+ if (!wocky_strdiff ("SCRAM-SHA-512-PLUS", priv->selected_mech))
+ {
+ ScramRes res = { self, NULL, FALSE };
+
+ g_assert_nonnull (priv->scram);
+
+ if (priv->problem == SERVER_PROBLEM_SCRAMBLED_BINDING)
+ {
+ gchar *r, *rd = g_strstr_len ((gchar *) response, -1, ",");
+
+ g_assert_true (response[0] == 'c' && response[1] == '=' && rd != NULL);
+
+ r = g_strdup_printf ("c=biws,%s", rd + 1);
+ g_free (response);
+ response = (guchar *) r;
+ }
+
+ wocky_sasl_scram_server_step_async (priv->scram, (gchar *) response,
+ handle_response_cb, priv->cancellable, &res);
+
+ while (!res.complete)
+ g_main_context_iteration (NULL, FALSE);
+
+ if (res.challenge)
+ {
+ ret = SASL_OK;
+ challenge = res.challenge;
+ challenge_len = strlen (challenge);
+ }
+ else
+ ret = SASL_BADAUTH;
+ }
+ else
+ {
#ifdef HAVE_LIBSASL2
ret = sasl_server_step (priv->sasl_conn, (gchar *) response,
(unsigned) response_len, &challenge, &challenge_len);
@@ -814,6 +1025,7 @@ handle_response (TestSaslAuthServer *self, WockyStanza *stanza)
challenge_len = 0;
challenge = "";
#endif
+ }
if (!check_sasl_return (self, ret))
goto out;
@@ -848,7 +1060,8 @@ handle_response (TestSaslAuthServer *self, WockyStanza *stanza)
}
if (priv->state == AUTH_STATE_FINAL_CHALLENGE &&
- priv->problem == SERVER_PROBLEM_FINAL_DATA_IN_SUCCESS)
+ (priv->problem == SERVER_PROBLEM_FINAL_DATA_IN_SUCCESS
+ || priv->problem == SERVER_PROBLEM_SCRAMBLED_BINDING))
{
auth_succeeded (self, challenge64);
}
@@ -1018,6 +1231,12 @@ test_sasl_auth_server_new (GIOStream *stream, gchar *mech,
priv->mech = g_strdup (mech);
priv->problem = problem;
+ if (!wocky_strdiff ("SCRAM-SHA-512-PLUS", mech))
+ {
+ priv->scram = g_object_new (WOCKY_TYPE_SASL_SCRAM, "server", servername,
+ "hash-algo", G_CHECKSUM_SHA512, NULL);
+ }
+
if (start)
{
priv->stream = g_object_ref (stream);
diff --git a/tests/wocky-test-sasl-auth-server.h b/tests/wocky-test-sasl-auth-server.h
index d24a9fa..0c89c6f 100644
--- a/tests/wocky-test-sasl-auth-server.h
+++ b/tests/wocky-test-sasl-auth-server.h
@@ -39,6 +39,9 @@ typedef enum {
SERVER_PROBLEM_DISLIKE_GOOGLE_JDD,
SERVER_PROBLEM_SPACE_CHALLENGE,
SERVER_PROBLEM_SLASH_CHALLENGE,
+ SERVER_PROBLEM_MANGLED_BINDING_DATA,
+ SERVER_PROBLEM_MANGLED_BINDING_FLAG,
+ SERVER_PROBLEM_SCRAMBLED_BINDING,
/* Not actually a problem, but let the server choose to put
* ``additional data with success'' in a success stanza. */
SERVER_PROBLEM_FINAL_DATA_IN_SUCCESS,
diff --git a/tests/wocky-test-sasl-auth.c b/tests/wocky-test-sasl-auth.c
index 166f232..83e4aab 100644
--- a/tests/wocky-test-sasl-auth.c
+++ b/tests/wocky-test-sasl-auth.c
@@ -280,6 +280,11 @@ main (int argc,
0, 0, SERVER_PROBLEM_FINAL_DATA_IN_SUCCESS, FALSE, FALSE,
"test", "test123", NULL },
+ SUCCESS("/xmpp-sasl/scram-sha2-plus-multistep", "SCRAM-SHA-512-PLUS", TRUE),
+ { "/xmpp-sasl/scram-sha2-final-data-in-success", "SCRAM-SHA-512-PLUS", TRUE,
+ 0, 0, SERVER_PROBLEM_FINAL_DATA_IN_SUCCESS, FALSE, FALSE,
+ "test", "test123", NULL },
+
FAIL("/xmpp-sasl/no-supported-mechs", "NONSENSE", TRUE,
WOCKY_AUTH_ERROR, WOCKY_AUTH_ERROR_NO_SUPPORTED_MECHANISMS,
SERVER_PROBLEM_NO_PROBLEM),
@@ -296,6 +301,9 @@ main (int argc,
{ "/xmpp-sasl/wrong-username-md5", "DIGEST-MD5", TRUE,
WOCKY_AUTH_ERROR, WOCKY_AUTH_ERROR_FAILURE,
SERVER_PROBLEM_INVALID_USERNAME, TRUE, FALSE, "test", "test123" },
+ { "/xmpp-sasl/wrong-username-sha2", "SCRAM-SHA-512-PLUS", TRUE,
+ WOCKY_AUTH_ERROR, WOCKY_AUTH_ERROR_FAILURE,
+ SERVER_PROBLEM_INVALID_USERNAME, TRUE, FALSE, "test", "test123" },
{ "/xmpp-sasl/wrong-password-plain", "PLAIN", TRUE,
WOCKY_AUTH_ERROR, WOCKY_AUTH_ERROR_FAILURE,
@@ -303,6 +311,9 @@ main (int argc,
{ "/xmpp-sasl/wrong-password-md5", "DIGEST-MD5", TRUE,
WOCKY_AUTH_ERROR, WOCKY_AUTH_ERROR_FAILURE,
SERVER_PROBLEM_INVALID_PASSWORD, FALSE, TRUE, "test", "test123" },
+ { "/xmpp-sasl/wrong-password-sha2", "SCRAM-SHA-512-PLUS", TRUE,
+ WOCKY_AUTH_ERROR, WOCKY_AUTH_ERROR_FAILURE,
+ SERVER_PROBLEM_INVALID_PASSWORD, FALSE, TRUE, "test", "test123" },
/* Redo the MD5-DIGEST test with a username, password and realm that
* happens to generate a \0 byte in the md5 hash of