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