* base64.c (gpgsm_create_writer): Allow to set the object name
[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 xtoi_1(p)   (*(p) <= '9'? (*(p)- '0'): \
43                      *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
44 #define xtoi_2(p)   ((xtoi_1(p) * 16) + xtoi_1((p)+1))
45
46
47 static ASSUAN_CONTEXT agent_ctx = NULL;
48
49 struct cipher_parm_s {
50   ASSUAN_CONTEXT ctx;
51   const char *ciphertext;
52   size_t ciphertextlen;
53 };
54
55 struct genkey_parm_s {
56   ASSUAN_CONTEXT ctx;
57   const char *sexp;
58   size_t sexplen;
59 };
60
61
62 struct membuf {
63   size_t len;
64   size_t size;
65   char *buf;
66   int out_of_core;
67 };
68
69
70 \f
71 /* A simple implemnation of a dynamic buffer.  Use init_membuf() to
72    create a buffer, put_membuf to append bytes and get_membuf to
73    release and return the buffer.  Allocation errors are detected but
74    only returned at the final get_membuf(), this helps not to clutter
75    the code with out of core checks.  */
76
77 static void
78 init_membuf (struct membuf *mb, int initiallen)
79 {
80   mb->len = 0;
81   mb->size = initiallen;
82   mb->out_of_core = 0;
83   mb->buf = xtrymalloc (initiallen);
84   if (!mb->buf)
85       mb->out_of_core = 1;
86 }
87
88 static void
89 put_membuf (struct membuf *mb, const void *buf, size_t len)
90 {
91   if (mb->out_of_core)
92     return;
93
94   if (mb->len + len >= mb->size)
95     {
96       char *p;
97       
98       mb->size += len + 1024;
99       p = xtryrealloc (mb->buf, mb->size);
100       if (!p)
101         {
102           mb->out_of_core = 1;
103           return;
104         }
105       mb->buf = p;
106     }
107   memcpy (mb->buf + mb->len, buf, len);
108   mb->len += len;
109 }
110
111 static void *
112 get_membuf (struct membuf *mb, size_t *len)
113 {
114   char *p;
115
116   if (mb->out_of_core)
117     {
118       xfree (mb->buf);
119       mb->buf = NULL;
120       return NULL;
121     }
122
123   p = mb->buf;
124   *len = mb->len;
125   mb->buf = NULL;
126   mb->out_of_core = 1; /* don't allow a reuse */
127   return p;
128 }
129
130
131 \f
132 /* Try to connect to the agent via socket or fork it off and work by
133    pipes.  Handle the server's initial greeting */
134 static int
135 start_agent (void)
136 {
137   int rc;
138   char *infostr, *p;
139
140   if (agent_ctx)
141     return 0; /* fixme: We need a context for each thread or serialize
142                  the access to the agent (which is suitable given that
143                  the agent is not MT */
144
145   infostr = getenv ("GPG_AGENT_INFO");
146   if (!infostr)
147     {
148       const char *pgmname;
149       ASSUAN_CONTEXT ctx;
150       const char *argv[3];
151
152       log_info (_("no running gpg-agent - starting one\n"));
153       
154       if (fflush (NULL))
155         {
156           log_error ("error flushing pending output: %s\n", strerror (errno));
157           return seterr (Write_Error);
158         }
159
160       if (!opt.agent_program || !*opt.agent_program)
161         opt.agent_program = "../agent/gpg-agent";
162       if ( !(pgmname = strrchr (opt.agent_program, '/')))
163         pgmname = opt.agent_program;
164       else
165         pgmname++;
166
167       argv[0] = pgmname;
168       argv[1] = "--server";
169       argv[2] = NULL;
170
171       /* connect to the agent and perform initial handshaking */
172       rc = assuan_pipe_connect (&ctx, opt.agent_program, (char**)argv, 0);
173       if (rc)
174         {
175           log_error ("can't connect to the agent: %s\n", assuan_strerror (rc));
176           return seterr (No_Agent);
177         }
178       agent_ctx = ctx;
179     }
180   else
181     {
182       infostr = xstrdup (infostr);
183       if ( !(p = strchr (infostr, ':')) || p == infostr
184            /* || (p-infostr)+1 >= sizeof client_addr.sun_path */)
185         {
186           log_error (_("malformed GPG_AGENT_INFO environment variable\n"));
187           xfree (infostr);
188           return seterr (General_Error);
189         }
190       *p = 0;
191       log_error (_("socket based agent communication not yet implemented\n"));
192       return seterr (Not_Implemented);
193     }
194
195   log_debug ("connection to agent established\n");
196   return 0;
197 }
198
199
200 static AssuanError
201 membuf_data_cb (void *opaque, const void *buffer, size_t length)
202 {
203   struct membuf *data = opaque;
204
205   put_membuf (data, buffer, length);
206   return 0;
207 }
208   
209
210
211 \f
212 /* Call the agent to do a sign operation using the key identified by
213    the hex string KEYGRIP. */
214 int
215 gpgsm_agent_pksign (const char *keygrip,
216                     unsigned char *digest, size_t digestlen, int digestalgo,
217                     char **r_buf, size_t *r_buflen )
218 {
219   int rc, i;
220   char *p, line[ASSUAN_LINELENGTH];
221   struct membuf data;
222   size_t len;
223
224   *r_buf = NULL;
225   rc = start_agent ();
226   if (rc)
227     return rc;
228
229   if (digestlen*2 + 50 > DIM(line))
230     return seterr (General_Error);
231
232   rc = assuan_transact (agent_ctx, "RESET", NULL, NULL, NULL, NULL);
233   if (rc)
234     return map_assuan_err (rc);
235
236   snprintf (line, DIM(line)-1, "SIGKEY %s", keygrip);
237   line[DIM(line)-1] = 0;
238   rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL);
239   if (rc)
240     return map_assuan_err (rc);
241
242   sprintf (line, "SETHASH %d ", digestalgo);
243   p = line + strlen (line);
244   for (i=0; i < digestlen ; i++, p += 2 )
245     sprintf (p, "%02X", digest[i]);
246   rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL);
247   if (rc)
248     return map_assuan_err (rc);
249
250   init_membuf (&data, 1024);
251   rc = assuan_transact (agent_ctx, "PKSIGN",
252                         membuf_data_cb, &data, NULL, NULL);
253   if (rc)
254     {
255       xfree (get_membuf (&data, &len));
256       return map_assuan_err (rc);
257     }
258   *r_buf = get_membuf (&data, r_buflen);
259
260   /* FIXME: check that the returned S-Exp is valid! */
261
262   return *r_buf? 0 : GNUPG_Out_Of_Core;
263 }
264
265
266
267 \f
268 /* Handle a CIPHERTEXT inquiry.  Note, we only send the data,
269    assuan_transact talkes care of flushing and writing the end */
270 static AssuanError
271 inq_ciphertext_cb (void *opaque, const char *keyword)
272 {
273   struct cipher_parm_s *parm = opaque; 
274   AssuanError rc;
275
276   rc = assuan_send_data (parm->ctx, parm->ciphertext, parm->ciphertextlen);
277   return rc; 
278 }
279
280
281 /* Call the agent to do a decrypt operation using the key identified by
282    the hex string KEYGRIP. */
283 int
284 gpgsm_agent_pkdecrypt (const char *keygrip,
285                        KsbaConstSexp ciphertext, 
286                        char **r_buf, size_t *r_buflen )
287 {
288   int rc;
289   char line[ASSUAN_LINELENGTH];
290   struct membuf data;
291   struct cipher_parm_s cipher_parm;
292   size_t n, len;
293   char *buf, *endp;
294   size_t ciphertextlen;
295   
296   if (!keygrip || strlen(keygrip) != 40 || !ciphertext || !r_buf || !r_buflen)
297     return GNUPG_Invalid_Value;
298   *r_buf = NULL;
299
300   ciphertextlen = gcry_sexp_canon_len (ciphertext, 0, NULL, NULL);
301   if (!ciphertextlen)
302     return GNUPG_Invalid_Value;
303
304   rc = start_agent ();
305   if (rc)
306     return rc;
307
308   rc = assuan_transact (agent_ctx, "RESET", NULL, NULL, NULL, NULL);
309   if (rc)
310     return map_assuan_err (rc);
311
312   assert ( DIM(line) >= 50 );
313   snprintf (line, DIM(line)-1, "SETKEY %s", keygrip);
314   line[DIM(line)-1] = 0;
315   rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL);
316   if (rc)
317     return map_assuan_err (rc);
318
319   init_membuf (&data, 1024);
320   cipher_parm.ctx = agent_ctx;
321   cipher_parm.ciphertext = ciphertext;
322   cipher_parm.ciphertextlen = ciphertextlen;
323   rc = assuan_transact (agent_ctx, "PKDECRYPT",
324                         membuf_data_cb, &data,
325                         inq_ciphertext_cb, &cipher_parm);
326   if (rc)
327     {
328       xfree (get_membuf (&data, &len));
329       return map_assuan_err (rc);
330     }
331
332   put_membuf (&data, "", 1); /* make sure it is 0 terminated */
333   buf = get_membuf (&data, &len);
334   if (!buf)
335     return seterr (Out_Of_Core);
336   assert (len);
337   len--; /* remove the terminating 0 */
338   n = strtoul (buf, &endp, 10);
339   if (!n || *endp != ':')
340     return seterr (Invalid_Sexp);
341   endp++;
342   if (endp-buf+n > len)
343     return seterr (Invalid_Sexp); /* oops len does not match internal len*/
344   memmove (buf, endp, n);
345   *r_buflen = n;
346   *r_buf = buf;
347   return 0;
348 }
349
350
351
352
353 \f
354 /* Handle a KEYPARMS inquiry.  Note, we only send the data,
355    assuan_transact takes care of flushing and writing the end */
356 static AssuanError
357 inq_genkey_parms (void *opaque, const char *keyword)
358 {
359   struct genkey_parm_s *parm = opaque; 
360   AssuanError rc;
361
362   rc = assuan_send_data (parm->ctx, parm->sexp, parm->sexplen);
363   return rc; 
364 }
365
366
367 \f
368 /* Call the agent to generate a newkey */
369 int
370 gpgsm_agent_genkey (KsbaConstSexp keyparms, KsbaSexp *r_pubkey)
371 {
372   int rc;
373   struct genkey_parm_s gk_parm;
374   struct membuf data;
375   size_t len;
376   char *buf;
377
378   *r_pubkey = NULL;
379   rc = start_agent ();
380   if (rc)
381     return rc;
382
383   rc = assuan_transact (agent_ctx, "RESET", NULL, NULL, NULL, NULL);
384   if (rc)
385     return map_assuan_err (rc);
386
387   init_membuf (&data, 1024);
388   gk_parm.ctx = agent_ctx;
389   gk_parm.sexp = keyparms;
390   gk_parm.sexplen = gcry_sexp_canon_len (keyparms, 0, NULL, NULL);
391   if (!gk_parm.sexplen)
392     return GNUPG_Invalid_Value;
393   rc = assuan_transact (agent_ctx, "GENKEY",
394                         membuf_data_cb, &data, 
395                         inq_genkey_parms, &gk_parm);
396   if (rc)
397     {
398       xfree (get_membuf (&data, &len));
399       return map_assuan_err (rc);
400     }
401   buf = get_membuf (&data, &len);
402   if (!buf)
403     return GNUPG_Out_Of_Core;
404   if (!gcry_sexp_canon_len (buf, len, NULL, NULL))
405     {
406       xfree (buf);
407       return GNUPG_Invalid_Sexp;
408     }
409   *r_pubkey = buf;
410   return 0;
411 }
412
413
414