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