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