summaryrefslogtreecommitdiffstats
path: root/agent
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2007-03-19 19:54:34 +0100
committerWerner Koch <wk@gnupg.org>2007-03-19 19:54:34 +0100
commit083010a53d213a1662afad1950c41fcb46939d7f (patch)
tree5ab93d4bc52314f4490ded33678cb3c6248e24c9 /agent
parentAllow export to work on systems without funopen/fopencookie. (diff)
downloadgnupg2-083010a53d213a1662afad1950c41fcb46939d7f.tar.xz
gnupg2-083010a53d213a1662afad1950c41fcb46939d7f.zip
* PKCS#12 import now tries several encodings in case the passphrase
was not utf-8 encoded.
Diffstat (limited to 'agent')
-rw-r--r--agent/ChangeLog10
-rw-r--r--agent/minip12.c179
2 files changed, 164 insertions, 25 deletions
diff --git a/agent/ChangeLog b/agent/ChangeLog
index cc1ae2d53..3afb61dc4 100644
--- a/agent/ChangeLog
+++ b/agent/ChangeLog
@@ -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
diff --git a/agent/minip12.c b/agent/minip12.c
index 25a38b9c8..d6029f7b0 100644
--- a/agent/minip12.c
+++ b/agent/minip12.c
@@ -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;