File CVE-2021-29157.patch of Package dovecot23.20136

diff --git a/src/lib-dict-extra/dict-fs.c b/src/lib-dict-extra/dict-fs.c
index 31af57867e..f39c86cdf9 100644
--- a/src/lib-dict-extra/dict-fs.c
+++ b/src/lib-dict-extra/dict-fs.c
@@ -68,8 +68,37 @@ static void fs_dict_deinit(struct dict *_dict)
 	i_free(dict);
 }
 
+/* Remove unsafe paths */
+static const char *fs_dict_escape_key(const char *key)
+{
+	const char *ptr;
+	string_t *new_key = NULL;
+	/* we take the slow path always if we see potential
+	   need for escaping */
+	while ((ptr = strstr(key, "/.")) != NULL) {
+		/* move to the first dot */
+		const char *ptr2 = ptr + 1;
+		/* find position of non-dot */
+		while (*ptr2 == '.') ptr2++;
+		if (new_key == NULL)
+			new_key = t_str_new(strlen(key));
+		str_append_data(new_key, key, ptr - key);
+		/* if ptr2 is / or end of string, escape */
+		if (*ptr2 == '/' || *ptr2 == '\0')
+			str_append(new_key, "/...");
+		else
+			str_append(new_key, "/.");
+		key = ptr + 2;
+	}
+	if (new_key == NULL)
+		return key;
+	str_append(new_key, key);
+	return str_c(new_key);
+}
+
 static const char *fs_dict_get_full_key(struct fs_dict *dict, const char *key)
 {
+	key = fs_dict_escape_key(key);
 	if (str_begins(key, DICT_PATH_SHARED))
 		return key + strlen(DICT_PATH_SHARED);
 	else if (str_begins(key, DICT_PATH_PRIVATE)) {
--- a/src/lib-oauth2/oauth2-jwt.c-orig	2021-06-17 15:48:47.937069922 +0200
+++ b/src/lib-oauth2/oauth2-jwt.c	2021-06-17 15:53:29.843386458 +0200
@@ -45,6 +45,34 @@
 	return 1;
 }
 
+/* Escapes '/' and '%' in identifier to %hex */
+static const char *escape_identifier(const char *identifier)
+{
+       size_t pos = strcspn(identifier, "/%");
+       /* nothing to escape */
+       if (identifier[pos] == '\0')
+               return identifier;
+
+       size_t len = strlen(identifier);
+       string_t *new_id = t_str_new(len);
+       str_append_data(new_id, identifier, pos);
+
+       for (size_t i = pos; i < len; i++) {
+               switch (identifier[i]) {
+               case '/':
+                       str_append(new_id, "%2f");
+                       break;
+               case '%':
+                       str_append(new_id, "%25");
+                       break;
+               default:
+                       str_append_c(new_id, identifier[i]);
+                       break;
+               }
+       }
+       return str_c(new_id);
+}
+
 static int oauth2_lookup_hmac_key(const struct oauth2_settings *set,
 				  const char *azp, const char *alg, const char *key_id,
 				  const buffer_t **hmac_key_r,
@@ -403,31 +431,8 @@
 	else if (*kid == '\0') {
 		*error_r = "'kid' field is empty";
 		return -1;
-	}
-
-	size_t pos = strcspn(kid, "./%");
-	if (pos < strlen(kid)) {
-		/* sanitize kid, cannot allow dots or / in it, so we encode them */
-		string_t *new_kid = t_str_new(strlen(kid));
-		/* put initial data */
-		str_append_data(new_kid, kid, pos);
-		for (const char *c = kid+pos; *c != '\0'; c++) {
-			switch (*c) {
-			case '.':
-				str_append(new_kid, "%2e");
-				break;
-			case '/':
-				str_append(new_kid, "%2f");
-				break;
-			case '%':
-				str_append(new_kid, "%25");
-				break;
-			default:
-				str_append_c(new_kid, *c);
-				break;
-			}
-		}
-		kid = str_c(new_kid);
+	} else {
+		kid = escape_identifier(kid);
 	}
 
 	/* parse body */
--- a/src/lib-oauth2/test-oauth2-jwt.c-orig	2021-06-17 15:47:42.257463288 +0200
+++ b/src/lib-oauth2/test-oauth2-jwt.c	2021-06-17 15:54:06.019172576 +0200
@@ -508,7 +508,7 @@
 	 void *ptr = buffer_append_space_unsafe(secret, 32);
 	 random_fill(ptr, 32);
 	 buffer_t *b64_key = t_base64_encode(0, (size_t)-1, secret->data, secret->used);
-	 save_key_to("HS256", "hello%2eworld%2f%25", str_c(b64_key));
+	 save_key_to("HS256", "hello.world%2f%25", str_c(b64_key));
 	/* make a token */
 	buffer_t *tokenbuf = create_jwt_token_kid("HS256", "hello.world/%");
 	/* sign it */
openSUSE Build Service is sponsored by