Line data Source code
1 : /* protect.c - Un/Protect a secret key
2 : * Copyright (C) 1998-2003, 2007, 2009, 2011 Free Software Foundation, Inc.
3 : * Copyright (C) 1998-2003, 2007, 2009, 2011, 2013-2015 Werner Koch
4 : *
5 : * This file is part of GnuPG.
6 : *
7 : * GnuPG is free software; you can redistribute it and/or modify
8 : * it under the terms of the GNU General Public License as published by
9 : * the Free Software Foundation; either version 3 of the License, or
10 : * (at your option) any later version.
11 : *
12 : * GnuPG is distributed in the hope that it will be useful,
13 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : * GNU General Public License for more details.
16 : *
17 : * You should have received a copy of the GNU General Public License
18 : * along with this program; if not, see <http://www.gnu.org/licenses/>.
19 : */
20 :
21 : #include <config.h>
22 : #include <errno.h>
23 : #include <stdio.h>
24 : #include <stdlib.h>
25 : #include <string.h>
26 : #include <ctype.h>
27 : #include <assert.h>
28 : #include <unistd.h>
29 : #include <sys/stat.h>
30 : #ifdef HAVE_W32_SYSTEM
31 : # ifdef HAVE_WINSOCK2_H
32 : # include <winsock2.h>
33 : # endif
34 : # include <windows.h>
35 : #else
36 : # include <sys/times.h>
37 : #endif
38 :
39 : #include "agent.h"
40 :
41 : #include "cvt-openpgp.h"
42 : #include "sexp-parse.h"
43 :
44 : /* The protection mode for encryption. The supported modes for
45 : decryption are listed in agent_unprotect(). */
46 : #define PROT_CIPHER GCRY_CIPHER_AES128
47 : #define PROT_CIPHER_STRING "aes"
48 : #define PROT_CIPHER_KEYLEN (128/8)
49 :
50 : /* Decode an rfc4880 encoded S2K count. */
51 : #define S2K_DECODE_COUNT(_val) ((16ul + ((_val) & 15)) << (((_val) >> 4) + 6))
52 :
53 :
54 : /* A table containing the information needed to create a protected
55 : private key. */
56 : static struct {
57 : const char *algo;
58 : const char *parmlist;
59 : int prot_from, prot_to;
60 : int ecc_hack;
61 : } protect_info[] = {
62 : { "rsa", "nedpqu", 2, 5 },
63 : { "dsa", "pqgyx", 4, 4 },
64 : { "elg", "pgyx", 3, 3 },
65 : { "ecdsa","pabgnqd", 6, 6, 1 },
66 : { "ecdh", "pabgnqd", 6, 6, 1 },
67 : { "ecc", "pabgnqd", 6, 6, 1 },
68 : { NULL }
69 : };
70 :
71 :
72 : /* A helper object for time measurement. */
73 : struct calibrate_time_s
74 : {
75 : #ifdef HAVE_W32_SYSTEM
76 : FILETIME creation_time, exit_time, kernel_time, user_time;
77 : #else
78 : clock_t ticks;
79 : #endif
80 : };
81 :
82 :
83 : static int
84 : hash_passphrase (const char *passphrase, int hashalgo,
85 : int s2kmode,
86 : const unsigned char *s2ksalt, unsigned long s2kcount,
87 : unsigned char *key, size_t keylen);
88 :
89 :
90 :
91 : /* Get the process time and store it in DATA. */
92 : static void
93 40 : calibrate_get_time (struct calibrate_time_s *data)
94 : {
95 : #ifdef HAVE_W32_SYSTEM
96 : # ifdef HAVE_W32CE_SYSTEM
97 : GetThreadTimes (GetCurrentThread (),
98 : # else
99 : GetProcessTimes (GetCurrentProcess (),
100 : # endif
101 : &data->creation_time, &data->exit_time,
102 : &data->kernel_time, &data->user_time);
103 : #else
104 : struct tms tmp;
105 :
106 40 : times (&tmp);
107 40 : data->ticks = tmp.tms_utime;
108 : #endif
109 40 : }
110 :
111 :
112 : static unsigned long
113 20 : calibrate_elapsed_time (struct calibrate_time_s *starttime)
114 : {
115 : struct calibrate_time_s stoptime;
116 :
117 20 : calibrate_get_time (&stoptime);
118 : #ifdef HAVE_W32_SYSTEM
119 : {
120 : unsigned long long t1, t2;
121 :
122 : t1 = (((unsigned long long)starttime->kernel_time.dwHighDateTime << 32)
123 : + starttime->kernel_time.dwLowDateTime);
124 : t1 += (((unsigned long long)starttime->user_time.dwHighDateTime << 32)
125 : + starttime->user_time.dwLowDateTime);
126 : t2 = (((unsigned long long)stoptime.kernel_time.dwHighDateTime << 32)
127 : + stoptime.kernel_time.dwLowDateTime);
128 : t2 += (((unsigned long long)stoptime.user_time.dwHighDateTime << 32)
129 : + stoptime.user_time.dwLowDateTime);
130 : return (unsigned long)((t2 - t1)/10000);
131 : }
132 : #else
133 40 : return (unsigned long)((((double) (stoptime.ticks - starttime->ticks))
134 20 : /CLOCKS_PER_SEC)*10000000);
135 : #endif
136 : }
137 :
138 :
139 : /* Run a test hashing for COUNT and return the time required in
140 : milliseconds. */
141 : static unsigned long
142 20 : calibrate_s2k_count_one (unsigned long count)
143 : {
144 : int rc;
145 : char keybuf[PROT_CIPHER_KEYLEN];
146 : struct calibrate_time_s starttime;
147 :
148 20 : calibrate_get_time (&starttime);
149 20 : rc = hash_passphrase ("123456789abcdef0", GCRY_MD_SHA1,
150 : 3, "saltsalt", count, keybuf, sizeof keybuf);
151 20 : if (rc)
152 0 : BUG ();
153 20 : return calibrate_elapsed_time (&starttime);
154 : }
155 :
156 :
157 : /* Measure the time we need to do the hash operations and deduce an
158 : S2K count which requires about 100ms of time. */
159 : static unsigned long
160 2 : calibrate_s2k_count (void)
161 : {
162 : unsigned long count;
163 : unsigned long ms;
164 :
165 20 : for (count = 65536; count; count *= 2)
166 : {
167 20 : ms = calibrate_s2k_count_one (count);
168 20 : if (opt.verbose > 1)
169 0 : log_info ("S2K calibration: %lu -> %lums\n", count, ms);
170 20 : if (ms > 100)
171 2 : break;
172 : }
173 :
174 2 : count = (unsigned long)(((double)count / ms) * 100);
175 2 : count /= 1024;
176 2 : count *= 1024;
177 2 : if (count < 65536)
178 0 : count = 65536;
179 :
180 2 : if (opt.verbose)
181 : {
182 0 : ms = calibrate_s2k_count_one (count);
183 0 : log_info ("S2K calibration: %lu -> %lums\n", count, ms);
184 : }
185 :
186 2 : return count;
187 : }
188 :
189 :
190 :
191 : /* Return the standard S2K count. */
192 : unsigned long
193 16 : get_standard_s2k_count (void)
194 : {
195 : static unsigned long count;
196 :
197 16 : if (!count)
198 2 : count = calibrate_s2k_count ();
199 :
200 : /* Enforce a lower limit. */
201 16 : return count < 65536 ? 65536 : count;
202 : }
203 :
204 :
205 : /* Same as get_standard_s2k_count but return the count in the encoding
206 : as described by rfc4880. */
207 : unsigned char
208 0 : get_standard_s2k_count_rfc4880 (void)
209 : {
210 : unsigned long iterations;
211 : unsigned int count;
212 : unsigned char result;
213 0 : unsigned char c=0;
214 :
215 0 : iterations = get_standard_s2k_count ();
216 0 : if (iterations >= 65011712)
217 0 : return 255;
218 :
219 : /* Need count to be in the range 16-31 */
220 0 : for (count=iterations>>6; count>=32; count>>=1)
221 0 : c++;
222 :
223 0 : result = (c<<4)|(count-16);
224 :
225 0 : if (S2K_DECODE_COUNT(result) < iterations)
226 0 : result++;
227 :
228 0 : return result;
229 :
230 : }
231 :
232 :
233 :
234 : /* Calculate the MIC for a private key or shared secret S-expression.
235 : SHA1HASH should point to a 20 byte buffer. This function is
236 : suitable for all algorithms. */
237 : static int
238 114 : calculate_mic (const unsigned char *plainkey, unsigned char *sha1hash)
239 : {
240 : const unsigned char *hash_begin, *hash_end;
241 : const unsigned char *s;
242 : size_t n;
243 : int is_shared_secret;
244 :
245 114 : s = plainkey;
246 114 : if (*s != '(')
247 0 : return gpg_error (GPG_ERR_INV_SEXP);
248 114 : s++;
249 114 : n = snext (&s);
250 114 : if (!n)
251 0 : return gpg_error (GPG_ERR_INV_SEXP);
252 114 : if (smatch (&s, n, "private-key"))
253 114 : is_shared_secret = 0;
254 0 : else if (smatch (&s, n, "shared-secret"))
255 0 : is_shared_secret = 1;
256 : else
257 0 : return gpg_error (GPG_ERR_UNKNOWN_SEXP);
258 114 : if (*s != '(')
259 0 : return gpg_error (GPG_ERR_UNKNOWN_SEXP);
260 114 : hash_begin = s;
261 114 : if (!is_shared_secret)
262 : {
263 114 : s++;
264 114 : n = snext (&s);
265 114 : if (!n)
266 0 : return gpg_error (GPG_ERR_INV_SEXP);
267 114 : s += n; /* Skip the algorithm name. */
268 : }
269 :
270 829 : while (*s == '(')
271 : {
272 601 : s++;
273 601 : n = snext (&s);
274 601 : if (!n)
275 0 : return gpg_error (GPG_ERR_INV_SEXP);
276 601 : s += n;
277 601 : n = snext (&s);
278 601 : if (!n)
279 0 : return gpg_error (GPG_ERR_INV_SEXP);
280 601 : s += n;
281 601 : if ( *s != ')' )
282 0 : return gpg_error (GPG_ERR_INV_SEXP);
283 601 : s++;
284 : }
285 114 : if (*s != ')')
286 0 : return gpg_error (GPG_ERR_INV_SEXP);
287 114 : s++;
288 114 : hash_end = s;
289 :
290 114 : gcry_md_hash_buffer (GCRY_MD_SHA1, sha1hash,
291 114 : hash_begin, hash_end - hash_begin);
292 :
293 114 : return 0;
294 : }
295 :
296 :
297 :
298 : /* Encrypt the parameter block starting at PROTBEGIN with length
299 : PROTLEN using the utf8 encoded key PASSPHRASE and return the entire
300 : encrypted block in RESULT or return with an error code. SHA1HASH
301 : is the 20 byte SHA-1 hash required for the integrity code.
302 :
303 : The parameter block is expected to be an incomplete S-Expression of
304 : the form (example in advanced format):
305 :
306 : (d #046129F..[some bytes not shown]..81#)
307 : (p #00e861b..[some bytes not shown]..f1#)
308 : (q #00f7a7c..[some bytes not shown]..61#)
309 : (u #304559a..[some bytes not shown]..9b#)
310 :
311 : the returned block is the S-Expression:
312 :
313 : (protected mode (parms) encrypted_octet_string)
314 :
315 : */
316 : static int
317 8 : do_encryption (const unsigned char *protbegin, size_t protlen,
318 : const char *passphrase, const unsigned char *sha1hash,
319 : unsigned char **result, size_t *resultlen,
320 : unsigned long s2k_count)
321 : {
322 : gcry_cipher_hd_t hd;
323 8 : const char *modestr = "openpgp-s2k3-sha1-" PROT_CIPHER_STRING "-cbc";
324 : int blklen, enclen, outlen;
325 8 : unsigned char *iv = NULL;
326 : int rc;
327 8 : char *outbuf = NULL;
328 : char *p;
329 : int saltpos, ivpos, encpos;
330 :
331 8 : *resultlen = 0;
332 8 : *result = NULL;
333 :
334 8 : rc = gcry_cipher_open (&hd, PROT_CIPHER, GCRY_CIPHER_MODE_CBC,
335 : GCRY_CIPHER_SECURE);
336 8 : if (rc)
337 0 : return rc;
338 :
339 :
340 : /* We need to work on a copy of the data because this makes it
341 : easier to add the trailer and the padding and more important we
342 : have to prefix the text with 2 parenthesis, so we have to
343 : allocate enough space for:
344 :
345 : ((<parameter_list>)(4:hash4:sha120:<hashvalue>)) + padding
346 :
347 : We always append a full block of random bytes as padding but
348 : encrypt only what is needed for a full blocksize. */
349 8 : blklen = gcry_cipher_get_algo_blklen (PROT_CIPHER);
350 8 : outlen = 2 + protlen + 2 + 6 + 6 + 23 + 2 + blklen;
351 8 : enclen = outlen/blklen * blklen;
352 8 : outbuf = gcry_malloc_secure (outlen);
353 8 : if (!outbuf)
354 0 : rc = out_of_core ();
355 8 : if (!rc)
356 : {
357 : /* Allocate random bytes to be used as IV, padding and s2k salt. */
358 8 : iv = xtrymalloc (blklen*2+8);
359 8 : if (!iv)
360 0 : rc = gpg_error (GPG_ERR_ENOMEM);
361 : else
362 : {
363 8 : gcry_create_nonce (iv, blklen*2+8);
364 8 : rc = gcry_cipher_setiv (hd, iv, blklen);
365 : }
366 : }
367 8 : if (!rc)
368 : {
369 : unsigned char *key;
370 8 : size_t keylen = PROT_CIPHER_KEYLEN;
371 :
372 8 : key = gcry_malloc_secure (keylen);
373 8 : if (!key)
374 0 : rc = out_of_core ();
375 : else
376 : {
377 16 : rc = hash_passphrase (passphrase, GCRY_MD_SHA1,
378 8 : 3, iv+2*blklen,
379 : s2k_count ? s2k_count : get_standard_s2k_count(),
380 : key, keylen);
381 8 : if (!rc)
382 8 : rc = gcry_cipher_setkey (hd, key, keylen);
383 8 : xfree (key);
384 : }
385 : }
386 8 : if (!rc)
387 : {
388 8 : p = outbuf;
389 8 : *p++ = '(';
390 8 : *p++ = '(';
391 8 : memcpy (p, protbegin, protlen);
392 8 : p += protlen;
393 8 : memcpy (p, ")(4:hash4:sha120:", 17);
394 8 : p += 17;
395 8 : memcpy (p, sha1hash, 20);
396 8 : p += 20;
397 8 : *p++ = ')';
398 8 : *p++ = ')';
399 8 : memcpy (p, iv+blklen, blklen);
400 8 : p += blklen;
401 8 : assert ( p - outbuf == outlen);
402 8 : rc = gcry_cipher_encrypt (hd, outbuf, enclen, NULL, 0);
403 : }
404 8 : gcry_cipher_close (hd);
405 8 : if (rc)
406 : {
407 0 : xfree (iv);
408 0 : xfree (outbuf);
409 0 : return rc;
410 : }
411 :
412 : /* Now allocate the buffer we want to return. This is
413 :
414 : (protected openpgp-s2k3-sha1-aes-cbc
415 : ((sha1 salt no_of_iterations) 16byte_iv)
416 : encrypted_octet_string)
417 :
418 : in canoncical format of course. We use asprintf and %n modifier
419 : and dummy values as placeholders. */
420 : {
421 : char countbuf[35];
422 :
423 8 : snprintf (countbuf, sizeof countbuf, "%lu",
424 : s2k_count ? s2k_count : get_standard_s2k_count ());
425 16 : p = xtryasprintf
426 : ("(9:protected%d:%s((4:sha18:%n_8bytes_%u:%s)%d:%n%*s)%d:%n%*s)",
427 8 : (int)strlen (modestr), modestr,
428 : &saltpos,
429 8 : (unsigned int)strlen (countbuf), countbuf,
430 : blklen, &ivpos, blklen, "",
431 : enclen, &encpos, enclen, "");
432 8 : if (!p)
433 : {
434 0 : gpg_error_t tmperr = out_of_core ();
435 0 : xfree (iv);
436 0 : xfree (outbuf);
437 0 : return tmperr;
438 : }
439 : }
440 8 : *resultlen = strlen (p);
441 8 : *result = (unsigned char*)p;
442 8 : memcpy (p+saltpos, iv+2*blklen, 8);
443 8 : memcpy (p+ivpos, iv, blklen);
444 8 : memcpy (p+encpos, outbuf, enclen);
445 8 : xfree (iv);
446 8 : xfree (outbuf);
447 8 : return 0;
448 : }
449 :
450 :
451 :
452 : /* Protect the key encoded in canonical format in PLAINKEY. We assume
453 : a valid S-Exp here. */
454 : int
455 11 : agent_protect (const unsigned char *plainkey, const char *passphrase,
456 : unsigned char **result, size_t *resultlen,
457 : unsigned long s2k_count)
458 : {
459 : int rc;
460 : const char *parmlist;
461 : int prot_from_idx, prot_to_idx;
462 : const unsigned char *s;
463 : const unsigned char *hash_begin, *hash_end;
464 : const unsigned char *prot_begin, *prot_end, *real_end;
465 : size_t n;
466 : int c, infidx, i;
467 : unsigned char hashvalue[20];
468 : char timestamp_exp[35];
469 : unsigned char *protected;
470 : size_t protectedlen;
471 11 : int depth = 0;
472 : unsigned char *p;
473 : gcry_md_hd_t md;
474 11 : int have_curve = 0;
475 :
476 : /* Create an S-expression with the protected-at timestamp. */
477 11 : memcpy (timestamp_exp, "(12:protected-at15:", 19);
478 11 : gnupg_get_isotime (timestamp_exp+19);
479 11 : timestamp_exp[19+15] = ')';
480 :
481 : /* Parse original key. */
482 11 : s = plainkey;
483 11 : if (*s != '(')
484 1 : return gpg_error (GPG_ERR_INV_SEXP);
485 10 : depth++;
486 10 : s++;
487 10 : n = snext (&s);
488 10 : if (!n)
489 0 : return gpg_error (GPG_ERR_INV_SEXP);
490 10 : if (!smatch (&s, n, "private-key"))
491 0 : return gpg_error (GPG_ERR_UNKNOWN_SEXP);
492 10 : if (*s != '(')
493 0 : return gpg_error (GPG_ERR_UNKNOWN_SEXP);
494 10 : depth++;
495 10 : hash_begin = s;
496 10 : s++;
497 10 : n = snext (&s);
498 10 : if (!n)
499 0 : return gpg_error (GPG_ERR_INV_SEXP);
500 :
501 53 : for (infidx=0; protect_info[infidx].algo
502 76 : && !smatch (&s, n, protect_info[infidx].algo); infidx++)
503 : ;
504 10 : if (!protect_info[infidx].algo)
505 0 : return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
506 :
507 : /* The parser below is a complete mess: To make it robust for ECC
508 : use we should reorder the s-expression to include only what we
509 : really need and thus guarantee the right order for saving stuff.
510 : This should be done before calling this function and maybe with
511 : the help of the new gcry_sexp_extract_param. */
512 10 : parmlist = protect_info[infidx].parmlist;
513 10 : prot_from_idx = protect_info[infidx].prot_from;
514 10 : prot_to_idx = protect_info[infidx].prot_to;
515 10 : prot_begin = prot_end = NULL;
516 44 : for (i=0; (c=parmlist[i]); i++)
517 : {
518 35 : if (i == prot_from_idx)
519 9 : prot_begin = s;
520 35 : if (*s != '(')
521 0 : return gpg_error (GPG_ERR_INV_SEXP);
522 35 : depth++;
523 35 : s++;
524 35 : n = snext (&s);
525 35 : if (!n)
526 0 : return gpg_error (GPG_ERR_INV_SEXP);
527 35 : if (n != 1 || c != *s)
528 : {
529 8 : if (n == 5 && !memcmp (s, "curve", 5)
530 7 : && !i && protect_info[infidx].ecc_hack)
531 : {
532 : /* This is a private ECC key but the first parameter is
533 : the name of the curve. We change the parameter list
534 : here to the one we expect in this case. */
535 7 : have_curve = 1;
536 7 : parmlist = "?qd";
537 7 : prot_from_idx = 2;
538 7 : prot_to_idx = 2;
539 : }
540 1 : else if (n == 5 && !memcmp (s, "flags", 5)
541 0 : && i == 1 && have_curve)
542 : {
543 : /* "curve" followed by "flags": Change again. */
544 0 : parmlist = "??qd";
545 0 : prot_from_idx = 3;
546 0 : prot_to_idx = 3;
547 : }
548 : else
549 1 : return gpg_error (GPG_ERR_INV_SEXP);
550 : }
551 34 : s += n;
552 34 : n = snext (&s);
553 34 : if (!n)
554 0 : return gpg_error (GPG_ERR_INV_SEXP);
555 34 : s +=n; /* skip value */
556 34 : if (*s != ')')
557 0 : return gpg_error (GPG_ERR_INV_SEXP);
558 34 : depth--;
559 34 : if (i == prot_to_idx)
560 9 : prot_end = s;
561 34 : s++;
562 : }
563 9 : if (*s != ')' || !prot_begin || !prot_end )
564 0 : return gpg_error (GPG_ERR_INV_SEXP);
565 9 : depth--;
566 9 : hash_end = s;
567 9 : s++;
568 : /* Skip to the end of the S-expression. */
569 9 : assert (depth == 1);
570 9 : rc = sskip (&s, &depth);
571 9 : if (rc)
572 1 : return rc;
573 8 : assert (!depth);
574 8 : real_end = s-1;
575 :
576 : /* Hash the stuff. Because the timestamp_exp won't get protected,
577 : we can't simply hash a continuous buffer but need to use several
578 : md_writes. */
579 8 : rc = gcry_md_open (&md, GCRY_MD_SHA1, 0 );
580 8 : if (rc)
581 0 : return rc;
582 8 : gcry_md_write (md, hash_begin, hash_end - hash_begin);
583 8 : gcry_md_write (md, timestamp_exp, 35);
584 8 : gcry_md_write (md, ")", 1);
585 8 : memcpy (hashvalue, gcry_md_read (md, GCRY_MD_SHA1), 20);
586 8 : gcry_md_close (md);
587 :
588 8 : rc = do_encryption (prot_begin, prot_end - prot_begin + 1,
589 : passphrase, hashvalue,
590 : &protected, &protectedlen, s2k_count);
591 8 : if (rc)
592 0 : return rc;
593 :
594 : /* Now create the protected version of the key. Note that the 10
595 : extra bytes are for for the inserted "protected-" string (the
596 : beginning of the plaintext reads: "((11:private-key(" ). The 35
597 : term is the space for (12:protected-at15:<timestamp>). */
598 8 : *resultlen = (10
599 8 : + (prot_begin-plainkey)
600 8 : + protectedlen
601 : + 35
602 8 : + (real_end-prot_end));
603 8 : *result = p = xtrymalloc (*resultlen);
604 8 : if (!p)
605 : {
606 0 : gpg_error_t tmperr = out_of_core ();
607 0 : xfree (protected);
608 0 : return tmperr;
609 : }
610 8 : memcpy (p, "(21:protected-", 14);
611 8 : p += 14;
612 8 : memcpy (p, plainkey+4, prot_begin - plainkey - 4);
613 8 : p += prot_begin - plainkey - 4;
614 8 : memcpy (p, protected, protectedlen);
615 8 : p += protectedlen;
616 :
617 8 : memcpy (p, timestamp_exp, 35);
618 8 : p += 35;
619 :
620 8 : memcpy (p, prot_end+1, real_end - prot_end);
621 8 : p += real_end - prot_end;
622 8 : assert ( p - *result == *resultlen);
623 8 : xfree (protected);
624 :
625 8 : return 0;
626 : }
627 :
628 :
629 :
630 : /* Do the actual decryption and check the return list for consistency. */
631 : static int
632 114 : do_decryption (const unsigned char *protected, size_t protectedlen,
633 : const char *passphrase,
634 : const unsigned char *s2ksalt, unsigned long s2kcount,
635 : const unsigned char *iv, size_t ivlen,
636 : int prot_cipher, int prot_cipher_keylen,
637 : unsigned char **result)
638 : {
639 114 : int rc = 0;
640 : int blklen;
641 : gcry_cipher_hd_t hd;
642 : unsigned char *outbuf;
643 : size_t reallen;
644 :
645 114 : blklen = gcry_cipher_get_algo_blklen (prot_cipher);
646 114 : if (protectedlen < 4 || (protectedlen%blklen))
647 0 : return gpg_error (GPG_ERR_CORRUPTED_PROTECTION);
648 :
649 114 : rc = gcry_cipher_open (&hd, prot_cipher, GCRY_CIPHER_MODE_CBC,
650 : GCRY_CIPHER_SECURE);
651 114 : if (rc)
652 0 : return rc;
653 :
654 114 : outbuf = gcry_malloc_secure (protectedlen);
655 114 : if (!outbuf)
656 0 : rc = out_of_core ();
657 114 : if (!rc)
658 114 : rc = gcry_cipher_setiv (hd, iv, ivlen);
659 114 : if (!rc)
660 : {
661 : unsigned char *key;
662 :
663 114 : key = gcry_malloc_secure (prot_cipher_keylen);
664 114 : if (!key)
665 0 : rc = out_of_core ();
666 : else
667 : {
668 114 : rc = hash_passphrase (passphrase, GCRY_MD_SHA1,
669 : 3, s2ksalt, s2kcount, key, prot_cipher_keylen);
670 114 : if (!rc)
671 114 : rc = gcry_cipher_setkey (hd, key, prot_cipher_keylen);
672 114 : xfree (key);
673 : }
674 : }
675 114 : if (!rc)
676 114 : rc = gcry_cipher_decrypt (hd, outbuf, protectedlen,
677 : protected, protectedlen);
678 114 : gcry_cipher_close (hd);
679 114 : if (rc)
680 : {
681 0 : xfree (outbuf);
682 0 : return rc;
683 : }
684 : /* Do a quick check first. */
685 114 : if (*outbuf != '(' && outbuf[1] != '(')
686 : {
687 0 : xfree (outbuf);
688 0 : return gpg_error (GPG_ERR_BAD_PASSPHRASE);
689 : }
690 : /* Check that we have a consistent S-Exp. */
691 114 : reallen = gcry_sexp_canon_len (outbuf, protectedlen, NULL, NULL);
692 114 : if (!reallen || (reallen + blklen < protectedlen) )
693 : {
694 0 : xfree (outbuf);
695 0 : return gpg_error (GPG_ERR_BAD_PASSPHRASE);
696 : }
697 114 : *result = outbuf;
698 114 : return 0;
699 : }
700 :
701 :
702 : /* Merge the parameter list contained in CLEARTEXT with the original
703 : protect lists PROTECTEDKEY by replacing the list at REPLACEPOS.
704 : Return the new list in RESULT and the MIC value in the 20 byte
705 : buffer SHA1HASH. CUTOFF and CUTLEN will receive the offset and the
706 : length of the resulting list which should go into the MIC
707 : calculation but then be removed. */
708 : static int
709 114 : merge_lists (const unsigned char *protectedkey,
710 : size_t replacepos,
711 : const unsigned char *cleartext,
712 : unsigned char *sha1hash,
713 : unsigned char **result, size_t *resultlen,
714 : size_t *cutoff, size_t *cutlen)
715 : {
716 : size_t n, newlistlen;
717 : unsigned char *newlist, *p;
718 : const unsigned char *s;
719 : const unsigned char *startpos, *endpos;
720 : int i, rc;
721 :
722 114 : *result = NULL;
723 114 : *resultlen = 0;
724 114 : *cutoff = 0;
725 114 : *cutlen = 0;
726 :
727 114 : if (replacepos < 26)
728 0 : return gpg_error (GPG_ERR_BUG);
729 :
730 : /* Estimate the required size of the resulting list. We have a large
731 : safety margin of >20 bytes (MIC hash from CLEARTEXT and the
732 : removed "protected-" */
733 114 : newlistlen = gcry_sexp_canon_len (protectedkey, 0, NULL, NULL);
734 114 : if (!newlistlen)
735 0 : return gpg_error (GPG_ERR_BUG);
736 114 : n = gcry_sexp_canon_len (cleartext, 0, NULL, NULL);
737 114 : if (!n)
738 0 : return gpg_error (GPG_ERR_BUG);
739 114 : newlistlen += n;
740 114 : newlist = gcry_malloc_secure (newlistlen);
741 114 : if (!newlist)
742 0 : return out_of_core ();
743 :
744 : /* Copy the initial segment */
745 114 : strcpy ((char*)newlist, "(11:private-key");
746 114 : p = newlist + 15;
747 114 : memcpy (p, protectedkey+15+10, replacepos-15-10);
748 114 : p += replacepos-15-10;
749 :
750 : /* copy the cleartext */
751 114 : s = cleartext;
752 114 : if (*s != '(' && s[1] != '(')
753 0 : return gpg_error (GPG_ERR_BUG); /*we already checked this */
754 114 : s += 2;
755 114 : startpos = s;
756 342 : while ( *s == '(' )
757 : {
758 114 : s++;
759 114 : n = snext (&s);
760 114 : if (!n)
761 0 : goto invalid_sexp;
762 114 : s += n;
763 114 : n = snext (&s);
764 114 : if (!n)
765 0 : goto invalid_sexp;
766 114 : s += n;
767 114 : if ( *s != ')' )
768 0 : goto invalid_sexp;
769 114 : s++;
770 : }
771 114 : if ( *s != ')' )
772 0 : goto invalid_sexp;
773 114 : endpos = s;
774 114 : s++;
775 : /* Intermezzo: Get the MIC */
776 114 : if (*s != '(')
777 0 : goto invalid_sexp;
778 114 : s++;
779 114 : n = snext (&s);
780 114 : if (!smatch (&s, n, "hash"))
781 0 : goto invalid_sexp;
782 114 : n = snext (&s);
783 114 : if (!smatch (&s, n, "sha1"))
784 0 : goto invalid_sexp;
785 114 : n = snext (&s);
786 114 : if (n != 20)
787 0 : goto invalid_sexp;
788 114 : memcpy (sha1hash, s, 20);
789 114 : s += n;
790 114 : if (*s != ')')
791 0 : goto invalid_sexp;
792 : /* End intermezzo */
793 :
794 : /* append the parameter list */
795 114 : memcpy (p, startpos, endpos - startpos);
796 114 : p += endpos - startpos;
797 :
798 : /* Skip over the protected list element in the original list. */
799 114 : s = protectedkey + replacepos;
800 114 : assert (*s == '(');
801 114 : s++;
802 114 : i = 1;
803 114 : rc = sskip (&s, &i);
804 114 : if (rc)
805 0 : goto failure;
806 : /* Record the position of the optional protected-at expression. */
807 114 : if (*s == '(')
808 : {
809 114 : const unsigned char *save_s = s;
810 114 : s++;
811 114 : n = snext (&s);
812 114 : if (smatch (&s, n, "protected-at"))
813 : {
814 114 : i = 1;
815 114 : rc = sskip (&s, &i);
816 114 : if (rc)
817 0 : goto failure;
818 114 : *cutlen = s - save_s;
819 : }
820 114 : s = save_s;
821 : }
822 114 : startpos = s;
823 114 : i = 2; /* we are inside this level */
824 114 : rc = sskip (&s, &i);
825 114 : if (rc)
826 0 : goto failure;
827 114 : assert (s[-1] == ')');
828 114 : endpos = s; /* one behind the end of the list */
829 :
830 : /* Append the rest. */
831 114 : if (*cutlen)
832 114 : *cutoff = p - newlist;
833 114 : memcpy (p, startpos, endpos - startpos);
834 114 : p += endpos - startpos;
835 :
836 :
837 : /* ready */
838 114 : *result = newlist;
839 114 : *resultlen = newlistlen;
840 114 : return 0;
841 :
842 : failure:
843 0 : wipememory (newlist, newlistlen);
844 0 : xfree (newlist);
845 0 : return rc;
846 :
847 : invalid_sexp:
848 0 : wipememory (newlist, newlistlen);
849 0 : xfree (newlist);
850 0 : return gpg_error (GPG_ERR_INV_SEXP);
851 : }
852 :
853 :
854 :
855 : /* Unprotect the key encoded in canonical format. We assume a valid
856 : S-Exp here. If a protected-at item is available, its value will
857 : be stored at protected_at unless this is NULL. */
858 : int
859 120 : agent_unprotect (ctrl_t ctrl,
860 : const unsigned char *protectedkey, const char *passphrase,
861 : gnupg_isotime_t protected_at,
862 : unsigned char **result, size_t *resultlen)
863 : {
864 : static struct {
865 : const char *name; /* Name of the protection method. */
866 : int algo; /* (A zero indicates the "openpgp-native" hack.) */
867 : int keylen; /* Used key length in bytes. */
868 : } algotable[] = {
869 : { "openpgp-s2k3-sha1-aes-cbc", GCRY_CIPHER_AES128, (128/8)},
870 : { "openpgp-s2k3-sha1-aes256-cbc", GCRY_CIPHER_AES256, (256/8)},
871 : { "openpgp-native", 0, 0 }
872 : };
873 : int rc;
874 : const unsigned char *s;
875 : const unsigned char *protect_list;
876 : size_t n;
877 : int infidx, i;
878 : unsigned char sha1hash[20], sha1hash2[20];
879 : const unsigned char *s2ksalt;
880 : unsigned long s2kcount;
881 : const unsigned char *iv;
882 : int prot_cipher, prot_cipher_keylen;
883 : const unsigned char *prot_begin;
884 : unsigned char *cleartext;
885 : unsigned char *final;
886 : size_t finallen;
887 : size_t cutoff, cutlen;
888 :
889 120 : if (protected_at)
890 0 : *protected_at = 0;
891 :
892 120 : s = protectedkey;
893 120 : if (*s != '(')
894 0 : return gpg_error (GPG_ERR_INV_SEXP);
895 120 : s++;
896 120 : n = snext (&s);
897 120 : if (!n)
898 0 : return gpg_error (GPG_ERR_INV_SEXP);
899 120 : if (!smatch (&s, n, "protected-private-key"))
900 0 : return gpg_error (GPG_ERR_UNKNOWN_SEXP);
901 120 : if (*s != '(')
902 0 : return gpg_error (GPG_ERR_UNKNOWN_SEXP);
903 120 : s++;
904 120 : n = snext (&s);
905 120 : if (!n)
906 0 : return gpg_error (GPG_ERR_INV_SEXP);
907 :
908 545 : for (infidx=0; protect_info[infidx].algo
909 730 : && !smatch (&s, n, protect_info[infidx].algo); infidx++)
910 : ;
911 120 : if (!protect_info[infidx].algo)
912 0 : return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
913 :
914 :
915 : /* See wether we have a protected-at timestamp. */
916 120 : protect_list = s; /* Save for later. */
917 120 : if (protected_at)
918 : {
919 0 : while (*s == '(')
920 : {
921 0 : prot_begin = s;
922 0 : s++;
923 0 : n = snext (&s);
924 0 : if (!n)
925 0 : return gpg_error (GPG_ERR_INV_SEXP);
926 0 : if (smatch (&s, n, "protected-at"))
927 : {
928 0 : n = snext (&s);
929 0 : if (!n)
930 0 : return gpg_error (GPG_ERR_INV_SEXP);
931 0 : if (n != 15)
932 0 : return gpg_error (GPG_ERR_UNKNOWN_SEXP);
933 0 : memcpy (protected_at, s, 15);
934 0 : protected_at[15] = 0;
935 0 : break;
936 : }
937 0 : s += n;
938 0 : i = 1;
939 0 : rc = sskip (&s, &i);
940 0 : if (rc)
941 0 : return rc;
942 : }
943 : }
944 :
945 : /* Now find the list with the protected information. Here is an
946 : example for such a list:
947 : (protected openpgp-s2k3-sha1-aes-cbc
948 : ((sha1 <salt> <count>) <Initialization_Vector>)
949 : <encrypted_data>)
950 : */
951 120 : s = protect_list;
952 : for (;;)
953 : {
954 505 : if (*s != '(')
955 0 : return gpg_error (GPG_ERR_INV_SEXP);
956 505 : prot_begin = s;
957 505 : s++;
958 505 : n = snext (&s);
959 505 : if (!n)
960 0 : return gpg_error (GPG_ERR_INV_SEXP);
961 505 : if (smatch (&s, n, "protected"))
962 120 : break;
963 385 : s += n;
964 385 : i = 1;
965 385 : rc = sskip (&s, &i);
966 385 : if (rc)
967 0 : return rc;
968 385 : }
969 : /* found */
970 120 : n = snext (&s);
971 120 : if (!n)
972 0 : return gpg_error (GPG_ERR_INV_SEXP);
973 :
974 : /* Lookup the protection algo. */
975 120 : prot_cipher = 0; /* (avoid gcc warning) */
976 120 : prot_cipher_keylen = 0; /* (avoid gcc warning) */
977 132 : for (i= 0; i < DIM (algotable); i++)
978 132 : if (smatch (&s, n, algotable[i].name))
979 : {
980 120 : prot_cipher = algotable[i].algo;
981 120 : prot_cipher_keylen = algotable[i].keylen;
982 120 : break;
983 : }
984 120 : if (i == DIM (algotable))
985 0 : return gpg_error (GPG_ERR_UNSUPPORTED_PROTECTION);
986 :
987 120 : if (!prot_cipher) /* This is "openpgp-native". */
988 : {
989 : gcry_sexp_t s_prot_begin;
990 :
991 6 : rc = gcry_sexp_sscan (&s_prot_begin, NULL,
992 : prot_begin,
993 : gcry_sexp_canon_len (prot_begin, 0,NULL,NULL));
994 6 : if (rc)
995 0 : return rc;
996 :
997 6 : rc = convert_from_openpgp_native (ctrl, s_prot_begin, passphrase, &final);
998 6 : gcry_sexp_release (s_prot_begin);
999 6 : if (!rc)
1000 : {
1001 6 : *result = final;
1002 6 : *resultlen = gcry_sexp_canon_len (final, 0, NULL, NULL);
1003 : }
1004 6 : return rc;
1005 : }
1006 :
1007 114 : if (*s != '(' || s[1] != '(')
1008 0 : return gpg_error (GPG_ERR_INV_SEXP);
1009 114 : s += 2;
1010 114 : n = snext (&s);
1011 114 : if (!n)
1012 0 : return gpg_error (GPG_ERR_INV_SEXP);
1013 114 : if (!smatch (&s, n, "sha1"))
1014 0 : return gpg_error (GPG_ERR_UNSUPPORTED_PROTECTION);
1015 114 : n = snext (&s);
1016 114 : if (n != 8)
1017 0 : return gpg_error (GPG_ERR_CORRUPTED_PROTECTION);
1018 114 : s2ksalt = s;
1019 114 : s += n;
1020 114 : n = snext (&s);
1021 114 : if (!n)
1022 0 : return gpg_error (GPG_ERR_CORRUPTED_PROTECTION);
1023 : /* We expect a list close as next, so we can simply use strtoul()
1024 : here. We might want to check that we only have digits - but this
1025 : is nothing we should worry about */
1026 114 : if (s[n] != ')' )
1027 0 : return gpg_error (GPG_ERR_INV_SEXP);
1028 :
1029 : /* Old versions of gpg-agent used the funny floating point number in
1030 : a byte encoding as specified by OpenPGP. However this is not
1031 : needed and thus we now store it as a plain unsigned integer. We
1032 : can easily distinguish the old format by looking at its value:
1033 : Less than 256 is an old-style encoded number; other values are
1034 : plain integers. In any case we check that they are at least
1035 : 65536 because we never used a lower value in the past and we
1036 : should have a lower limit. */
1037 114 : s2kcount = strtoul ((const char*)s, NULL, 10);
1038 114 : if (!s2kcount)
1039 0 : return gpg_error (GPG_ERR_CORRUPTED_PROTECTION);
1040 114 : if (s2kcount < 256)
1041 0 : s2kcount = (16ul + (s2kcount & 15)) << ((s2kcount >> 4) + 6);
1042 114 : if (s2kcount < 65536)
1043 0 : return gpg_error (GPG_ERR_CORRUPTED_PROTECTION);
1044 :
1045 114 : s += n;
1046 114 : s++; /* skip list end */
1047 :
1048 114 : n = snext (&s);
1049 114 : if (n != 16) /* Wrong blocksize for IV (we support only 128 bit). */
1050 0 : return gpg_error (GPG_ERR_CORRUPTED_PROTECTION);
1051 114 : iv = s;
1052 114 : s += n;
1053 114 : if (*s != ')' )
1054 0 : return gpg_error (GPG_ERR_INV_SEXP);
1055 114 : s++;
1056 114 : n = snext (&s);
1057 114 : if (!n)
1058 0 : return gpg_error (GPG_ERR_INV_SEXP);
1059 :
1060 114 : cleartext = NULL; /* Avoid cc warning. */
1061 114 : rc = do_decryption (s, n,
1062 : passphrase, s2ksalt, s2kcount,
1063 : iv, 16, prot_cipher, prot_cipher_keylen,
1064 : &cleartext);
1065 114 : if (rc)
1066 0 : return rc;
1067 :
1068 114 : rc = merge_lists (protectedkey, prot_begin-protectedkey, cleartext,
1069 : sha1hash, &final, &finallen, &cutoff, &cutlen);
1070 : /* Albeit cleartext has been allocated in secure memory and thus
1071 : xfree will wipe it out, we do an extra wipe just in case
1072 : somethings goes badly wrong. */
1073 114 : wipememory (cleartext, n);
1074 114 : xfree (cleartext);
1075 114 : if (rc)
1076 0 : return rc;
1077 :
1078 114 : rc = calculate_mic (final, sha1hash2);
1079 114 : if (!rc && memcmp (sha1hash, sha1hash2, 20))
1080 0 : rc = gpg_error (GPG_ERR_CORRUPTED_PROTECTION);
1081 114 : if (rc)
1082 : {
1083 0 : wipememory (final, finallen);
1084 0 : xfree (final);
1085 0 : return rc;
1086 : }
1087 : /* Now remove the part which is included in the MIC but should not
1088 : go into the final thing. */
1089 114 : if (cutlen)
1090 : {
1091 114 : memmove (final+cutoff, final+cutoff+cutlen, finallen-cutoff-cutlen);
1092 114 : finallen -= cutlen;
1093 : }
1094 :
1095 114 : *result = final;
1096 114 : *resultlen = gcry_sexp_canon_len (final, 0, NULL, NULL);
1097 114 : return 0;
1098 : }
1099 :
1100 : /* Check the type of the private key, this is one of the constants:
1101 : PRIVATE_KEY_UNKNOWN if we can't figure out the type (this is the
1102 : value 0), PRIVATE_KEY_CLEAR for an unprotected private key.
1103 : PRIVATE_KEY_PROTECTED for an protected private key or
1104 : PRIVATE_KEY_SHADOWED for a sub key where the secret parts are
1105 : stored elsewhere. Finally PRIVATE_KEY_OPENPGP_NONE may be returned
1106 : is the key is still in the openpgp-native format but without
1107 : protection. */
1108 : int
1109 372 : agent_private_key_type (const unsigned char *privatekey)
1110 : {
1111 : const unsigned char *s;
1112 : size_t n;
1113 : int i;
1114 :
1115 372 : s = privatekey;
1116 372 : if (*s != '(')
1117 0 : return PRIVATE_KEY_UNKNOWN;
1118 372 : s++;
1119 372 : n = snext (&s);
1120 372 : if (!n)
1121 0 : return PRIVATE_KEY_UNKNOWN;
1122 372 : if (smatch (&s, n, "protected-private-key"))
1123 : {
1124 : /* We need to check whether this is openpgp-native protected
1125 : with the protection method "none". In that case we return a
1126 : different key type so that the caller knows that there is no
1127 : need to ask for a passphrase. */
1128 120 : if (*s != '(')
1129 0 : return PRIVATE_KEY_PROTECTED; /* Unknown sexp - assume protected. */
1130 120 : s++;
1131 120 : n = snext (&s);
1132 120 : if (!n)
1133 0 : return PRIVATE_KEY_UNKNOWN; /* Invalid sexp. */
1134 120 : s += n; /* Skip over the algo */
1135 :
1136 : /* Find the (protected ...) list. */
1137 : for (;;)
1138 : {
1139 505 : if (*s != '(')
1140 0 : return PRIVATE_KEY_UNKNOWN; /* Invalid sexp. */
1141 505 : s++;
1142 505 : n = snext (&s);
1143 505 : if (!n)
1144 0 : return PRIVATE_KEY_UNKNOWN; /* Invalid sexp. */
1145 505 : if (smatch (&s, n, "protected"))
1146 120 : break;
1147 385 : s += n;
1148 385 : i = 1;
1149 385 : if (sskip (&s, &i))
1150 0 : return PRIVATE_KEY_UNKNOWN; /* Invalid sexp. */
1151 385 : }
1152 : /* Found - Is this openpgp-native? */
1153 120 : n = snext (&s);
1154 120 : if (!n)
1155 0 : return PRIVATE_KEY_UNKNOWN; /* Invalid sexp. */
1156 120 : if (smatch (&s, n, "openpgp-native")) /* Yes. */
1157 : {
1158 6 : if (*s != '(')
1159 0 : return PRIVATE_KEY_UNKNOWN; /* Unknown sexp. */
1160 6 : s++;
1161 6 : n = snext (&s);
1162 6 : if (!n)
1163 0 : return PRIVATE_KEY_UNKNOWN; /* Invalid sexp. */
1164 6 : s += n; /* Skip over "openpgp-private-key". */
1165 : /* Find the (protection ...) list. */
1166 : for (;;)
1167 : {
1168 36 : if (*s != '(')
1169 0 : return PRIVATE_KEY_UNKNOWN; /* Invalid sexp. */
1170 36 : s++;
1171 36 : n = snext (&s);
1172 36 : if (!n)
1173 0 : return PRIVATE_KEY_UNKNOWN; /* Invalid sexp. */
1174 36 : if (smatch (&s, n, "protection"))
1175 6 : break;
1176 30 : s += n;
1177 30 : i = 1;
1178 30 : if (sskip (&s, &i))
1179 0 : return PRIVATE_KEY_UNKNOWN; /* Invalid sexp. */
1180 30 : }
1181 : /* Found - Is the mode "none"? */
1182 6 : n = snext (&s);
1183 6 : if (!n)
1184 0 : return PRIVATE_KEY_UNKNOWN; /* Invalid sexp. */
1185 6 : log_debug ("openpgp-native protection '%.*s'\n", (int)n, s);
1186 6 : if (smatch (&s, n, "none"))
1187 0 : return PRIVATE_KEY_OPENPGP_NONE; /* Yes. */
1188 : }
1189 :
1190 120 : return PRIVATE_KEY_PROTECTED;
1191 : }
1192 252 : if (smatch (&s, n, "shadowed-private-key"))
1193 0 : return PRIVATE_KEY_SHADOWED;
1194 252 : if (smatch (&s, n, "private-key"))
1195 252 : return PRIVATE_KEY_CLEAR;
1196 0 : return PRIVATE_KEY_UNKNOWN;
1197 : }
1198 :
1199 :
1200 :
1201 : /* Transform a passphrase into a suitable key of length KEYLEN and
1202 : store this key in the caller provided buffer KEY. The caller must
1203 : provide an HASHALGO, a valid S2KMODE (see rfc-2440) and depending on
1204 : that mode an S2KSALT of 8 random bytes and an S2KCOUNT.
1205 :
1206 : Returns an error code on failure. */
1207 : static int
1208 148 : hash_passphrase (const char *passphrase, int hashalgo,
1209 : int s2kmode,
1210 : const unsigned char *s2ksalt,
1211 : unsigned long s2kcount,
1212 : unsigned char *key, size_t keylen)
1213 : {
1214 : /* The key derive function does not support a zero length string for
1215 : the passphrase in the S2K modes. Return a better suited error
1216 : code than GPG_ERR_INV_DATA. */
1217 148 : if (!passphrase || !*passphrase)
1218 0 : return gpg_error (GPG_ERR_NO_PASSPHRASE);
1219 148 : return gcry_kdf_derive (passphrase, strlen (passphrase),
1220 : s2kmode == 3? GCRY_KDF_ITERSALTED_S2K :
1221 0 : s2kmode == 1? GCRY_KDF_SALTED_S2K :
1222 0 : s2kmode == 0? GCRY_KDF_SIMPLE_S2K : GCRY_KDF_NONE,
1223 : hashalgo, s2ksalt, 8, s2kcount,
1224 : keylen, key);
1225 : }
1226 :
1227 :
1228 : gpg_error_t
1229 6 : s2k_hash_passphrase (const char *passphrase, int hashalgo,
1230 : int s2kmode,
1231 : const unsigned char *s2ksalt,
1232 : unsigned int s2kcount,
1233 : unsigned char *key, size_t keylen)
1234 : {
1235 6 : return hash_passphrase (passphrase, hashalgo, s2kmode, s2ksalt,
1236 6 : S2K_DECODE_COUNT (s2kcount),
1237 : key, keylen);
1238 : }
1239 :
1240 :
1241 :
1242 :
1243 : /* Create an canonical encoded S-expression with the shadow info from
1244 : a card's SERIALNO and the IDSTRING. */
1245 : unsigned char *
1246 0 : make_shadow_info (const char *serialno, const char *idstring)
1247 : {
1248 : const char *s;
1249 : char *info, *p;
1250 : char numbuf[20];
1251 : size_t n;
1252 :
1253 0 : for (s=serialno, n=0; *s && s[1]; s += 2)
1254 0 : n++;
1255 :
1256 0 : info = p = xtrymalloc (1 + sizeof numbuf + n
1257 : + sizeof numbuf + strlen (idstring) + 1 + 1);
1258 0 : if (!info)
1259 0 : return NULL;
1260 0 : *p++ = '(';
1261 0 : p = stpcpy (p, smklen (numbuf, sizeof numbuf, n, NULL));
1262 0 : for (s=serialno; *s && s[1]; s += 2)
1263 0 : *(unsigned char *)p++ = xtoi_2 (s);
1264 0 : p = stpcpy (p, smklen (numbuf, sizeof numbuf, strlen (idstring), NULL));
1265 0 : p = stpcpy (p, idstring);
1266 0 : *p++ = ')';
1267 0 : *p = 0;
1268 0 : return (unsigned char *)info;
1269 : }
1270 :
1271 :
1272 :
1273 : /* Create a shadow key from a public key. We use the shadow protocol
1274 : "ti-v1" and insert the S-expressionn SHADOW_INFO. The resulting
1275 : S-expression is returned in an allocated buffer RESULT will point
1276 : to. The input parameters are expected to be valid canonicalized
1277 : S-expressions */
1278 : int
1279 0 : agent_shadow_key (const unsigned char *pubkey,
1280 : const unsigned char *shadow_info,
1281 : unsigned char **result)
1282 : {
1283 : const unsigned char *s;
1284 : const unsigned char *point;
1285 : size_t n;
1286 0 : int depth = 0;
1287 : char *p;
1288 0 : size_t pubkey_len = gcry_sexp_canon_len (pubkey, 0, NULL,NULL);
1289 0 : size_t shadow_info_len = gcry_sexp_canon_len (shadow_info, 0, NULL,NULL);
1290 :
1291 0 : if (!pubkey_len || !shadow_info_len)
1292 0 : return gpg_error (GPG_ERR_INV_VALUE);
1293 0 : s = pubkey;
1294 0 : if (*s != '(')
1295 0 : return gpg_error (GPG_ERR_INV_SEXP);
1296 0 : depth++;
1297 0 : s++;
1298 0 : n = snext (&s);
1299 0 : if (!n)
1300 0 : return gpg_error (GPG_ERR_INV_SEXP);
1301 0 : if (!smatch (&s, n, "public-key"))
1302 0 : return gpg_error (GPG_ERR_UNKNOWN_SEXP);
1303 0 : if (*s != '(')
1304 0 : return gpg_error (GPG_ERR_UNKNOWN_SEXP);
1305 0 : depth++;
1306 0 : s++;
1307 0 : n = snext (&s);
1308 0 : if (!n)
1309 0 : return gpg_error (GPG_ERR_INV_SEXP);
1310 0 : s += n; /* skip over the algorithm name */
1311 :
1312 0 : while (*s != ')')
1313 : {
1314 0 : if (*s != '(')
1315 0 : return gpg_error (GPG_ERR_INV_SEXP);
1316 0 : depth++;
1317 0 : s++;
1318 0 : n = snext (&s);
1319 0 : if (!n)
1320 0 : return gpg_error (GPG_ERR_INV_SEXP);
1321 0 : s += n;
1322 0 : n = snext (&s);
1323 0 : if (!n)
1324 0 : return gpg_error (GPG_ERR_INV_SEXP);
1325 0 : s +=n; /* skip value */
1326 0 : if (*s != ')')
1327 0 : return gpg_error (GPG_ERR_INV_SEXP);
1328 0 : depth--;
1329 0 : s++;
1330 : }
1331 0 : point = s; /* insert right before the point */
1332 0 : depth--;
1333 0 : s++;
1334 0 : assert (depth == 1);
1335 :
1336 : /* Calculate required length by taking in account: the "shadowed-"
1337 : prefix, the "shadowed", "t1-v1" as well as some parenthesis */
1338 0 : n = 12 + pubkey_len + 1 + 3+8 + 2+5 + shadow_info_len + 1;
1339 0 : *result = xtrymalloc (n);
1340 0 : p = (char*)*result;
1341 0 : if (!p)
1342 0 : return out_of_core ();
1343 0 : p = stpcpy (p, "(20:shadowed-private-key");
1344 : /* (10:public-key ...)*/
1345 0 : memcpy (p, pubkey+14, point - (pubkey+14));
1346 0 : p += point - (pubkey+14);
1347 0 : p = stpcpy (p, "(8:shadowed5:t1-v1");
1348 0 : memcpy (p, shadow_info, shadow_info_len);
1349 0 : p += shadow_info_len;
1350 0 : *p++ = ')';
1351 0 : memcpy (p, point, pubkey_len - (point - pubkey));
1352 0 : p += pubkey_len - (point - pubkey);
1353 :
1354 0 : return 0;
1355 : }
1356 :
1357 : /* Parse a canonical encoded shadowed key and return a pointer to the
1358 : inner list with the shadow_info */
1359 : int
1360 0 : agent_get_shadow_info (const unsigned char *shadowkey,
1361 : unsigned char const **shadow_info)
1362 : {
1363 : const unsigned char *s;
1364 : size_t n;
1365 0 : int depth = 0;
1366 :
1367 0 : s = shadowkey;
1368 0 : if (*s != '(')
1369 0 : return gpg_error (GPG_ERR_INV_SEXP);
1370 0 : depth++;
1371 0 : s++;
1372 0 : n = snext (&s);
1373 0 : if (!n)
1374 0 : return gpg_error (GPG_ERR_INV_SEXP);
1375 0 : if (!smatch (&s, n, "shadowed-private-key"))
1376 0 : return gpg_error (GPG_ERR_UNKNOWN_SEXP);
1377 0 : if (*s != '(')
1378 0 : return gpg_error (GPG_ERR_UNKNOWN_SEXP);
1379 0 : depth++;
1380 0 : s++;
1381 0 : n = snext (&s);
1382 0 : if (!n)
1383 0 : return gpg_error (GPG_ERR_INV_SEXP);
1384 0 : s += n; /* skip over the algorithm name */
1385 :
1386 : for (;;)
1387 : {
1388 0 : if (*s == ')')
1389 0 : return gpg_error (GPG_ERR_UNKNOWN_SEXP);
1390 0 : if (*s != '(')
1391 0 : return gpg_error (GPG_ERR_INV_SEXP);
1392 0 : depth++;
1393 0 : s++;
1394 0 : n = snext (&s);
1395 0 : if (!n)
1396 0 : return gpg_error (GPG_ERR_INV_SEXP);
1397 0 : if (smatch (&s, n, "shadowed"))
1398 0 : break;
1399 0 : s += n;
1400 0 : n = snext (&s);
1401 0 : if (!n)
1402 0 : return gpg_error (GPG_ERR_INV_SEXP);
1403 0 : s +=n; /* skip value */
1404 0 : if (*s != ')')
1405 0 : return gpg_error (GPG_ERR_INV_SEXP);
1406 0 : depth--;
1407 0 : s++;
1408 0 : }
1409 : /* Found the shadowed list, S points to the protocol */
1410 0 : n = snext (&s);
1411 0 : if (!n)
1412 0 : return gpg_error (GPG_ERR_INV_SEXP);
1413 0 : if (smatch (&s, n, "t1-v1"))
1414 : {
1415 0 : if (*s != '(')
1416 0 : return gpg_error (GPG_ERR_INV_SEXP);
1417 0 : *shadow_info = s;
1418 : }
1419 : else
1420 0 : return gpg_error (GPG_ERR_UNSUPPORTED_PROTOCOL);
1421 0 : return 0;
1422 : }
1423 :
1424 :
1425 : /* Parse the canonical encoded SHADOW_INFO S-expression. On success
1426 : the hex encoded serial number is returned as a malloced strings at
1427 : R_HEXSN and the Id string as a malloced string at R_IDSTR. On
1428 : error an error code is returned and NULL is stored at the result
1429 : parameters addresses. If the serial number or the ID string is not
1430 : required, NULL may be passed for them. */
1431 : gpg_error_t
1432 0 : parse_shadow_info (const unsigned char *shadow_info,
1433 : char **r_hexsn, char **r_idstr, int *r_pinlen)
1434 : {
1435 : const unsigned char *s;
1436 : size_t n;
1437 :
1438 0 : if (r_hexsn)
1439 0 : *r_hexsn = NULL;
1440 0 : if (r_idstr)
1441 0 : *r_idstr = NULL;
1442 0 : if (r_pinlen)
1443 0 : *r_pinlen = 0;
1444 :
1445 0 : s = shadow_info;
1446 0 : if (*s != '(')
1447 0 : return gpg_error (GPG_ERR_INV_SEXP);
1448 0 : s++;
1449 0 : n = snext (&s);
1450 0 : if (!n)
1451 0 : return gpg_error (GPG_ERR_INV_SEXP);
1452 :
1453 0 : if (r_hexsn)
1454 : {
1455 0 : *r_hexsn = bin2hex (s, n, NULL);
1456 0 : if (!*r_hexsn)
1457 0 : return gpg_error_from_syserror ();
1458 : }
1459 0 : s += n;
1460 :
1461 0 : n = snext (&s);
1462 0 : if (!n)
1463 : {
1464 0 : if (r_hexsn)
1465 : {
1466 0 : xfree (*r_hexsn);
1467 0 : *r_hexsn = NULL;
1468 : }
1469 0 : return gpg_error (GPG_ERR_INV_SEXP);
1470 : }
1471 :
1472 0 : if (r_idstr)
1473 : {
1474 0 : *r_idstr = xtrymalloc (n+1);
1475 0 : if (!*r_idstr)
1476 : {
1477 0 : if (r_hexsn)
1478 : {
1479 0 : xfree (*r_hexsn);
1480 0 : *r_hexsn = NULL;
1481 : }
1482 0 : return gpg_error_from_syserror ();
1483 : }
1484 0 : memcpy (*r_idstr, s, n);
1485 0 : (*r_idstr)[n] = 0;
1486 : }
1487 :
1488 : /* Parse the optional PINLEN. */
1489 0 : n = snext (&s);
1490 0 : if (!n)
1491 0 : return 0;
1492 :
1493 0 : if (r_pinlen)
1494 : {
1495 0 : char *tmpstr = xtrymalloc (n+1);
1496 0 : if (!tmpstr)
1497 : {
1498 0 : if (r_hexsn)
1499 : {
1500 0 : xfree (*r_hexsn);
1501 0 : *r_hexsn = NULL;
1502 : }
1503 0 : if (r_idstr)
1504 : {
1505 0 : xfree (*r_idstr);
1506 0 : *r_idstr = NULL;
1507 : }
1508 0 : return gpg_error_from_syserror ();
1509 : }
1510 0 : memcpy (tmpstr, s, n);
1511 0 : tmpstr[n] = 0;
1512 :
1513 0 : *r_pinlen = (int)strtol (tmpstr, NULL, 10);
1514 0 : xfree (tmpstr);
1515 : }
1516 :
1517 0 : return 0;
1518 : }
|