--- Begin Message ---
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
--- End Message ---