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