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;
+}
}
}
-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)
{