From: Stephan Bosch Date: Sun, 5 Nov 2023 20:06:07 +0000 (+0100) Subject: lib-sasl: mech-scram - Implement SCRAM-SHA-1-PLUS and SCRAM-SHA-256-PLUS X-Git-Tag: 2.4.0~12 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=13ebb561b22e2c0758d0f1ca706e149df306c913;p=thirdparty%2Fdovecot%2Fcore.git lib-sasl: mech-scram - Implement SCRAM-SHA-1-PLUS and SCRAM-SHA-256-PLUS --- diff --git a/src/lib-sasl/dsasl-client-private.h b/src/lib-sasl/dsasl-client-private.h index b67964ffa1..cc8e9ba4e7 100644 --- a/src/lib-sasl/dsasl-client-private.h +++ b/src/lib-sasl/dsasl-client-private.h @@ -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); diff --git a/src/lib-sasl/dsasl-client.c b/src/lib-sasl/dsasl-client.c index ebe6ffbd01..71d6bef957 100644 --- a/src/lib-sasl/dsasl-client.c +++ b/src/lib-sasl/dsasl-client.c @@ -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) diff --git a/src/lib-sasl/mech-scram.c b/src/lib-sasl/mech-scram.c index d42fbc58a2..65f0c07b90 100644 --- a/src/lib-sasl/mech-scram.c +++ b/src/lib-sasl/mech-scram.c @@ -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, +};