[git] GnuPG - branch, master, updated. post-nuke-of-trailing-ws-35-g35c731d

by Werner Koch cvs at cvs.gnupg.org
Thu Mar 10 15:55:58 CET 2011


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "The GNU Privacy Guard".

The branch, master has been updated
       via  35c731d88937c6711d27660d08cdb8d458dee848 (commit)
      from  87a6a1c3fe4b86a7db30fcce4d1e21e86d561e0f (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 35c731d88937c6711d27660d08cdb8d458dee848
Author: Werner Koch <wk at gnupg.org>
Date:   Thu Mar 10 15:27:10 2011 +0100

    Support pkcs#12 import of PBES2 encoded data.
    
    This is so that we read compatible with gnutls's certtool.  Only
    AES-128 is supported.  The latest Libgcrypt from git is required.
    
    Fixes bug#1321.

diff --git a/sm/ChangeLog b/sm/ChangeLog
index dc5989a..30e71ba 100644
--- a/sm/ChangeLog
+++ b/sm/ChangeLog
@@ -1,3 +1,12 @@
+2011-03-10  Werner Koch  <wk at g10code.com>
+
+	* minip12.c (oid_pkcs5PBKDF2, oid_pkcs5PBES2, oid_aes128_CBC): New.
+	(set_key_iv_pbes2): New.
+	(crypt_block): Add args IV and IVLEN.  Call set_key_iv_pbes2.
+	(decrypt_block): Add args IV and IVLEN.
+	(parse_bag_encrypted_data): Hack to support PBES2 data.
+	(parse_bag_data): Ditto.
+
 2011-03-03  Werner Koch  <wk at g10code.com>
 
 	* base64.c (base64_finish_write): Do not copy to radbuf to get rid
diff --git a/sm/minip12.c b/sm/minip12.c
index 10f7c99..7b53a81 100644
--- a/sm/minip12.c
+++ b/sm/minip12.c
@@ -1,5 +1,5 @@
 /* minip12.c - A minimal pkcs-12 implementation.
- * Copyright (C) 2002, 2003, 2004, 2006 Free Software Foundation, Inc.
+ * Copyright (C) 2002, 2003, 2004, 2006, 2011 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -104,6 +104,12 @@ static unsigned char const oid_pbeWithSHAAnd40BitRC2_CBC[10] = {
 static unsigned char const oid_x509Certificate_for_pkcs_12[10] = {
   0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x16, 0x01 };
 
+static unsigned char const oid_pkcs5PBKDF2[9] = {
+  0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x05, 0x0C };
+static unsigned char const oid_pkcs5PBES2[9] = {
+  0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x05, 0x0D };
+static unsigned char const oid_aes128_CBC[9] = {
+  0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x02 };
 
 static unsigned char const oid_rsaEncryption[9] = {
   0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01 };
@@ -447,9 +453,54 @@ set_key_iv (gcry_cipher_hd_t chd, char *salt, size_t saltlen, int iter,
 }
 
 
+static int
+set_key_iv_pbes2 (gcry_cipher_hd_t chd, char *salt, size_t saltlen, int iter,
+                  const void *iv, size_t ivlen, const char *pw, int algo)
+{
+  unsigned char *keybuf;
+  size_t keylen;
+  int rc;
+
+  keylen = gcry_cipher_get_algo_keylen (algo);
+  if (!keylen)
+    return -1;
+  keybuf = gcry_malloc_secure (keylen);
+  if (!keybuf)
+    return -1;
+
+  rc = gcry_kdf_derive (pw, strlen (pw),
+                        GCRY_KDF_PBKDF2, GCRY_MD_SHA1,
+                        salt, saltlen, iter, keylen, keybuf);
+  if (rc)
+    {
+      log_error ("gcry_kdf_derive failed: %s\n", gpg_strerror (rc));
+      gcry_free (keybuf);
+      return -1;
+    }
+
+  rc = gcry_cipher_setkey (chd, keybuf, keylen);
+  gcry_free (keybuf);
+  if (rc)
+    {
+      log_error ("gcry_cipher_setkey failed: %s\n", gpg_strerror (rc));
+      return -1;
+    }
+
+
+  rc = gcry_cipher_setiv (chd, iv, ivlen);
+  if (rc)
+    {
+      log_error ("gcry_cipher_setiv failed: %s\n", gpg_strerror (rc));
+      return -1;
+    }
+  return 0;
+}
+
+
 static void
 crypt_block (unsigned char *buffer, size_t length, char *salt, size_t saltlen,
-             int iter, const char *pw, int cipher_algo, int encrypt)
+             int iter, const void *iv, size_t ivlen,
+             const char *pw, int cipher_algo, int encrypt)
 {
   gcry_cipher_hd_t chd;
   int rc;
@@ -461,8 +512,11 @@ crypt_block (unsigned char *buffer, size_t length, char *salt, size_t saltlen,
       wipememory (buffer, length);
       return;
     }
-  if (set_key_iv (chd, salt, saltlen, iter, pw,
-                  cipher_algo == GCRY_CIPHER_RFC2268_40? 5:24))
+
+  if (cipher_algo == GCRY_CIPHER_AES128
+      ? set_key_iv_pbes2 (chd, salt, saltlen, iter, iv, ivlen, pw, cipher_algo)
+      : set_key_iv (chd, salt, saltlen, iter, pw,
+                    cipher_algo == GCRY_CIPHER_RFC2268_40? 5:24))
     {
       wipememory (buffer, length);
       goto leave;
@@ -495,7 +549,8 @@ crypt_block (unsigned char *buffer, size_t length, char *salt, size_t saltlen,
 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 iter, const void *iv, size_t ivlen,
+               const char *pw, int cipher_algo,
                int (*check_fnc) (const void *, size_t))
 {
   static const char * const charsets[] = {
@@ -566,7 +621,7 @@ decrypt_block (const void *ciphertext, unsigned char *plaintext, size_t length,
                     charsets[charsetidx]);
         }
       memcpy (plaintext, ciphertext, length);
-      crypt_block (plaintext, length, salt, saltlen, iter,
+      crypt_block (plaintext, length, salt, saltlen, iter, iv, ivlen,
                    convertedpw? convertedpw:pw, cipher_algo, 0);
       if (check_fnc (plaintext, length))
         break; /* Decryption succeeded. */
@@ -618,12 +673,14 @@ parse_bag_encrypted_data (const unsigned char *buffer, size_t length,
   const char *where;
   char salt[20];
   size_t saltlen;
+  char iv[16];
   unsigned int iter;
   unsigned char *plain = NULL;
   int bad_pass = 0;
   unsigned char *cram_buffer = NULL;
   size_t consumed = 0; /* Number of bytes consumed from the orginal buffer. */
   int is_3des = 0;
+  int is_pbes2 = 0;
   gcry_mpi_t *result = NULL;
   int result_count;
 
@@ -683,35 +740,111 @@ parse_bag_encrypted_data (const unsigned char *buffer, size_t length,
       n -= DIM(oid_pbeWithSHAAnd3_KeyTripleDES_CBC);
       is_3des = 1;
     }
+  else if (!ti.class && ti.tag == TAG_OBJECT_ID
+           && ti.length == DIM(oid_pkcs5PBES2)
+           && !memcmp (p, oid_pkcs5PBES2, ti.length))
+    {
+      p += ti.length;
+      n -= ti.length;
+      is_pbes2 = 1;
+    }
   else
     goto bailout;
 
-  where = "rc2or3des-params";
-  if (parse_tag (&p, &n, &ti))
-    goto bailout;
-  if (ti.class || ti.tag != TAG_SEQUENCE)
-    goto bailout;
-  if (parse_tag (&p, &n, &ti))
-    goto bailout;
-  if (ti.class || ti.tag != TAG_OCTET_STRING
-      || ti.length < 8 || ti.length > 20 )
-    goto bailout;
-  saltlen = ti.length;
-  memcpy (salt, p, saltlen);
-  p += saltlen;
-  n -= saltlen;
-  if (parse_tag (&p, &n, &ti))
-    goto bailout;
-  if (ti.class || ti.tag != TAG_INTEGER || !ti.length )
-    goto bailout;
-  for (iter=0; ti.length; ti.length--)
+  if (is_pbes2)
+    {
+      where = "pkcs5PBES2-params";
+      if (parse_tag (&p, &n, &ti))
+        goto bailout;
+      if (ti.class || ti.tag != TAG_SEQUENCE)
+        goto bailout;
+      if (parse_tag (&p, &n, &ti))
+        goto bailout;
+      if (ti.class || ti.tag != TAG_SEQUENCE)
+        goto bailout;
+      if (parse_tag (&p, &n, &ti))
+        goto bailout;
+      if (!(!ti.class && ti.tag == TAG_OBJECT_ID
+            && ti.length == DIM(oid_pkcs5PBKDF2)
+            && !memcmp (p, oid_pkcs5PBKDF2, ti.length)))
+        goto bailout; /* Not PBKDF2.  */
+      p += ti.length;
+      n -= ti.length;
+      if (parse_tag (&p, &n, &ti))
+        goto bailout;
+      if (ti.class || ti.tag != TAG_SEQUENCE)
+        goto bailout;
+      if (parse_tag (&p, &n, &ti))
+        goto bailout;
+      if (!(!ti.class && ti.tag == TAG_OCTET_STRING
+            && ti.length >= 8 && ti.length < sizeof salt))
+        goto bailout;  /* No salt or unsupported length.  */
+      saltlen = ti.length;
+      memcpy (salt, p, saltlen);
+      p += saltlen;
+      n -= saltlen;
+
+      if (parse_tag (&p, &n, &ti))
+        goto bailout;
+      if (!(!ti.class && ti.tag == TAG_INTEGER && ti.length))
+        goto bailout;  /* No valid iteration count.  */
+      for (iter=0; ti.length; ti.length--)
+        {
+          iter <<= 8;
+          iter |= (*p++) & 0xff;
+          n--;
+        }
+      /* Note: We don't support the optional parameters but assume
+         that the algorithmIdentifier follows. */
+      if (parse_tag (&p, &n, &ti))
+        goto bailout;
+      if (ti.class || ti.tag != TAG_SEQUENCE)
+        goto bailout;
+      if (parse_tag (&p, &n, &ti))
+        goto bailout;
+      if (!(!ti.class && ti.tag == TAG_OBJECT_ID
+            && ti.length == DIM(oid_aes128_CBC)
+            && !memcmp (p, oid_aes128_CBC, ti.length)))
+        goto bailout; /* Not AES-128.  */
+      p += ti.length;
+      n -= ti.length;
+      if (parse_tag (&p, &n, &ti))
+        goto bailout;
+      if (!(!ti.class && ti.tag == TAG_OCTET_STRING && ti.length == sizeof iv))
+        goto bailout; /* Bad IV.  */
+      memcpy (iv, p, sizeof iv);
+      p += sizeof iv;
+      n -= sizeof iv;
+    }
+  else
     {
-      iter <<= 8;
-      iter |= (*p++) & 0xff;
-      n--;
+      where = "rc2or3des-params";
+      if (parse_tag (&p, &n, &ti))
+        goto bailout;
+      if (ti.class || ti.tag != TAG_SEQUENCE)
+        goto bailout;
+      if (parse_tag (&p, &n, &ti))
+        goto bailout;
+      if (ti.class || ti.tag != TAG_OCTET_STRING
+          || ti.length < 8 || ti.length > 20 )
+        goto bailout;
+      saltlen = ti.length;
+      memcpy (salt, p, saltlen);
+      p += saltlen;
+      n -= saltlen;
+      if (parse_tag (&p, &n, &ti))
+        goto bailout;
+      if (ti.class || ti.tag != TAG_INTEGER || !ti.length )
+        goto bailout;
+      for (iter=0; ti.length; ti.length--)
+        {
+          iter <<= 8;
+          iter |= (*p++) & 0xff;
+          n--;
+        }
     }
 
-  where = "rc2or3des-ciphertext";
+  where = "rc2or3desoraes-ciphertext";
   if (parse_tag (&p, &n, &ti))
     goto bailout;
 
@@ -735,7 +868,8 @@ parse_bag_encrypted_data (const unsigned char *buffer, size_t length,
   else
     goto bailout;
 
-  log_info ("%lu bytes of %s encrypted text\n",ti.length,is_3des?"3DES":"RC2");
+  log_info ("%lu bytes of %s encrypted text\n",ti.length,
+            is_pbes2?"AES128":is_3des?"3DES":"RC2");
 
   plain = gcry_malloc_secure (ti.length);
   if (!plain)
@@ -743,8 +877,10 @@ parse_bag_encrypted_data (const unsigned char *buffer, size_t length,
       log_error ("error allocating decryption buffer\n");
       goto bailout;
     }
-  decrypt_block (p, plain, ti.length, salt, saltlen, iter, pw,
-                 is_3des? GCRY_CIPHER_3DES : GCRY_CIPHER_RFC2268_40,
+  decrypt_block (p, plain, ti.length, salt, saltlen, iter,
+                 iv, is_pbes2?16:0, pw,
+                 is_pbes2 ? GCRY_CIPHER_AES128 :
+                 is_3des  ? GCRY_CIPHER_3DES : GCRY_CIPHER_RFC2268_40,
                  bag_decrypted_data_p);
   n = ti.length;
   startoffset = 0;
@@ -950,7 +1086,7 @@ parse_bag_encrypted_data (const unsigned char *buffer, size_t length,
          that is less or equal to the cipher's block length.  We can
          reasonable assume that all valid data will be longer than
          just one block. */
-      if (n <= 8)
+      if (n <= (is_pbes2? 16:8))
         n = 0;
 
       /* Skip the optional SET with the pkcs12 cert attributes. */
@@ -965,7 +1101,7 @@ parse_bag_encrypted_data (const unsigned char *buffer, size_t length,
             { /* The optional SET. */
               p += ti.length;
               n -= ti.length;
-              if (n <= 8)
+              if (n <= (is_pbes2?16:8))
                 n = 0;
               if (n && parse_tag (&p, &n, &ti))
                 goto bailout;
@@ -1049,6 +1185,7 @@ parse_bag_data (const unsigned char *buffer, size_t length, int startoffset,
   const char *where;
   char salt[20];
   size_t saltlen;
+  char iv[16];
   unsigned int iter;
   int len;
   unsigned char *plain = NULL;
@@ -1056,6 +1193,7 @@ parse_bag_data (const unsigned char *buffer, size_t length, int startoffset,
   int result_count, i;
   unsigned char *cram_buffer = NULL;
   size_t consumed = 0; /* Number of bytes consumed from the orginal buffer. */
+  int is_pbes2 = 0;
 
   where = "start";
   if (parse_tag (&p, &n, &ti))
@@ -1119,46 +1257,126 @@ parse_bag_data (const unsigned char *buffer, size_t length, int startoffset,
     goto bailout;
   if (parse_tag (&p, &n, &ti))
     goto bailout;
-  if (ti.class || ti.tag != TAG_OBJECT_ID
-      || ti.length != DIM(oid_pbeWithSHAAnd3_KeyTripleDES_CBC)
-      || memcmp (p, oid_pbeWithSHAAnd3_KeyTripleDES_CBC,
-                 DIM(oid_pbeWithSHAAnd3_KeyTripleDES_CBC)))
+  if (ti.class == 0 && ti.tag == TAG_OBJECT_ID
+      && ti.length == DIM(oid_pbeWithSHAAnd3_KeyTripleDES_CBC)
+      && !memcmp (p, oid_pbeWithSHAAnd3_KeyTripleDES_CBC,
+                  DIM(oid_pbeWithSHAAnd3_KeyTripleDES_CBC)))
+    {
+      p += DIM(oid_pbeWithSHAAnd3_KeyTripleDES_CBC);
+      n -= DIM(oid_pbeWithSHAAnd3_KeyTripleDES_CBC);
+    }
+  else if (ti.class == 0 && ti.tag == TAG_OBJECT_ID
+           && ti.length == DIM(oid_pkcs5PBES2)
+           && !memcmp (p, oid_pkcs5PBES2, DIM(oid_pkcs5PBES2)))
+    {
+      p += DIM(oid_pkcs5PBES2);
+      n -= DIM(oid_pkcs5PBES2);
+      is_pbes2 = 1;
+    }
+  else
     goto bailout;
-  p += DIM(oid_pbeWithSHAAnd3_KeyTripleDES_CBC);
-  n -= DIM(oid_pbeWithSHAAnd3_KeyTripleDES_CBC);
 
-  where = "3des-params";
-  if (parse_tag (&p, &n, &ti))
-    goto bailout;
-  if (ti.class || ti.tag != TAG_SEQUENCE)
-    goto bailout;
-  if (parse_tag (&p, &n, &ti))
-    goto bailout;
-  if (ti.class || ti.tag != TAG_OCTET_STRING
-      || ti.length < 8 || ti.length > 20)
-    goto bailout;
-  saltlen = ti.length;
-  memcpy (salt, p, saltlen);
-  p += saltlen;
-  n -= saltlen;
-  if (parse_tag (&p, &n, &ti))
-    goto bailout;
-  if (ti.class || ti.tag != TAG_INTEGER || !ti.length )
-    goto bailout;
-  for (iter=0; ti.length; ti.length--)
+  if (is_pbes2)
+    {
+      where = "pkcs5PBES2-params";
+      if (parse_tag (&p, &n, &ti))
+        goto bailout;
+      if (ti.class || ti.tag != TAG_SEQUENCE)
+        goto bailout;
+      if (parse_tag (&p, &n, &ti))
+        goto bailout;
+      if (ti.class || ti.tag != TAG_SEQUENCE)
+        goto bailout;
+      if (parse_tag (&p, &n, &ti))
+        goto bailout;
+      if (!(!ti.class && ti.tag == TAG_OBJECT_ID
+            && ti.length == DIM(oid_pkcs5PBKDF2)
+            && !memcmp (p, oid_pkcs5PBKDF2, ti.length)))
+        goto bailout; /* Not PBKDF2.  */
+      p += ti.length;
+      n -= ti.length;
+      if (parse_tag (&p, &n, &ti))
+        goto bailout;
+      if (ti.class || ti.tag != TAG_SEQUENCE)
+        goto bailout;
+      if (parse_tag (&p, &n, &ti))
+        goto bailout;
+      if (!(!ti.class && ti.tag == TAG_OCTET_STRING
+            && ti.length >= 8 && ti.length < sizeof salt))
+        goto bailout;  /* No salt or unsupported length.  */
+      saltlen = ti.length;
+      memcpy (salt, p, saltlen);
+      p += saltlen;
+      n -= saltlen;
+
+      if (parse_tag (&p, &n, &ti))
+        goto bailout;
+      if (!(!ti.class && ti.tag == TAG_INTEGER && ti.length))
+        goto bailout;  /* No valid iteration count.  */
+      for (iter=0; ti.length; ti.length--)
+        {
+          iter <<= 8;
+          iter |= (*p++) & 0xff;
+          n--;
+        }
+      /* Note: We don't support the optional parameters but assume
+         that the algorithmIdentifier follows. */
+      if (parse_tag (&p, &n, &ti))
+        goto bailout;
+      if (ti.class || ti.tag != TAG_SEQUENCE)
+        goto bailout;
+      if (parse_tag (&p, &n, &ti))
+        goto bailout;
+      if (!(!ti.class && ti.tag == TAG_OBJECT_ID
+            && ti.length == DIM(oid_aes128_CBC)
+            && !memcmp (p, oid_aes128_CBC, ti.length)))
+        goto bailout; /* Not AES-128.  */
+      p += ti.length;
+      n -= ti.length;
+      if (parse_tag (&p, &n, &ti))
+        goto bailout;
+      if (!(!ti.class && ti.tag == TAG_OCTET_STRING && ti.length == sizeof iv))
+        goto bailout; /* Bad IV.  */
+      memcpy (iv, p, sizeof iv);
+      p += sizeof iv;
+      n -= sizeof iv;
+    }
+  else
     {
-      iter <<= 8;
-      iter |= (*p++) & 0xff;
-      n--;
+      where = "3des-params";
+      if (parse_tag (&p, &n, &ti))
+        goto bailout;
+      if (ti.class || ti.tag != TAG_SEQUENCE)
+        goto bailout;
+      if (parse_tag (&p, &n, &ti))
+        goto bailout;
+      if (ti.class || ti.tag != TAG_OCTET_STRING
+          || ti.length < 8 || ti.length > 20)
+        goto bailout;
+      saltlen = ti.length;
+      memcpy (salt, p, saltlen);
+      p += saltlen;
+      n -= saltlen;
+      if (parse_tag (&p, &n, &ti))
+        goto bailout;
+      if (ti.class || ti.tag != TAG_INTEGER || !ti.length )
+        goto bailout;
+      for (iter=0; ti.length; ti.length--)
+        {
+          iter <<= 8;
+          iter |= (*p++) & 0xff;
+          n--;
+        }
     }
 
-  where = "3des-ciphertext";
+  where = "3desoraes-ciphertext";
   if (parse_tag (&p, &n, &ti))
     goto bailout;
   if (ti.class || ti.tag != TAG_OCTET_STRING || !ti.length )
     goto bailout;
 
-  log_info ("%lu bytes of 3DES encrypted text\n", ti.length);
+  log_info ("%lu bytes of %s encrypted text\n",
+            ti.length, is_pbes2? "AES128":"3DES");
 
   plain = gcry_malloc_secure (ti.length);
   if (!plain)
@@ -1167,8 +1385,9 @@ parse_bag_data (const unsigned char *buffer, size_t length, int startoffset,
       goto bailout;
     }
   consumed += p - p_start + ti.length;
-  decrypt_block (p, plain, ti.length, salt, saltlen, iter, pw,
-                 GCRY_CIPHER_3DES,
+  decrypt_block (p, plain, ti.length, salt, saltlen, iter,
+                 iv, is_pbes2? 16:0, pw,
+                 is_pbes2? GCRY_CIPHER_AES128 : GCRY_CIPHER_3DES,
                  bag_data_p);
   n = ti.length;
   startoffset = 0;
@@ -2223,7 +2442,7 @@ p12_build (gcry_mpi_t *kparms, const void *cert, size_t certlen,
 
       /* Encrypt it. */
       gcry_randomize (salt, 8, GCRY_STRONG_RANDOM);
-      crypt_block (buffer, buflen, salt, 8, 2048, pw,
+      crypt_block (buffer, buflen, salt, 8, 2048, NULL, 0, pw,
                    GCRY_CIPHER_RFC2268_40, 1);
 
       /* Encode the encrypted stuff into a bag. */
@@ -2246,7 +2465,8 @@ p12_build (gcry_mpi_t *kparms, const void *cert, size_t certlen,
 
       /* Encrypt it. */
       gcry_randomize (salt, 8, GCRY_STRONG_RANDOM);
-      crypt_block (buffer, buflen, salt, 8, 2048, pw, GCRY_CIPHER_3DES, 1);
+      crypt_block (buffer, buflen, salt, 8, 2048, NULL, 0,
+                   pw, GCRY_CIPHER_3DES, 1);
 
       /* Encode the encrypted stuff into a bag. */
       if (cert && certlen)

-----------------------------------------------------------------------

Summary of changes:
 sm/ChangeLog |    9 ++
 sm/minip12.c |  356 +++++++++++++++++++++++++++++++++++++++++++++++-----------
 2 files changed, 297 insertions(+), 68 deletions(-)


hooks/post-receive
-- 
The GNU Privacy Guard
http://git.gnupg.org




More information about the Gnupg-commits mailing list