Updated FSF's address.
[gnupg.git] / agent / protect.c
1 /* protect.c - Un/Protect a secret key
2  * Copyright (C) 1998, 1999, 2000, 2001, 2002,
3  *               2003 Free Software Foundation, Inc.
4  *
5  * This file is part of GnuPG.
6  *
7  * GnuPG is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * GnuPG is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
20  * USA.
21  */
22
23 #include <config.h>
24 #include <errno.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <ctype.h>
29 #include <assert.h>
30 #include <unistd.h>
31 #include <sys/stat.h>
32
33 #include "agent.h"
34
35 #include "sexp-parse.h"
36
37 #define PROT_CIPHER        GCRY_CIPHER_AES
38 #define PROT_CIPHER_STRING "aes"
39 #define PROT_CIPHER_KEYLEN (128/8)
40
41
42 /* A table containing the information needed to create a protected
43    private key */
44 static struct {
45   const char *algo;
46   const char *parmlist;
47   int prot_from, prot_to;
48 } protect_info[] = {
49   { "rsa",  "nedpqu", 2, 5 },
50   { "dsa",  "pqgyx", 4, 4 },
51   { "elg",  "pgyx", 3, 3 },
52   { NULL }
53 };
54
55
56 static int
57 hash_passphrase (const char *passphrase, int hashalgo,
58                  int s2kmode,
59                  const unsigned char *s2ksalt, unsigned long s2kcount,
60                  unsigned char *key, size_t keylen);
61
62
63 \f
64 /* Calculate the MIC for a private key S-Exp. SHA1HASH should point to
65    a 20 byte buffer.  This function is suitable for any algorithms. */
66 static int 
67 calculate_mic (const unsigned char *plainkey, unsigned char *sha1hash)
68 {
69   const unsigned char *hash_begin, *hash_end;
70   const unsigned char *s;
71   size_t n;
72
73   s = plainkey;
74   if (*s != '(')
75     return gpg_error (GPG_ERR_INV_SEXP);
76   s++;
77   n = snext (&s);
78   if (!n)
79     return gpg_error (GPG_ERR_INV_SEXP); 
80   if (!smatch (&s, n, "private-key"))
81     return gpg_error (GPG_ERR_UNKNOWN_SEXP); 
82   if (*s != '(')
83     return gpg_error (GPG_ERR_UNKNOWN_SEXP);
84   hash_begin = s;
85   s++;
86   n = snext (&s);
87   if (!n)
88     return gpg_error (GPG_ERR_INV_SEXP); 
89   s += n; /* skip over the algorithm name */
90
91   while (*s == '(')
92     {
93       s++;
94       n = snext (&s);
95       if (!n)
96         return gpg_error (GPG_ERR_INV_SEXP); 
97       s += n;
98       n = snext (&s);
99       if (!n)
100         return gpg_error (GPG_ERR_INV_SEXP); 
101       s += n;
102       if ( *s != ')' )
103         return gpg_error (GPG_ERR_INV_SEXP); 
104       s++;
105     }
106   if (*s != ')')
107     return gpg_error (GPG_ERR_INV_SEXP); 
108   s++;
109   hash_end = s;
110
111   gcry_md_hash_buffer (GCRY_MD_SHA1, sha1hash,
112                        hash_begin, hash_end - hash_begin);
113
114   return 0;
115 }
116
117
118 \f
119 /* Encrypt the parameter block starting at PROTBEGIN with length
120    PROTLEN using the utf8 encoded key PASSPHRASE and return the entire
121    encrypted block in RESULT or return with an error code.  SHA1HASH
122    is the 20 byte SHA-1 hash required for the integrity code.
123
124    The parameter block is expected to be an incomplete S-Expression of
125    the form (example in advanced format):
126
127      (d #046129F..[some bytes not shown]..81#)
128      (p #00e861b..[some bytes not shown]..f1#)
129      (q #00f7a7c..[some bytes not shown]..61#)
130      (u #304559a..[some bytes not shown]..9b#) 
131
132    the returned block is the S-Expression:
133
134     (protected mode (parms) encrypted_octet_string)
135
136 */
137 static int
138 do_encryption (const unsigned char *protbegin, size_t protlen, 
139                const char *passphrase,  const unsigned char *sha1hash,
140                unsigned char **result, size_t *resultlen)
141 {
142   gcry_cipher_hd_t hd;
143   const char *modestr = "openpgp-s2k3-sha1-" PROT_CIPHER_STRING "-cbc";
144   int blklen, enclen, outlen;
145   unsigned char *iv = NULL;
146   int rc;
147   char *outbuf = NULL;
148   char *p;
149   int saltpos, ivpos, encpos;
150
151   *resultlen = 0;
152   *result = NULL;
153
154   rc = gcry_cipher_open (&hd, PROT_CIPHER, GCRY_CIPHER_MODE_CBC,
155                          GCRY_CIPHER_SECURE);
156   if (rc)
157     return rc;
158
159
160   /* We need to work on a copy of the data because this makes it
161      easier to add the trailer and the padding and more important we
162      have to prefix the text with 2 parenthesis, so we have to
163      allocate enough space for:
164
165      ((<parameter_list>)(4:hash4:sha120:<hashvalue>)) + padding
166
167      We always append a full block of random bytes as padding but
168      encrypt only what is needed for a full blocksize */
169   blklen = gcry_cipher_get_algo_blklen (PROT_CIPHER);
170   outlen = 2 + protlen + 2 + 6 + 6 + 23 + 2 + blklen;
171   enclen = outlen/blklen * blklen;
172   outbuf = gcry_malloc_secure (outlen);
173   if (!outbuf)
174     rc = out_of_core ();
175   if (!rc)
176     {
177       /* Allocate random bytes to be used as IV, padding and s2k salt. */
178       iv = xtrymalloc (blklen*2+8);
179       if (!iv)
180         rc = gpg_error (GPG_ERR_ENOMEM);
181       gcry_create_nonce (iv, blklen*2+8);
182       rc = gcry_cipher_setiv (hd, iv, blklen);
183     }
184   if (!rc)
185     {
186       unsigned char *key;
187       size_t keylen = PROT_CIPHER_KEYLEN;
188       
189       key = gcry_malloc_secure (keylen);
190       if (!key)
191         rc = out_of_core ();
192       else
193         {
194           rc = hash_passphrase (passphrase, GCRY_MD_SHA1,
195                                 3, iv+2*blklen, 96, key, keylen);
196           if (!rc)
197             rc = gcry_cipher_setkey (hd, key, keylen);
198           xfree (key);
199         }
200     }
201   if (!rc)
202     {
203       p = outbuf;
204       *p++ = '(';
205       *p++ = '(';
206       memcpy (p, protbegin, protlen);
207       p += protlen;
208       memcpy (p, ")(4:hash4:sha120:", 17);
209       p += 17;
210       memcpy (p, sha1hash, 20);
211       p += 20;
212       *p++ = ')';
213       *p++ = ')';
214       memcpy (p, iv+blklen, blklen); 
215       p += blklen;
216       assert ( p - outbuf == outlen);
217       rc = gcry_cipher_encrypt (hd, outbuf, enclen, NULL, 0);
218     }
219   gcry_cipher_close (hd);
220   if (rc)
221     {
222       xfree (iv);
223       xfree (outbuf);
224       return rc;
225     }
226
227   /* Now allocate the buffer we want to return.  This is
228
229      (protected openpgp-s2k3-sha1-aes-cbc
230        ((sha1 salt no_of_iterations) 16byte_iv)
231        encrypted_octet_string)
232        
233      in canoncical format of course.  We use asprintf and %n modifier
234      and spaces as palceholders.  */
235   asprintf (&p,
236             "(9:protected%d:%s((4:sha18:%n_8bytes_2:96)%d:%n%*s)%d:%n%*s)",
237             (int)strlen (modestr), modestr,
238             &saltpos, 
239             blklen, &ivpos, blklen, "",
240             enclen, &encpos, enclen, "");
241   if (p)
242     { /* asprintf does not use our malloc system */
243       char *psave = p;
244       p = xtrymalloc (strlen (psave)+1);
245       if (p)
246         strcpy (p, psave);
247       free (psave);
248     }
249   if (!p)
250     {
251       gpg_error_t tmperr = out_of_core ();
252       xfree (iv);
253       xfree (outbuf);
254       return tmperr;
255     }
256   *resultlen = strlen (p);
257   *result = (unsigned char*)p;
258   memcpy (p+saltpos, iv+2*blklen, 8);
259   memcpy (p+ivpos, iv, blklen);
260   memcpy (p+encpos, outbuf, enclen);
261   xfree (iv);
262   xfree (outbuf);
263   return 0;
264 }
265
266
267
268 /* Protect the key encoded in canonical format in PLAINKEY.  We assume
269    a valid S-Exp here. */
270 int 
271 agent_protect (const unsigned char *plainkey, const char *passphrase,
272                unsigned char **result, size_t *resultlen)
273 {
274   int rc;
275   const unsigned char *s;
276   const unsigned char *hash_begin, *hash_end;
277   const unsigned char *prot_begin, *prot_end, *real_end;
278   size_t n;
279   int c, infidx, i;
280   unsigned char hashvalue[20];
281   unsigned char *protected;
282   size_t protectedlen;
283   int depth = 0;
284   unsigned char *p;
285
286   s = plainkey;
287   if (*s != '(')
288     return gpg_error (GPG_ERR_INV_SEXP);
289   depth++;
290   s++;
291   n = snext (&s);
292   if (!n)
293     return gpg_error (GPG_ERR_INV_SEXP); 
294   if (!smatch (&s, n, "private-key"))
295     return gpg_error (GPG_ERR_UNKNOWN_SEXP); 
296   if (*s != '(')
297     return gpg_error (GPG_ERR_UNKNOWN_SEXP);
298   depth++;
299   hash_begin = s;
300   s++;
301   n = snext (&s);
302   if (!n)
303     return gpg_error (GPG_ERR_INV_SEXP); 
304
305   for (infidx=0; protect_info[infidx].algo
306               && !smatch (&s, n, protect_info[infidx].algo); infidx++)
307     ;
308   if (!protect_info[infidx].algo)
309     return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM); 
310
311   prot_begin = prot_end = NULL;
312   for (i=0; (c=protect_info[infidx].parmlist[i]); i++)
313     {
314       if (i == protect_info[infidx].prot_from)
315         prot_begin = s;
316       if (*s != '(')
317         return gpg_error (GPG_ERR_INV_SEXP);
318       depth++;
319       s++;
320       n = snext (&s);
321       if (!n)
322         return gpg_error (GPG_ERR_INV_SEXP); 
323       if (n != 1 || c != *s)
324         return gpg_error (GPG_ERR_INV_SEXP); 
325       s += n;
326       n = snext (&s);
327       if (!n)
328         return gpg_error (GPG_ERR_INV_SEXP); 
329       s +=n; /* skip value */
330       if (*s != ')')
331         return gpg_error (GPG_ERR_INV_SEXP); 
332       depth--;
333       if (i == protect_info[infidx].prot_to)
334         prot_end = s;
335       s++;
336     }
337   if (*s != ')' || !prot_begin || !prot_end )
338     return gpg_error (GPG_ERR_INV_SEXP); 
339   depth--;
340   hash_end = s;
341   s++;
342   /* skip to the end of the S-exp */
343   assert (depth == 1);
344   rc = sskip (&s, &depth);
345   if (rc)
346     return rc;
347   assert (!depth);
348   real_end = s-1;
349
350   gcry_md_hash_buffer (GCRY_MD_SHA1, hashvalue,
351                        hash_begin, hash_end - hash_begin + 1);
352
353   rc = do_encryption (prot_begin, prot_end - prot_begin + 1,
354                       passphrase,  hashvalue,
355                       &protected, &protectedlen);
356   if (rc)
357     return rc;
358
359   /* Now create the protected version of the key.  Note that the 10
360      extra bytes are for for the inserted "protected-" string (the
361      beginning of the plaintext reads: "((11:private-key(" ). */
362   *resultlen = (10
363                 + (prot_begin-plainkey)
364                 + protectedlen
365                 + (real_end-prot_end));
366   *result = p = xtrymalloc (*resultlen);
367   if (!p)
368     {
369       gpg_error_t tmperr = out_of_core ();
370       xfree (protected);
371       return tmperr;
372     }
373   memcpy (p, "(21:protected-", 14);
374   p += 14;
375   memcpy (p, plainkey+4, prot_begin - plainkey - 4);
376   p += prot_begin - plainkey - 4;
377   memcpy (p, protected, protectedlen);
378   p += protectedlen;
379   memcpy (p, prot_end+1, real_end - prot_end);
380   p += real_end - prot_end;
381   assert ( p - *result == *resultlen);
382   xfree (protected);
383   return 0;
384 }
385
386 \f
387 /* Do the actual decryption and check the return list for consistency.  */
388 static int
389 do_decryption (const unsigned char *protected, size_t protectedlen, 
390                const char *passphrase, 
391                const unsigned char *s2ksalt, unsigned long s2kcount,
392                const unsigned char *iv, size_t ivlen,
393                unsigned char **result)
394 {
395   int rc = 0;
396   int blklen;
397   gcry_cipher_hd_t hd;
398   unsigned char *outbuf;
399   size_t reallen;
400
401   blklen = gcry_cipher_get_algo_blklen (PROT_CIPHER);
402   if (protectedlen < 4 || (protectedlen%blklen))
403     return gpg_error (GPG_ERR_CORRUPTED_PROTECTION);
404
405   rc = gcry_cipher_open (&hd, PROT_CIPHER, GCRY_CIPHER_MODE_CBC,
406                          GCRY_CIPHER_SECURE);
407   if (rc)
408     return rc;
409
410   outbuf = gcry_malloc_secure (protectedlen);
411   if (!outbuf)
412     rc = out_of_core ();
413   if (!rc)
414     rc = gcry_cipher_setiv (hd, iv, ivlen);
415   if (!rc)
416     {
417       unsigned char *key;
418       size_t keylen = PROT_CIPHER_KEYLEN;
419       
420       key = gcry_malloc_secure (keylen);
421       if (!key)
422         rc = out_of_core ();
423       else
424         {
425           rc = hash_passphrase (passphrase, GCRY_MD_SHA1,
426                                 3, s2ksalt, s2kcount, key, keylen);
427           if (!rc)
428             rc = gcry_cipher_setkey (hd, key, keylen);
429           xfree (key);
430         }
431     }
432   if (!rc)
433     rc = gcry_cipher_decrypt (hd, outbuf, protectedlen,
434                               protected, protectedlen);
435   gcry_cipher_close (hd);
436   if (rc)
437     {
438       xfree (outbuf);
439       return rc;
440     }
441   /* Do a quick check first. */
442   if (*outbuf != '(' && outbuf[1] != '(')
443     {
444       xfree (outbuf);
445       return gpg_error (GPG_ERR_BAD_PASSPHRASE);
446     }
447   /* Check that we have a consistent S-Exp. */
448   reallen = gcry_sexp_canon_len (outbuf, protectedlen, NULL, NULL);
449   if (!reallen || (reallen + blklen < protectedlen) )
450     {
451       xfree (outbuf);
452       return gpg_error (GPG_ERR_BAD_PASSPHRASE);
453     }
454   *result = outbuf;
455   return 0;
456 }
457
458
459 /* Merge the parameter list contained in CLEARTEXT with the original
460    protect lists PROTECTEDKEY by replacing the list at REPLACEPOS.
461    Return the new list in RESULT and the MIC value in the 20 byte
462    buffer SHA1HASH. */
463 static int
464 merge_lists (const unsigned char *protectedkey,
465              size_t replacepos, 
466              const unsigned char *cleartext,
467              unsigned char *sha1hash,
468              unsigned char **result, size_t *resultlen)
469 {
470   size_t n, newlistlen;
471   unsigned char *newlist, *p;
472   const unsigned char *s;
473   const unsigned char *startpos, *endpos;
474   int i, rc;
475   
476   *result = NULL;
477   *resultlen = 0;
478
479   if (replacepos < 26)
480     return gpg_error (GPG_ERR_BUG);
481
482   /* Estimate the required size of the resulting list.  We have a large
483      safety margin of >20 bytes (MIC hash from CLEARTEXT and the
484      removed "protected-" */
485   newlistlen = gcry_sexp_canon_len (protectedkey, 0, NULL, NULL);
486   if (!newlistlen)
487     return gpg_error (GPG_ERR_BUG);
488   n = gcry_sexp_canon_len (cleartext, 0, NULL, NULL);
489   if (!n)
490     return gpg_error (GPG_ERR_BUG);
491   newlistlen += n;
492   newlist = gcry_malloc_secure (newlistlen);
493   if (!newlist)
494     return out_of_core ();
495
496   /* Copy the initial segment */
497   strcpy ((char*)newlist, "(11:private-key");
498   p = newlist + 15;
499   memcpy (p, protectedkey+15+10, replacepos-15-10);
500   p += replacepos-15-10;
501
502   /* copy the cleartext */
503   s = cleartext;
504   if (*s != '(' && s[1] != '(')
505     return gpg_error (GPG_ERR_BUG);  /*we already checked this */
506   s += 2;
507   startpos = s;
508   while ( *s == '(' )
509     {
510       s++;
511       n = snext (&s);
512       if (!n)
513         goto invalid_sexp;
514       s += n;
515       n = snext (&s);
516       if (!n)
517         goto invalid_sexp;
518       s += n;
519       if ( *s != ')' )
520         goto invalid_sexp;
521       s++;
522     }
523   if ( *s != ')' )
524     goto invalid_sexp;
525   endpos = s;
526   s++;
527   /* short intermezzo: Get the MIC */
528   if (*s != '(')
529     goto invalid_sexp;
530   s++;
531   n = snext (&s);
532   if (!smatch (&s, n, "hash"))
533     goto invalid_sexp;
534   n = snext (&s);
535   if (!smatch (&s, n, "sha1"))
536     goto invalid_sexp; 
537   n = snext (&s);
538   if (n != 20)
539     goto invalid_sexp;
540   memcpy (sha1hash, s, 20);
541   s += n;
542   if (*s != ')')
543     goto invalid_sexp;
544   /* end intermezzo */
545
546   /* append the parameter list */
547   memcpy (p, startpos, endpos - startpos);
548   p += endpos - startpos;
549   
550   /* skip overt the protected list element in the original list */
551   s = protectedkey + replacepos;
552   assert (*s == '(');
553   s++;
554   i = 1;
555   rc = sskip (&s, &i);
556   if (rc)
557     goto failure;
558   startpos = s;
559   i = 2; /* we are inside this level */
560   rc = sskip (&s, &i);
561   if (rc)
562     goto failure;
563   assert (s[-1] == ')');
564   endpos = s; /* one behind the end of the list */
565
566   /* append the rest */
567   memcpy (p, startpos, endpos - startpos);
568   p += endpos - startpos;
569
570   /* ready */
571   *result = newlist;
572   *resultlen = newlistlen;
573   return 0;
574
575  failure:
576   wipememory (newlist, newlistlen);
577   xfree (newlist);
578   return rc;
579
580  invalid_sexp:
581   wipememory (newlist, newlistlen);
582   xfree (newlist);
583   return gpg_error (GPG_ERR_INV_SEXP);
584 }
585
586
587
588 /* Unprotect the key encoded in canonical format.  We assume a valid
589    S-Exp here. */
590 int 
591 agent_unprotect (const unsigned char *protectedkey, const char *passphrase,
592                  unsigned char **result, size_t *resultlen)
593 {
594   int rc;
595   const unsigned char *s;
596   size_t n;
597   int infidx, i;
598   unsigned char sha1hash[20], sha1hash2[20];
599   const unsigned char *s2ksalt;
600   unsigned long s2kcount;
601   const unsigned char *iv;
602   const unsigned char *prot_begin;
603   unsigned char *cleartext;
604   unsigned char *final;
605   size_t finallen;
606
607   s = protectedkey;
608   if (*s != '(')
609     return gpg_error (GPG_ERR_INV_SEXP);
610   s++;
611   n = snext (&s);
612   if (!n)
613     return gpg_error (GPG_ERR_INV_SEXP); 
614   if (!smatch (&s, n, "protected-private-key"))
615     return gpg_error (GPG_ERR_UNKNOWN_SEXP); 
616   if (*s != '(')
617     return gpg_error (GPG_ERR_UNKNOWN_SEXP);
618   s++;
619   n = snext (&s);
620   if (!n)
621     return gpg_error (GPG_ERR_INV_SEXP); 
622
623   for (infidx=0; protect_info[infidx].algo
624               && !smatch (&s, n, protect_info[infidx].algo); infidx++)
625     ;
626   if (!protect_info[infidx].algo)
627     return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM); 
628
629   /* Now find the list with the protected information.  Here is an
630      example for such a list:
631      (protected openpgp-s2k3-sha1-aes-cbc 
632         ((sha1 <salt> <count>) <Initialization_Vector>)
633         <encrypted_data>)
634    */
635   for (;;)
636     {
637       if (*s != '(')
638         return gpg_error (GPG_ERR_INV_SEXP);
639       prot_begin = s;
640       s++;
641       n = snext (&s);
642       if (!n)
643         return gpg_error (GPG_ERR_INV_SEXP); 
644       if (smatch (&s, n, "protected"))
645         break;
646       s += n;
647       i = 1;
648       rc = sskip (&s, &i);
649       if (rc)
650         return rc;
651     }
652   /* found */
653   n = snext (&s);
654   if (!n)
655     return gpg_error (GPG_ERR_INV_SEXP); 
656   if (!smatch (&s, n, "openpgp-s2k3-sha1-" PROT_CIPHER_STRING "-cbc"))
657     return gpg_error (GPG_ERR_UNSUPPORTED_PROTECTION);
658   if (*s != '(' || s[1] != '(')
659     return gpg_error (GPG_ERR_INV_SEXP);
660   s += 2;
661   n = snext (&s);
662   if (!n)
663     return gpg_error (GPG_ERR_INV_SEXP); 
664   if (!smatch (&s, n, "sha1"))
665     return gpg_error (GPG_ERR_UNSUPPORTED_PROTECTION);
666   n = snext (&s);
667   if (n != 8)
668     return gpg_error (GPG_ERR_CORRUPTED_PROTECTION);
669   s2ksalt = s;
670   s += n;
671   n = snext (&s);
672   if (!n)
673     return gpg_error (GPG_ERR_CORRUPTED_PROTECTION);
674   /* We expect a list close as next, so we can simply use strtoul()
675      here.  We might want to check that we only have digits - but this
676      is nothing we should worry about */
677   if (s[n] != ')' )
678     return gpg_error (GPG_ERR_INV_SEXP);
679   s2kcount = strtoul ((const char*)s, NULL, 10);
680   if (!s2kcount)
681     return gpg_error (GPG_ERR_CORRUPTED_PROTECTION);
682   s += n;
683   s++; /* skip list end */
684
685   n = snext (&s);
686   if (n != 16) /* Wrong blocksize for IV (we support only aes-128). */
687     return gpg_error (GPG_ERR_CORRUPTED_PROTECTION);
688   iv = s;
689   s += n;
690   if (*s != ')' )
691     return gpg_error (GPG_ERR_INV_SEXP);
692   s++;
693   n = snext (&s);
694   if (!n)
695     return gpg_error (GPG_ERR_INV_SEXP); 
696   
697   rc = do_decryption (s, n,
698                       passphrase, s2ksalt, s2kcount,
699                       iv, 16,
700                       &cleartext);
701   if (rc)
702     return rc;
703
704   rc = merge_lists (protectedkey, prot_begin-protectedkey, cleartext,
705                     sha1hash, &final, &finallen);
706   /* Albeit cleartext has been allocated in secure memory and thus
707      xfree will wipe it out, we do an extra wipe just in case
708      somethings goes badly wrong. */
709   wipememory (cleartext, n);
710   xfree (cleartext);
711   if (rc)
712     return rc;
713
714   rc = calculate_mic (final, sha1hash2);
715   if (!rc && memcmp (sha1hash, sha1hash2, 20))
716     rc = gpg_error (GPG_ERR_CORRUPTED_PROTECTION);
717   if (rc)
718     {
719       wipememory (final, finallen);
720       xfree (final);
721       return rc;
722     }
723
724   *result = final;
725   *resultlen = gcry_sexp_canon_len (final, 0, NULL, NULL);
726   return 0;
727 }
728
729 /* Check the type of the private key, this is one of the constants:
730    PRIVATE_KEY_UNKNOWN if we can't figure out the type (this is the
731    value 0), PRIVATE_KEY_CLEAR for an unprotected private key.
732    PRIVATE_KEY_PROTECTED for an protected private key or
733    PRIVATE_KEY_SHADOWED for a sub key where the secret parts are stored
734    elsewhere. */
735 int
736 agent_private_key_type (const unsigned char *privatekey)
737 {
738   const unsigned char *s;
739   size_t n;
740
741   s = privatekey;
742   if (*s != '(')
743     return PRIVATE_KEY_UNKNOWN;
744   s++;
745   n = snext (&s);
746   if (!n)
747     return PRIVATE_KEY_UNKNOWN;
748   if (smatch (&s, n, "protected-private-key"))
749     return PRIVATE_KEY_PROTECTED;
750   if (smatch (&s, n, "shadowed-private-key"))
751     return PRIVATE_KEY_SHADOWED;
752   if (smatch (&s, n, "private-key"))
753     return PRIVATE_KEY_CLEAR;
754   return PRIVATE_KEY_UNKNOWN;
755 }
756
757
758 \f
759 /* Transform a passphrase into a suitable key of length KEYLEN and
760    store this key in the caller provided buffer KEY.  The caller must
761    provide an HASHALGO, a valid S2KMODE (see rfc-2440) and depending on
762    that mode an S2KSALT of 8 random bytes and an S2KCOUNT (a suitable
763    value is 96).
764   
765    Returns an error code on failure.  */
766 static int
767 hash_passphrase (const char *passphrase, int hashalgo,
768                  int s2kmode,
769                  const unsigned char *s2ksalt,
770                  unsigned long s2kcount,
771                  unsigned char *key, size_t keylen)
772 {
773   int rc;
774   gcry_md_hd_t md;
775   int pass, i;
776   int used = 0;
777   int pwlen = strlen (passphrase);
778
779   if ( (s2kmode != 0 && s2kmode != 1 && s2kmode != 3)
780       || !hashalgo || !keylen || !key || !passphrase)
781     return gpg_error (GPG_ERR_INV_VALUE);
782   if ((s2kmode == 1 ||s2kmode == 3) && !s2ksalt)
783     return gpg_error (GPG_ERR_INV_VALUE);
784   
785   rc = gcry_md_open (&md, hashalgo, GCRY_MD_FLAG_SECURE);
786   if (rc)
787     return rc;
788
789   for (pass=0; used < keylen; pass++)
790     {
791       if (pass)
792         {
793           gcry_md_reset (md);
794           for (i=0; i < pass; i++) /* preset the hash context */
795             gcry_md_putc (md, 0);
796         }
797
798       if (s2kmode == 1 || s2kmode == 3)
799         {
800           int len2 = pwlen + 8;
801           unsigned long count = len2;
802
803           if (s2kmode == 3)
804             {
805               count = (16ul + (s2kcount & 15)) << ((s2kcount >> 4) + 6);
806               if (count < len2)
807                 count = len2;
808             }
809
810           while (count > len2)
811             {
812               gcry_md_write (md, s2ksalt, 8);
813               gcry_md_write (md, passphrase, pwlen);
814               count -= len2;
815             }
816           if (count < 8)
817             gcry_md_write (md, s2ksalt, count);
818           else 
819             {
820               gcry_md_write (md, s2ksalt, 8);
821               count -= 8;
822               gcry_md_write (md, passphrase, count);
823             }
824         }
825       else
826         gcry_md_write (md, passphrase, pwlen);
827       
828       gcry_md_final (md);
829       i = gcry_md_get_algo_dlen (hashalgo);
830       if (i > keylen - used)
831         i = keylen - used;
832       memcpy  (key+used, gcry_md_read (md, hashalgo), i);
833       used += i;
834     }
835   gcry_md_close(md);
836   return 0;
837 }
838
839
840 \f
841
842 /* Create an canonical encoded S-expression with the shadow info from
843    a card's SERIALNO and the IDSTRING.  */
844 unsigned char *
845 make_shadow_info (const char *serialno, const char *idstring)
846 {
847   const char *s;
848   char *info, *p;
849   char numbuf[21];
850   int n;
851
852   for (s=serialno, n=0; *s && s[1]; s += 2)
853     n++;
854
855   info = p = xtrymalloc (1 + 21 + n
856                            + 21 + strlen (idstring) + 1 + 1);
857   if (!info)
858     return NULL;
859   *p++ = '(';
860   sprintf (numbuf, "%d:", n);
861   p = stpcpy (p, numbuf);
862   for (s=serialno; *s && s[1]; s += 2)
863     *(unsigned char *)p++ = xtoi_2 (s);
864   sprintf (numbuf, "%d:", strlen (idstring));
865   p = stpcpy (p, numbuf);
866   p = stpcpy (p, idstring);
867   *p++ = ')';
868   *p = 0;
869   return (unsigned char *)info;
870 }
871
872
873
874 /* Create a shadow key from a public key.  We use the shadow protocol
875   "ti-v1" and insert the S-expressionn SHADOW_INFO.  The resulting
876   S-expression is returned in an allocated buffer RESULT will point
877   to. The input parameters are expected to be valid canonicalized
878   S-expressions */
879 int 
880 agent_shadow_key (const unsigned char *pubkey,
881                   const unsigned char *shadow_info,
882                   unsigned char **result)
883 {
884   const unsigned char *s;
885   const unsigned char *point;
886   size_t n;
887   int depth = 0;
888   char *p;
889   size_t pubkey_len = gcry_sexp_canon_len (pubkey, 0, NULL,NULL);
890   size_t shadow_info_len = gcry_sexp_canon_len (shadow_info, 0, NULL,NULL);
891
892   if (!pubkey_len || !shadow_info_len)
893     return gpg_error (GPG_ERR_INV_VALUE);
894   s = pubkey;
895   if (*s != '(')
896     return gpg_error (GPG_ERR_INV_SEXP);
897   depth++;
898   s++;
899   n = snext (&s);
900   if (!n)
901     return gpg_error (GPG_ERR_INV_SEXP); 
902   if (!smatch (&s, n, "public-key"))
903     return gpg_error (GPG_ERR_UNKNOWN_SEXP); 
904   if (*s != '(')
905     return gpg_error (GPG_ERR_UNKNOWN_SEXP);
906   depth++;
907   s++;
908   n = snext (&s); 
909   if (!n)
910     return gpg_error (GPG_ERR_INV_SEXP); 
911   s += n; /* skip over the algorithm name */
912
913   while (*s != ')')
914     {
915       if (*s != '(')
916         return gpg_error (GPG_ERR_INV_SEXP);
917       depth++;
918       s++;
919       n = snext (&s);
920       if (!n) 
921         return gpg_error (GPG_ERR_INV_SEXP); 
922       s += n;
923       n = snext (&s);
924       if (!n)
925         return gpg_error (GPG_ERR_INV_SEXP); 
926       s +=n; /* skip value */
927       if (*s != ')')
928         return gpg_error (GPG_ERR_INV_SEXP); 
929       depth--;
930       s++;
931     }
932   point = s; /* insert right before the point */
933   depth--;
934   s++;
935   assert (depth == 1);
936
937   /* Calculate required length by taking in account: the "shadowed-"
938      prefix, the "shadowed", "t1-v1" as well as some parenthesis */
939   n = 12 + pubkey_len + 1 + 3+8 + 2+5 + shadow_info_len + 1;
940   *result = xtrymalloc (n);
941   p = (char*)*result;
942   if (!p)
943       return out_of_core ();
944   p = stpcpy (p, "(20:shadowed-private-key");
945   /* (10:public-key ...)*/
946   memcpy (p, pubkey+14, point - (pubkey+14));
947   p += point - (pubkey+14);
948   p = stpcpy (p, "(8:shadowed5:t1-v1");
949   memcpy (p, shadow_info, shadow_info_len);
950   p += shadow_info_len;
951   *p++ = ')';
952   memcpy (p, point, pubkey_len - (point - pubkey));
953   p += pubkey_len - (point - pubkey);
954
955   return 0;
956 }
957
958 /* Parse a canonical encoded shadowed key and return a pointer to the
959    inner list with the shadow_info */
960 int 
961 agent_get_shadow_info (const unsigned char *shadowkey,
962                        unsigned char const **shadow_info)
963 {
964   const unsigned char *s;
965   size_t n;
966   int depth = 0;
967
968   s = shadowkey;
969   if (*s != '(')
970     return gpg_error (GPG_ERR_INV_SEXP);
971   depth++;
972   s++;
973   n = snext (&s);
974   if (!n)
975     return gpg_error (GPG_ERR_INV_SEXP); 
976   if (!smatch (&s, n, "shadowed-private-key"))
977     return gpg_error (GPG_ERR_UNKNOWN_SEXP); 
978   if (*s != '(')
979     return gpg_error (GPG_ERR_UNKNOWN_SEXP);
980   depth++;
981   s++;
982   n = snext (&s); 
983   if (!n)
984     return gpg_error (GPG_ERR_INV_SEXP); 
985   s += n; /* skip over the algorithm name */
986
987   for (;;)
988     {
989       if (*s == ')')
990         return gpg_error (GPG_ERR_UNKNOWN_SEXP);
991       if (*s != '(')
992         return gpg_error (GPG_ERR_INV_SEXP);
993       depth++;
994       s++;
995       n = snext (&s);
996       if (!n) 
997         return gpg_error (GPG_ERR_INV_SEXP); 
998       if (smatch (&s, n, "shadowed"))
999         break;
1000       s += n;
1001       n = snext (&s);
1002       if (!n)
1003         return gpg_error (GPG_ERR_INV_SEXP); 
1004       s +=n; /* skip value */
1005       if (*s != ')')
1006         return gpg_error (GPG_ERR_INV_SEXP); 
1007       depth--;
1008       s++;
1009     }
1010   /* Found the shadowed list, S points to the protocol */
1011   n = snext (&s);
1012   if (!n) 
1013     return gpg_error (GPG_ERR_INV_SEXP); 
1014   if (smatch (&s, n, "t1-v1"))
1015     {
1016       if (*s != '(')
1017         return gpg_error (GPG_ERR_INV_SEXP);
1018       *shadow_info = s;
1019     }
1020   else
1021     return gpg_error (GPG_ERR_UNSUPPORTED_PROTOCOL);
1022   return 0;
1023 }
1024