[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#991321: unblock: dovecot/1:2.3.13+dfsg1-2



Package: release.debian.org
Severity: normal
User: release.debian.org@packages.debian.org
Usertags: unblock

Please unblock package dovecot

[ Reason ]

Dovecot 1:2.3.13+dfsg1-2 includes two targeted security fixes and no other
changes.  The relevant section of debian/changelog is:

dovecot (1:2.3.13+dfsg1-2) unstable; urgency=high

  * Import upstream fixes for security issues (Closes: #990566):
    - CVE-2021-29157: Path traversal issue allowing an attacker with
      access to the local filesystem can trick OAuth2 authentication into
      using an HS256 validation key from an attacker-controlled location
    - CVE-2021-33515: Sensitive information could be redirected to an
      attacker-controlled address because of a STARTTLS command injection
      bug in the submission service

 -- Noah Meyerhans <noahm@debian.org>  Tue, 20 Jul 2021 08:05:19 -0700

[ Impact ]

We release bullseye with known security issues and will likely need to fix them
in a subsequent point release.

[ Tests ]

I've done basic functionality testing.  Additionally, the fixes are backported
from upstream's changes and are already included in Ubuntu's security archive,
so they've gotten reasonable test coverage at that level.  I do not have
reproducers for the security issues, so I have been unable to verify
experimentally that the problems have been fixed.

[ Risks ]

Code changes are reasonably straightforward, and as mentioned are already
deployed elsewhere.  Further, they impact what I believe to be less common
features of dovecot, meaning that even in the worst-case scenario, impact is
likely to be limited to a small number of users.

[ Checklist ]
  [x] all changes are documented in the d/changelog
  [x] I reviewed all changes and I approve them
  [x] attach debdiff against the package in testing

[ Other info ]

n/a

unblock dovecot/1:2.3.13+dfsg1-2
diff -Nru dovecot-2.3.13+dfsg1/debian/changelog dovecot-2.3.13+dfsg1/debian/changelog
--- dovecot-2.3.13+dfsg1/debian/changelog	2021-01-25 23:38:17.000000000 +0000
+++ dovecot-2.3.13+dfsg1/debian/changelog	2021-07-20 15:05:19.000000000 +0000
@@ -1,3 +1,15 @@
+dovecot (1:2.3.13+dfsg1-2) unstable; urgency=high
+
+  * Import upstream fixes for security issues (Closes: #990566):
+    - CVE-2021-29157: Path traversal issue allowing an attacker with
+      access to the local filesystem can trick OAuth2 authentication into
+      using an HS256 validation key from an attacker-controlled location
+    - CVE-2021-33515: Sensitive information could be redirected to an
+      attacker-controlled address because of a STARTTLS command injection
+      bug in the submission service
+
+ -- Noah Meyerhans <noahm@debian.org>  Tue, 20 Jul 2021 08:05:19 -0700
+
 dovecot (1:2.3.13+dfsg1-1) unstable; urgency=medium
 
   [ Christian Göttsche ]
diff -Nru dovecot-2.3.13+dfsg1/debian/patches/CVE-2021-29157.patch dovecot-2.3.13+dfsg1/debian/patches/CVE-2021-29157.patch
--- dovecot-2.3.13+dfsg1/debian/patches/CVE-2021-29157.patch	1970-01-01 00:00:00.000000000 +0000
+++ dovecot-2.3.13+dfsg1/debian/patches/CVE-2021-29157.patch	2021-07-19 22:09:38.000000000 +0000
@@ -0,0 +1,134 @@
+Description: fix incorrectly escapes kid and azp fields in JWT tokens
+Origin: https://launchpadlibrarian.net/544092180/dovecot_1%3A2.3.13+dfsg1-1ubuntu1_1%3A2.3.13+dfsg1-1ubuntu1.1.diff.gz
+
+--- a/src/lib-dict-extra/dict-fs.c
++++ b/src/lib-dict-extra/dict-fs.c
+@@ -67,8 +67,37 @@ static void fs_dict_deinit(struct 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
++++ b/src/lib-oauth2/oauth2-jwt.c
+@@ -250,6 +250,34 @@ oauth2_jwt_copy_fields(ARRAY_TYPE(oauth2
+ 	}
+ }
+ 
++/* 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_jwt_header_process(struct json_tree *tree, const char **alg_r,
+ 			  const char **kid_r, const char **error_r)
+@@ -349,6 +377,8 @@ oauth2_jwt_body_process(const struct oau
+ 	const char *azp = get_field(tree, "azp");
+ 	if (azp == NULL)
+ 		azp = "default";
++	else
++		azp = escape_identifier(azp);
+ 
+ 	if (oauth2_validate_signature(set, azp, alg, kid, blobs, error_r) < 0)
+ 		return -1;
+@@ -401,31 +431,8 @@ int oauth2_try_parse_jwt(const struct oa
+ 	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
++++ b/src/lib-oauth2/test-oauth2-jwt.c
+@@ -508,7 +508,7 @@ static void test_jwt_kid_escape(void)
+ 	 void *ptr = buffer_append_space_unsafe(secret, 32);
+ 	 random_fill(ptr, 32);
+ 	 buffer_t *b64_key = t_base64_encode(0, SIZE_MAX, 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 */
diff -Nru dovecot-2.3.13+dfsg1/debian/patches/CVE-2021-33515.patch dovecot-2.3.13+dfsg1/debian/patches/CVE-2021-33515.patch
--- dovecot-2.3.13+dfsg1/debian/patches/CVE-2021-33515.patch	1970-01-01 00:00:00.000000000 +0000
+++ dovecot-2.3.13+dfsg1/debian/patches/CVE-2021-33515.patch	2021-07-19 22:05:12.000000000 +0000
@@ -0,0 +1,62 @@
+commit 321c339756f9b2b98fb7326359d1333adebb5295
+Author: Stephan Bosch <stephan.bosch@open-xchange.com>
+Date:   Sat May 22 00:16:38 2021 +0200
+
+    lib-smtp: smtp-server-connection - Fix STARTTLS command injection vulnerability.
+    
+    The input handler kept reading more commands even though the input was locked by
+    the STARTTLS command, thereby causing it to read the command pipelined beyond
+    STARTTLS. This causes a STARTTLS command injection vulerability.
+
+--- a/src/lib-smtp/smtp-server-cmd-starttls.c
++++ b/src/lib-smtp/smtp-server-cmd-starttls.c
+@@ -37,6 +37,13 @@ static int cmd_starttls_start(struct smt
+ 		return -1;
+ 	}
+ 
++	/* The command queue must be empty at this point. If anything were to be
++	   queued somehow, this connection is vulnerable to STARTTLS command
++	   insertion.
++	 */
++	i_assert(conn->command_queue_count == 0 &&
++		 conn->command_queue_head == NULL);
++
+ 	/* RFC 3207, Section 4.2:
+ 
+ 	   Upon completion of the TLS handshake, the SMTP protocol is reset to
+@@ -107,6 +114,13 @@ cmd_starttls_next(struct smtp_server_cmd
+ 	const struct smtp_server_callbacks *callbacks = conn->callbacks;
+ 	int ret;
+ 
++	/* The command queue can only contain the STARTTLS command at this
++	   point. If anything beyond the STARTTLS were queued somehow, this
++	   connection is vulnerable to STARTTLS command insertion.
++	 */
++	i_assert(conn->command_queue_count == 1 &&
++	         conn->command_queue_tail == command);
++
+ 	smtp_server_connection_set_state(conn, SMTP_SERVER_STATE_STARTTLS,
+ 					 NULL);
+ 
+--- a/src/lib-smtp/smtp-server-connection.c
++++ b/src/lib-smtp/smtp-server-connection.c
+@@ -440,7 +440,7 @@ smtp_server_connection_handle_input(stru
+ 
+ 	/* Parse commands */
+ 	ret = 1;
+-	while (!conn->closing && ret != 0) {
++	while (!conn->closing && !conn->input_locked && ret != 0) {
+ 		while ((ret = smtp_command_parse_next(
+ 			conn->smtp_parser, &cmd_name, &cmd_params,
+ 			&error_code, &error)) > 0) {
+@@ -464,6 +464,10 @@ smtp_server_connection_handle_input(stru
+ 
+ 			if (conn->disconnected)
+ 				return;
++			/* Last command locked the input; stop trying to read
++			   more. */
++			if (conn->input_locked)
++				break;
+ 			/* Client indicated it will close after this command;
+ 			   stop trying to read more. */
+ 			if (conn->closing)
diff -Nru dovecot-2.3.13+dfsg1/debian/patches/series dovecot-2.3.13+dfsg1/debian/patches/series
--- dovecot-2.3.13+dfsg1/debian/patches/series	2021-01-25 23:38:17.000000000 +0000
+++ dovecot-2.3.13+dfsg1/debian/patches/series	2021-07-19 22:05:12.000000000 +0000
@@ -16,3 +16,5 @@
 Fix-32bit-sign-comparisons.patch
 Fix-32-bit-test-case.patch
 Improve-cross-compile-support.patch
+CVE-2021-29157.patch
+CVE-2021-33515.patch

Reply to: