Decryption does now work
[gnupg.git] / sm / call-agent.c
1 /* call-agent.c - divert operations to the agent
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 #include <config.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <unistd.h> 
27 #include <time.h>
28 #include <assert.h>
29
30 #include <gcrypt.h>
31
32 #include "gpgsm.h"
33 #include "../assuan/assuan.h"
34 #include "i18n.h"
35
36 #ifdef _POSIX_OPEN_MAX
37 #define MAX_OPEN_FDS _POSIX_OPEN_MAX
38 #else
39 #define MAX_OPEN_FDS 20
40 #endif
41
42 #define LINELENGTH 1002 /* 1000 + [CR,]LF */
43
44 #define xtoi_1(p)   (*(p) <= '9'? (*(p)- '0'): \
45                      *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
46 #define xtoi_2(p)   ((xtoi_1(p) * 16) + xtoi_1((p)+1))
47
48
49 static ASSUAN_CONTEXT agent_ctx = NULL;
50
51 struct cipher_parm_s {
52   ASSUAN_CONTEXT ctx;
53   const char *ciphertext;
54   size_t ciphertextlen;
55 };
56
57
58 struct membuf {
59   size_t len;
60   size_t size;
61   char *buf;
62   int out_of_core;
63 };
64
65
66 \f
67 /* A simple implemnation of a dynamic buffer.  Use init_membuf() to
68    create a buffer, put_membuf to append bytes and get_membuf to
69    release and return the buffer.  Allocation errors are detected but
70    only returned at the final get_membuf(), this helps not to clutter
71    the code with out of core checks.  */
72
73 static void
74 init_membuf (struct membuf *mb, int initiallen)
75 {
76   mb->len = 0;
77   mb->size = initiallen;
78   mb->out_of_core = 0;
79   mb->buf = xtrymalloc (initiallen);
80   if (!mb->buf)
81       mb->out_of_core = 1;
82 }
83
84 static void
85 put_membuf (struct membuf *mb, const void *buf, size_t len)
86 {
87   if (mb->out_of_core)
88     return;
89
90   if (mb->len + len >= mb->size)
91     {
92       char *p;
93       
94       mb->size += len + 1024;
95       p = xtryrealloc (mb->buf, mb->size);
96       if (!p)
97         {
98           mb->out_of_core = 1;
99           return;
100         }
101       mb->buf = p;
102     }
103   memcpy (mb->buf + mb->len, buf, len);
104   mb->len += len;
105 }
106
107 static void *
108 get_membuf (struct membuf *mb, size_t *len)
109 {
110   char *p;
111
112   if (mb->out_of_core)
113     {
114       xfree (mb->buf);
115       mb->buf = NULL;
116       return NULL;
117     }
118
119   p = mb->buf;
120   *len = mb->len;
121   mb->buf = NULL;
122   mb->out_of_core = 1; /* don't allow a reuse */
123   return p;
124 }
125
126
127 \f
128 /* Try to connect to the agent via socket or fork it off and work by
129    pipes.  Handle the server's initial greeting */
130 static int
131 start_agent (void)
132 {
133   int rc;
134   char *infostr, *p;
135
136   if (agent_ctx)
137     return 0; /* fixme: We need a context for each thread or serialize
138                  the access to the agent (which is suitable given that
139                  the agent is not MT */
140
141   infostr = getenv ("GPG_AGENT_INFO");
142   if (!infostr)
143     {
144       const char *pgmname;
145       ASSUAN_CONTEXT ctx;
146       const char *argv[3];
147
148       log_info (_("no running gpg-agent - starting one\n"));
149       
150       if (fflush (NULL))
151         {
152           log_error ("error flushing pending output: %s\n", strerror (errno));
153           return seterr (Write_Error);
154         }
155
156       if (!opt.agent_program || !*opt.agent_program)
157         opt.agent_program = "../agent/gpg-agent";
158       if ( !(pgmname = strrchr (opt.agent_program, '/')))
159         pgmname = opt.agent_program;
160       else
161         pgmname++;
162
163       argv[0] = pgmname;
164       argv[1] = "--server";
165       argv[2] = NULL;
166
167       /* connect to the agent and perform initial handshaking */
168       rc = assuan_pipe_connect (&ctx, opt.agent_program, (char**)argv);
169       if (rc)
170         {
171           log_error ("can't connect to the agent: %s\n", assuan_strerror (rc));
172           return seterr (No_Agent);
173         }
174       agent_ctx = ctx;
175     }
176   else
177     {
178       infostr = xstrdup (infostr);
179       if ( !(p = strchr (infostr, ':')) || p == infostr
180            /* || (p-infostr)+1 >= sizeof client_addr.sun_path */)
181         {
182           log_error (_("malformed GPG_AGENT_INFO environment variable\n"));
183           xfree (infostr);
184           return seterr (General_Error);
185         }
186       *p = 0;
187       log_error (_("socket based agent communication not yet implemented\n"));
188       return seterr (Not_Implemented);
189     }
190
191   log_debug ("connection to agent established\n");
192
193   if (DBG_AGENT)
194     {
195       log_debug ("waiting for debugger [hit RETURN when ready] .....\n");
196       getchar ();
197       log_debug ("... okay\n");
198     }
199
200   return 0;
201 }
202
203
204 static AssuanError
205 membuf_data_cb (void *opaque, const void *buffer, size_t length)
206 {
207   struct membuf *data = opaque;
208
209   put_membuf (data, buffer, length);
210   return 0;
211 }
212   
213
214
215 \f
216 /* Call the agent to do a sign operation using the key identified by
217    the hex string KEYGRIP. */
218 int
219 gpgsm_agent_pksign (const char *keygrip,
220                     unsigned char *digest, size_t digestlen, int digestalgo,
221                     char **r_buf, size_t *r_buflen )
222 {
223   int rc, i;
224   char *p, line[LINELENGTH];
225   struct membuf data;
226   size_t len;
227
228   *r_buf = NULL;
229   rc = start_agent ();
230   if (rc)
231     return rc;
232
233   if (digestlen*2 + 50 > DIM(line))
234     return seterr (General_Error);
235
236   rc = assuan_transact (agent_ctx, "RESET", NULL, NULL, NULL, NULL);
237   if (rc)
238     return map_assuan_err (rc);
239
240   snprintf (line, DIM(line)-1, "SIGKEY %s", keygrip);
241   line[DIM(line)-1] = 0;
242   rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL);
243   if (rc)
244     return map_assuan_err (rc);
245
246   sprintf (line, "SETHASH %d ", digestalgo);
247   p = line + strlen (line);
248   for (i=0; i < digestlen ; i++, p += 2 )
249     sprintf (p, "%02X", digest[i]);
250   rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL);
251   if (rc)
252     return map_assuan_err (rc);
253
254   init_membuf (&data, 1024);
255   rc = assuan_transact (agent_ctx, "PKSIGN",
256                         membuf_data_cb, &data, NULL, NULL);
257   if (rc)
258     {
259       xfree (get_membuf (&data, &len));
260       return map_assuan_err (rc);
261     }
262   *r_buf = get_membuf (&data, r_buflen);
263   return *r_buf? 0 : GNUPG_Out_Of_Core;
264 }
265
266
267
268 \f
269 /* Handle a CIPHERTEXT inquiry.  Note, we only send the data,
270    assuan_transact talkes care of flushing and writing the end */
271 static AssuanError
272 inq_ciphertext_cb (void *opaque, const char *keyword)
273 {
274   struct cipher_parm_s *parm = opaque; 
275   AssuanError rc;
276
277   rc = assuan_send_data (parm->ctx, parm->ciphertext, parm->ciphertextlen);
278   return rc; 
279 }
280
281
282 /* Call the agent to do a decrypt operation using the key identified by
283    the hex string KEYGRIP. */
284 int
285 gpgsm_agent_pkdecrypt (const char *keygrip,
286                        const char *ciphertext, size_t ciphertextlen,
287                        char **r_buf, size_t *r_buflen )
288 {
289   int rc;
290   char line[LINELENGTH];
291   struct membuf data;
292   struct cipher_parm_s cipher_parm;
293   size_t n, len;
294   char *buf, *endp;
295   
296   if (!keygrip || strlen(keygrip) != 40 || !ciphertext || !r_buf || !r_buflen)
297     return GNUPG_Invalid_Value;
298   *r_buf = NULL;
299
300   rc = start_agent ();
301   if (rc)
302     return rc;
303
304   rc = assuan_transact (agent_ctx, "RESET", NULL, NULL, NULL, NULL);
305   if (rc)
306     return map_assuan_err (rc);
307
308   assert ( DIM(line) >= 50 );
309   snprintf (line, DIM(line)-1, "SETKEY %s", keygrip);
310   line[DIM(line)-1] = 0;
311   rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL);
312   if (rc)
313     return map_assuan_err (rc);
314
315   init_membuf (&data, 1024);
316   cipher_parm.ctx = agent_ctx;
317   cipher_parm.ciphertext = ciphertext;
318   cipher_parm.ciphertextlen = ciphertextlen;
319   rc = assuan_transact (agent_ctx, "PKDECRYPT",
320                         membuf_data_cb, &data,
321                         inq_ciphertext_cb, &cipher_parm);
322   if (rc)
323     {
324       xfree (get_membuf (&data, &len));
325       return map_assuan_err (rc);
326     }
327
328   put_membuf (&data, "", 1); /* make sure it is 0 terminated */
329   buf = get_membuf (&data, &len);
330   if (!buf)
331     return seterr (Out_Of_Core);
332   assert (len);
333   len--; /* remove the terminating 0 */
334   n = strtoul (buf, &endp, 10);
335   if (!n || *endp != ':')
336     return seterr (Invalid_Sexp);
337   endp++;
338   if (endp-buf+n > len)
339     return seterr (Invalid_Sexp); /* oops len does not match internal len*/
340   memmove (buf, endp, n);
341   *r_buflen = n;
342   *r_buf = buf;
343   return 0;
344 }
345
346
347
348
349
350
351