summaryrefslogtreecommitdiffstats
path: root/agent/minip12.c
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2002-06-25 19:50:59 +0200
committerWerner Koch <wk@gnupg.org>2002-06-25 19:50:59 +0200
commitc65009a2c5e73d0bfee6b8ff499a161fcf735f93 (patch)
treed3cdbd170c7461bfbf2786fbf2b25689a94a2a6a /agent/minip12.c
parent* certdump.c (print_dn_part): Always print a leading slash, (diff)
downloadgnupg2-c65009a2c5e73d0bfee6b8ff499a161fcf735f93.tar.xz
gnupg2-c65009a2c5e73d0bfee6b8ff499a161fcf735f93.zip
* protect-tool.c (rsa_key_check): New.NEWPG-0-3-8
(import_p12_file): New. (main): New command --p12-import. * minip12.c, minip12.h: New.
Diffstat (limited to 'agent/minip12.c')
-rw-r--r--agent/minip12.c805
1 files changed, 805 insertions, 0 deletions
diff --git a/agent/minip12.c b/agent/minip12.c
new file mode 100644
index 000000000..29531b23b
--- /dev/null
+++ b/agent/minip12.c
@@ -0,0 +1,805 @@
+/* minip12.c - A minilam pkcs-12 implementation.
+ * Copyright (C) 2002 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <gcrypt.h>
+
+#undef TEST
+
+#ifdef TEST
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+#endif
+
+#include "../jnlib/logging.h"
+#include "minip12.h"
+
+#ifndef DIM
+#define DIM(v) (sizeof(v)/sizeof((v)[0]))
+#endif
+
+enum
+{
+ UNIVERSAL = 0,
+ APPLICATION = 1,
+ CONTEXT = 2,
+ PRIVATE = 3
+};
+
+
+enum
+{
+ TAG_NONE = 0,
+ TAG_BOOLEAN = 1,
+ TAG_INTEGER = 2,
+ TAG_BIT_STRING = 3,
+ TAG_OCTET_STRING = 4,
+ TAG_NULL = 5,
+ TAG_OBJECT_ID = 6,
+ TAG_OBJECT_DESCRIPTOR = 7,
+ TAG_EXTERNAL = 8,
+ TAG_REAL = 9,
+ TAG_ENUMERATED = 10,
+ TAG_EMBEDDED_PDV = 11,
+ TAG_UTF8_STRING = 12,
+ TAG_REALTIVE_OID = 13,
+ TAG_SEQUENCE = 16,
+ TAG_SET = 17,
+ TAG_NUMERIC_STRING = 18,
+ TAG_PRINTABLE_STRING = 19,
+ TAG_TELETEX_STRING = 20,
+ TAG_VIDEOTEX_STRING = 21,
+ TAG_IA5_STRING = 22,
+ TAG_UTC_TIME = 23,
+ TAG_GENERALIZED_TIME = 24,
+ TAG_GRAPHIC_STRING = 25,
+ TAG_VISIBLE_STRING = 26,
+ TAG_GENERAL_STRING = 27,
+ TAG_UNIVERSAL_STRING = 28,
+ TAG_CHARACTER_STRING = 29,
+ TAG_BMP_STRING = 30
+};
+
+
+static unsigned char const oid_data[9] = {
+ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x01 };
+static unsigned char const oid_encryptedData[9] = {
+ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x06 };
+static unsigned char const oid_pkcs_12_pkcs_8ShroudedKeyBag[11] = {
+ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x0C, 0x0A, 0x01, 0x02 };
+static unsigned char const oid_pbeWithSHAAnd3_KeyTripleDES_CBC[10] = {
+ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x0C, 0x01, 0x03 };
+
+static unsigned char const oid_rsaEncryption[9] = {
+ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01 };
+
+
+
+struct tag_info {
+ int class;
+ int is_constructed;
+ unsigned long tag;
+ unsigned long length; /* length part of the TLV */
+ int nhdr;
+ int ndef; /* It is an indefinite length */
+};
+
+
+/* Parse the buffer at the address BUFFER which is of SIZE and return
+ the tag and the length part from the TLV triplet. Update BUFFER
+ and SIZE on success. */
+static int
+parse_tag (unsigned char const **buffer, size_t *size, struct tag_info *ti)
+{
+ int c;
+ unsigned long tag;
+ const unsigned char *buf = *buffer;
+ size_t length = *size;
+
+ ti->length = 0;
+ ti->ndef = 0;
+ ti->nhdr = 0;
+
+ /* Get the tag */
+ if (!length)
+ return -1; /* premature eof */
+ c = *buf++; length--;
+ ti->nhdr++;
+
+ ti->class = (c & 0xc0) >> 6;
+ ti->is_constructed = !!(c & 0x20);
+ tag = c & 0x1f;
+
+ if (tag == 0x1f)
+ {
+ tag = 0;
+ do
+ {
+ tag <<= 7;
+ if (!length)
+ return -1; /* premature eof */
+ c = *buf++; length--;
+ ti->nhdr++;
+ tag |= c & 0x7f;
+ }
+ while (c & 0x80);
+ }
+ ti->tag = tag;
+
+ /* Get the length */
+ if (!length)
+ return -1; /* prematureeof */
+ c = *buf++; length--;
+ ti->nhdr++;
+
+ if ( !(c & 0x80) )
+ ti->length = c;
+ else if (c == 0x80)
+ ti->ndef = 1;
+ else if (c == 0xff)
+ return -1; /* forbidden length value */
+ else
+ {
+ unsigned long len = 0;
+ int count = c & 0x7f;
+
+ for (; count; count--)
+ {
+ len <<= 8;
+ if (!length)
+ return -1; /* premature_eof */
+ c = *buf++; length--;
+ ti->nhdr++;
+ len |= c & 0xff;
+ }
+ ti->length = len;
+ }
+
+ if (ti->class == UNIVERSAL && !ti->tag)
+ ti->length = 0;
+
+ if (ti->length > length)
+ return -1; /* data larger than buffer. */
+
+ *buffer = buf;
+ *size = length;
+ return 0;
+}
+
+
+static int
+string_to_key (int id, char *salt, int iter, const char *pw,
+ int req_keylen, unsigned char *keybuf)
+{
+ int rc, i, j;
+ GcryMDHd md;
+ GcryMPI num_b1 = NULL;
+ int pwlen;
+ unsigned char hash[20], buf_b[64], buf_i[128], *p;
+ size_t cur_keylen;
+ size_t n;
+
+ cur_keylen = 0;
+ pwlen = strlen (pw);
+ if (pwlen > 63/2)
+ {
+ log_error ("password too long\n");
+ return -1;
+ }
+
+ /* Store salt and password in BUF_I */
+ p = buf_i;
+ for(i=0; i < 64; i++)
+ *p++ = salt [i%8];
+ for(i=j=0; i < 64; i += 2)
+ {
+ *p++ = 0;
+ *p++ = pw[j];
+ if (++j > pwlen) /* Note, that we include the trailing zero */
+ j = 0;
+ }
+
+ for (;;)
+ {
+ md = gcry_md_open (GCRY_MD_SHA1, 0);
+ if (!md)
+ {
+ log_error ( "gcry_md_open failed: %s\n", gcry_strerror (-1));
+ return -1;
+ }
+ for(i=0; i < 64; i++)
+ gcry_md_putc (md, id);
+ gcry_md_write (md, buf_i, 128);
+ memcpy (hash, gcry_md_read (md, 0), 20);
+ gcry_md_close (md);
+ for (i=1; i < iter; i++)
+ gcry_md_hash_buffer (GCRY_MD_SHA1, hash, hash, 20);
+
+ for (i=0; i < 20 && cur_keylen < req_keylen; i++)
+ keybuf[cur_keylen++] = hash[i];
+ if (cur_keylen == req_keylen)
+ {
+ gcry_mpi_release (num_b1);
+ return 0; /* ready */
+ }
+
+ /* need more bytes. */
+ for(i=0; i < 64; i++)
+ buf_b[i] = hash[i % 20];
+ n = 64;
+ rc = gcry_mpi_scan (&num_b1, GCRYMPI_FMT_USG, buf_b, &n);
+ if (rc)
+ {
+ log_error ( "gcry_mpi_scan failed: %s\n", gcry_strerror (rc));
+ return -1;
+ }
+ gcry_mpi_add_ui (num_b1, num_b1, 1);
+ for (i=0; i < 128; i += 64)
+ {
+ GcryMPI num_ij;
+
+ n = 64;
+ rc = gcry_mpi_scan (&num_ij, GCRYMPI_FMT_USG, buf_i + i, &n);
+ if (rc)
+ {
+ log_error ( "gcry_mpi_scan failed: %s\n",
+ gcry_strerror (rc));
+ return -1;
+ }
+ gcry_mpi_add (num_ij, num_ij, num_b1);
+ gcry_mpi_clear_highbit (num_ij, 64*8);
+ n = 64;
+ rc = gcry_mpi_print (GCRYMPI_FMT_USG, buf_i + i, &n, num_ij);
+ if (rc)
+ {
+ log_error ( "gcry_mpi_print failed: %s\n",
+ gcry_strerror (rc));
+ return -1;
+ }
+ gcry_mpi_release (num_ij);
+ }
+ }
+}
+
+
+static int
+set_key_iv (GcryCipherHd chd, char *salt, int iter, const char *pw)
+{
+ unsigned char keybuf[24];
+ int rc;
+
+ if (string_to_key (1, salt, iter, pw, 24, keybuf))
+ return -1;
+ rc = gcry_cipher_setkey (chd, keybuf, 24);
+ if (rc)
+ {
+ log_error ( "gcry_cipher_setkey failed: %s\n", gcry_strerror (rc));
+ return -1;
+ }
+
+ if (string_to_key (2, salt, iter, pw, 8, keybuf))
+ return -1;
+ rc = gcry_cipher_setiv (chd, keybuf, 8);
+ if (rc)
+ {
+ log_error ("gcry_cipher_setiv failed: %s\n", gcry_strerror (rc));
+ return -1;
+ }
+ return 0;
+}
+
+
+static void
+decrypt_block (unsigned char *buffer, size_t length, char *salt, int iter,
+ const char *pw)
+{
+ GcryCipherHd chd;
+ int rc;
+
+ chd = gcry_cipher_open (GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_CBC, 0);
+ if (!chd)
+ {
+ log_error ( "gcry_cipher_open failed: %s\n", gcry_strerror(-1));
+ return;
+ }
+ if (set_key_iv (chd, salt, iter, pw))
+ goto leave;
+
+ rc = gcry_cipher_decrypt (chd, buffer, length, NULL, 0);
+ if (rc)
+ {
+ log_error ( "gcry_cipher_decrypt failed: %s\n", gcry_strerror (rc));
+ goto leave;
+ }
+
+/* { */
+/* FILE *fp = fopen("inner.der", "wb"); */
+/* fwrite (buffer, 1, length, fp); */
+/* fclose (fp); */
+/* } */
+
+ leave:
+ gcry_cipher_close (chd);
+}
+
+
+
+
+static int
+parse_bag_encrypted_data (const unsigned char *buffer, size_t length,
+ int startoffset)
+{
+ struct tag_info ti;
+ const unsigned char *p = buffer;
+ size_t n = length;
+ const char *where;
+
+ where = "start";
+ if (parse_tag (&p, &n, &ti))
+ goto bailout;
+ if (ti.class != CONTEXT || ti.tag)
+ goto bailout;
+ if (parse_tag (&p, &n, &ti))
+ goto bailout;
+ if (ti.tag != TAG_SEQUENCE)
+ goto bailout;
+
+ where = "bag.encryptedData.version";
+ if (parse_tag (&p, &n, &ti))
+ goto bailout;
+ if (ti.tag != TAG_INTEGER || ti.length != 1 || *p != 0)
+ goto bailout;
+ p++; n--;
+ if (parse_tag (&p, &n, &ti))
+ goto bailout;
+ if (ti.tag != TAG_SEQUENCE)
+ goto bailout;
+
+ where = "bag.encryptedData.data";
+ if (parse_tag (&p, &n, &ti))
+ goto bailout;
+ if (ti.tag != TAG_OBJECT_ID || ti.length != DIM(oid_data)
+ || memcmp (p, oid_data, DIM(oid_data)))
+ goto bailout;
+ p += DIM(oid_data);
+ n -= DIM(oid_data);
+
+ /* fixme: continue parsing */
+
+ return 0;
+ bailout:
+ log_error ("encrptedData error at \"%s\", offset %u\n",
+ where, (p - buffer)+startoffset);
+ return -1;
+}
+
+static GcryMPI *
+parse_bag_data (const unsigned char *buffer, size_t length, int startoffset,
+ const char *pw)
+{
+ int rc;
+ struct tag_info ti;
+ const unsigned char *p = buffer;
+ size_t n = length;
+ const char *where;
+ char salt[8];
+ unsigned int iter;
+ int len;
+ unsigned char *plain = NULL;
+ GcryMPI *result = NULL;
+ int result_count, i;
+
+ where = "start";
+ if (parse_tag (&p, &n, &ti))
+ goto bailout;
+ if (ti.class != CONTEXT || ti.tag)
+ goto bailout;
+ if (parse_tag (&p, &n, &ti))
+ goto bailout;
+ if (ti.class || ti.tag != TAG_OCTET_STRING)
+ goto bailout;
+
+ where = "data.outerseqs";
+ 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;
+
+ where = "data.objectidentifier";
+ if (parse_tag (&p, &n, &ti))
+ goto bailout;
+ if (ti.class || ti.tag != TAG_OBJECT_ID
+ || ti.length != DIM(oid_pkcs_12_pkcs_8ShroudedKeyBag)
+ || memcmp (p, oid_pkcs_12_pkcs_8ShroudedKeyBag,
+ DIM(oid_pkcs_12_pkcs_8ShroudedKeyBag)))
+ goto bailout;
+ p += DIM(oid_pkcs_12_pkcs_8ShroudedKeyBag);
+ n -= DIM(oid_pkcs_12_pkcs_8ShroudedKeyBag);
+
+ where = "shrouded,outerseqs";
+ if (parse_tag (&p, &n, &ti))
+ goto bailout;
+ if (ti.class != CONTEXT || ti.tag)
+ 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_SEQUENCE)
+ 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)))
+ 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 )
+ goto bailout;
+ memcpy (salt, p, 8);
+ p += 8;
+ n -= 8;
+ 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";
+ 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);
+
+ plain = gcry_malloc_secure (ti.length);
+ if (!plain)
+ {
+ log_error ("error allocating decryption buffer\n");
+ goto bailout;
+ }
+ memcpy (plain, p, ti.length);
+ decrypt_block (plain, ti.length, salt, iter, pw);
+ n = ti.length;
+ startoffset = 0;
+ buffer = p = plain;
+
+ where = "decrypted-text";
+ if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_SEQUENCE)
+ goto bailout;
+ if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_INTEGER
+ || ti.length != 1 || *p)
+ goto bailout;
+ p++; n--;
+ if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_SEQUENCE)
+ goto bailout;
+ len = ti.length;
+ if (parse_tag (&p, &n, &ti))
+ goto bailout;
+ if (len < ti.nhdr)
+ goto bailout;
+ len -= ti.nhdr;
+ if (ti.class || ti.tag != TAG_OBJECT_ID
+ || ti.length != DIM(oid_rsaEncryption)
+ || memcmp (p, oid_rsaEncryption,
+ DIM(oid_rsaEncryption)))
+ goto bailout;
+ p += DIM (oid_rsaEncryption);
+ n -= DIM (oid_rsaEncryption);
+ if (len < ti.length)
+ goto bailout;
+ len -= ti.length;
+ if (n < len)
+ goto bailout;
+ p += len;
+ n -= len;
+ if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_OCTET_STRING)
+ goto bailout;
+ if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_SEQUENCE)
+ goto bailout;
+ len = ti.length;
+
+ result = gcry_calloc (10, sizeof *result);
+ if (!result)
+ {
+ log_error ( "error allocating result array\n");
+ goto bailout;
+ }
+ result_count = 0;
+
+ where = "reading.key-parameters";
+ for (result_count=0; len && result_count < 9;)
+ {
+ int dummy_n;
+
+ if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_INTEGER)
+ goto bailout;
+ if (len < ti.nhdr)
+ goto bailout;
+ len -= ti.nhdr;
+ if (len < ti.length)
+ goto bailout;
+ len -= ti.length;
+ dummy_n = ti.length;
+ if (!result_count && ti.length == 1 && !*p)
+ ; /* ignore the very first one if it is a 0 */
+ else
+ {
+ rc = gcry_mpi_scan (result+result_count, GCRYMPI_FMT_USG, p,
+ &dummy_n);
+ if (rc)
+ {
+ log_error ("error parsing key parameter: %s\n",
+ gcry_strerror (rc));
+ goto bailout;
+ }
+ result_count++;
+ }
+ p += ti.length;
+ n -= ti.length;
+ }
+ if (len)
+ goto bailout;
+
+ return result;
+
+ bailout:
+ gcry_free (plain);
+ if (result)
+ {
+ for (i=0; result[i]; i++)
+ gcry_mpi_release (result[i]);
+ gcry_free (result);
+ }
+ log_error ( "data error at \"%s\", offset %u\n",
+ where, (p - buffer) + startoffset);
+ return NULL;
+}
+
+
+/* Parse a PKCS12 object and return an array of MPI representing the
+ secret key parameters. This is a very limited inplementation in
+ that it is only able to look for 3DES encoded enctyptedData and
+ tries to extract the first private key object it finds. In case of
+ an error NULL is returned. */
+GcryMPI *
+p12_parse (const unsigned char *buffer, size_t length, const char *pw)
+{
+ struct tag_info ti;
+ const unsigned char *p = buffer;
+ size_t n = length;
+ const char *where;
+ int bagseqlength, len;
+
+ where = "pfx";
+ if (parse_tag (&p, &n, &ti))
+ goto bailout;
+ if (ti.tag != TAG_SEQUENCE)
+ goto bailout;
+
+ where = "pfxVersion";
+ if (parse_tag (&p, &n, &ti))
+ goto bailout;
+ if (ti.tag != TAG_INTEGER || ti.length != 1 || *p != 3)
+ goto bailout;
+ p++; n--;
+
+ where = "authSave";
+ if (parse_tag (&p, &n, &ti))
+ goto bailout;
+ if (ti.tag != TAG_SEQUENCE)
+ goto bailout;
+ if (parse_tag (&p, &n, &ti))
+ goto bailout;
+ if (ti.tag != TAG_OBJECT_ID || ti.length != DIM(oid_data)
+ || memcmp (p, oid_data, DIM(oid_data)))
+ goto bailout;
+ p += DIM(oid_data);
+ n -= DIM(oid_data);
+
+ if (parse_tag (&p, &n, &ti))
+ goto bailout;
+ if (ti.class != CONTEXT || ti.tag)
+ goto bailout;
+ if (parse_tag (&p, &n, &ti))
+ goto bailout;
+ if (ti.class != UNIVERSAL || ti.tag != TAG_OCTET_STRING)
+ goto bailout;
+
+ where = "bags";
+ if (parse_tag (&p, &n, &ti))
+ goto bailout;
+ if (ti.class != UNIVERSAL || ti.tag != TAG_SEQUENCE)
+ goto bailout;
+ bagseqlength = ti.length;
+ while (bagseqlength)
+ {
+ log_error ( "at offset %u\n", (p - buffer));
+ where = "bag-sequence";
+ if (parse_tag (&p, &n, &ti))
+ goto bailout;
+ if (ti.class != UNIVERSAL || ti.tag != TAG_SEQUENCE)
+ goto bailout;
+
+ if (bagseqlength < ti.nhdr)
+ goto bailout;
+ bagseqlength -= ti.nhdr;
+ if (bagseqlength < ti.length)
+ goto bailout;
+ bagseqlength -= ti.length;
+ len = ti.length;
+
+ if (parse_tag (&p, &n, &ti))
+ goto bailout;
+ len -= ti.nhdr;
+ if (ti.tag == TAG_OBJECT_ID && ti.length == DIM(oid_encryptedData)
+ && !memcmp (p, oid_encryptedData, DIM(oid_encryptedData)))
+ {
+ p += DIM(oid_encryptedData);
+ n -= DIM(oid_encryptedData);
+ len -= DIM(oid_encryptedData);
+ where = "bag.encryptedData";
+ if (parse_bag_encrypted_data (p, n, (p - buffer)))
+ goto bailout;
+ }
+ else if (ti.tag == TAG_OBJECT_ID && ti.length == DIM(oid_data)
+ && !memcmp (p, oid_data, DIM(oid_data)))
+ {
+ p += DIM(oid_data);
+ n -= DIM(oid_data);
+ len -= DIM(oid_data);
+ return parse_bag_data (p, n, (p-buffer), pw);
+ }
+ else
+ log_info ( "unknown bag type - skipped\n");
+
+ if (len < 0 || len > n)
+ goto bailout;
+ p += len;
+ n -= len;
+ }
+
+ return NULL;
+ bailout:
+ log_error ("error at \"%s\", offset %u\n", where, (p - buffer));
+ return NULL;
+}
+
+#if 0 /* unser construction. */
+/* Expect the RSA key parameters in KPARMS and a password in
+ PW. Create a PKCS structure from it and return it as well as the
+ length in R_LENGTH; return NULL in case of an error. */
+unsigned char *
+p12_build (GcryMPI *kparms, const char *pw, size_t *r_length)
+{
+ int i;
+ unsigned char *result;
+ size_t resultlen;
+
+ for (i=0; kparms[i]; i++)
+ ;
+ if (i != 8)
+ {
+ log_error ("invalid paramters for p12_build\n");
+ return NULL;
+ }
+
+
+ *r_length = resultlen;
+ return result;
+}
+#endif
+
+
+#ifdef TEST
+int
+main (int argc, char **argv)
+{
+ FILE *fp;
+ struct stat st;
+ char *buf;
+ size_t buflen;
+ GcryMPI *result;
+
+ if (argc != 3)
+ {
+ fprintf (stderr, "usage: testp12 file passphrase\n");
+ return 1;
+ }
+
+ gcry_control (GCRYCTL_DISABLE_SECMEM, NULL);
+ gcry_control (GCRYCTL_INITIALIZATION_FINISHED, NULL);
+
+ fp = fopen (argv[1], "rb");
+ if (!fp)
+ {
+ fprintf (stderr, "can't open `%s': %s\n", argv[1], strerror (errno));
+ return 1;
+ }
+
+ if (fstat (fileno(fp), &st))
+ {
+ fprintf (stderr, "can't stat `%s': %s\n", argv[1], strerror (errno));
+ return 1;
+ }
+
+ buflen = st.st_size;
+ buf = malloc (buflen+1);
+ if (!buf || fread (buf, buflen, 1, fp) != 1)
+ {
+ fprintf (stderr, "error reading `%s': %s\n", argv[1], strerror (errno));
+ return 1;
+ }
+ fclose (fp);
+
+ result = p12_parse (buf, buflen, argv[2]);
+ if (result)
+ {
+ int i, rc;
+ char *buf;
+
+ for (i=0; result[i]; i++)
+ {
+ rc = gcry_mpi_aprint (GCRYMPI_FMT_HEX, (void**)&buf,
+ NULL, result[i]);
+ if (rc)
+ printf ("%d: [error printing number: %s]\n",
+ i, gcry_strerror (rc));
+ else
+ {
+ printf ("%d: %s\n", i, buf);
+ gcry_free (buf);
+ }
+ }
+ }
+
+ return 0;
+
+}
+#endif /* TEST */