6fe9d2c6c60ccd7a76515e91e0ae5b6f3baec4b7
[gnupg.git] / agent / minip12.c
1 /* minip12.c - A minilam pkcs-12 implementation.
2  *      Copyright (C) 2002 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <assert.h>
28 #include <gcrypt.h>
29
30 #undef TEST 
31
32 #ifdef TEST
33 #include <sys/stat.h>
34 #include <unistd.h>
35 #include <errno.h>
36 #endif
37
38 #include "../jnlib/logging.h"
39 #include "minip12.h"
40
41 #ifndef DIM
42 #define DIM(v)               (sizeof(v)/sizeof((v)[0]))
43 #endif
44
45 enum
46 {
47   UNIVERSAL = 0,
48   APPLICATION = 1,
49   CONTEXT = 2,
50   PRIVATE = 3
51 };
52
53
54 enum
55 {
56   TAG_NONE = 0,
57   TAG_BOOLEAN = 1,
58   TAG_INTEGER = 2,
59   TAG_BIT_STRING = 3,
60   TAG_OCTET_STRING = 4,
61   TAG_NULL = 5,
62   TAG_OBJECT_ID = 6,
63   TAG_OBJECT_DESCRIPTOR = 7,
64   TAG_EXTERNAL = 8,
65   TAG_REAL = 9,
66   TAG_ENUMERATED = 10,
67   TAG_EMBEDDED_PDV = 11,
68   TAG_UTF8_STRING = 12,
69   TAG_REALTIVE_OID = 13,
70   TAG_SEQUENCE = 16,
71   TAG_SET = 17,
72   TAG_NUMERIC_STRING = 18,
73   TAG_PRINTABLE_STRING = 19,
74   TAG_TELETEX_STRING = 20,
75   TAG_VIDEOTEX_STRING = 21,
76   TAG_IA5_STRING = 22,
77   TAG_UTC_TIME = 23,
78   TAG_GENERALIZED_TIME = 24,
79   TAG_GRAPHIC_STRING = 25,
80   TAG_VISIBLE_STRING = 26,
81   TAG_GENERAL_STRING = 27,
82   TAG_UNIVERSAL_STRING = 28,
83   TAG_CHARACTER_STRING = 29,
84   TAG_BMP_STRING = 30
85 };
86
87
88 static unsigned char const oid_data[9] = {
89   0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x01 };
90 static unsigned char const oid_encryptedData[9] = {
91   0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x06 };
92 static unsigned char const oid_pkcs_12_pkcs_8ShroudedKeyBag[11] = {
93   0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x0C, 0x0A, 0x01, 0x02 };
94 static unsigned char const oid_pbeWithSHAAnd3_KeyTripleDES_CBC[10] = {
95   0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x0C, 0x01, 0x03 };
96
97 static unsigned char const oid_rsaEncryption[9] = {
98   0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01 };
99
100
101
102 struct tag_info {
103   int class;
104   int is_constructed;
105   unsigned long tag;
106   unsigned long length;  /* length part of the TLV */
107   int nhdr;
108   int ndef;              /* It is an indefinite length */
109 };
110
111
112 /* Parse the buffer at the address BUFFER which is of SIZE and return
113    the tag and the length part from the TLV triplet.  Update BUFFER
114    and SIZE on success. */
115 static int 
116 parse_tag (unsigned char const **buffer, size_t *size, struct tag_info *ti)
117 {
118   int c;
119   unsigned long tag;
120   const unsigned char *buf = *buffer;
121   size_t length = *size;
122
123   ti->length = 0;
124   ti->ndef = 0;
125   ti->nhdr = 0;
126
127   /* Get the tag */
128   if (!length)
129     return -1; /* premature eof */
130   c = *buf++; length--;
131   ti->nhdr++;
132
133   ti->class = (c & 0xc0) >> 6;
134   ti->is_constructed = !!(c & 0x20);
135   tag = c & 0x1f;
136
137   if (tag == 0x1f)
138     {
139       tag = 0;
140       do
141         {
142           tag <<= 7;
143           if (!length)
144             return -1; /* premature eof */
145           c = *buf++; length--;
146           ti->nhdr++;
147           tag |= c & 0x7f;
148         }
149       while (c & 0x80);
150     }
151   ti->tag = tag;
152
153   /* Get the length */
154   if (!length)
155     return -1; /* prematureeof */
156   c = *buf++; length--;
157   ti->nhdr++;
158
159   if ( !(c & 0x80) )
160     ti->length = c;
161   else if (c == 0x80)
162     ti->ndef = 1;
163   else if (c == 0xff)
164     return -1; /* forbidden length value */
165   else
166     {
167       unsigned long len = 0;
168       int count = c & 0x7f;
169
170       for (; count; count--)
171         {
172           len <<= 8;
173           if (!length)
174             return -1; /* premature_eof */
175           c = *buf++; length--;
176           ti->nhdr++;
177           len |= c & 0xff;
178         }
179       ti->length = len;
180     }
181   
182   if (ti->class == UNIVERSAL && !ti->tag)
183     ti->length = 0;
184
185   if (ti->length > length)
186     return -1; /* data larger than buffer. */
187   
188   *buffer = buf;
189   *size = length;
190   return 0;
191 }
192
193
194 static int 
195 string_to_key (int id, char *salt, int iter, const char *pw,
196                int req_keylen, unsigned char *keybuf)
197 {
198   int rc, i, j;
199   GcryMDHd md;
200   GcryMPI num_b1 = NULL;
201   int pwlen;
202   unsigned char hash[20], buf_b[64], buf_i[128], *p;
203   size_t cur_keylen;
204   size_t n;
205
206   cur_keylen = 0;
207   pwlen = strlen (pw);
208   if (pwlen > 63/2)
209     {
210       log_error ("password too long\n");
211       return -1;
212     }
213
214   /* Store salt and password in BUF_I */
215   p = buf_i;
216   for(i=0; i < 64; i++)
217     *p++ = salt [i%8];
218   for(i=j=0; i < 64; i += 2)
219     {
220       *p++ = 0;
221       *p++ = pw[j];
222       if (++j > pwlen) /* Note, that we include the trailing zero */
223         j = 0;
224     }
225
226   for (;;)
227     {
228       md = gcry_md_open (GCRY_MD_SHA1, 0);
229       if (!md)
230         {
231           log_error ( "gcry_md_open failed: %s\n", gcry_strerror (-1));
232           return -1;
233         }
234       for(i=0; i < 64; i++)
235         gcry_md_putc (md, id);
236       gcry_md_write (md, buf_i, 128);
237       memcpy (hash, gcry_md_read (md, 0), 20);
238       gcry_md_close (md);
239       for (i=1; i < iter; i++)
240         gcry_md_hash_buffer (GCRY_MD_SHA1, hash, hash, 20);
241
242       for (i=0; i < 20 && cur_keylen < req_keylen; i++)
243         keybuf[cur_keylen++] = hash[i];
244       if (cur_keylen == req_keylen)
245         {
246           gcry_mpi_release (num_b1);
247           return 0; /* ready */
248         }
249       
250       /* need more bytes. */
251       for(i=0; i < 64; i++)
252         buf_b[i] = hash[i % 20];
253       n = 64;
254       rc = gcry_mpi_scan (&num_b1, GCRYMPI_FMT_USG, buf_b, &n);
255       if (rc)
256         {
257           log_error ( "gcry_mpi_scan failed: %s\n", gcry_strerror (rc));
258           return -1;
259         }
260       gcry_mpi_add_ui (num_b1, num_b1, 1);
261       for (i=0; i < 128; i += 64)
262         {
263           GcryMPI num_ij;
264
265           n = 64;
266           rc = gcry_mpi_scan (&num_ij, GCRYMPI_FMT_USG, buf_i + i, &n);
267           if (rc)
268             {
269               log_error ( "gcry_mpi_scan failed: %s\n",
270                        gcry_strerror (rc));
271               return -1;
272             }
273           gcry_mpi_add (num_ij, num_ij, num_b1);
274           gcry_mpi_clear_highbit (num_ij, 64*8);
275           n = 64;
276           rc = gcry_mpi_print (GCRYMPI_FMT_USG, buf_i + i, &n, num_ij);
277           if (rc)
278             {
279               log_error ( "gcry_mpi_print failed: %s\n",
280                        gcry_strerror (rc));
281               return -1;
282             }
283           gcry_mpi_release (num_ij);
284         }
285     }
286 }
287
288
289 static int 
290 set_key_iv (GcryCipherHd chd, char *salt, int iter, const char *pw)
291 {
292   unsigned char keybuf[24];
293   int rc;
294
295   if (string_to_key (1, salt, iter, pw, 24, keybuf))
296     return -1;
297   rc = gcry_cipher_setkey (chd, keybuf, 24);
298   if (rc)
299     {
300       log_error ( "gcry_cipher_setkey failed: %s\n", gcry_strerror (rc));
301       return -1;
302     }
303
304   if (string_to_key (2, salt, iter, pw, 8, keybuf))
305     return -1;
306   rc = gcry_cipher_setiv (chd, keybuf, 8);
307   if (rc)
308     {
309       log_error ("gcry_cipher_setiv failed: %s\n", gcry_strerror (rc));
310       return -1;
311     }
312   return 0;
313 }
314
315
316 static void
317 decrypt_block (unsigned char *buffer, size_t length, char *salt, int iter,
318                const char *pw)
319 {
320   GcryCipherHd chd;
321   int rc;
322
323   chd = gcry_cipher_open (GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_CBC, 0);
324   if (!chd)
325     {
326       log_error ( "gcry_cipher_open failed: %s\n", gcry_strerror(-1));
327       return;
328     }
329   if (set_key_iv (chd, salt, iter, pw))
330     goto leave;
331
332   rc = gcry_cipher_decrypt (chd, buffer, length, NULL, 0);
333   if (rc)
334     {
335       log_error ( "gcry_cipher_decrypt failed: %s\n", gcry_strerror (rc));
336       goto leave;
337     }
338
339 /*    { */
340 /*      FILE *fp = fopen("inner.der", "wb"); */
341 /*      fwrite (buffer, 1, length, fp); */
342 /*      fclose (fp); */
343 /*    } */
344
345  leave:
346   gcry_cipher_close (chd);
347 }
348   
349
350
351
352 static int
353 parse_bag_encrypted_data (const unsigned char *buffer, size_t length,
354                           int startoffset)
355 {
356   struct tag_info ti;
357   const unsigned char *p = buffer;
358   size_t n = length;
359   const char *where;
360
361   where = "start";
362   if (parse_tag (&p, &n, &ti))
363     goto bailout;
364   if (ti.class != CONTEXT || ti.tag)
365     goto bailout;
366   if (parse_tag (&p, &n, &ti))
367     goto bailout;
368   if (ti.tag != TAG_SEQUENCE)
369     goto bailout;
370
371   where = "bag.encryptedData.version";
372   if (parse_tag (&p, &n, &ti))
373     goto bailout;
374   if (ti.tag != TAG_INTEGER || ti.length != 1 || *p != 0)
375     goto bailout;
376   p++; n--;
377   if (parse_tag (&p, &n, &ti))
378     goto bailout;
379   if (ti.tag != TAG_SEQUENCE)
380     goto bailout;
381
382   where = "bag.encryptedData.data";
383   if (parse_tag (&p, &n, &ti))
384     goto bailout;
385   if (ti.tag != TAG_OBJECT_ID || ti.length != DIM(oid_data)
386       || memcmp (p, oid_data, DIM(oid_data)))
387     goto bailout;
388   p += DIM(oid_data);
389   n -= DIM(oid_data);
390
391   /* fixme: continue parsing */
392
393   return 0;
394  bailout:
395   log_error ("encrptedData error at \"%s\", offset %u\n",
396              where, (p - buffer)+startoffset);
397   return -1;
398 }
399
400 static GcryMPI *
401 parse_bag_data (const unsigned char *buffer, size_t length, int startoffset,
402                 const char *pw)
403 {
404   int rc;
405   struct tag_info ti;
406   const unsigned char *p = buffer;
407   size_t n = length;
408   const char *where;
409   char salt[8];
410   unsigned int iter;
411   int len;
412   unsigned char *plain = NULL;
413   GcryMPI *result = NULL;
414   int result_count, i;
415
416   where = "start";
417   if (parse_tag (&p, &n, &ti))
418     goto bailout;
419   if (ti.class != CONTEXT || ti.tag)
420     goto bailout;
421   if (parse_tag (&p, &n, &ti))
422     goto bailout;
423   if (ti.class || ti.tag != TAG_OCTET_STRING)
424     goto bailout;
425
426   where = "data.outerseqs";
427   if (parse_tag (&p, &n, &ti))
428     goto bailout;
429   if (ti.class || ti.tag != TAG_SEQUENCE)
430     goto bailout;
431   if (parse_tag (&p, &n, &ti))
432     goto bailout;
433   if (ti.class || ti.tag != TAG_SEQUENCE)
434     goto bailout;
435
436   where = "data.objectidentifier";
437   if (parse_tag (&p, &n, &ti))
438     goto bailout;
439   if (ti.class || ti.tag != TAG_OBJECT_ID
440       || ti.length != DIM(oid_pkcs_12_pkcs_8ShroudedKeyBag)
441       || memcmp (p, oid_pkcs_12_pkcs_8ShroudedKeyBag,
442                  DIM(oid_pkcs_12_pkcs_8ShroudedKeyBag)))
443     goto bailout;
444   p += DIM(oid_pkcs_12_pkcs_8ShroudedKeyBag);
445   n -= DIM(oid_pkcs_12_pkcs_8ShroudedKeyBag);
446
447   where = "shrouded,outerseqs";
448   if (parse_tag (&p, &n, &ti))
449     goto bailout;
450   if (ti.class != CONTEXT || ti.tag)
451     goto bailout;
452   if (parse_tag (&p, &n, &ti))
453     goto bailout;
454   if (ti.class || ti.tag != TAG_SEQUENCE)
455     goto bailout;
456   if (parse_tag (&p, &n, &ti))
457     goto bailout;
458   if (ti.class || ti.tag != TAG_SEQUENCE)
459     goto bailout;
460   if (parse_tag (&p, &n, &ti))
461     goto bailout;
462   if (ti.class || ti.tag != TAG_OBJECT_ID
463       || ti.length != DIM(oid_pbeWithSHAAnd3_KeyTripleDES_CBC)
464       || memcmp (p, oid_pbeWithSHAAnd3_KeyTripleDES_CBC,
465                  DIM(oid_pbeWithSHAAnd3_KeyTripleDES_CBC)))
466     goto bailout;
467   p += DIM(oid_pbeWithSHAAnd3_KeyTripleDES_CBC);
468   n -= DIM(oid_pbeWithSHAAnd3_KeyTripleDES_CBC);
469
470   where = "3des-params";
471   if (parse_tag (&p, &n, &ti))
472     goto bailout;
473   if (ti.class || ti.tag != TAG_SEQUENCE)
474     goto bailout;
475   if (parse_tag (&p, &n, &ti))
476     goto bailout;
477   if (ti.class || ti.tag != TAG_OCTET_STRING || ti.length != 8 )
478     goto bailout;
479   memcpy (salt, p, 8);
480   p += 8;
481   n -= 8;
482   if (parse_tag (&p, &n, &ti))
483     goto bailout;
484   if (ti.class || ti.tag != TAG_INTEGER || !ti.length )
485     goto bailout;
486   for (iter=0; ti.length; ti.length--)
487     {
488       iter <<= 8;
489       iter |= (*p++) & 0xff; 
490       n--;
491     }
492   
493   where = "3des-ciphertext";
494   if (parse_tag (&p, &n, &ti))
495     goto bailout;
496   if (ti.class || ti.tag != TAG_OCTET_STRING || !ti.length )
497     goto bailout;
498   
499   log_info ("%lu bytes of 3DES encrypted text\n", ti.length);
500   
501   plain = gcry_malloc_secure (ti.length);
502   if (!plain)
503     {
504       log_error ("error allocating decryption buffer\n");
505       goto bailout;
506     }
507   memcpy (plain, p, ti.length);
508   decrypt_block (plain, ti.length, salt, iter, pw);
509   n = ti.length;
510   startoffset = 0;
511   buffer = p = plain;
512
513   where = "decrypted-text";
514   if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_SEQUENCE)
515     goto bailout;
516   if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_INTEGER
517       || ti.length != 1 || *p)
518     goto bailout;
519   p++; n--;
520   if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_SEQUENCE)
521     goto bailout;
522   len = ti.length;
523   if (parse_tag (&p, &n, &ti))
524     goto bailout;
525   if (len < ti.nhdr)
526     goto bailout;
527   len -= ti.nhdr;
528   if (ti.class || ti.tag != TAG_OBJECT_ID
529       || ti.length != DIM(oid_rsaEncryption)
530       || memcmp (p, oid_rsaEncryption,
531                  DIM(oid_rsaEncryption)))
532     goto bailout;
533   p += DIM (oid_rsaEncryption);
534   n -= DIM (oid_rsaEncryption);
535   if (len < ti.length)
536     goto bailout;
537   len -= ti.length;
538   if (n < len)
539     goto bailout;
540   p += len;
541   n -= len;
542   if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_OCTET_STRING)
543     goto bailout;
544   if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_SEQUENCE)
545     goto bailout;
546   len = ti.length;
547
548   result = gcry_calloc (10, sizeof *result);
549   if (!result)
550     {
551       log_error ( "error allocating result array\n");
552       goto bailout;
553     }
554   result_count = 0;
555
556   where = "reading.key-parameters";
557   for (result_count=0; len && result_count < 9;)
558     {
559       int dummy_n;
560
561       if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_INTEGER)
562         goto bailout;
563       if (len < ti.nhdr)
564         goto bailout;
565       len -= ti.nhdr;
566       if (len < ti.length)
567         goto bailout;
568       len -= ti.length;
569       dummy_n = ti.length;
570       if (!result_count && ti.length == 1 && !*p)
571         ; /* ignore the very first one if it is a 0 */
572       else 
573         {
574           rc = gcry_mpi_scan (result+result_count, GCRYMPI_FMT_USG, p,
575                               &dummy_n);
576           if (rc)
577             {
578               log_error ("error parsing key parameter: %s\n",
579                          gcry_strerror (rc));
580               goto bailout;
581             }
582           result_count++;
583         }
584       p += ti.length;
585       n -= ti.length;
586     }
587   if (len)
588     goto bailout;
589
590   return result;
591
592  bailout:
593   gcry_free (plain);
594   if (result)
595     {
596       for (i=0; result[i]; i++)
597         gcry_mpi_release (result[i]);
598       gcry_free (result);
599     }
600   log_error ( "data error at \"%s\", offset %u\n",
601               where, (p - buffer) + startoffset);
602   return NULL;
603 }
604
605
606 /* Parse a PKCS12 object and return an array of MPI representing the
607    secret key parameters.  This is a very limited inplementation in
608    that it is only able to look for 3DES encoded enctyptedData and
609    tries to extract the first private key object it finds.  In case of
610    an error NULL is returned. */
611 GcryMPI *
612 p12_parse (const unsigned char *buffer, size_t length, const char *pw)
613 {
614   struct tag_info ti;
615   const unsigned char *p = buffer;
616   size_t n = length;
617   const char *where;
618   int bagseqlength, len;
619
620   where = "pfx";
621   if (parse_tag (&p, &n, &ti))
622     goto bailout;
623   if (ti.tag != TAG_SEQUENCE)
624     goto bailout;
625
626   where = "pfxVersion";
627   if (parse_tag (&p, &n, &ti))
628     goto bailout;
629   if (ti.tag != TAG_INTEGER || ti.length != 1 || *p != 3)
630     goto bailout;
631   p++; n--;
632   
633   where = "authSave";
634   if (parse_tag (&p, &n, &ti))
635     goto bailout;
636   if (ti.tag != TAG_SEQUENCE)
637     goto bailout;
638   if (parse_tag (&p, &n, &ti))
639     goto bailout;
640   if (ti.tag != TAG_OBJECT_ID || ti.length != DIM(oid_data)
641       || memcmp (p, oid_data, DIM(oid_data)))
642     goto bailout;
643   p += DIM(oid_data);
644   n -= DIM(oid_data);
645
646   if (parse_tag (&p, &n, &ti))
647     goto bailout;
648   if (ti.class != CONTEXT || ti.tag)
649     goto bailout;
650   if (parse_tag (&p, &n, &ti))
651     goto bailout;
652   if (ti.class != UNIVERSAL || ti.tag != TAG_OCTET_STRING)
653     goto bailout;
654
655   where = "bags";
656   if (parse_tag (&p, &n, &ti))
657     goto bailout;
658   if (ti.class != UNIVERSAL || ti.tag != TAG_SEQUENCE)
659     goto bailout;
660   bagseqlength = ti.length;
661   while (bagseqlength)
662     {
663       /*log_debug ( "at offset %u\n", (p - buffer));*/
664       where = "bag-sequence";
665       if (parse_tag (&p, &n, &ti))
666         goto bailout;
667       if (ti.class != UNIVERSAL || ti.tag != TAG_SEQUENCE)
668         goto bailout;
669
670       if (bagseqlength < ti.nhdr)
671         goto bailout;
672       bagseqlength -= ti.nhdr;
673       if (bagseqlength < ti.length)
674         goto bailout;
675       bagseqlength -= ti.length;
676       len = ti.length;
677
678       if (parse_tag (&p, &n, &ti))
679         goto bailout;
680       len -= ti.nhdr;
681       if (ti.tag == TAG_OBJECT_ID && ti.length == DIM(oid_encryptedData)
682           && !memcmp (p, oid_encryptedData, DIM(oid_encryptedData)))
683         {
684           p += DIM(oid_encryptedData);
685           n -= DIM(oid_encryptedData);
686           len -= DIM(oid_encryptedData);
687           where = "bag.encryptedData";
688           if (parse_bag_encrypted_data (p, n, (p - buffer)))
689             goto bailout;
690         }
691       else if (ti.tag == TAG_OBJECT_ID && ti.length == DIM(oid_data)
692           && !memcmp (p, oid_data, DIM(oid_data)))
693         {
694           p += DIM(oid_data);
695           n -= DIM(oid_data);
696           len -= DIM(oid_data);
697           return parse_bag_data (p, n, (p-buffer), pw);
698         }
699       else
700         log_info ( "unknown bag type - skipped\n");
701
702       if (len < 0 || len > n)
703         goto bailout;
704       p += len;
705       n -= len;
706     }
707   
708   return NULL;
709  bailout:
710   log_error ("error at \"%s\", offset %u\n", where, (p - buffer));
711   return NULL;
712 }
713
714 #if 0 /* unser construction. */
715 /* Expect the RSA key parameters in KPARMS and a password in
716    PW. Create a PKCS structure from it and return it as well as the
717    length in R_LENGTH; return NULL in case of an error. */
718 unsigned char * 
719 p12_build (GcryMPI *kparms, const char *pw, size_t *r_length)
720 {
721   int i;
722   unsigned char *result;
723   size_t resultlen;
724
725   for (i=0; kparms[i]; i++)
726     ;
727   if (i != 8)
728     {
729       log_error ("invalid paramters for p12_build\n");
730       return NULL;
731     }
732
733
734   *r_length = resultlen;
735   return result;
736 }
737 #endif
738
739
740 #ifdef TEST
741 int
742 main (int argc, char **argv)
743 {
744   FILE *fp;
745   struct stat st;
746   char *buf;
747   size_t buflen;
748   GcryMPI *result;
749
750   if (argc != 3)
751     {
752       fprintf (stderr, "usage: testp12 file passphrase\n");
753       return 1;
754     }
755
756   gcry_control (GCRYCTL_DISABLE_SECMEM, NULL);
757   gcry_control (GCRYCTL_INITIALIZATION_FINISHED, NULL);
758
759   fp = fopen (argv[1], "rb");
760   if (!fp)
761     {
762       fprintf (stderr, "can't open `%s': %s\n", argv[1], strerror (errno));
763       return 1;
764     }
765   
766   if (fstat (fileno(fp), &st))
767     {
768       fprintf (stderr, "can't stat `%s': %s\n", argv[1], strerror (errno));
769       return 1;
770     }
771
772   buflen = st.st_size;
773   buf = malloc (buflen+1);
774   if (!buf || fread (buf, buflen, 1, fp) != 1)
775     {
776       fprintf (stderr, "error reading `%s': %s\n", argv[1], strerror (errno));
777       return 1;
778     }
779   fclose (fp);
780
781   result = p12_parse (buf, buflen, argv[2]);
782   if (result)
783     {
784       int i, rc;
785       char *buf;
786
787       for (i=0; result[i]; i++)
788         {
789           rc = gcry_mpi_aprint (GCRYMPI_FMT_HEX, (void**)&buf,
790                                 NULL, result[i]);
791           if (rc)
792             printf ("%d: [error printing number: %s]\n",
793                     i, gcry_strerror (rc));
794           else
795             {
796               printf ("%d: %s\n", i, buf);
797               gcry_free (buf);
798             }
799         }
800     }
801
802   return 0;
803
804 }
805 #endif /* TEST */