From: Stephan Bosch Date: Fri, 21 Feb 2025 01:14:35 +0000 (+0100) Subject: lib-auth: auth-scram-server - Use auth-gs2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=ceeaadad10ed2f71e12bcea301d70e7173b64859;p=thirdparty%2Fdovecot%2Fcore.git lib-auth: auth-scram-server - Use auth-gs2 --- diff --git a/src/lib-auth/auth-scram-server.c b/src/lib-auth/auth-scram-server.c index b6b4062c8c..3a884e0ba1 100644 --- a/src/lib-auth/auth-scram-server.c +++ b/src/lib-auth/auth-scram-server.c @@ -17,6 +17,7 @@ #include "strfuncs.h" #include "strnum.h" +#include "auth-gs2.h" #include "auth-scram-server.h" /* s-nonce length */ @@ -92,37 +93,6 @@ void auth_scram_server_deinit(struct auth_scram_server *server) pool_unref(&server->pool); } -static const char *auth_scram_unescape_username(const char *in) -{ - string_t *out; - - /* RFC 5802, Section 5.1: - - The characters ',' or '=' in usernames are sent as '=2C' and '=3D' - respectively. If the server receives a username that contains '=' - not followed by either '2C' or '3D', then the server MUST fail the - authentication. - */ - - out = t_str_new(64); - for (; *in != '\0'; in++) { - i_assert(in[0] != ','); /* strsplit should have caught this */ - - if (in[0] == '=') { - if (in[1] == '2' && in[2] == 'C') - str_append_c(out, ','); - else if (in[1] == '3' && in[2] == 'D') - str_append_c(out, '='); - else - return NULL; - in += 2; - } else { - str_append_c(out, *in); - } - } - return str_c(out); -} - static int auth_scram_parse_client_first(struct auth_scram_server *server, const unsigned char *data, size_t size, @@ -130,13 +100,11 @@ auth_scram_parse_client_first(struct auth_scram_server *server, const char **login_username_r, const char **error_r) { - const char *login_username = NULL; - const char *data_cstr, *p; - const char *gs2_header, *gs2_cbind_flag, *authzid; - const char *cfm_bare, *username, *nonce; + struct auth_gs2_header gs2_header; + const unsigned char *gs2_header_end; + const char *cfm_bare, *login_username = NULL, *username, *nonce; const char *const *fields; - - data_cstr = gs2_header = t_strndup(data, size); + const char *error; /* RFC 5802, Section 7: @@ -158,25 +126,18 @@ auth_scram_parse_client_first(struct auth_scram_server *server, ;; MUST be ignored. attr-val = ALPHA "=" value */ - p = strchr(data_cstr, ','); - if (p == NULL) { - *error_r = "Invalid initial client message: " - "Missing first ',' in GS2 header"; - return -1; - } - gs2_cbind_flag = t_strdup_until(data_cstr, p); - data_cstr = p + 1; - p = strchr(data_cstr, ','); - if (p == NULL) { - *error_r = "Invalid initial client message: " - "Missing second ',' in GS2 header"; + if (auth_gs2_header_decode(data, size, FALSE, + &gs2_header, &gs2_header_end, &error) < 0) { + *error_r = t_strdup_printf("Invalid initial client message: %s", + error); return -1; } - authzid = t_strdup_until(data_cstr, p); - gs2_header = t_strdup_until(gs2_header, p + 1); - cfm_bare = p + 1; + size_t gs2_header_size = gs2_header_end - data; + size_t cfm_bare_size = size - gs2_header_size; + + cfm_bare = t_strndup(gs2_header_end, cfm_bare_size); fields = t_strsplit(cfm_bare, ","); if (str_array_length(fields) < 2) { *error_r = "Invalid initial client message: " @@ -191,20 +152,16 @@ auth_scram_parse_client_first(struct auth_scram_server *server, enum auth_scram_cbind_server_support cbind_support = server->set.cbind_support; - switch (gs2_cbind_flag[0]) { - case 'p': - if (gs2_cbind_flag[1] != '=' || gs2_cbind_flag[2] == '\0') { - *error_r = "Invalid GS2 header"; - return -1; - } + switch (gs2_header.cbind.status) { + case AUTH_GS2_CBIND_STATUS_PROVIDED: if (cbind_support == AUTH_SCRAM_CBIND_SERVER_SUPPORT_NONE) { *error_r = "Channel binding not supported"; return -1; } - auth_scram_server_start_channel_binding(server, - &gs2_cbind_flag[2]); + auth_scram_server_start_channel_binding( + server, gs2_header.cbind.name); break; - case 'y': + case AUTH_GS2_CBIND_STATUS_NO_SERVER_SUPPORT: /* RFC 5802, Section 6: If the flag is set to "y" and the server supports channel @@ -222,7 +179,7 @@ auth_scram_parse_client_first(struct auth_scram_server *server, return -1; } break; - case 'n': + case AUTH_GS2_CBIND_STATUS_NO_CLIENT_SUPPORT: if (cbind_support == AUTH_SCRAM_CBIND_SERVER_SUPPORT_REQUIRED) { *error_r = "Channel binding required"; return -1; @@ -236,20 +193,8 @@ auth_scram_parse_client_first(struct auth_scram_server *server, /* authzid = "a=" saslname ;; Protocol specific. */ - if (authzid[0] == '\0') - ; - else if (authzid[0] == 'a' && authzid[1] == '=') { - /* Unescape authzid */ - login_username = auth_scram_unescape_username(authzid + 2); - - if (login_username == NULL) { - *error_r = "authzid escaping is invalid"; - return -1; - } - } else { - *error_r = "Invalid authzid field"; - return -1; - } + if (gs2_header.authzid != NULL) + login_username = gs2_header.authzid; /* reserved-mext = "m=" 1*(value-char) */ @@ -260,9 +205,12 @@ auth_scram_parse_client_first(struct auth_scram_server *server, /* username = "n=" saslname */ if (username[0] == 'n' && username[1] == '=') { + const char *uname_enc = username + 2; + size_t uname_enc_size = strlen(uname_enc); + /* Unescape username */ - username = auth_scram_unescape_username(username + 2); - if (username == NULL) { + if (auth_gs2_decode_username((const unsigned char *)uname_enc, + uname_enc_size, &username) < 0) { *error_r = "Username escaping is invalid"; return -1; } @@ -282,9 +230,8 @@ auth_scram_parse_client_first(struct auth_scram_server *server, *username_r = username; *login_username_r = login_username; - server->gs2_header = p_strdup(server->pool, gs2_header); - server->client_first_message_bare = - p_strdup(server->pool, cfm_bare); + server->gs2_header = p_strndup(server->pool, data, gs2_header_size); + server->client_first_message_bare = p_strdup(server->pool, cfm_bare); return 0; }