]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-sasl: mech-scram - Implement SCRAM-SHA-1-PLUS and SCRAM-SHA-256-PLUS
authorStephan Bosch <stephan.bosch@open-xchange.com>
Sun, 5 Nov 2023 20:06:07 +0000 (21:06 +0100)
committerStephan Bosch <stephan.bosch@open-xchange.com>
Fri, 17 Jan 2025 17:36:39 +0000 (18:36 +0100)
src/lib-sasl/dsasl-client-private.h
src/lib-sasl/dsasl-client.c
src/lib-sasl/mech-scram.c

index b67964ffa1dc833c195350b665ad24a784a0f3af..cc8e9ba4e7c4af02bff39b2833f1c3726e1ff8ed 100644 (file)
@@ -43,7 +43,9 @@ extern const struct dsasl_client_mech dsasl_client_mech_login;
 extern const struct dsasl_client_mech dsasl_client_mech_oauthbearer;
 extern const struct dsasl_client_mech dsasl_client_mech_xoauth2;
 extern const struct dsasl_client_mech dsasl_client_mech_scram_sha_1;
+extern const struct dsasl_client_mech dsasl_client_mech_scram_sha_1_plus;
 extern const struct dsasl_client_mech dsasl_client_mech_scram_sha_256;
+extern const struct dsasl_client_mech dsasl_client_mech_scram_sha_256_plus;
 
 void dsasl_client_mech_register(const struct dsasl_client_mech *mech);
 void dsasl_client_mech_unregister(const struct dsasl_client_mech *mech);
index ebe6ffbd0114dc667fe323cc65fb8e7e8dc936b7..71d6bef957d35bf3729931b58c0657eed6dccccf 100644 (file)
@@ -153,7 +153,9 @@ void dsasl_clients_init(void)
        dsasl_client_mech_register(&dsasl_client_mech_oauthbearer);
        dsasl_client_mech_register(&dsasl_client_mech_xoauth2);
        dsasl_client_mech_register(&dsasl_client_mech_scram_sha_1);
+       dsasl_client_mech_register(&dsasl_client_mech_scram_sha_1_plus);
        dsasl_client_mech_register(&dsasl_client_mech_scram_sha_256);
+       dsasl_client_mech_register(&dsasl_client_mech_scram_sha_256_plus);
 }
 
 void dsasl_clients_deinit(void)
index d42fbc58a2a7dc82e0ec8afc2e85337d42ef07c6..65f0c07b909cea91ef8bb58482c60d47d4f04735 100644 (file)
@@ -9,24 +9,66 @@
 struct scram_dsasl_client {
        struct dsasl_client client;
 
+       const char *cbind_type;
+       const buffer_t *cbind_data;
        struct auth_scram_client scram_client;
 };
 
-static void mech_scram_init(struct scram_dsasl_client *sclient)
+static int
+mech_scram_init_channel_binding(struct scram_dsasl_client *sclient,
+                               const char **error_r)
+{
+       struct dsasl_client *client = &sclient->client;
+       const char *type;
+       const buffer_t *cbind_data;
+
+       if (client->channel_version >= SSL_IOSTREAM_PROTOCOL_VERSION_TLS1_3)
+               type = SSL_CHANNEL_BIND_TYPE_TLS_EXPORTER;
+       else
+               type = SSL_CHANNEL_BIND_TYPE_TLS_UNIQUE;
+
+       if (dasl_client_get_channel_binding(client, type,
+                                           &cbind_data, error_r) < 0)
+               return -1;
+
+       sclient->cbind_type = type;
+       sclient->cbind_data = buffer_clone(client->pool, cbind_data, 0);
+       return 0;
+}
+
+static int mech_scram_init(struct scram_dsasl_client *sclient,
+                          const char **error_r)
 {
        struct dsasl_client *client = &sclient->client;
        const struct hash_method *hmethod;
+       bool cbind = FALSE;
 
        /* SCRAM-SHA-1 */
        if (client->mech == &dsasl_client_mech_scram_sha_1) {
                hmethod = &hash_method_sha1;
+       /* SCRAM-SHA-1-PLUS */
+       } else if (client->mech == &dsasl_client_mech_scram_sha_1_plus) {
+               hmethod = &hash_method_sha1;
+               cbind = TRUE;
        /* SCRAM-SHA-256 */
        } else if (client->mech == &dsasl_client_mech_scram_sha_256) {
                hmethod = &hash_method_sha256;
+       /* SCRAM-SHA-256-PLUS */
+       } else if (client->mech == &dsasl_client_mech_scram_sha_256_plus) {
+               hmethod = &hash_method_sha256;
+               cbind = TRUE;
        } else {
                i_unreached();
        }
 
+       /* FIXME: We should determine server support for -PLUS mechanisms
+          explicitly and always initialize channel binding, so that the correct
+          p=,y,n gs2-header is sent. This is only possible when the SASL client
+          has access to the list of mechanisms announced by the server, which
+          is currently not available. */
+       if (cbind && mech_scram_init_channel_binding(sclient, error_r) < 0)
+               return -1;
+
        struct auth_scram_client_settings scram_set;
 
        i_zero(&scram_set);
@@ -34,9 +76,15 @@ static void mech_scram_init(struct scram_dsasl_client *sclient)
        scram_set.authid = client->set.authid;
        scram_set.authzid = client->set.authzid;
        scram_set.password = client->password;
+       scram_set.cbind_support = (cbind ? // FIXME: See above.
+                                  AUTH_SCRAM_CBIND_SERVER_SUPPORT_REQUIRED :
+                                  AUTH_SCRAM_CBIND_SERVER_SUPPORT_NONE);
+       scram_set.cbind_type = sclient->cbind_type;
+       scram_set.cbind_data = sclient->cbind_data;
 
        auth_scram_client_init(&sclient->scram_client, client->pool,
                               &scram_set);
+       return 0;
 }
 
 static int
@@ -47,8 +95,9 @@ mech_scram_input(struct dsasl_client *client,
        struct scram_dsasl_client *sclient =
                container_of(client, struct scram_dsasl_client, client);
 
-       if (sclient->scram_client.state == AUTH_SCRAM_CLIENT_STATE_INIT)
-               mech_scram_init(sclient);
+       if (sclient->scram_client.state == AUTH_SCRAM_CLIENT_STATE_INIT &&
+           mech_scram_init(sclient, error_r) < 0)
+               return -1;
 
        return auth_scram_client_input(&sclient->scram_client,
                                       input, input_len, error_r);
@@ -62,6 +111,9 @@ mech_scram_output(struct dsasl_client *client,
        struct scram_dsasl_client *sclient =
                container_of(client, struct scram_dsasl_client, client);
 
+       *output_r = NULL;
+       *output_len_r = 0;
+
        if (client->set.authid == NULL) {
                *error_r = "authid not set";
                return -1;
@@ -71,8 +123,9 @@ mech_scram_output(struct dsasl_client *client,
                return -1;
        }
 
-       if (sclient->scram_client.state == AUTH_SCRAM_CLIENT_STATE_INIT)
-               mech_scram_init(sclient);
+       if (sclient->scram_client.state == AUTH_SCRAM_CLIENT_STATE_INIT &&
+           mech_scram_init(sclient, error_r) < 0)
+               return -1;
 
        auth_scram_client_output(&sclient->scram_client,
                                 output_r, output_len_r);
@@ -96,6 +149,15 @@ const struct dsasl_client_mech dsasl_client_mech_scram_sha_1 = {
        .free = mech_scram_free,
 };
 
+const struct dsasl_client_mech dsasl_client_mech_scram_sha_1_plus = {
+       .name = "SCRAM-SHA-1-PLUS",
+       .struct_size = sizeof(struct scram_dsasl_client),
+
+       .input = mech_scram_input,
+       .output = mech_scram_output,
+       .free = mech_scram_free,
+};
+
 const struct dsasl_client_mech dsasl_client_mech_scram_sha_256 = {
        .name = "SCRAM-SHA-256",
        .struct_size = sizeof(struct scram_dsasl_client),
@@ -104,3 +166,12 @@ const struct dsasl_client_mech dsasl_client_mech_scram_sha_256 = {
        .output = mech_scram_output,
        .free = mech_scram_free,
 };
+
+const struct dsasl_client_mech dsasl_client_mech_scram_sha_256_plus = {
+       .name = "SCRAM-SHA-256-PLUS",
+       .struct_size = sizeof(struct scram_dsasl_client),
+
+       .input = mech_scram_input,
+       .output = mech_scram_output,
+       .free = mech_scram_free,
+};