Line data Source code
1 : /* protect-tool.c - A tool to test the secret key protection
2 : * Copyright (C) 2002, 2003, 2004, 2006 Free Software Foundation, Inc.
3 : *
4 : * This file is part of GnuPG.
5 : *
6 : * GnuPG is free software; you can redistribute it and/or modify
7 : * it under the terms of the GNU General Public License as published by
8 : * the Free Software Foundation; either version 3 of the License, or
9 : * (at your option) any later version.
10 : *
11 : * GnuPG is distributed in the hope that it will be useful,
12 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : * GNU General Public License for more details.
15 : *
16 : * You should have received a copy of the GNU General Public License
17 : * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 : */
19 :
20 : #include <config.h>
21 :
22 : #include <stdio.h>
23 : #include <stdlib.h>
24 : #include <stddef.h>
25 : #include <stdarg.h>
26 : #include <string.h>
27 : #include <errno.h>
28 : #include <assert.h>
29 : #include <sys/stat.h>
30 : #include <unistd.h>
31 : #ifdef HAVE_LOCALE_H
32 : #include <locale.h>
33 : #endif
34 : #ifdef HAVE_LANGINFO_CODESET
35 : #include <langinfo.h>
36 : #endif
37 : #ifdef HAVE_DOSISH_SYSTEM
38 : #include <fcntl.h> /* for setmode() */
39 : #endif
40 :
41 : #include "agent.h"
42 : #include "i18n.h"
43 : #include "get-passphrase.h"
44 : #include "sysutils.h"
45 : #include "../common/init.h"
46 :
47 :
48 : enum cmd_and_opt_values
49 : {
50 : aNull = 0,
51 : oVerbose = 'v',
52 : oArmor = 'a',
53 : oPassphrase = 'P',
54 :
55 : oProtect = 'p',
56 : oUnprotect = 'u',
57 :
58 : oNoVerbose = 500,
59 : oShadow,
60 : oShowShadowInfo,
61 : oShowKeygrip,
62 : oS2Kcalibration,
63 : oCanonical,
64 :
65 : oStore,
66 : oForce,
67 : oHaveCert,
68 : oNoFailOnExist,
69 : oHomedir,
70 : oPrompt,
71 : oStatusMsg,
72 :
73 : oAgentProgram
74 : };
75 :
76 :
77 : struct rsa_secret_key_s
78 : {
79 : gcry_mpi_t n; /* public modulus */
80 : gcry_mpi_t e; /* public exponent */
81 : gcry_mpi_t d; /* exponent */
82 : gcry_mpi_t p; /* prime p. */
83 : gcry_mpi_t q; /* prime q. */
84 : gcry_mpi_t u; /* inverse of p mod q. */
85 : };
86 :
87 :
88 : static const char *opt_homedir;
89 : static int opt_armor;
90 : static int opt_canonical;
91 : static int opt_store;
92 : static int opt_force;
93 : static int opt_no_fail_on_exist;
94 : static int opt_have_cert;
95 : static const char *opt_passphrase;
96 : static char *opt_prompt;
97 : static int opt_status_msg;
98 : static const char *opt_agent_program;
99 :
100 : static char *get_passphrase (int promptno);
101 : static void release_passphrase (char *pw);
102 :
103 :
104 : static ARGPARSE_OPTS opts[] = {
105 : ARGPARSE_group (300, N_("@Commands:\n ")),
106 :
107 : ARGPARSE_c (oProtect, "protect", "protect a private key"),
108 : ARGPARSE_c (oUnprotect, "unprotect", "unprotect a private key"),
109 : ARGPARSE_c (oShadow, "shadow", "create a shadow entry for a public key"),
110 : ARGPARSE_c (oShowShadowInfo, "show-shadow-info", "return the shadow info"),
111 : ARGPARSE_c (oShowKeygrip, "show-keygrip", "show the \"keygrip\""),
112 : ARGPARSE_c (oS2Kcalibration, "s2k-calibration", "@"),
113 :
114 : ARGPARSE_group (301, N_("@\nOptions:\n ")),
115 :
116 : ARGPARSE_s_n (oVerbose, "verbose", "verbose"),
117 : ARGPARSE_s_n (oArmor, "armor", "write output in advanced format"),
118 : ARGPARSE_s_n (oCanonical, "canonical", "write output in canonical format"),
119 :
120 : ARGPARSE_s_s (oPassphrase, "passphrase", "|STRING|use passphrase STRING"),
121 : ARGPARSE_s_n (oHaveCert, "have-cert",
122 : "certificate to export provided on STDIN"),
123 : ARGPARSE_s_n (oStore, "store",
124 : "store the created key in the appropriate place"),
125 : ARGPARSE_s_n (oForce, "force",
126 : "force overwriting"),
127 : ARGPARSE_s_n (oNoFailOnExist, "no-fail-on-exist", "@"),
128 : ARGPARSE_s_s (oHomedir, "homedir", "@"),
129 : ARGPARSE_s_s (oPrompt, "prompt",
130 : "|ESCSTRING|use ESCSTRING as prompt in pinentry"),
131 : ARGPARSE_s_n (oStatusMsg, "enable-status-msg", "@"),
132 :
133 : ARGPARSE_s_s (oAgentProgram, "agent-program", "@"),
134 :
135 : ARGPARSE_end ()
136 : };
137 :
138 : static const char *
139 0 : my_strusage (int level)
140 : {
141 : const char *p;
142 0 : switch (level)
143 : {
144 0 : case 11: p = "gpg-protect-tool (" GNUPG_NAME ")";
145 0 : break;
146 0 : case 13: p = VERSION; break;
147 0 : case 17: p = PRINTABLE_OS_NAME; break;
148 0 : case 19: p = _("Please report bugs to <@EMAIL@>.\n"); break;
149 :
150 : case 1:
151 0 : case 40: p = _("Usage: gpg-protect-tool [options] (-h for help)\n");
152 0 : break;
153 0 : case 41: p = _("Syntax: gpg-protect-tool [options] [args]\n"
154 : "Secret key maintenance tool\n");
155 0 : break;
156 :
157 0 : default: p = NULL;
158 : }
159 0 : return p;
160 : }
161 :
162 :
163 : /* static void */
164 : /* print_mpi (const char *text, gcry_mpi_t a) */
165 : /* { */
166 : /* char *buf; */
167 : /* void *bufaddr = &buf; */
168 : /* int rc; */
169 :
170 : /* rc = gcry_mpi_aprint (GCRYMPI_FMT_HEX, bufaddr, NULL, a); */
171 : /* if (rc) */
172 : /* log_info ("%s: [error printing number: %s]\n", text, gpg_strerror (rc)); */
173 : /* else */
174 : /* { */
175 : /* log_info ("%s: %s\n", text, buf); */
176 : /* gcry_free (buf); */
177 : /* } */
178 : /* } */
179 :
180 :
181 :
182 : static unsigned char *
183 0 : make_canonical (const char *fname, const char *buf, size_t buflen)
184 : {
185 : int rc;
186 : size_t erroff, len;
187 : gcry_sexp_t sexp;
188 : unsigned char *result;
189 :
190 0 : rc = gcry_sexp_sscan (&sexp, &erroff, buf, buflen);
191 0 : if (rc)
192 : {
193 0 : log_error ("invalid S-Expression in '%s' (off=%u): %s\n",
194 : fname, (unsigned int)erroff, gpg_strerror (rc));
195 0 : return NULL;
196 : }
197 0 : len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_CANON, NULL, 0);
198 0 : assert (len);
199 0 : result = xmalloc (len);
200 0 : len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_CANON, result, len);
201 0 : assert (len);
202 0 : gcry_sexp_release (sexp);
203 0 : return result;
204 : }
205 :
206 : static char *
207 0 : make_advanced (const unsigned char *buf, size_t buflen)
208 : {
209 : int rc;
210 : size_t erroff, len;
211 : gcry_sexp_t sexp;
212 : char *result;
213 :
214 0 : rc = gcry_sexp_sscan (&sexp, &erroff, (const char*)buf, buflen);
215 0 : if (rc)
216 : {
217 0 : log_error ("invalid canonical S-Expression (off=%u): %s\n",
218 : (unsigned int)erroff, gpg_strerror (rc));
219 0 : return NULL;
220 : }
221 0 : len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_ADVANCED, NULL, 0);
222 0 : assert (len);
223 0 : result = xmalloc (len);
224 0 : len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_ADVANCED, result, len);
225 0 : assert (len);
226 0 : gcry_sexp_release (sexp);
227 0 : return result;
228 : }
229 :
230 :
231 : static char *
232 0 : read_file (const char *fname, size_t *r_length)
233 : {
234 : FILE *fp;
235 : char *buf;
236 : size_t buflen;
237 :
238 0 : if (!strcmp (fname, "-"))
239 : {
240 0 : size_t nread, bufsize = 0;
241 :
242 0 : fp = stdin;
243 : #ifdef HAVE_DOSISH_SYSTEM
244 : setmode ( fileno(fp) , O_BINARY );
245 : #endif
246 0 : buf = NULL;
247 0 : buflen = 0;
248 : #define NCHUNK 8192
249 : do
250 : {
251 0 : bufsize += NCHUNK;
252 0 : if (!buf)
253 0 : buf = xmalloc (bufsize);
254 : else
255 0 : buf = xrealloc (buf, bufsize);
256 :
257 0 : nread = fread (buf+buflen, 1, NCHUNK, fp);
258 0 : if (nread < NCHUNK && ferror (fp))
259 : {
260 0 : log_error ("error reading '[stdin]': %s\n", strerror (errno));
261 0 : xfree (buf);
262 0 : return NULL;
263 : }
264 0 : buflen += nread;
265 : }
266 0 : while (nread == NCHUNK);
267 : #undef NCHUNK
268 :
269 : }
270 : else
271 : {
272 : struct stat st;
273 :
274 0 : fp = fopen (fname, "rb");
275 0 : if (!fp)
276 : {
277 0 : log_error ("can't open '%s': %s\n", fname, strerror (errno));
278 0 : return NULL;
279 : }
280 :
281 0 : if (fstat (fileno(fp), &st))
282 : {
283 0 : log_error ("can't stat '%s': %s\n", fname, strerror (errno));
284 0 : fclose (fp);
285 0 : return NULL;
286 : }
287 :
288 0 : buflen = st.st_size;
289 0 : buf = xmalloc (buflen+1);
290 0 : if (fread (buf, buflen, 1, fp) != 1)
291 : {
292 0 : log_error ("error reading '%s': %s\n", fname, strerror (errno));
293 0 : fclose (fp);
294 0 : xfree (buf);
295 0 : return NULL;
296 : }
297 0 : fclose (fp);
298 : }
299 :
300 0 : *r_length = buflen;
301 0 : return buf;
302 : }
303 :
304 :
305 : static unsigned char *
306 0 : read_key (const char *fname)
307 : {
308 : char *buf;
309 : size_t buflen;
310 : unsigned char *key;
311 :
312 0 : buf = read_file (fname, &buflen);
313 0 : if (!buf)
314 0 : return NULL;
315 0 : key = make_canonical (fname, buf, buflen);
316 0 : xfree (buf);
317 0 : return key;
318 : }
319 :
320 :
321 :
322 : static void
323 0 : read_and_protect (const char *fname)
324 : {
325 : int rc;
326 : unsigned char *key;
327 : unsigned char *result;
328 : size_t resultlen;
329 : char *pw;
330 :
331 0 : key = read_key (fname);
332 0 : if (!key)
333 0 : return;
334 :
335 0 : pw = get_passphrase (1);
336 0 : rc = agent_protect (key, pw, &result, &resultlen, 0);
337 0 : release_passphrase (pw);
338 0 : xfree (key);
339 0 : if (rc)
340 : {
341 0 : log_error ("protecting the key failed: %s\n", gpg_strerror (rc));
342 0 : return;
343 : }
344 :
345 0 : if (opt_armor)
346 : {
347 0 : char *p = make_advanced (result, resultlen);
348 0 : xfree (result);
349 0 : if (!p)
350 0 : return;
351 0 : result = (unsigned char*)p;
352 0 : resultlen = strlen (p);
353 : }
354 :
355 0 : fwrite (result, resultlen, 1, stdout);
356 0 : xfree (result);
357 : }
358 :
359 :
360 : static void
361 0 : read_and_unprotect (const char *fname)
362 : {
363 : int rc;
364 : unsigned char *key;
365 : unsigned char *result;
366 : size_t resultlen;
367 : char *pw;
368 : gnupg_isotime_t protected_at;
369 :
370 0 : key = read_key (fname);
371 0 : if (!key)
372 0 : return;
373 :
374 0 : rc = agent_unprotect (NULL, key, (pw=get_passphrase (1)),
375 : protected_at, &result, &resultlen);
376 0 : release_passphrase (pw);
377 0 : xfree (key);
378 0 : if (rc)
379 : {
380 0 : if (opt_status_msg)
381 0 : log_info ("[PROTECT-TOOL:] bad-passphrase\n");
382 0 : log_error ("unprotecting the key failed: %s\n", gpg_strerror (rc));
383 0 : return;
384 : }
385 0 : if (opt.verbose)
386 0 : log_info ("key protection done at %.4s-%.2s-%.2s %.2s:%.2s:%s\n",
387 : protected_at, protected_at+4, protected_at+6,
388 : protected_at+9, protected_at+11, protected_at+13);
389 :
390 :
391 0 : if (opt_armor)
392 : {
393 0 : char *p = make_advanced (result, resultlen);
394 0 : xfree (result);
395 0 : if (!p)
396 0 : return;
397 0 : result = (unsigned char*)p;
398 0 : resultlen = strlen (p);
399 : }
400 :
401 0 : fwrite (result, resultlen, 1, stdout);
402 0 : xfree (result);
403 : }
404 :
405 :
406 :
407 : static void
408 0 : read_and_shadow (const char *fname)
409 : {
410 : int rc;
411 : unsigned char *key;
412 : unsigned char *result;
413 : size_t resultlen;
414 0 : unsigned char dummy_info[] = "(8:313233342:43)";
415 :
416 0 : key = read_key (fname);
417 0 : if (!key)
418 0 : return;
419 :
420 0 : rc = agent_shadow_key (key, dummy_info, &result);
421 0 : xfree (key);
422 0 : if (rc)
423 : {
424 0 : log_error ("shadowing the key failed: %s\n", gpg_strerror (rc));
425 0 : return;
426 : }
427 0 : resultlen = gcry_sexp_canon_len (result, 0, NULL,NULL);
428 0 : assert (resultlen);
429 :
430 0 : if (opt_armor)
431 : {
432 0 : char *p = make_advanced (result, resultlen);
433 0 : xfree (result);
434 0 : if (!p)
435 0 : return;
436 0 : result = (unsigned char*)p;
437 0 : resultlen = strlen (p);
438 : }
439 :
440 0 : fwrite (result, resultlen, 1, stdout);
441 0 : xfree (result);
442 : }
443 :
444 : static void
445 0 : show_shadow_info (const char *fname)
446 : {
447 : int rc;
448 : unsigned char *key;
449 : const unsigned char *info;
450 : size_t infolen;
451 :
452 0 : key = read_key (fname);
453 0 : if (!key)
454 0 : return;
455 :
456 0 : rc = agent_get_shadow_info (key, &info);
457 0 : xfree (key);
458 0 : if (rc)
459 : {
460 0 : log_error ("get_shadow_info failed: %s\n", gpg_strerror (rc));
461 0 : return;
462 : }
463 0 : infolen = gcry_sexp_canon_len (info, 0, NULL,NULL);
464 0 : assert (infolen);
465 :
466 0 : if (opt_armor)
467 : {
468 0 : char *p = make_advanced (info, infolen);
469 0 : if (!p)
470 0 : return;
471 0 : fwrite (p, strlen (p), 1, stdout);
472 0 : xfree (p);
473 : }
474 : else
475 0 : fwrite (info, infolen, 1, stdout);
476 : }
477 :
478 :
479 : static void
480 0 : show_file (const char *fname)
481 : {
482 : unsigned char *key;
483 : size_t keylen;
484 : char *p;
485 :
486 0 : key = read_key (fname);
487 0 : if (!key)
488 0 : return;
489 :
490 0 : keylen = gcry_sexp_canon_len (key, 0, NULL,NULL);
491 0 : assert (keylen);
492 :
493 0 : if (opt_canonical)
494 : {
495 0 : fwrite (key, keylen, 1, stdout);
496 : }
497 : else
498 : {
499 0 : p = make_advanced (key, keylen);
500 0 : if (p)
501 : {
502 0 : fwrite (p, strlen (p), 1, stdout);
503 0 : xfree (p);
504 : }
505 : }
506 0 : xfree (key);
507 : }
508 :
509 : static void
510 0 : show_keygrip (const char *fname)
511 : {
512 : unsigned char *key;
513 : gcry_sexp_t private;
514 : unsigned char grip[20];
515 : int i;
516 :
517 0 : key = read_key (fname);
518 0 : if (!key)
519 0 : return;
520 :
521 0 : if (gcry_sexp_new (&private, key, 0, 0))
522 : {
523 0 : log_error ("gcry_sexp_new failed\n");
524 0 : return;
525 : }
526 0 : xfree (key);
527 :
528 0 : if (!gcry_pk_get_keygrip (private, grip))
529 : {
530 0 : log_error ("can't calculate keygrip\n");
531 0 : return;
532 : }
533 0 : gcry_sexp_release (private);
534 :
535 0 : for (i=0; i < 20; i++)
536 0 : printf ("%02X", grip[i]);
537 0 : putchar ('\n');
538 : }
539 :
540 :
541 :
542 :
543 :
544 : int
545 0 : main (int argc, char **argv )
546 : {
547 : ARGPARSE_ARGS pargs;
548 0 : int cmd = 0;
549 : const char *fname;
550 :
551 0 : early_system_init ();
552 0 : set_strusage (my_strusage);
553 0 : gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
554 0 : log_set_prefix ("gpg-protect-tool", 1);
555 :
556 : /* Make sure that our subsystems are ready. */
557 0 : i18n_init ();
558 0 : init_common_subsystems (&argc, &argv);
559 :
560 0 : if (!gcry_check_version (NEED_LIBGCRYPT_VERSION) )
561 : {
562 0 : log_fatal( _("%s is too old (need %s, have %s)\n"), "libgcrypt",
563 : NEED_LIBGCRYPT_VERSION, gcry_check_version (NULL) );
564 : }
565 :
566 0 : setup_libgcrypt_logging ();
567 0 : gcry_control (GCRYCTL_INIT_SECMEM, 16384, 0);
568 :
569 :
570 0 : opt_homedir = default_homedir ();
571 :
572 :
573 0 : pargs.argc = &argc;
574 0 : pargs.argv = &argv;
575 0 : pargs.flags= 1; /* (do not remove the args) */
576 0 : while (arg_parse (&pargs, opts) )
577 : {
578 0 : switch (pargs.r_opt)
579 : {
580 0 : case oVerbose: opt.verbose++; break;
581 0 : case oArmor: opt_armor=1; break;
582 0 : case oCanonical: opt_canonical=1; break;
583 0 : case oHomedir: opt_homedir = pargs.r.ret_str; break;
584 :
585 0 : case oAgentProgram: opt_agent_program = pargs.r.ret_str; break;
586 :
587 0 : case oProtect: cmd = oProtect; break;
588 0 : case oUnprotect: cmd = oUnprotect; break;
589 0 : case oShadow: cmd = oShadow; break;
590 0 : case oShowShadowInfo: cmd = oShowShadowInfo; break;
591 0 : case oShowKeygrip: cmd = oShowKeygrip; break;
592 0 : case oS2Kcalibration: cmd = oS2Kcalibration; break;
593 :
594 0 : case oPassphrase: opt_passphrase = pargs.r.ret_str; break;
595 0 : case oStore: opt_store = 1; break;
596 0 : case oForce: opt_force = 1; break;
597 0 : case oNoFailOnExist: opt_no_fail_on_exist = 1; break;
598 0 : case oHaveCert: opt_have_cert = 1; break;
599 0 : case oPrompt: opt_prompt = pargs.r.ret_str; break;
600 0 : case oStatusMsg: opt_status_msg = 1; break;
601 :
602 0 : default: pargs.err = ARGPARSE_PRINT_ERROR; break;
603 : }
604 : }
605 0 : if (log_get_errorcount (0))
606 0 : exit (2);
607 :
608 0 : fname = "-";
609 0 : if (argc == 1)
610 0 : fname = *argv;
611 0 : else if (argc > 1)
612 0 : usage (1);
613 :
614 : /* Set the information which can't be taken from envvars. */
615 0 : gnupg_prepare_get_passphrase (GPG_ERR_SOURCE_DEFAULT,
616 : opt.verbose,
617 : opt_homedir,
618 : opt_agent_program,
619 : NULL, NULL, NULL);
620 :
621 0 : if (opt_prompt)
622 0 : opt_prompt = percent_plus_unescape (opt_prompt, 0);
623 :
624 0 : if (cmd == oProtect)
625 0 : read_and_protect (fname);
626 0 : else if (cmd == oUnprotect)
627 0 : read_and_unprotect (fname);
628 0 : else if (cmd == oShadow)
629 0 : read_and_shadow (fname);
630 0 : else if (cmd == oShowShadowInfo)
631 0 : show_shadow_info (fname);
632 0 : else if (cmd == oShowKeygrip)
633 0 : show_keygrip (fname);
634 0 : else if (cmd == oS2Kcalibration)
635 : {
636 0 : if (!opt.verbose)
637 0 : opt.verbose++; /* We need to see something. */
638 0 : get_standard_s2k_count ();
639 : }
640 : else
641 0 : show_file (fname);
642 :
643 0 : agent_exit (0);
644 : return 8; /*NOTREACHED*/
645 : }
646 :
647 : void
648 0 : agent_exit (int rc)
649 : {
650 0 : rc = rc? rc : log_get_errorcount(0)? 2 : 0;
651 0 : exit (rc);
652 : }
653 :
654 :
655 : /* Return the passphrase string and ask the agent if it has not been
656 : set from the command line PROMPTNO select the prompt to display:
657 : 0 = default
658 : 1 = taken from the option --prompt
659 : 2 = for unprotecting a pkcs#12 object
660 : 3 = for protecting a new pkcs#12 object
661 : 4 = for protecting an imported pkcs#12 in our system
662 : */
663 : static char *
664 0 : get_passphrase (int promptno)
665 : {
666 : char *pw;
667 : int err;
668 : const char *desc;
669 : char *orig_codeset;
670 0 : int repeat = 0;
671 :
672 0 : if (opt_passphrase)
673 0 : return xstrdup (opt_passphrase);
674 :
675 0 : orig_codeset = i18n_switchto_utf8 ();
676 :
677 0 : if (promptno == 1 && opt_prompt)
678 : {
679 0 : desc = opt_prompt;
680 : }
681 0 : else if (promptno == 2)
682 : {
683 0 : desc = _("Please enter the passphrase to unprotect the "
684 : "PKCS#12 object.");
685 : }
686 0 : else if (promptno == 3)
687 : {
688 0 : desc = _("Please enter the passphrase to protect the "
689 : "new PKCS#12 object.");
690 0 : repeat = 1;
691 : }
692 0 : else if (promptno == 4)
693 : {
694 0 : desc = _("Please enter the passphrase to protect the "
695 : "imported object within the GnuPG system.");
696 0 : repeat = 1;
697 : }
698 : else
699 0 : desc = _("Please enter the passphrase or the PIN\n"
700 : "needed to complete this operation.");
701 :
702 0 : i18n_switchback (orig_codeset);
703 :
704 0 : err = gnupg_get_passphrase (NULL, NULL, _("Passphrase:"), desc,
705 : repeat, repeat, 1, &pw);
706 0 : if (err)
707 : {
708 0 : if (gpg_err_code (err) == GPG_ERR_CANCELED
709 0 : || gpg_err_code (err) == GPG_ERR_FULLY_CANCELED)
710 0 : log_info (_("cancelled\n"));
711 : else
712 0 : log_error (_("error while asking for the passphrase: %s\n"),
713 : gpg_strerror (err));
714 0 : agent_exit (0);
715 : }
716 0 : assert (pw);
717 :
718 0 : return pw;
719 : }
720 :
721 :
722 : static void
723 0 : release_passphrase (char *pw)
724 : {
725 0 : if (pw)
726 : {
727 0 : wipememory (pw, strlen (pw));
728 0 : xfree (pw);
729 : }
730 0 : }
731 :
732 :
733 : /* Stub function. */
734 : gpg_error_t
735 0 : convert_from_openpgp_native (gcry_sexp_t s_pgp, const char *passphrase,
736 : unsigned char **r_key)
737 : {
738 : (void)s_pgp;
739 : (void)passphrase;
740 : (void)r_key;
741 0 : return gpg_error (GPG_ERR_BUG);
742 : }
|