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 */