1 /* call-scd.c - fork of the scdaemon to do SC operations
2 * Copyright (C) 2001, 2002 Free Software Foundation, Inc.
4 * This file is part of GnuPG.
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.
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.
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
32 #include "../assuan/assuan.h"
34 #ifdef _POSIX_OPEN_MAX
35 #define MAX_OPEN_FDS _POSIX_OPEN_MAX
37 #define MAX_OPEN_FDS 20
40 static ASSUAN_CONTEXT scd_ctx = NULL;
42 /* callback parameter for learn card */
44 void (*kpinfo_cb)(void*, const char *);
48 struct inq_needpin_s {
50 int (*getpin_cb)(void *, const char *, char*, size_t);
63 /* A simple implemnation of a dynamic buffer. Use init_membuf() to
64 create a buffer, put_membuf to append bytes and get_membuf to
65 release and return the buffer. Allocation errors are detected but
66 only returned at the final get_membuf(), this helps not to clutter
67 the code with out of core checks. */
70 init_membuf (struct membuf *mb, int initiallen)
73 mb->size = initiallen;
75 mb->buf = xtrymalloc (initiallen);
81 put_membuf (struct membuf *mb, const void *buf, size_t len)
86 if (mb->len + len >= mb->size)
90 mb->size += len + 1024;
91 p = xtryrealloc (mb->buf, mb->size);
99 memcpy (mb->buf + mb->len, buf, len);
104 get_membuf (struct membuf *mb, size_t *len)
118 mb->out_of_core = 1; /* don't allow a reuse */
125 /* Fork off the SCdaemon if this has not already been done */
135 return 0; /* No need to serialize things because the agent is
136 expected to tun as a single-thread (or may be in
137 future using libpth) */
139 log_debug ("no running SCdaemon - starting it\n");
143 log_error ("error flushing pending output: %s\n", strerror (errno));
144 return seterr (Write_Error);
147 /* FIXME: change the default location of the program */
148 if (!opt.scdaemon_program || !*opt.scdaemon_program)
149 opt.scdaemon_program = "../scd/scdaemon";
150 if ( !(pgmname = strrchr (opt.scdaemon_program, '/')))
151 pgmname = opt.scdaemon_program;
156 argv[1] = "--server";
159 /* connect to the pinentry and perform initial handshaking */
160 rc = assuan_pipe_connect (&ctx, opt.scdaemon_program, (char**)argv, 0);
163 log_error ("can't connect to the SCdaemon: %s\n",
164 assuan_strerror (rc));
165 return seterr (No_Scdaemon);
169 log_debug ("connection to SCdaemon established\n");
176 learn_status_cb (void *opaque, const char *line)
178 struct learn_parm_s *parm = opaque;
179 const char *keyword = line;
182 for (keywordlen=0; *line && !spacep (line); line++, keywordlen++)
184 while (spacep (line))
186 if (keywordlen == 11 && !memcmp (keyword, "KEYPAIRINFO", keywordlen))
188 parm->kpinfo_cb (parm->kpinfo_cb_arg, line);
190 else if (keywordlen == 8 && !memcmp (keyword, "SERIALNO", keywordlen))
192 log_debug ("learn_status_cb: serialno `%s'\n", line);
195 log_debug ("learn_status_cb: ignoring `%.*s'\n", keywordlen, keyword);
200 /* Perform the learn command and return a list of all private keys
201 stored on the card. */
203 agent_card_learn (void (*kpinfo_cb)(void*, const char *), void *kpinfo_cb_arg)
206 struct learn_parm_s parm;
212 memset (&parm, 0, sizeof parm);
213 parm.kpinfo_cb = kpinfo_cb;
214 parm.kpinfo_cb_arg = kpinfo_cb_arg;
215 rc = assuan_transact (scd_ctx, "LEARN --force",
216 NULL, NULL, NULL, NULL,
217 learn_status_cb, &parm);
219 return map_assuan_err (rc);
227 get_serialno_cb (void *opaque, const char *line)
229 char **serialno = opaque;
230 const char *keyword = line;
234 for (keywordlen=0; *line && !spacep (line); line++, keywordlen++)
236 while (spacep (line))
239 if (keywordlen == 8 && !memcmp (keyword, "SERIALNO", keywordlen))
242 return ASSUAN_Unexpected_Status;
243 for (n=0,s=line; hexdigitp (s); s++, n++)
245 if (!n || (n&1)|| !(spacep (s) || !*s) )
246 return ASSUAN_Invalid_Status;
247 *serialno = xtrymalloc (n+1);
249 return ASSUAN_Out_Of_Core;
250 memcpy (*serialno, line, n);
257 /* Return the serial number of the card or an appropriate error. The
258 serial number is returned as a hexstring. */
260 agent_card_serialno (char **r_serialno)
263 char *serialno = NULL;
269 /* Hmm, do we really need this reset - scddaemon should do this or
270 we can do this if we for some reason figure out that the
271 operation might have failed due to a missing RESET. Hmmm, I feel
272 this is really SCdaemon's duty */
273 rc = assuan_transact (scd_ctx, "RESET", NULL, NULL, NULL, NULL, NULL, NULL);
275 return map_assuan_err (rc);
277 rc = assuan_transact (scd_ctx, "SERIALNO",
278 NULL, NULL, NULL, NULL,
279 get_serialno_cb, &serialno);
283 return map_assuan_err (rc);
285 *r_serialno = serialno;
291 membuf_data_cb (void *opaque, const void *buffer, size_t length)
293 struct membuf *data = opaque;
296 put_membuf (data, buffer, length);
300 /* Handle the NEEDPIN inquiry. */
302 inq_needpin (void *opaque, const char *line)
304 struct inq_needpin_s *parm = opaque;
309 if (!(!strncmp (line, "NEEDPIN", 7) && (line[7] == ' ' || !line[7])))
311 log_error ("unsupported inquiry `%s'\n", line);
312 return ASSUAN_Inquire_Unknown;
317 pin = gcry_malloc_secure (pinlen);
319 return ASSUAN_Out_Of_Core;
321 rc = parm->getpin_cb (parm->getpin_cb_arg, line, pin, pinlen);
323 rc = ASSUAN_Canceled;
325 rc = assuan_send_data (parm->ctx, pin, pinlen);
333 /* Create a signature using the current card */
335 agent_card_pksign (const char *keyid,
336 int (*getpin_cb)(void *, const char *, char*, size_t),
338 const unsigned char *indata, size_t indatalen,
339 char **r_buf, size_t *r_buflen)
342 char *p, line[ASSUAN_LINELENGTH];
344 struct inq_needpin_s inqparm;
346 unsigned char *sigbuf;
354 if (indatalen*2 + 50 > DIM(line))
355 return seterr (General_Error);
357 sprintf (line, "SETDATA ");
358 p = line + strlen (line);
359 for (i=0; i < indatalen ; i++, p += 2 )
360 sprintf (p, "%02X", indata[i]);
361 rc = assuan_transact (scd_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
363 return map_assuan_err (rc);
365 init_membuf (&data, 1024);
366 inqparm.ctx = scd_ctx;
367 inqparm.getpin_cb = getpin_cb;
368 inqparm.getpin_cb_arg = getpin_cb_arg;
369 snprintf (line, DIM(line)-1, "PKSIGN %s", keyid);
370 line[DIM(line)-1] = 0;
371 rc = assuan_transact (scd_ctx, line,
372 membuf_data_cb, &data,
373 inq_needpin, &inqparm,
377 xfree (get_membuf (&data, &len));
378 return map_assuan_err (rc);
380 sigbuf = get_membuf (&data, &sigbuflen);
382 /* create an S-expression from it which is formatted like this:
383 "(7:sig-val(3:rsa(1:sSIGBUFLEN:SIGBUF)))" */
384 *r_buflen = 21 + 11 + sigbuflen + 4;
385 *r_buf = xtrymalloc (*r_buflen);
389 return GNUPG_Out_Of_Core;
391 p = stpcpy (*r_buf, "(7:sig-val(3:rsa(1:s" );
392 sprintf (p, "%u:", (unsigned int)sigbuflen);
394 memcpy (p, sigbuf, sigbuflen);
399 assert (gcry_sexp_canon_len (*r_buf, *r_buflen, NULL, NULL));
403 /* Decipher INDATA using the current card. Note that the returned value is */
405 agent_card_pkdecrypt (const char *keyid,
406 int (*getpin_cb)(void *, const char *, char*, size_t),
408 const unsigned char *indata, size_t indatalen,
409 char **r_buf, size_t *r_buflen)
412 char *p, line[ASSUAN_LINELENGTH];
414 struct inq_needpin_s inqparm;
422 /* FIXME: use secure memory where appropriate */
423 if (indatalen*2 + 50 > DIM(line))
424 return seterr (General_Error);
426 sprintf (line, "SETDATA ");
427 p = line + strlen (line);
428 for (i=0; i < indatalen ; i++, p += 2 )
429 sprintf (p, "%02X", indata[i]);
430 rc = assuan_transact (scd_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
432 return map_assuan_err (rc);
434 init_membuf (&data, 1024);
435 inqparm.ctx = scd_ctx;
436 inqparm.getpin_cb = getpin_cb;
437 inqparm.getpin_cb_arg = getpin_cb_arg;
438 snprintf (line, DIM(line)-1, "PKDECRYPT %s", keyid);
439 line[DIM(line)-1] = 0;
440 rc = assuan_transact (scd_ctx, line,
441 membuf_data_cb, &data,
442 inq_needpin, &inqparm,
446 xfree (get_membuf (&data, &len));
447 return map_assuan_err (rc);
449 *r_buf = get_membuf (&data, r_buflen);
451 return GNUPG_Out_Of_Core;
458 /* Read a certificate with ID into R_BUF and R_BUFLEN. */
460 agent_card_readcert (const char *id, char **r_buf, size_t *r_buflen)
463 char line[ASSUAN_LINELENGTH];
472 init_membuf (&data, 1024);
473 snprintf (line, DIM(line)-1, "READCERT %s", id);
474 line[DIM(line)-1] = 0;
475 rc = assuan_transact (scd_ctx, line,
476 membuf_data_cb, &data,
481 xfree (get_membuf (&data, &len));
482 return map_assuan_err (rc);
484 *r_buf = get_membuf (&data, r_buflen);
486 return GNUPG_Out_Of_Core;
493 /* Read a key with ID and return it in an allocate buffer pointed to
494 by r_BUF as a valid S-expression. */
496 agent_card_readkey (const char *id, unsigned char **r_buf)
499 char line[ASSUAN_LINELENGTH];
508 init_membuf (&data, 1024);
509 snprintf (line, DIM(line)-1, "READKEY %s", id);
510 line[DIM(line)-1] = 0;
511 rc = assuan_transact (scd_ctx, line,
512 membuf_data_cb, &data,
517 xfree (get_membuf (&data, &len));
518 return map_assuan_err (rc);
520 *r_buf = get_membuf (&data, &buflen);
522 return GNUPG_Out_Of_Core;
524 if (!gcry_sexp_canon_len (*r_buf, buflen, NULL, NULL))
526 xfree (*r_buf); *r_buf = NULL;
527 return GNUPG_Invalid_Value;