* genkey.c: Store the secret part and return the public part.
[gnupg.git] / agent / command.c
1 /* command.c - gpg-agent command handler
2  *      Copyright (C) 2001, 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 /* FIXME: we should not use the default assuan buffering but setup
22    some buffering in secure mempory to protect session keys etc. */
23
24 #include <config.h>
25 #include <errno.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <ctype.h>
30 #include <unistd.h>
31
32 #include "agent.h"
33 #include "../assuan/assuan.h"
34
35 /* maximum allowed size of the inquired ciphertext */
36 #define MAXLEN_CIPHERTEXT 4096
37 /* maximum allowed size of the key parameters */
38 #define MAXLEN_KEYPARAM 1024
39
40 #define set_error(e,t) assuan_set_error (ctx, ASSUAN_ ## e, (t))
41
42
43 #if MAX_DIGEST_LEN < 20
44 #error MAX_DIGEST_LEN shorter than keygrip
45 #endif
46
47 /* Data used to associate an Assuan context with local server data */
48 struct server_local_s {
49   ASSUAN_CONTEXT assuan_ctx;
50   int message_fd;
51 };
52
53
54
55
56 \f
57 static void
58 reset_notify (ASSUAN_CONTEXT ctx)
59 {
60   CTRL ctrl = assuan_get_pointer (ctx);
61
62   memset (ctrl->keygrip, 0, 20);
63   ctrl->have_keygrip = 0;
64   ctrl->digest.valuelen = 0;
65 }
66
67 /* SIGKEY <hexstring_with_keygrip>
68    SETKEY <hexstring_with_keygrip>
69   
70    Set the  key used for a sign or decrypt operation */
71 static int
72 cmd_sigkey (ASSUAN_CONTEXT ctx, char *line)
73 {
74   int n;
75   char *p;
76   CTRL ctrl = assuan_get_pointer (ctx);
77   unsigned char *buf;
78
79   /* parse the hash value */
80   for (p=line,n=0; hexdigitp (p); p++, n++)
81     ;
82   if (*p)
83     return set_error (Parameter_Error, "invalid hexstring");
84   if ((n&1))
85     return set_error (Parameter_Error, "odd number of digits");
86   n /= 2;
87   if (n != 20)
88     return set_error (Parameter_Error, "invalid length of keygrip");
89
90   buf = ctrl->keygrip;
91   for (p=line, n=0; n < 20; p += 2, n++)
92     buf[n] = xtoi_2 (p);
93   ctrl->have_keygrip = 1;
94   return 0;
95 }
96
97 /* SETHASH <algonumber> <hexstring> 
98
99   The client can use this command to tell the server about the data
100   (which usually is a hash) to be signed. */
101 static int
102 cmd_sethash (ASSUAN_CONTEXT ctx, char *line)
103 {
104   int n;
105   char *p;
106   CTRL ctrl = assuan_get_pointer (ctx);
107   unsigned char *buf;
108   char *endp;
109   int algo;
110
111   /* parse the algo number and check it */
112   algo = (int)strtoul (line, &endp, 10);
113   for (line = endp; *line == ' ' || *line == '\t'; line++)
114     ;
115   if (!algo || gcry_md_test_algo (algo))
116     return set_error (Unsupported_Algorithm, NULL);
117   ctrl->digest.algo = algo;
118
119   /* parse the hash value */
120   for (p=line,n=0; hexdigitp (p); p++, n++)
121     ;
122   if (*p)
123     return set_error (Parameter_Error, "invalid hexstring");
124   if ((n&1))
125     return set_error (Parameter_Error, "odd number of digits");
126   n /= 2;
127   if (n != 16 && n != 20 && n != 24 && n != 32)
128     return set_error (Parameter_Error, "unsupported length of hash");
129   if (n > MAX_DIGEST_LEN)
130     return set_error (Parameter_Error, "hash value to long");
131
132   buf = ctrl->digest.value;
133   ctrl->digest.valuelen = n;
134   for (p=line, n=0; n < ctrl->digest.valuelen; p += 2, n++)
135     buf[n] = xtoi_2 (p);
136   for (; n < ctrl->digest.valuelen; n++)
137     buf[n] = 0;
138   return 0;
139 }
140
141
142 /* PKSIGN <options>
143
144    Perform the actual sign operation. Neither input nor output are
145    sensitive to eavesdropping */
146 static int
147 cmd_pksign (ASSUAN_CONTEXT ctx, char *line)
148 {
149   int rc;
150   CTRL ctrl = assuan_get_pointer (ctx);
151
152   rc = agent_pksign (ctrl, assuan_get_data_fp (ctx));
153   return map_to_assuan_status (rc);
154 }
155
156 /* PKDECRYPT <options>
157
158    Perform the actual decrypt operation.  Input is not 
159    sensitive to eavesdropping */
160 static int
161 cmd_pkdecrypt (ASSUAN_CONTEXT ctx, char *line)
162 {
163   int rc;
164   CTRL ctrl = assuan_get_pointer (ctx);
165   char *value;
166   size_t valuelen;
167
168   /* First inquire the data to decrypt */
169   rc = assuan_inquire (ctx, "CIPHERTEXT",
170                        &value, &valuelen, MAXLEN_CIPHERTEXT);
171   if (rc)
172     return rc;
173
174   rc = agent_pkdecrypt (ctrl, value, valuelen, assuan_get_data_fp (ctx));
175   xfree (value);
176   return map_to_assuan_status (rc);
177 }
178
179
180 /* GENKEY
181
182    Generate a new key, store the secret part and return the public
183    part.  Here is an example transaction:
184
185    C: GENKEY
186    S: INQUIRE KEYPARM
187    C: D (genkey (rsa (nbits  1024)))
188    C: END
189    S: D (public-key
190    S: D   (rsa (n 326487324683264) (e 10001)))
191    S  OK key created
192 */
193
194 static int
195 cmd_genkey (ASSUAN_CONTEXT ctx, char *line)
196 {
197   CTRL ctrl = assuan_get_pointer (ctx);
198   int rc;
199   char *value;
200   size_t valuelen;
201
202   /* First inquire the parameters */
203   rc = assuan_inquire (ctx, "KEYPARAM", &value, &valuelen, MAXLEN_KEYPARAM);
204   if (rc)
205     return rc;
206
207   rc = agent_genkey (ctrl, value, valuelen, assuan_get_data_fp (ctx));
208   xfree (value);
209   return map_to_assuan_status (rc);
210 }
211
212
213 /* GET_PASSPHRASE <cache_id> [<error_message> <prompt> <description>]
214
215    This function is usually used to ask for a passphrase to be used
216    for conventional encryption, but may aslo be used by programs which
217    need specal handling of passphrases.  This command uses a syntax
218    which helps clients to use the agent with minimum effort.  The
219    agent either returns with an error or with a OK followed by the hex
220    encoded passphrase.  Note that the length of the strings is
221    implicitly limited by the maximum length of a command.
222 */
223
224 static int
225 cmd_get_passphrase (ASSUAN_CONTEXT ctx, char *line)
226 {
227   int rc;
228   char *response;
229   char *desc, *prompt, *errtext;
230
231   /* FIXME: Parse that stuff */
232   desc = "We need a passphrase";
233   prompt = NULL;
234   errtext = "try again";
235
236   rc = agent_get_passphrase (&response, desc, prompt, errtext);
237   if (!rc)
238     {
239       rc = assuan_set_okay_line (ctx, response);
240       xfree (response);
241     }
242
243   return map_to_assuan_status (rc);
244 }
245
246
247 /* CLEAR_PASSPHRASE <cache_id>
248
249    may be used to invalidate the cache entry for a passphrase.  The
250    function returns with OK even when ther eis no cached passphrase.
251 */
252
253 static int
254 cmd_clear_passphrase (ASSUAN_CONTEXT ctx, char *line)
255 {
256   int rc;
257
258   /* fixme: no caching yet. so return with OK */
259   rc = 0;
260
261   return map_to_assuan_status (rc);
262 }
263
264
265 \f
266 /* Tell the assuan library about our commands */
267 static int
268 register_commands (ASSUAN_CONTEXT ctx)
269 {
270   static struct {
271     const char *name;
272     int cmd_id;
273     int (*handler)(ASSUAN_CONTEXT, char *line);
274   } table[] = {
275     { "SIGKEY",     0,  cmd_sigkey },
276     { "SETKEY",     0,  cmd_sigkey },
277     { "SETHASH",    0,  cmd_sethash },
278     { "PKSIGN",     0,  cmd_pksign },
279     { "PKDECRYPT",  0,  cmd_pkdecrypt },
280     { "GENKEY",     0,  cmd_genkey },
281     { "GET_PASSPHRASE",0, cmd_get_passphrase },
282     { "CLEAR_PASSPHRASE",0, cmd_clear_passphrase },
283     { "",     ASSUAN_CMD_INPUT, NULL }, 
284     { "",     ASSUAN_CMD_OUTPUT, NULL }, 
285     { NULL }
286   };
287   int i, j, rc;
288
289   for (i=j=0; table[i].name; i++)
290     {
291       rc = assuan_register_command (ctx,
292                                     table[i].cmd_id? table[i].cmd_id
293                                                    : (ASSUAN_CMD_USER + j++),
294                                     table[i].name, table[i].handler);
295       if (rc)
296         return rc;
297     } 
298   assuan_register_reset_notify (ctx, reset_notify);
299   return 0;
300 }
301
302
303 /* Startup the server */
304 void
305 start_command_handler (void)
306 {
307   int rc;
308   int filedes[2];
309   ASSUAN_CONTEXT ctx;
310   struct server_control_s ctrl;
311
312   memset (&ctrl, 0, sizeof ctrl);
313
314   /* For now we use a simple pipe based server so that we can work
315      from scripts.  We will later add options to run as a daemon and
316      wait for requests on a Unix domain socket */
317   filedes[0] = 0;
318   filedes[1] = 1;
319   rc = assuan_init_pipe_server (&ctx, filedes);
320   if (rc)
321     {
322       log_error ("failed to initialize the server: %s\n",
323                  assuan_strerror(rc));
324       agent_exit (2);
325     }
326   rc = register_commands (ctx);
327   if (rc)
328     {
329       log_error ("failed to the register commands with Assuan: %s\n",
330                  assuan_strerror(rc));
331       agent_exit (2);
332     }
333
334   assuan_set_pointer (ctx, &ctrl);
335   ctrl.server_local = xcalloc (1, sizeof *ctrl.server_local);
336   ctrl.server_local->assuan_ctx = ctx;
337   ctrl.server_local->message_fd = -1;
338
339   for (;;)
340     {
341       rc = assuan_accept (ctx);
342       if (rc == -1)
343         {
344           break;
345         }
346       else if (rc)
347         {
348           log_info ("Assuan accept problem: %s\n", assuan_strerror (rc));
349           break;
350         }
351       
352       rc = assuan_process (ctx);
353       if (rc)
354         {
355           log_info ("Assuan processing failed: %s\n", assuan_strerror (rc));
356           continue;
357         }
358     }
359
360
361   assuan_deinit_pipe_server (ctx);
362 }
363