After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 752392 - gcr-viewer won't unlock p12 certificate with password length > 31 characters
gcr-viewer won't unlock p12 certificate with password length > 31 characters
Status: RESOLVED OBSOLETE
Product: gcr
Classification: Core
Component: General
3.20.x
Other Linux
: Normal normal
: ---
Assigned To: GNOME keyring maintainer(s)
GNOME keyring maintainer(s)
Depends on:
Blocks:
 
 
Reported: 2015-07-14 21:38 UTC by Marcelo Fernández
Modified: 2021-05-17 13:19 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
test case (8.94 KB, patch)
2016-04-05 12:20 UTC, Tobias Mueller
none Details | Review
patch for PCKS#12 files with long password (2.64 KB, patch)
2016-04-14 14:25 UTC, Andrei M
none Details | Review
patch for pkcs12 files with long password (3.14 KB, patch)
2016-04-20 12:44 UTC, Andrei M
none Details | Review

Description Marcelo Fernández 2015-07-14 21:38:23 UTC
I am unable to import a p12 s/mime certificate using gcr if the certificate is encrypted with a password containing 32 or more characters. When trying to unlock the certificate, gcr responds as if the password entered was incorrect.

Reported at: https://bugs.launchpad.net/ubuntu/+source/gcr/+bug/1400192

Thank you
Comment 1 Andrei M 2016-03-13 13:30:39 UTC
Hi,

Is this bug stil not fixed? I would like to work on it.
Comment 2 Marcelo Fernández 2016-03-13 13:58:45 UTC
Hi Andrei,

I don't know if it's fixed in upstream yet...

Regards
Comment 3 Stef Walter 2016-03-13 14:35:49 UTC
Andrei, that would be great. No fix for this has landed in git yet.
Comment 4 Andrei M 2016-03-15 15:59:48 UTC
Hi,

I am not familiar with the gcr code, but I narrowed down some files where this bug might happen. I hope you can follow the wall text and give me some hints where this bug may happen because I still cannot figure it out ("-------->" is just a delimiter I've used to show the "flow" of the calls):


--------> FILE: gcr/ui/gcr-viewer-widget.c:

static gboolean
on_parser_authenticate_for_unlock (GcrParser *parser,
                                   guint count,
                                   gpointer user_data)
{
	GcrUnlockRenderer *unlock = GCR_UNLOCK_RENDERER (user_data);
	const gchar *password;

	if (count == 0) {
		password = _gcr_unlock_renderer_get_password (unlock);
		gcr_parser_add_password (parser, password);
	}

	return TRUE;
}

--------> in the same file, the above function is attached to a signal:

static void
on_unlock_renderer_clicked (GcrUnlockRenderer *unlock,
                            gpointer user_data)
{
        .........................
	/* Override our main authenticate signal handler */
	sig = g_signal_connect (self->pv->parser, "authenticate",
	                        G_CALLBACK (on_parser_authenticate_for_unlock), unlock);
        .........................
}

--------> FILE: gcr/ui/gcr-unlock-renderer.c (I'm guessing this is the function called to retrieve the password from the entry box)

const gchar *
_gcr_unlock_renderer_get_password (GcrUnlockRenderer *self)
{
	g_return_val_if_fail (GCR_IS_UNLOCK_RENDERER (self), NULL);
	return gtk_entry_get_text (self->pv->entry);
}

--------> FILE: gcr/gcr/gcr-parser.c
(the docstring for this function says:
/*Add a password to the set of passwords to try when parsing locked or   encrypted items. This is usually called from the #GcrParser::authenticate signal.
 */)

void
gcr_parser_add_password (GcrParser *self, const gchar *password)
{
	g_return_if_fail (GCR_IS_PARSER (self));
	g_ptr_array_add (self->pv->passwords, egg_secure_strdup (password));
}

--------> FILE: gcr/egg/egg-secure-memory.h

static inline void* egg_secure_strdup (const char *str) { \
		return egg_secure_strdup_full (G_STRINGIFY (tag), str, EGG_SECURE_USE_FALLBACK); \


--------> FILE: gcr/egg/egg-secure-memory.c

char*
egg_secure_strdup_full (const char *tag,
                        const char *str,
                        int options)
{
	size_t len;
	char *res;

	if (!str)
		return NULL;

	len = strlen (str) + 1;
	res = (char *)egg_secure_alloc_full (tag, len, options);
	strcpy (res, str);
	return res;
}

--------> in the same file as above we have this function ("egg_secure_alloc_full") which I believe is the last to be called:

void*
egg_secure_alloc_full (const char *tag,
                       size_t length,
                       int flags)
{
	Block *block;
	void *memory = NULL;

	if (tag == NULL)
		tag = "?";

	if (length > 0xFFFFFFFF / 2) {
		if (egg_secure_warnings)
			fprintf (stderr, "tried to allocate an insane amount of memory: %lu\n", (unsigned long)length);
		return NULL;
	}

	/* Can't allocate zero bytes */
	if (length == 0)
		return NULL;

	DO_LOCK ();

		for (block = all_blocks; block; block = block->next) {
			memory = sec_alloc (block, tag, length);
			if (memory)
				break;
		}

		/* None of the current blocks have space, allocate new */
		if (!memory) {
			block = sec_block_create (length, tag);
			if (block)
				memory = sec_alloc (block, tag, length);
		}

#ifdef WITH_VALGRIND
		if (memory != NULL)
			VALGRIND_MALLOCLIKE_BLOCK (memory, length, sizeof (void*), 1);
#endif

	DO_UNLOCK ();

	if (!memory && (flags & EGG_SECURE_USE_FALLBACK) && EGG_SECURE_GLOBALS.fallback != NULL) {
		memory = EGG_SECURE_GLOBALS.fallback (NULL, length);
		if (memory) /* Our returned memory is always zeroed */
			memset (memory, 0, length);
	}

	if (!memory)
		errno = ENOMEM;

	return memory;
}
Comment 5 Stef Walter 2016-03-15 16:03:13 UTC
Do you have a reproducer? I would suggest building a test case (see test-parser.c) for parsing this such a file with a long password. Then it'll be easier to track why and where it fails.
Comment 6 Andrei M 2016-03-15 16:10:37 UTC
No I don't have, but I reproduced the error myself by manual typying it (:/).
I am going to do that now , thanks.
Comment 7 Tobias Mueller 2016-04-05 12:20:39 UTC
Created attachment 325417 [details] [review]
test case

It seems that gcr/gcr-parser.c around line 940 fails as it returns NULL:

        asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-8-EncryptedPrivateKeyInfo", data);
Comment 8 Tobias Mueller 2016-04-12 16:47:02 UTC
There seems to be a limit in generate_pkcs12 in egg/egg-symkey.c

Andrei found the verify_pkcs12_safe to return GCR_ERROR_LOCKED. Drilling further down, generate_pkcs12 seems to be the culprit.

    /* Bring in the password, as 16bits per character BMP string, ie: UCS2 */
    if (utf8_password) {
        p2 = utf8_password;
        for (i = 0; i < 64; i += 2) {


It clearly only regards 32 characters of the password.
If the password is shorter than 32 characters, the password is repeated, it seems.

So it seems as if the password should indeed be normalised to 32 characters. I don't know what to do with longer passwords though. I guess the PKCS#12 spec has some answers...
Comment 9 Andrei M 2016-04-14 14:25:38 UTC
Created attachment 326008 [details] [review]
patch for PCKS#12 files with long password

This patch does not yet solve the problem, but it adheres to the current way GnuTLS API is generating keys from password strings (as shown here https://gitlab.com/gnutls/gnutls/blob/master/lib/x509/pkcs12_encr.c#L57).

There might be something else that needs to be changed in the function I modified it (generate_pkcs12) but at the moment I am missing more information.


I would appreciate any feedback for this work, as I've spent some time searching what was the actual problem. Thanks :-)
Comment 10 Andrei M 2016-04-20 12:44:18 UTC
Created attachment 326410 [details] [review]
patch for pkcs12 files with long password

As Tobias said above, password with more than 31 characters are truncated,
so rest of the chars aren't taking into account when the hash is generated.

So I've increased the buffer size and the loop range is now formalized to this
((n_password/32)*64)+64

This works and unlocks the certificate, but somehow only "half" of it is displayed in the GUI ...
Comment 11 Tobias Mueller 2016-06-06 11:13:48 UTC
FWIW: gpgsm also cannot decode the p12 file.

>gpgsm --import  gcr/fixtures/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.p12 
gpgsm: 1016 bytes of RC2 encrypted text
gpgsm: password too long
gpgsm: decryption failed; trying charset 'ISO-8859-1'
gpgsm: password too long
gpgsm: decryption failed; trying charset 'ISO-8859-15'
gpgsm: password too long
gpgsm: decryption failed; trying charset 'ISO-8859-2'
gpgsm: password too long
gpgsm: decryption failed; trying charset 'ISO-8859-3'
gpgsm: password too long
gpgsm: decryption failed; trying charset 'ISO-8859-4'
gpgsm: password too long
gpgsm: decryption failed; trying charset 'ISO-8859-5'
gpgsm: password too long
gpgsm: decryption failed; trying charset 'ISO-8859-6'
gpgsm: password too long
gpgsm: decryption failed; trying charset 'ISO-8859-7'
gpgsm: password too long
gpgsm: decryption failed; trying charset 'ISO-8859-8'
gpgsm: password too long
gpgsm: decryption failed; trying charset 'ISO-8859-9'
gpgsm: password too long
gpgsm: decryption failed; trying charset 'KOI8-R'
gpgsm: password too long
gpgsm: decryption failed; trying charset 'IBM437'
gpgsm: password too long
gpgsm: decryption failed; trying charset 'IBM850'
gpgsm: password too long
gpgsm: decryption failed; trying charset 'EUC-JP'
gpgsm: password too long
gpgsm: decryption failed; trying charset 'BIG5'
gpgsm: password too long
gpgsm: encryptedData error at "outer.outer.seq", offset 2
gpgsm: possibly bad passphrase given
gpgsm: error at "bag.encryptedData", offset 49
gpgsm: error parsing or decrypting the PKCS#12 file
gpgsm: total number processed: 0


That's on the aaaa....p12 file I generated with 

    openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout
    privateKey.key -out certificate.crt
    
and then
    
    openssl pkcs12 -export -in certs/personal.crt -inkey keys/personal.key
    -certfile certs/ca.crt -name "My example certificate" -out
    personal.example.p12

So maybe this is a problem with the spec.
What's the reference for both the current implement and the expected behaviour?
Comment 12 GNOME Infrastructure Team 2021-05-17 13:19:16 UTC
-- GitLab Migration Automatic Message --

This bug has been migrated to GNOME's GitLab instance and has been closed from further activity.

You can subscribe and participate further through the new bug through this link to our GitLab instance: https://gitlab.gnome.org/GNOME/gcr/-/issues/75.