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