* protect-tool.c: Add command --show-keygrip
[gnupg.git] / agent / protect-tool.c
1 /* protect-tool.c - A tool to text the secret key protection
2  *      Copyright (C) 2002 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 2 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, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #include <config.h>
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <stddef.h>
26 #include <stdarg.h>
27 #include <string.h>
28 #include <errno.h>
29 #include <assert.h>
30 #include <sys/stat.h>
31 #include <unistd.h>
32
33 #include <gcrypt.h>
34
35 #define JNLIB_NEED_LOG_LOGV
36 #include "agent.h"
37
38 #define N_(a) a
39 #define _(a) a
40
41
42 enum cmd_and_opt_values 
43 { aNull = 0,
44   oVerbose        = 'v',
45   oArmor          = 'a',
46   oPassphrase     = 'P',
47
48   oProtect        = 'p',
49   oUnprotect      = 'u',
50   
51   oNoVerbose = 500,
52   oShadow,
53   oShowShadowInfo,
54   oShowKeygrip,
55
56 aTest };
57
58
59 static int opt_armor;
60 static const char *passphrase = "abc";
61
62 static ARGPARSE_OPTS opts[] = {
63   
64   { 301, NULL, 0, N_("@Options:\n ") },
65
66   { oVerbose, "verbose",   0, "verbose" },
67   { oArmor,   "armor",     0, "write output in advanced format" },
68   { oPassphrase, "passphrase", 2, "|STRING| Use passphrase STRING" },
69   { oProtect, "protect",     256, "protect a private key"},
70   { oUnprotect, "unprotect", 256, "unprotect a private key"},
71   { oShadow,  "shadow", 256, "create a shadow entry for a priblic key"},
72   { oShowShadowInfo,  "show-shadow-info", 256, "return the shadow info"},
73   { oShowKeygrip, "show-keygrip", 256, " show the \"keygrip\""},
74
75   {0}
76 };
77
78 static const char *
79 my_strusage (int level)
80 {
81   const char *p;
82   switch (level)
83     {
84     case 11: p = "protect-tool (GnuPG)";
85       break;
86     case 13: p = VERSION; break;
87     case 17: p = PRINTABLE_OS_NAME; break;
88     case 19: p = _("Please report bugs to <" PACKAGE_BUGREPORT ">.\n");
89       break;
90     case 1:
91     case 40: p =  _("Usage: protect-tool [options] (-h for help)\n");
92       break;
93     case 41: p =  _("Syntax: protect-tool [options] [args]]\n"
94                     "INTERNAL USE ONLY!\n");
95     break;
96     
97     default: p = NULL;
98     }
99   return p;
100 }
101
102
103
104 static void
105 i18n_init (void)
106 {
107 #ifdef USE_SIMPLE_GETTEXT
108     set_gettext_file( PACKAGE );
109 #else
110 #ifdef ENABLE_NLS
111     /* gtk_set_locale (); HMMM: We have not yet called gtk_init */
112     bindtextdomain( PACKAGE, GNUPG_LOCALEDIR );
113     textdomain( PACKAGE );
114 #endif
115 #endif
116 }
117
118
119
120 /* Used by gcry for logging */
121 static void
122 my_gcry_logger (void *dummy, int level, const char *fmt, va_list arg_ptr)
123 {
124   /* translate the log levels */
125   switch (level)
126     {
127     case GCRY_LOG_CONT: level = JNLIB_LOG_CONT; break;
128     case GCRY_LOG_INFO: level = JNLIB_LOG_INFO; break;
129     case GCRY_LOG_WARN: level = JNLIB_LOG_WARN; break;
130     case GCRY_LOG_ERROR:level = JNLIB_LOG_ERROR; break;
131     case GCRY_LOG_FATAL:level = JNLIB_LOG_FATAL; break;
132     case GCRY_LOG_BUG:  level = JNLIB_LOG_BUG; break;
133     case GCRY_LOG_DEBUG:level = JNLIB_LOG_DEBUG; break;
134     default:            level = JNLIB_LOG_ERROR; break;      }
135   log_logv (level, fmt, arg_ptr);
136 }
137
138 \f
139 static unsigned char *
140 make_canonical (const char *fname, const char *buf, size_t buflen)
141 {
142   int rc;
143   size_t erroff, len;
144   GCRY_SEXP sexp;
145   unsigned char *result;
146
147   rc = gcry_sexp_sscan (&sexp, &erroff, buf, buflen);
148   if (rc)
149     {
150       log_error ("invalid S-Expression in `%s' (off=%u): %s\n",
151                  fname, (unsigned int)erroff, gcry_strerror (rc));
152       return NULL;
153     }
154   len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_CANON, NULL, 0);
155   assert (len);
156   result = xmalloc (len);
157   len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_CANON, result, len);
158   assert (len);
159   gcry_sexp_release (sexp);
160   return result;
161 }
162
163 static char *
164 make_advanced (const unsigned char *buf, size_t buflen)
165 {
166   int rc;
167   size_t erroff, len;
168   GCRY_SEXP sexp;
169   unsigned char *result;
170
171   rc = gcry_sexp_sscan (&sexp, &erroff, buf, buflen);
172   if (rc)
173     {
174       log_error ("invalid canonical S-Expression (off=%u): %s\n",
175                  (unsigned int)erroff, gcry_strerror (rc));
176       return NULL;
177     }
178   len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_ADVANCED, NULL, 0);
179   assert (len);
180   result = xmalloc (len);
181   len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_ADVANCED, result, len);
182   assert (len);
183   gcry_sexp_release (sexp);
184   return result;
185 }
186
187
188 static unsigned char *
189 read_key (const char *fname)
190 {
191   FILE *fp;
192   struct stat st;
193   char *buf;
194   size_t buflen;
195   unsigned char *key;
196   
197   fp = fopen (fname, "rb");
198   if (!fp)
199     {
200       log_error ("can't open `%s': %s\n", fname, strerror (errno));
201       return NULL;
202     }
203   
204   if (fstat (fileno(fp), &st))
205     {
206       log_error ("can't stat `%s': %s\n", fname, strerror (errno));
207       fclose (fp);
208       return NULL;
209     }
210
211   buflen = st.st_size;
212   buf = xmalloc (buflen+1);
213   if (fread (buf, buflen, 1, fp) != 1)
214     {
215       log_error ("error reading `%s': %s\n", fname, strerror (errno));
216       fclose (fp);
217       xfree (buf);
218       return NULL;
219     }
220   fclose (fp);
221
222   key = make_canonical (fname, buf, buflen);
223   xfree (buf);
224   return key;
225 }
226
227
228 \f
229 static void
230 read_and_protect (const char *fname)
231 {
232   int  rc;
233   unsigned char *key;
234   unsigned char *result;
235   size_t resultlen;
236   
237   key = read_key (fname);
238   if (!key)
239     return;
240
241   rc = agent_protect (key, passphrase, &result, &resultlen);
242   xfree (key);
243   if (rc)
244     {
245       log_error ("protecting the key failed: %s\n", gnupg_strerror (rc));
246       return;
247     }
248   
249   if (opt_armor)
250     {
251       char *p = make_advanced (result, resultlen);
252       xfree (result);
253       if (!p)
254         return;
255       result = p;
256       resultlen = strlen (p);
257     }
258
259   fwrite (result, resultlen, 1, stdout);
260   xfree (result);
261 }
262
263
264 static void
265 read_and_unprotect (const char *fname)
266 {
267   int  rc;
268   unsigned char *key;
269   unsigned char *result;
270   size_t resultlen;
271   
272   key = read_key (fname);
273   if (!key)
274     return;
275
276   rc = agent_unprotect (key, passphrase, &result, &resultlen);
277   xfree (key);
278   if (rc)
279     {
280       log_error ("unprotecting the key failed: %s\n", gnupg_strerror (rc));
281       return;
282     }
283   
284   if (opt_armor)
285     {
286       char *p = make_advanced (result, resultlen);
287       xfree (result);
288       if (!p)
289         return;
290       result = p;
291       resultlen = strlen (p);
292     }
293
294   fwrite (result, resultlen, 1, stdout);
295   xfree (result);
296 }
297
298
299 \f
300 static void
301 read_and_shadow (const char *fname)
302 {
303   int  rc;
304   unsigned char *key;
305   unsigned char *result;
306   size_t resultlen;
307   
308   key = read_key (fname);
309   if (!key)
310     return;
311
312   rc = agent_shadow_key (key, "(8:313233342:43)", &result);
313   xfree (key);
314   if (rc)
315     {
316       log_error ("shadowing the key failed: %s\n", gnupg_strerror (rc));
317       return;
318     }
319   resultlen = gcry_sexp_canon_len (result, 0, NULL,NULL);
320   assert (resultlen);
321   
322   if (opt_armor)
323     {
324       char *p = make_advanced (result, resultlen);
325       xfree (result);
326       if (!p)
327         return;
328       result = p;
329       resultlen = strlen (p);
330     }
331
332   fwrite (result, resultlen, 1, stdout);
333   xfree (result);
334 }
335
336 static void
337 show_shadow_info (const char *fname)
338 {
339   int  rc;
340   unsigned char *key;
341   const unsigned char *info;
342   size_t infolen;
343   
344   key = read_key (fname);
345   if (!key)
346     return;
347
348   rc = agent_get_shadow_info (key, &info);
349   xfree (key);
350   if (rc)
351     {
352       log_error ("get_shadow_info failed: %s\n", gnupg_strerror (rc));
353       return;
354     }
355   infolen = gcry_sexp_canon_len (info, 0, NULL,NULL);
356   assert (infolen);
357   
358   if (opt_armor)
359     {
360       char *p = make_advanced (info, infolen);
361       if (!p)
362         return;
363       fwrite (p, strlen (p), 1, stdout);
364       xfree (p);
365     }
366   else
367     fwrite (info, infolen, 1, stdout);
368 }
369
370
371 static void
372 show_file (const char *fname)
373 {
374   unsigned char *key;
375   size_t keylen;
376   char *p;
377   
378   key = read_key (fname);
379   if (!key)
380     return;
381
382   keylen = gcry_sexp_canon_len (key, 0, NULL,NULL);
383   assert (keylen);
384
385   p = make_advanced (key, keylen);
386   xfree (key);
387   if (p)
388     {
389       fwrite (p, strlen (p), 1, stdout);
390       xfree (p);
391     }
392 }
393
394 static void
395 show_keygrip (const char *fname)
396 {
397   unsigned char *key;
398   GcrySexp private;
399   unsigned char grip[20];
400   int i;
401   
402   key = read_key (fname);
403   if (!key)
404     return;
405
406   if (gcry_sexp_new (&private, key, 0, 0))
407     {
408       log_error ("gcry_sexp_new failed\n");
409       return;
410     } 
411   xfree (key);
412
413   if (!gcry_pk_get_keygrip (private, grip))
414     {
415       log_error ("can't calculate keygrip\n");
416       return;
417     }
418   gcry_sexp_release (private);
419
420   for (i=0; i < 20; i++)
421     printf ("%02X", grip[i]);
422   putchar ('\n');
423 }
424
425
426
427
428 int
429 main (int argc, char **argv )
430 {
431   ARGPARSE_ARGS pargs;
432   int cmd = 0;
433
434   set_strusage (my_strusage);
435   gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
436   log_set_prefix ("protect-tool", 1); 
437   i18n_init ();
438
439   if (!gcry_check_version ( "1.1.5" ) )
440     {
441       log_fatal( _("libgcrypt is too old (need %s, have %s)\n"),
442                  "1.1.5", gcry_check_version (NULL) );
443     }
444
445   gcry_set_log_handler (my_gcry_logger, NULL);
446   
447   gcry_control (GCRYCTL_INIT_SECMEM, 16384, 0);
448
449   pargs.argc = &argc;
450   pargs.argv = &argv;
451   pargs.flags=  1;  /* do not remove the args */
452   while (arg_parse (&pargs, opts) )
453     {
454       switch (pargs.r_opt)
455         {
456         case oVerbose: opt.verbose++; break;
457         case oArmor:   opt_armor=1; break;
458
459         case oProtect: cmd = oProtect; break;
460         case oUnprotect: cmd = oUnprotect; break;
461         case oShadow: cmd = oShadow; break;
462         case oShowShadowInfo: cmd = oShowShadowInfo; break;
463         case oShowKeygrip: cmd = oShowKeygrip; break;
464
465         case oPassphrase: passphrase = pargs.r.ret_str; break;
466
467         default : pargs.err = 2; break;
468         }
469     }
470   if (log_get_errorcount(0))
471     exit(2);
472
473   if (argc != 1)
474     usage (1);
475
476   if (cmd == oProtect)
477     read_and_protect (*argv);
478   else if (cmd == oUnprotect)
479     read_and_unprotect (*argv);
480   else if (cmd == oShadow)
481     read_and_shadow (*argv);
482   else if (cmd == oShowShadowInfo)
483     show_shadow_info (*argv);
484   else if (cmd == oShowKeygrip)
485     show_keygrip (*argv);
486   else
487     show_file (*argv);
488
489   return 0;
490 }
491
492 void
493 agent_exit (int rc)
494 {
495   rc = rc? rc : log_get_errorcount(0)? 2 : 0;
496   exit (rc);
497 }