From: Stephan Bosch Date: Mon, 26 Sep 2022 23:34:45 +0000 (+0200) Subject: auth: mech-scram - Move parse_scram_client_final() to auth-scram-server.c. X-Git-Tag: 2.4.0~3143 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c5862da7e9b39ad37e9acecfc064f8a3ca1d44a5;p=thirdparty%2Fdovecot%2Fcore.git auth: mech-scram - Move parse_scram_client_final() to auth-scram-server.c. --- diff --git a/src/auth/auth-scram-server.c b/src/auth/auth-scram-server.c index 731d5c7f3e..dbe6a1e407 100644 --- a/src/auth/auth-scram-server.c +++ b/src/auth/auth-scram-server.c @@ -238,3 +238,86 @@ static bool verify_credentials(struct scram_auth_request *request) return mem_equals_timing_safe(stored_key, request->stored_key, sizeof(stored_key)); } + +static bool +parse_scram_client_final(struct scram_auth_request *request, + const unsigned char *data, size_t size, + const char **error_r) +{ + const struct hash_method *hmethod = request->hash_method; + const char **fields, *cbind_input, *nonce_str; + unsigned int field_count; + string_t *str; + + /* RFC 5802, Section 7: + + client-final-message-without-proof = + channel-binding "," nonce ["," + extensions] + client-final-message = + client-final-message-without-proof "," proof + */ + fields = t_strsplit(t_strndup(data, size), ","); + field_count = str_array_length(fields); + if (field_count < 3) { + *error_r = "Invalid final client message"; + return FALSE; + } + + /* channel-binding = "c=" base64 + ;; base64 encoding of cbind-input. + + cbind-data = 1*OCTET + cbind-input = gs2-header [ cbind-data ] + ;; cbind-data MUST be present for + ;; gs2-cbind-flag of "p" and MUST be absent + ;; for "y" or "n". + */ + cbind_input = request->gs2_header; + str = t_str_new(2 + MAX_BASE64_ENCODED_SIZE(strlen(cbind_input))); + str_append(str, "c="); + base64_encode(cbind_input, strlen(cbind_input), str); + + if (strcmp(fields[0], str_c(str)) != 0) { + *error_r = "Invalid channel binding data"; + return FALSE; + } + + /* nonce = "r=" c-nonce [s-nonce] + ;; Second part provided by server. + c-nonce = printable + s-nonce = printable + */ + nonce_str = t_strconcat("r=", request->cnonce, request->snonce, NULL); + if (strcmp(fields[1], nonce_str) != 0) { + *error_r = "Wrong nonce"; + return FALSE; + } + + /* proof = "p=" base64 + */ + if (fields[field_count-1][0] == 'p') { + size_t len = strlen(&fields[field_count-1][2]); + + request->proof = buffer_create_dynamic(request->pool, + MAX_BASE64_DECODED_SIZE(len)); + if (base64_decode(&fields[field_count-1][2], len, + request->proof) < 0) { + *error_r = "Invalid base64 encoding"; + return FALSE; + } + if (request->proof->used != hmethod->digest_size) { + *error_r = "Invalid ClientProof length"; + return FALSE; + } + } else { + *error_r = "Invalid ClientProof"; + return FALSE; + } + + (void)str_array_remove(fields, fields[field_count-1]); + request->client_final_message_without_proof = + p_strdup(request->pool, t_strarray_join(fields, ",")); + + return TRUE; +} diff --git a/src/auth/mech-scram.c b/src/auth/mech-scram.c index b506d19056..232ae97caa 100644 --- a/src/auth/mech-scram.c +++ b/src/auth/mech-scram.c @@ -128,89 +128,6 @@ credentials_callback(enum passdb_result result, } } -static bool -parse_scram_client_final(struct scram_auth_request *request, - const unsigned char *data, size_t size, - const char **error_r) -{ - const struct hash_method *hmethod = request->hash_method; - const char **fields, *cbind_input, *nonce_str; - unsigned int field_count; - string_t *str; - - /* RFC 5802, Section 7: - - client-final-message-without-proof = - channel-binding "," nonce ["," - extensions] - client-final-message = - client-final-message-without-proof "," proof - */ - fields = t_strsplit(t_strndup(data, size), ","); - field_count = str_array_length(fields); - if (field_count < 3) { - *error_r = "Invalid final client message"; - return FALSE; - } - - /* channel-binding = "c=" base64 - ;; base64 encoding of cbind-input. - - cbind-data = 1*OCTET - cbind-input = gs2-header [ cbind-data ] - ;; cbind-data MUST be present for - ;; gs2-cbind-flag of "p" and MUST be absent - ;; for "y" or "n". - */ - cbind_input = request->gs2_header; - str = t_str_new(2 + MAX_BASE64_ENCODED_SIZE(strlen(cbind_input))); - str_append(str, "c="); - base64_encode(cbind_input, strlen(cbind_input), str); - - if (strcmp(fields[0], str_c(str)) != 0) { - *error_r = "Invalid channel binding data"; - return FALSE; - } - - /* nonce = "r=" c-nonce [s-nonce] - ;; Second part provided by server. - c-nonce = printable - s-nonce = printable - */ - nonce_str = t_strconcat("r=", request->cnonce, request->snonce, NULL); - if (strcmp(fields[1], nonce_str) != 0) { - *error_r = "Wrong nonce"; - return FALSE; - } - - /* proof = "p=" base64 - */ - if (fields[field_count-1][0] == 'p') { - size_t len = strlen(&fields[field_count-1][2]); - - request->proof = buffer_create_dynamic(request->pool, - MAX_BASE64_DECODED_SIZE(len)); - if (base64_decode(&fields[field_count-1][2], len, - request->proof) < 0) { - *error_r = "Invalid base64 encoding"; - return FALSE; - } - if (request->proof->used != hmethod->digest_size) { - *error_r = "Invalid ClientProof length"; - return FALSE; - } - } else { - *error_r = "Invalid ClientProof"; - return FALSE; - } - - (void)str_array_remove(fields, fields[field_count-1]); - request->client_final_message_without_proof = - p_strdup(request->pool, t_strarray_join(fields, ",")); - - return TRUE; -} - void mech_scram_auth_continue(struct auth_request *auth_request, const unsigned char *data, size_t data_size) {