Added decryption, some code cleanup
[gnupg.git] / agent / command.c
1 /* command.c - gpg-agent command handler
2  *      Copyright (C) 2001 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
38
39 #define set_error(e,t) assuan_set_error (ctx, ASSUAN_ ## e, (t))
40 #define digitp(a) ((a) >= '0' && (a) <= '9')
41 #define hexdigitp(a) (digitp (a)                     \
42                       || ((a) >= 'A' && (a) <= 'F')  \
43                       || ((a) >= 'a' && (a) <= 'f'))
44 #define atoi_1(p)   (*(p) - '0' )
45 #define atoi_2(p)   ((atoi_1(p) * 10) + atoi_1((p)+1))
46 /* assumes ASCII and pre-checked values */
47 #define xtoi_1(p)   (*(p) <= '9'? (*(p)- '0'): \
48                      *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
49 #define xtoi_2(p)   ((xtoi_1(p) * 16) + xtoi_1((p)+1))
50
51 #if MAX_DIGEST_LEN < 20
52 #error MAX_DIGEST_LEN shorter than keygrip
53 #endif
54
55 /* Data used to associate an Assuan context with local server data */
56 struct server_local_s {
57   ASSUAN_CONTEXT assuan_ctx;
58   int message_fd;
59 };
60
61
62 /* Map GNUPG_xxx error codes to Assuan status codes
63    FIXME: duplicated from ../sm/server.c */
64 static int
65 rc_to_assuan_status (int rc)
66 {
67   switch (rc)
68     {
69     case 0: break;
70     case GNUPG_Bad_Certificate:   rc = ASSUAN_Bad_Certificate; break;
71     case GNUPG_Bad_Certificate_Path: rc = ASSUAN_Bad_Certificate_Path; break;
72     case GNUPG_Missing_Certificate: rc = ASSUAN_Missing_Certificate; break;
73     case GNUPG_No_Data:           rc = ASSUAN_No_Data_Available; break;
74     case GNUPG_Bad_Signature:     rc = ASSUAN_Bad_Signature; break;
75     case GNUPG_Not_Implemented:   rc = ASSUAN_Not_Implemented; break;
76     case GNUPG_No_Agent:          rc = ASSUAN_No_Agent; break;
77     case GNUPG_Agent_Error:       rc = ASSUAN_Agent_Error; break;
78     case GNUPG_No_Public_Key:     rc = ASSUAN_No_Public_Key; break;
79     case GNUPG_No_Secret_Key:     rc = ASSUAN_No_Secret_Key; break;
80     case GNUPG_Invalid_Data:      rc = ASSUAN_Invalid_Data; break;
81
82     case GNUPG_Read_Error: 
83     case GNUPG_Write_Error:
84     case GNUPG_IO_Error: 
85       rc = ASSUAN_Server_IO_Error;
86       break;
87     case GNUPG_Out_Of_Core:    
88     case GNUPG_Resource_Limit: 
89       rc = ASSUAN_Server_Resource_Problem;
90       break;
91     case GNUPG_Bug: 
92     case GNUPG_Internal_Error:   
93       rc = ASSUAN_Server_Bug;
94       break;
95     default: 
96       rc = ASSUAN_Server_Fault;
97       break;
98     }
99   return rc;
100 }
101
102
103 \f
104 static void
105 reset_notify (ASSUAN_CONTEXT ctx)
106 {
107   CTRL ctrl = assuan_get_pointer (ctx);
108
109   memset (ctrl->keygrip, 0, 20);
110   ctrl->have_keygrip = 0;
111   ctrl->digest.valuelen = 0;
112 }
113
114 /* SIGKEY <hexstring_with_keygrip>
115    SETKEY <hexstring_with_keygrip>
116   
117    Set the  key used for a sign or decrypt operation */
118 static int
119 cmd_sigkey (ASSUAN_CONTEXT ctx, char *line)
120 {
121   int n;
122   char *p;
123   CTRL ctrl = assuan_get_pointer (ctx);
124   unsigned char *buf;
125
126   /* parse the hash value */
127   for (p=line,n=0; hexdigitp (*p); p++, n++)
128     ;
129   if (*p)
130     return set_error (Parameter_Error, "invalid hexstring");
131   if ((n&1))
132     return set_error (Parameter_Error, "odd number of digits");
133   n /= 2;
134   if (n != 20)
135     return set_error (Parameter_Error, "invalid length of keygrip");
136
137   buf = ctrl->keygrip;
138   for (p=line, n=0; n < 20; p += 2, n++)
139     buf[n] = xtoi_2 (p);
140   ctrl->have_keygrip = 1;
141   return 0;
142 }
143
144 /* SETHASH <algonumber> <hexstring> 
145
146   The client can use this command to tell the server about the data
147   (which usually is a hash) to be signed. */
148 static int
149 cmd_sethash (ASSUAN_CONTEXT ctx, char *line)
150 {
151   int n;
152   char *p;
153   CTRL ctrl = assuan_get_pointer (ctx);
154   unsigned char *buf;
155   char *endp;
156   int algo;
157
158   /* parse the algo number and check it */
159   algo = (int)strtoul (line, &endp, 10);
160   for (line = endp; *line == ' ' || *line == '\t'; line++)
161     ;
162   if (!algo || gcry_md_test_algo (algo))
163     return set_error (Unsupported_Algorithm, NULL);
164   ctrl->digest.algo = algo;
165
166   /* parse the hash value */
167   for (p=line,n=0; hexdigitp (*p); p++, n++)
168     ;
169   if (*p)
170     return set_error (Parameter_Error, "invalid hexstring");
171   if ((n&1))
172     return set_error (Parameter_Error, "odd number of digits");
173   n /= 2;
174   if (n != 16 && n != 20 && n != 24 && n != 32)
175     return set_error (Parameter_Error, "unsupported length of hash");
176   if (n > MAX_DIGEST_LEN)
177     return set_error (Parameter_Error, "hash value to long");
178
179   buf = ctrl->digest.value;
180   ctrl->digest.valuelen = n;
181   for (p=line, n=0; n < ctrl->digest.valuelen; p += 2, n++)
182     buf[n] = xtoi_2 (p);
183   for (; n < ctrl->digest.valuelen; n++)
184     buf[n] = 0;
185   return 0;
186 }
187
188
189 /* PKSIGN <options>
190
191    Perform the actual sign operation. Neither input nor output are
192    sensitive to eavesdropping */
193 static int
194 cmd_pksign (ASSUAN_CONTEXT ctx, char *line)
195 {
196   int rc;
197   CTRL ctrl = assuan_get_pointer (ctx);
198
199   rc = agent_pksign (ctrl, assuan_get_data_fp (ctx));
200   return rc_to_assuan_status (rc);
201 }
202
203 /* PKDECRYPT <options>
204
205    Perform the actual decrypt operation.  Input is not 
206    sensitive to eavesdropping */
207 static int
208 cmd_pkdecrypt (ASSUAN_CONTEXT ctx, char *line)
209 {
210   int rc;
211   CTRL ctrl = assuan_get_pointer (ctx);
212   char *value;
213   size_t valuelen;
214
215   /* First inquire the data to decrypt */
216   rc = assuan_inquire (ctx, "CIPHERTEXT",
217                        &value, &valuelen, MAXLEN_CIPHERTEXT);
218   if (rc)
219     return rc;
220
221   rc = agent_pkdecrypt (ctrl, value, valuelen, assuan_get_data_fp (ctx));
222   xfree (value);
223   return rc_to_assuan_status (rc);
224 }
225
226
227 \f
228 /* Tell the assuan library about our commands */
229 static int
230 register_commands (ASSUAN_CONTEXT ctx)
231 {
232   static struct {
233     const char *name;
234     int cmd_id;
235     int (*handler)(ASSUAN_CONTEXT, char *line);
236   } table[] = {
237     { "SIGKEY",     0,  cmd_sigkey },
238     { "SETKEY",     0,  cmd_sigkey },
239     { "SETHASH",    0,  cmd_sethash },
240     { "PKSIGN",     0,  cmd_pksign },
241     { "PKDECRYPT",  0,  cmd_pkdecrypt },
242     { "",     ASSUAN_CMD_INPUT, NULL }, 
243     { "",     ASSUAN_CMD_OUTPUT, NULL }, 
244     { NULL }
245   };
246   int i, j, rc;
247
248   for (i=j=0; table[i].name; i++)
249     {
250       rc = assuan_register_command (ctx,
251                                     table[i].cmd_id? table[i].cmd_id
252                                                    : (ASSUAN_CMD_USER + j++),
253                                     table[i].name, table[i].handler);
254       if (rc)
255         return rc;
256     } 
257   assuan_register_reset_notify (ctx, reset_notify);
258   return 0;
259 }
260
261
262 /* Startup the server */
263 void
264 start_command_handler (void)
265 {
266   int rc;
267   int filedes[2];
268   ASSUAN_CONTEXT ctx;
269   struct server_control_s ctrl;
270
271   memset (&ctrl, 0, sizeof ctrl);
272
273   /* For now we use a simple pipe based server so that we can work
274      from scripts.  We will later add options to run as a daemon and
275      wait for requests on a Unix domain socket */
276   filedes[0] = 0;
277   filedes[1] = 1;
278   rc = assuan_init_pipe_server (&ctx, filedes);
279   if (rc)
280     {
281       log_error ("failed to initialize the server: %s\n",
282                  assuan_strerror(rc));
283       agent_exit (2);
284     }
285   rc = register_commands (ctx);
286   if (rc)
287     {
288       log_error ("failed to the register commands with Assuan: %s\n",
289                  assuan_strerror(rc));
290       agent_exit (2);
291     }
292
293   assuan_set_pointer (ctx, &ctrl);
294   ctrl.server_local = xcalloc (1, sizeof *ctrl.server_local);
295   ctrl.server_local->assuan_ctx = ctx;
296   ctrl.server_local->message_fd = -1;
297
298   log_info ("Assuan started\n");
299   for (;;)
300     {
301       rc = assuan_accept (ctx);
302       if (rc == -1)
303         {
304           log_info ("Assuan terminated\n");
305           break;
306         }
307       else if (rc)
308         {
309           log_info ("Assuan accept problem: %s\n", assuan_strerror (rc));
310           break;
311         }
312       
313       rc = assuan_process (ctx);
314       if (rc)
315         {
316           log_info ("Assuan processing failed: %s\n", assuan_strerror (rc));
317           continue;
318         }
319     }
320
321
322   assuan_deinit_pipe_server (ctx);
323 }
324