2006-06-09 Marcus Brinkmann <marcus@g10code.de>
[gnupg.git] / agent / protect.c
blob45bdae496ca17b04053ae93ef27bba24de280edd
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 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)
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 return 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 unsigned 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 unsigned char *iv = NULL;
145 int rc;
146 char *outbuf = NULL;
147 char *p;
148 int saltpos, ivpos, encpos;
150 *resultlen = 0;
151 *result = NULL;
153 rc = gcry_cipher_open (&hd, PROT_CIPHER, GCRY_CIPHER_MODE_CBC,
154 GCRY_CIPHER_SECURE);
155 if (rc)
156 return rc;
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:
164 ((<parameter_list>)(4:hash4:sha120:<hashvalue>)) + padding
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)
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);
183 if (!rc)
185 unsigned char *key;
186 size_t keylen = PROT_CIPHER_KEYLEN;
188 key = gcry_malloc_secure (keylen);
189 if (!key)
190 rc = out_of_core ();
191 else
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);
200 if (!rc)
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);
218 gcry_cipher_close (hd);
219 if (rc)
221 xfree (iv);
222 xfree (outbuf);
223 return rc;
226 /* Now allocate the buffer we want to return. This is
228 (protected openpgp-s2k3-sha1-aes-cbc
229 ((sha1 salt no_of_iterations) 16byte_iv)
230 encrypted_octet_string)
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);
248 if (!p)
250 gpg_error_t tmperr = out_of_core ();
251 xfree (iv);
252 xfree (outbuf);
253 return tmperr;
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;
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)
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;
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);
304 for (infidx=0; protect_info[infidx].algo
305 && !smatch (&s, n, protect_info[infidx].algo); infidx++)
307 if (!protect_info[infidx].algo)
308 return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
310 prot_begin = prot_end = NULL;
311 for (i=0; (c=protect_info[infidx].parmlist[i]); i++)
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++;
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;
349 gcry_md_hash_buffer (GCRY_MD_SHA1, hashvalue,
350 hash_begin, hash_end - hash_begin + 1);
352 rc = do_encryption (prot_begin, prot_end - prot_begin + 1,
353 passphrase, hashvalue,
354 &protected, &protectedlen);
355 if (rc)
356 return rc;
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)
368 gpg_error_t tmperr = out_of_core ();
369 xfree (protected);
370 return tmperr;
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;
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)
394 int rc = 0;
395 int blklen;
396 gcry_cipher_hd_t hd;
397 unsigned char *outbuf;
398 size_t reallen;
400 blklen = gcry_cipher_get_algo_blklen (PROT_CIPHER);
401 if (protectedlen < 4 || (protectedlen%blklen))
402 return gpg_error (GPG_ERR_CORRUPTED_PROTECTION);
404 rc = gcry_cipher_open (&hd, PROT_CIPHER, GCRY_CIPHER_MODE_CBC,
405 GCRY_CIPHER_SECURE);
406 if (rc)
407 return rc;
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)
416 unsigned char *key;
417 size_t keylen = PROT_CIPHER_KEYLEN;
419 key = gcry_malloc_secure (keylen);
420 if (!key)
421 rc = out_of_core ();
422 else
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);
431 if (!rc)
432 rc = gcry_cipher_decrypt (hd, outbuf, protectedlen,
433 protected, protectedlen);
434 gcry_cipher_close (hd);
435 if (rc)
437 xfree (outbuf);
438 return rc;
440 /* Do a quick check first. */
441 if (*outbuf != '(' && outbuf[1] != '(')
443 xfree (outbuf);
444 return gpg_error (GPG_ERR_BAD_PASSPHRASE);
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) )
450 xfree (outbuf);
451 return gpg_error (GPG_ERR_BAD_PASSPHRASE);
453 *result = outbuf;
454 return 0;
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)
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;
475 *result = NULL;
476 *resultlen = 0;
478 if (replacepos < 26)
479 return gpg_error (GPG_ERR_BUG);
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 ();
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;
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 == '(' )
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++;
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 */
545 /* append the parameter list */
546 memcpy (p, startpos, endpos - startpos);
547 p += endpos - startpos;
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 */
565 /* append the rest */
566 memcpy (p, startpos, endpos - startpos);
567 p += endpos - startpos;
569 /* ready */
570 *result = newlist;
571 *resultlen = newlistlen;
572 return 0;
574 failure:
575 wipememory (newlist, newlistlen);
576 xfree (newlist);
577 return rc;
579 invalid_sexp:
580 wipememory (newlist, newlistlen);
581 xfree (newlist);
582 return gpg_error (GPG_ERR_INV_SEXP);
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)
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;
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);
622 for (infidx=0; protect_info[infidx].algo
623 && !smatch (&s, n, protect_info[infidx].algo); infidx++)
625 if (!protect_info[infidx].algo)
626 return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
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>)
634 for (;;)
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;
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 */
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);
696 rc = do_decryption (s, n,
697 passphrase, s2ksalt, s2kcount,
698 iv, 16,
699 &cleartext);
700 if (rc)
701 return rc;
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;
713 rc = calculate_mic (final, sha1hash2);
714 if (!rc && memcmp (sha1hash, sha1hash2, 20))
715 rc = gpg_error (GPG_ERR_CORRUPTED_PROTECTION);
716 if (rc)
718 wipememory (final, finallen);
719 xfree (final);
720 return rc;
723 *result = final;
724 *resultlen = gcry_sexp_canon_len (final, 0, NULL, NULL);
725 return 0;
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. */
735 agent_private_key_type (const unsigned char *privatekey)
737 const unsigned char *s;
738 size_t n;
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;
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).
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)
772 int rc;
773 gcry_md_hd_t md;
774 int pass, i;
775 int used = 0;
776 int pwlen = strlen (passphrase);
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);
784 rc = gcry_md_open (&md, hashalgo, GCRY_MD_FLAG_SECURE);
785 if (rc)
786 return rc;
788 for (pass=0; used < keylen; pass++)
790 if (pass)
792 gcry_md_reset (md);
793 for (i=0; i < pass; i++) /* preset the hash context */
794 gcry_md_putc (md, 0);
797 if (s2kmode == 1 || s2kmode == 3)
799 int len2 = pwlen + 8;
800 unsigned long count = len2;
802 if (s2kmode == 3)
804 count = (16ul + (s2kcount & 15)) << ((s2kcount >> 4) + 6);
805 if (count < len2)
806 count = len2;
809 while (count > len2)
811 gcry_md_write (md, s2ksalt, 8);
812 gcry_md_write (md, passphrase, pwlen);
813 count -= len2;
815 if (count < 8)
816 gcry_md_write (md, s2ksalt, count);
817 else
819 gcry_md_write (md, s2ksalt, 8);
820 count -= 8;
821 gcry_md_write (md, passphrase, count);
824 else
825 gcry_md_write (md, passphrase, pwlen);
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;
834 gcry_md_close(md);
835 return 0;
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)
846 const char *s;
847 char *info, *p;
848 char numbuf[21];
849 int n;
851 for (s=serialno, n=0; *s && s[1]; s += 2)
852 n++;
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;
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)
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);
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 */
912 while (*s != ')')
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++;
931 point = s; /* insert right before the point */
932 depth--;
933 s++;
934 assert (depth == 1);
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);
954 return 0;
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)
963 const unsigned char *s;
964 size_t n;
965 int depth = 0;
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 */
986 for (;;)
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++;
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"))
1015 if (*s != '(')
1016 return gpg_error (GPG_ERR_INV_SEXP);
1017 *shadow_info = s;
1019 else
1020 return gpg_error (GPG_ERR_UNSUPPORTED_PROTOCOL);
1021 return 0;