* PKCS#12 import now tries several encodings in case the passphrase

was not utf-8 encoded.
This commit is contained in:
Werner Koch 2007-03-19 18:54:34 +00:00
parent 9e95c2dff6
commit 083010a53d
4 changed files with 167 additions and 29 deletions

3
NEWS
View File

@ -4,6 +4,9 @@ Noteworthy changes in version 2.0.4
* The Assuan key listing commands are now also working for systems
without the funopen/fopencookie API.
* PKCS#12 import now tries several encodings in case the passphrase
was not utf-8 encoded.
Noteworthy changes in version 2.0.3 (2007-03-08)
------------------------------------------------

4
TODO
View File

@ -83,10 +83,6 @@
* sm/
** check that we issue NO_SECKEY xxx if a -u key was not found
We don't. The messages returned are also wrong (recipient vs. signer).
** cmd_export
Does only work on systems with funopen/fopencookie. Changing is
easy.
* jnlib/
** provide jnlib_malloc and try to remove all jnlib_xmalloc.

View File

@ -1,3 +1,10 @@
2007-03-19 Werner Koch <wk@g10code.com>
* minip12.c: Include iconv.h.
(decrypt_block): New.
(parse_bag_encrypted_data, parse_bag_data): Use it here.
(bag_data_p, bag_decrypted_data_p): New helpers.
2007-03-06 Werner Koch <wk@g10code.com>
* gpg-agent.c (main) <gpgconf>: Add entries for all ttl options.
@ -1749,7 +1756,8 @@ Fri Aug 18 14:27:14 CEST 2000 Werner Koch <wk@openit.de>
* Makefile.am: New.
Copyright 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
Copyright 2001, 2002, 2003, 2004, 2005,
2007 Free Software Foundation, Inc.
This file is free software; as a special exception the author gives
unlimited permission to copy and/or distribute it, with or without

View File

@ -27,6 +27,7 @@
#include <string.h>
#include <assert.h>
#include <gcrypt.h>
#include <iconv.h>
#ifdef TEST
#include <sys/stat.h>
@ -41,6 +42,12 @@
#define DIM(v) (sizeof(v)/sizeof((v)[0]))
#endif
#ifndef ICONV_CONST
#define ICONV_CONST
#endif
enum
{
UNIVERSAL = 0,
@ -483,6 +490,120 @@ crypt_block (unsigned char *buffer, size_t length, char *salt, size_t saltlen,
}
/* Decrypt a block of data and try several encodings of the key.
CIPHERTEXT is the encrypted data of size LENGTH bytes; PLAINTEXT is
a buffer of the same size to receive the decryption result. SALT,
SALTLEN, ITER and PW are the information required for decryption
and CIPHER_ALGO is the algorithm id to use. CHECK_FNC is a
function called with the plaintext and used to check whether the
decryption succeeded; i.e. that a correct passphrase has been
given. That function shall return true if the decryption has likely
succeeded. */
static void
decrypt_block (const void *ciphertext, unsigned char *plaintext, size_t length,
char *salt, size_t saltlen,
int iter, const char *pw, int cipher_algo,
int (*check_fnc) (const void *, size_t))
{
static const char const *charsets[] = {
"", /* No conversion - use the UTF-8 passphrase direct. */
"ISO-8859-1",
"ISO-8859-15",
"ISO-8859-2",
"ISO-8859-3",
"ISO-8859-4",
"ISO-8859-5",
"ISO-8859-6",
"ISO-8859-7",
"ISO-8859-8",
"ISO-8859-9",
"KOI8-R",
NULL
};
int charsetidx = 0;
char *convertedpw = NULL; /* Malloced and converted password or NULL. */
size_t convertedpwsize = 0; /* Allocated length. */
for (charsetidx=0; charsets[charsetidx]; charsetidx++)
{
if (*charsets[charsetidx])
{
iconv_t cd;
const char *inptr;
char *outptr;
size_t inbytes, outbytes;
if (!convertedpw)
{
/* We assume one byte encodings. Thus we can allocate
the buffer of the same size as the original
passphrase; the result will actually be shorter
then. */
convertedpwsize = strlen (pw) + 1;
convertedpw = gcry_malloc_secure (convertedpwsize);
if (!convertedpw)
{
log_info ("out of secure memory while"
" converting passphrase\n");
break; /* Give up. */
}
}
cd = iconv_open (charsets[charsetidx], "utf-8");
if (cd == (iconv_t)(-1))
continue;
inptr = pw;
inbytes = strlen (pw);
outptr = convertedpw;
outbytes = convertedpwsize - 1;
if ( iconv (cd, (ICONV_CONST char **)&inptr, &inbytes,
&outptr, &outbytes) == (size_t)-1)
{
iconv_close (cd);
continue;
}
*outptr = 0;
iconv_close (cd);
log_info ("decryption failed; trying charset `%s'\n",
charsets[charsetidx]);
}
memcpy (plaintext, ciphertext, length);
crypt_block (plaintext, length, salt, saltlen, iter,
convertedpw? convertedpw:pw, cipher_algo, 0);
if (check_fnc (plaintext, length))
break; /* Decryption succeeded. */
}
gcry_free (convertedpw);
}
/* Return true if the decryption of an bag_encrypted_data object has
likely succeeded. */
static int
bag_decrypted_data_p (const void *plaintext, size_t length)
{
struct tag_info ti;
const unsigned char *p = plaintext;
size_t n = length;
/* { */
/* # warning debug code is enabled */
/* FILE *fp = fopen ("tmp-rc2-plain.der", "wb"); */
/* if (!fp || fwrite (p, n, 1, fp) != 1) */
/* exit (2); */
/* fclose (fp); */
/* } */
if (parse_tag (&p, &n, &ti))
return 0;
if (ti.class || ti.tag != TAG_SEQUENCE)
return 0;
if (parse_tag (&p, &n, &ti))
return 0;
return 1;
}
/* Note: If R_RESULT is passed as NULL, a key object as already be
processed and thus we need to skip it here. */
@ -624,23 +745,13 @@ parse_bag_encrypted_data (const unsigned char *buffer, size_t length,
log_error ("error allocating decryption buffer\n");
goto bailout;
}
memcpy (plain, p, ti.length);
crypt_block (plain, ti.length, salt, saltlen,
iter, pw,
is_3des? GCRY_CIPHER_3DES : GCRY_CIPHER_RFC2268_40,
0);
decrypt_block (p, plain, ti.length, salt, saltlen, iter, pw,
is_3des? GCRY_CIPHER_3DES : GCRY_CIPHER_RFC2268_40,
bag_decrypted_data_p);
n = ti.length;
startoffset = 0;
p_start = p = plain;
/* { */
/* # warning debug code is enabled */
/* FILE *fp = fopen ("tmp-rc2-plain.der", "wb"); */
/* if (!fp || fwrite (p, n, 1, fp) != 1) */
/* exit (2); */
/* fclose (fp); */
/* } */
where = "outer.outer.seq";
if (parse_tag (&p, &n, &ti))
{
@ -899,6 +1010,34 @@ parse_bag_encrypted_data (const unsigned char *buffer, size_t length,
return -1;
}
/* Return true if the decryption of a bag_data object has likely
succeeded. */
static int
bag_data_p (const void *plaintext, size_t length)
{
struct tag_info ti;
const unsigned char *p = plaintext;
size_t n = length;
/* { */
/* # warning debug code is enabled */
/* FILE *fp = fopen ("tmp-3des-plain-key.der", "wb"); */
/* if (!fp || fwrite (p, n, 1, fp) != 1) */
/* exit (2); */
/* fclose (fp); */
/* } */
if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_SEQUENCE)
return 0;
if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_INTEGER
|| ti.length != 1 || *p)
return 0;
return 1;
}
static gcry_mpi_t *
parse_bag_data (const unsigned char *buffer, size_t length, int startoffset,
size_t *r_consumed, const char *pw)
@ -1028,22 +1167,14 @@ parse_bag_data (const unsigned char *buffer, size_t length, int startoffset,
log_error ("error allocating decryption buffer\n");
goto bailout;
}
memcpy (plain, p, ti.length);
consumed += p - p_start + ti.length;
crypt_block (plain, ti.length, salt, saltlen, iter, pw, GCRY_CIPHER_3DES, 0);
decrypt_block (p, plain, ti.length, salt, saltlen, iter, pw,
GCRY_CIPHER_3DES,
bag_data_p);
n = ti.length;
startoffset = 0;
p_start = p = plain;
/* { */
/* # warning debug code is enabled */
/* FILE *fp = fopen ("tmp-rc2-plain-key.der", "wb"); */
/* if (!fp || fwrite (p, n, 1, fp) != 1) */
/* exit (2); */
/* fclose (fp); */
/* } */
where = "decrypted-text";
if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_SEQUENCE)
goto bailout;