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