* genkey.c (store_key): Protect the key.
[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
53 aTest };
54
55
56 static int opt_armor;
57 static const char *passphrase = "abc";
58
59 static ARGPARSE_OPTS opts[] = {
60   
61   { 301, NULL, 0, N_("@Options:\n ") },
62
63   { oVerbose, "verbose",   0, "verbose" },
64   { oArmor,   "armor",     0, "write output in advanced format" },
65   { oPassphrase, "passphrase", 2, "|STRING| Use passphrase STRING" },
66   { oProtect, "protect",     256, "protect a private key"},
67   { oUnprotect, "unprotect", 256, "unprotect a private key"},
68
69   {0}
70 };
71
72 static const char *
73 my_strusage (int level)
74 {
75   const char *p;
76   switch (level)
77     {
78     case 11: p = "protect-tool (GnuPG)";
79       break;
80     case 13: p = VERSION; break;
81     case 17: p = PRINTABLE_OS_NAME; break;
82     case 19: p = _("Please report bugs to <" PACKAGE_BUGREPORT ">.\n");
83       break;
84     case 1:
85     case 40: p =  _("Usage: protect-tool [options] (-h for help)\n");
86       break;
87     case 41: p =  _("Syntax: protect-tool [options] [args]]\n"
88                     "INTERNAL USE ONLY!\n");
89     break;
90     
91     default: p = NULL;
92     }
93   return p;
94 }
95
96
97
98 static void
99 i18n_init (void)
100 {
101 #ifdef USE_SIMPLE_GETTEXT
102     set_gettext_file( PACKAGE );
103 #else
104 #ifdef ENABLE_NLS
105     /* gtk_set_locale (); HMMM: We have not yet called gtk_init */
106     bindtextdomain( PACKAGE, GNUPG_LOCALEDIR );
107     textdomain( PACKAGE );
108 #endif
109 #endif
110 }
111
112
113
114 /* Used by gcry for logging */
115 static void
116 my_gcry_logger (void *dummy, int level, const char *fmt, va_list arg_ptr)
117 {
118   /* translate the log levels */
119   switch (level)
120     {
121     case GCRY_LOG_CONT: level = JNLIB_LOG_CONT; break;
122     case GCRY_LOG_INFO: level = JNLIB_LOG_INFO; break;
123     case GCRY_LOG_WARN: level = JNLIB_LOG_WARN; break;
124     case GCRY_LOG_ERROR:level = JNLIB_LOG_ERROR; break;
125     case GCRY_LOG_FATAL:level = JNLIB_LOG_FATAL; break;
126     case GCRY_LOG_BUG:  level = JNLIB_LOG_BUG; break;
127     case GCRY_LOG_DEBUG:level = JNLIB_LOG_DEBUG; break;
128     default:            level = JNLIB_LOG_ERROR; break;  
129     }
130   log_logv (level, fmt, arg_ptr);
131 }
132
133 \f
134 static unsigned char *
135 make_canonical (const char *fname, const char *buf, size_t buflen)
136 {
137   int rc;
138   size_t erroff, len;
139   GCRY_SEXP sexp;
140   unsigned char *result;
141
142   rc = gcry_sexp_sscan (&sexp, &erroff, buf, buflen);
143   if (rc)
144     {
145       log_error ("invalid S-Expression in `%s' (off=%u): %s\n",
146                  fname, (unsigned int)erroff, gcry_strerror (rc));
147       return NULL;
148     }
149   len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_CANON, NULL, 0);
150   assert (len);
151   result = xmalloc (len);
152   len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_CANON, result, len);
153   assert (len);
154   gcry_sexp_release (sexp);
155   return result;
156 }
157
158 static char *
159 make_advanced (const unsigned char *buf, size_t buflen)
160 {
161   int rc;
162   size_t erroff, len;
163   GCRY_SEXP sexp;
164   unsigned char *result;
165
166   rc = gcry_sexp_sscan (&sexp, &erroff, buf, buflen);
167   if (rc)
168     {
169       log_error ("invalid canonical S-Expression (off=%u): %s\n",
170                  (unsigned int)erroff, gcry_strerror (rc));
171       return NULL;
172     }
173   len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_ADVANCED, NULL, 0);
174   assert (len);
175   result = xmalloc (len);
176   len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_ADVANCED, result, len);
177   assert (len);
178   gcry_sexp_release (sexp);
179   return result;
180 }
181
182
183 static unsigned char *
184 read_key (const char *fname)
185 {
186   FILE *fp;
187   struct stat st;
188   char *buf;
189   size_t buflen;
190   unsigned char *key;
191   
192   fp = fopen (fname, "rb");
193   if (!fp)
194     {
195       log_error ("can't open `%s': %s\n", fname, strerror (errno));
196       return NULL;
197     }
198   
199   if (fstat (fileno(fp), &st))
200     {
201       log_error ("can't stat `%s': %s\n", fname, strerror (errno));
202       fclose (fp);
203       return NULL;
204     }
205
206   buflen = st.st_size;
207   buf = xmalloc (buflen+1);
208   if (fread (buf, buflen, 1, fp) != 1)
209     {
210       log_error ("error reading `%s': %s\n", fname, strerror (errno));
211       fclose (fp);
212       xfree (buf);
213       return NULL;
214     }
215   fclose (fp);
216
217   key = make_canonical (fname, buf, buflen);
218   xfree (buf);
219   return key;
220 }
221
222
223 \f
224 static void
225 read_and_protect (const char *fname)
226 {
227   int  rc;
228   unsigned char *key;
229   unsigned char *result;
230   size_t resultlen;
231   
232   key = read_key (fname);
233   if (!key)
234     return;
235
236   rc = agent_protect (key, passphrase, &result, &resultlen);
237   xfree (key);
238   if (rc)
239     {
240       log_error ("protecting the key failed: %s\n", gnupg_strerror (rc));
241       return;
242     }
243   
244   if (opt_armor)
245     {
246       char *p = make_advanced (result, resultlen);
247       xfree (result);
248       if (!p)
249         return;
250       result = p;
251       resultlen = strlen (p);
252     }
253
254   fwrite (result, resultlen, 1, stdout);
255   xfree (result);
256 }
257
258
259 static void
260 read_and_unprotect (const char *fname)
261 {
262   int  rc;
263   unsigned char *key;
264   unsigned char *result;
265   size_t resultlen;
266   
267   key = read_key (fname);
268   if (!key)
269     return;
270
271   rc = agent_unprotect (key, passphrase, &result, &resultlen);
272   xfree (key);
273   if (rc)
274     {
275       log_error ("unprotecting the key failed: %s\n", gnupg_strerror (rc));
276       return;
277     }
278   
279   if (opt_armor)
280     {
281       char *p = make_advanced (result, resultlen);
282       xfree (result);
283       if (!p)
284         return;
285       result = p;
286       resultlen = strlen (p);
287     }
288
289   fwrite (result, resultlen, 1, stdout);
290   xfree (result);
291 }
292
293
294
295 int
296 main (int argc, char **argv )
297 {
298   ARGPARSE_ARGS pargs;
299   int cmd = 0;
300
301   set_strusage (my_strusage);
302   gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
303   log_set_prefix ("protect-tool", 1); 
304   i18n_init ();
305
306   if (!gcry_check_version ( "1.1.5" ) )
307     {
308       log_fatal( _("libgcrypt is too old (need %s, have %s)\n"),
309                  "1.1.5", gcry_check_version (NULL) );
310     }
311
312   gcry_set_log_handler (my_gcry_logger, NULL);
313   
314   gcry_control (GCRYCTL_INIT_SECMEM, 16384, 0);
315
316   pargs.argc = &argc;
317   pargs.argv = &argv;
318   pargs.flags=  1;  /* do not remove the args */
319   while (arg_parse (&pargs, opts) )
320     {
321       switch (pargs.r_opt)
322         {
323         case oVerbose: opt.verbose++; break;
324         case oArmor:   opt_armor=1; break;
325
326         case oProtect: cmd = oProtect; break;
327         case oUnprotect: cmd = oUnprotect; break;
328
329         case oPassphrase: passphrase = pargs.r.ret_str; break;
330
331         default : pargs.err = 2; break;
332         }
333     }
334   if (log_get_errorcount(0))
335     exit(2);
336
337   if (argc != 1)
338     usage (1);
339
340   if (cmd == oProtect)
341     read_and_protect (*argv);
342   else if (cmd == oUnprotect)
343     read_and_unprotect (*argv);
344   else
345     log_info ("no action requested\n");
346
347   return 0;
348 }
349
350 void
351 agent_exit (int rc)
352 {
353   rc = rc? rc : log_get_errorcount(0)? 2 : 0;
354   exit (rc);
355 }