[evolution] I#1568 - Cannot import PKCS12 certificate with non-ASCII or empty password



commit 87d713340f992cc6f79464c036d4d4933285935d
Author: Milan Crha <mcrha redhat com>
Date:   Tue Apr 5 16:13:15 2022 +0200

    I#1568 - Cannot import PKCS12 certificate with non-ASCII or empty password
    
    Closes https://gitlab.gnome.org/GNOME/evolution/-/issues/1568

 src/smime/lib/e-pkcs12.c | 151 ++++++++++++++++++++++++++++++++---------------
 1 file changed, 102 insertions(+), 49 deletions(-)
---
diff --git a/src/smime/lib/e-pkcs12.c b/src/smime/lib/e-pkcs12.c
index a2e6096af7..3fce513ebe 100644
--- a/src/smime/lib/e-pkcs12.c
+++ b/src/smime/lib/e-pkcs12.c
@@ -146,6 +146,7 @@ prompt_for_password (gchar *title,
                      gchar *prompt,
                      SECItem *pwd)
 {
+       gboolean res = TRUE;
        gchar *passwd;
 
        passwd = e_passwords_ask_password (
@@ -155,59 +156,63 @@ prompt_for_password (gchar *title,
 
        if (passwd) {
                gsize len = strlen (passwd);
-               const gchar *inptr = passwd;
-               guchar *outptr;
-               gunichar2 c;
-
-               SECITEM_AllocItem (NULL, pwd, sizeof (gunichar2) * (len + 1));
-
-               outptr = pwd->data;
-               while (inptr && (c = (gunichar2) (g_utf8_get_char (inptr) & 0xffff))) {
-                       inptr = g_utf8_next_char (inptr);
-                       c = GUINT16_TO_BE (c);
-                       *outptr++ = ((gchar *) &c)[0];
-                       *outptr++ = ((gchar *) &c)[1];
-               }
 
-               outptr[0] = 0;
-               outptr[1] = 0;
+               pwd->len = len * 3 + 2;
+               pwd->data = (unsigned char *) PORT_ZAlloc (pwd->len);
+
+               if (pwd->data) {
+                       PRBool toUnicode = PR_TRUE;
+                       #if G_BYTE_ORDER == G_LITTLE_ENDIAN
+                       PRBool swapUnicode = PR_TRUE;
+                       #else
+                       PRBool swapUnicode = PR_FALSE;
+                       #endif
+                       if (PORT_UCS2_ASCIIConversion (toUnicode, (unsigned char *) passwd, len, pwd->data, 
pwd->len, &pwd->len, swapUnicode) == PR_FALSE) {
+                               res = FALSE;
+                       } else if ((pwd->len >= 2) && (pwd->data[pwd->len - 1] || pwd->data[pwd->len - 2])) {
+                               if (pwd->len + 2 > 3 * len)
+                                       pwd->data = (unsigned char *) PORT_Realloc (pwd->data, pwd->len + 2);
+                               if (!pwd->data) {
+                                       res = FALSE;
+                               } else {
+                                       pwd->len += 2;
+                                       pwd->data[pwd->len - 1] = 0;
+                                       pwd->data[pwd->len - 2] = 0;
+                               }
+                       }
+               } else {
+                       res = FALSE;
+               }
 
                memset (passwd, 0, strlen (passwd));
                g_free (passwd);
+
+               if (!res && pwd->data) {
+                       PORT_Free (pwd->data);
+                       pwd->data = NULL;
+                       pwd->len = 0;
+               }
        }
 
-       return TRUE;
+       return res;
 }
 
-static gboolean
-import_from_file_helper (EPKCS12 *pkcs12,
-                         PK11SlotInfo *slot,
-                         const gchar *path,
-                         gboolean *aWantRetry,
-                         GError **error)
+static SEC_PKCS12DecoderContext *
+read_with_password (PK11SlotInfo *slot,
+                   const gchar *path,
+                   SECItem *passwd,
+                   SECStatus *out_status,
+                   gboolean *out_rv,
+                   GError **error)
 {
-       /*nsNSSShutDownPreventionLock locker; */
-       gboolean rv;
-       SECStatus srv = SECSuccess;
        SEC_PKCS12DecoderContext *dcx = NULL;
-       SECItem passwd;
-       GError *err = NULL;
 
-       *aWantRetry = FALSE;
-
-       passwd.data = NULL;
-       rv = prompt_for_password (
-               _("PKCS12 File Password"),
-               _("Enter password for PKCS12 file:"), &passwd);
-       if (!rv) goto finish;
-       if (passwd.data == NULL) {
-               handle_error (PKCS12_USER_CANCELED);
-               return TRUE;
-       }
+       *out_status = SECFailure;
+       *out_rv = FALSE;
 
        /* initialize the decoder */
        dcx = SEC_PKCS12DecoderStart (
-               &passwd,
+               passwd,
                slot,
                /* we specify NULL for all the
                 * funcs + data so it'll use the
@@ -215,27 +220,72 @@ import_from_file_helper (EPKCS12 *pkcs12,
                NULL, NULL, NULL,
                NULL, NULL, NULL);
        if (!dcx) {
-               srv = SECFailure;
-               goto finish;
+               *out_status = SECFailure;
+               return NULL;
        }
        /* read input file and feed it to the decoder */
-       rv = input_to_decoder (dcx, path, &err);
-       if (!rv) {
+       *out_rv = input_to_decoder (dcx, path, error);
+       if (!*out_rv) {
 #ifdef notyet
                /* XXX we need this to check the gerror */
                if (NS_ERROR_ABORT == rv) {
                        /* inputToDecoder indicated a NSS error */
-                       srv = SECFailure;
+                       *out_status = SECFailure;
                }
 #else
-               srv = SECFailure;
+               *out_status = SECFailure;
 #endif
-               goto finish;
+               SEC_PKCS12DecoderFinish (dcx);
+
+               return NULL;
        }
 
        /* verify the blob */
-       srv = SEC_PKCS12DecoderVerify (dcx);
-       if (srv) goto finish;
+       *out_status = SEC_PKCS12DecoderVerify (dcx);
+       if (*out_status) {
+               SEC_PKCS12DecoderFinish (dcx);
+               dcx = NULL;
+       }
+
+       return dcx;
+}
+
+static gboolean
+import_from_file_helper (EPKCS12 *pkcs12,
+                         PK11SlotInfo *slot,
+                         const gchar *path,
+                         gboolean *aWantRetry,
+                         GError **error)
+{
+       /*nsNSSShutDownPreventionLock locker; */
+       gboolean rv;
+       SECStatus srv = SECSuccess;
+       SEC_PKCS12DecoderContext *dcx = NULL;
+       SECItem passwd;
+
+       *aWantRetry = FALSE;
+
+       memset (&passwd, 0, sizeof (SECItem));
+
+       /* First try without password */
+       dcx = read_with_password (slot, path, &passwd, &srv, &rv, NULL);
+
+       /* if failed, ask for password */
+       if (!dcx) {
+               passwd.data = NULL;
+               rv = prompt_for_password (
+                       _("PKCS12 File Password"),
+                       _("Enter password for PKCS12 file:"), &passwd);
+               if (!rv)
+                       goto finish;
+               if (passwd.data == NULL) {
+                       handle_error (PKCS12_USER_CANCELED);
+                       return TRUE;
+               }
+
+               dcx = read_with_password (slot, path, &passwd, &srv, &rv, error);
+       }
+
        /* validate bags */
        srv = SEC_PKCS12DecoderValidateBags (dcx, nickname_collision);
        if (srv) goto finish;
@@ -249,7 +299,8 @@ import_from_file_helper (EPKCS12 *pkcs12,
         * We should use that error code instead of inventing a new one
         * for every error possible. */
        if (srv != SECSuccess) {
-               if (SEC_ERROR_BAD_PASSWORD == PORT_GetError ()) {
+               if (SEC_ERROR_BAD_PASSWORD == PORT_GetError () ||
+                   SEC_ERROR_INVALID_ARGS == PORT_GetError ()) {
                        *aWantRetry = TRUE;
                }
                handle_error (PKCS12_NSS_ERROR);
@@ -259,6 +310,8 @@ import_from_file_helper (EPKCS12 *pkcs12,
        /* finish the decoder */
        if (dcx)
                SEC_PKCS12DecoderFinish (dcx);
+       if (passwd.data)
+               PORT_Free (passwd.data);
        return TRUE;
 }
 


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