Handle corrupted decrypted passwords gracefully.
authorAndrej Kacian <ticho@claws-mail.org>
Thu, 6 Sep 2018 20:11:05 +0000 (22:11 +0200)
committerAndrej Kacian <ticho@claws-mail.org>
Thu, 6 Sep 2018 20:11:05 +0000 (22:11 +0200)
Check whether the decrypted password is a valid UTF-8
string, and return an empty string if not, instead of
returning garbage, probably not NULL-terminated data,
and causing problems down the road.

src/password.c

index 8f764e3467d1a57207439c7e07651a619db7ee32..463715b74cc8e7bda5ca0b78d009dcb6d9c832ab 100644 (file)
@@ -418,6 +418,7 @@ gchar *password_decrypt_gnutls(const gchar *password,
        unsigned char *buf;
        guint rounds;
        size_t commapos;
+       gboolean valid_utf8;
 
        g_return_val_if_fail(password != NULL, NULL);
        g_return_val_if_fail(decryption_passphrase != NULL, NULL);
@@ -522,7 +523,29 @@ gchar *password_decrypt_gnutls(const gchar *password,
        g_free(iv.data);
 
        /* 'buf+blocklen' should now be pointing to the plaintext
-        * password string. The first block contains random data from the IV. */
+        * password string.
+        * (The first block contains random data from the IV.)
+        *
+        * At this point, it should be a valid UTF-8 string. Let's make sure. */
+
+       /* First, let's assume there's just garbage and play it safe
+        * by looking for a first NULL byte within the decrypted range.
+        * (We could really use g_strchr_len() here instead, but Glib
+        * doesn't have that.) */
+       if (!g_strstr_len(buf + blocklen, len - blocklen, "\0")) {
+               debug_print("Could not find a NULL byte in the decrypted password.\n");
+               valid_utf8 = FALSE;
+       } else {
+               /* There is a NULL byte, we can rely on strlen() returning
+                * a sane value, so we don't read past the end of the allocated
+                * buffer. */
+               valid_utf8 = g_utf8_validate(buf + blocklen, strlen(buf + blocklen), NULL);
+       }
+
+       if (!valid_utf8)
+               debug_print("Decrypted password is not a valid UTF-8 string!\n");
+       cm_return_val_if_fail(valid_utf8, NULL);
+
        tmp = g_strndup(buf + blocklen, strlen(buf + blocklen));
        memset(buf, 0, len);
        g_free(buf);