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