Allow pkcs#10 creation directkly from a smart card
[gnupg.git] / sm / call-agent.c
1 /* call-agent.c - divert operations to the agent
2  *      Copyright (C) 2001, 2002, 2003, 2005 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
19  * USA.
20  */
21
22 #include <config.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <errno.h>
27 #include <unistd.h> 
28 #include <time.h>
29 #include <assert.h>
30 #ifdef HAVE_LOCALE_H
31 #include <locale.h>
32 #endif
33
34 #include "gpgsm.h"
35 #include <gcrypt.h>
36 #include <assuan.h>
37 #include "i18n.h"
38 #include "asshelp.h"
39 #include "keydb.h" /* fixme: Move this to import.c */
40 #include "../common/membuf.h"
41
42
43 static assuan_context_t agent_ctx = NULL;
44 static int force_pipe_server = 0;
45
46 struct cipher_parm_s
47 {
48   assuan_context_t ctx;
49   const unsigned char *ciphertext;
50   size_t ciphertextlen;
51 };
52
53 struct genkey_parm_s
54 {
55   assuan_context_t ctx;
56   const unsigned char *sexp;
57   size_t sexplen;
58 };
59
60 struct learn_parm_s
61 {
62   int error;
63   assuan_context_t ctx;
64   membuf_t *data;
65 };
66
67
68 \f
69 /* Try to connect to the agent via socket or fork it off and work by
70    pipes.  Handle the server's initial greeting */
71 static int
72 start_agent (ctrl_t ctrl)
73 {
74   int rc = 0;
75   char *infostr, *p;
76   assuan_context_t ctx;
77
78   if (agent_ctx)
79     return 0; /* fixme: We need a context for each thread or serialize
80                  the access to the agent (which is suitable given that
81                  the agent is not MT. */
82
83   infostr = force_pipe_server? NULL : getenv ("GPG_AGENT_INFO");
84   if (!infostr || !*infostr)
85     {
86       const char *pgmname;
87       const char *argv[3];
88       char *sockname;
89       int no_close_list[3];
90       int i;
91
92       /* First check whether we can connect at the standard
93          socket.  */
94       sockname = make_filename (opt.homedir, "S.gpg-agent", NULL);
95       rc = assuan_socket_connect (&ctx, sockname, 0);
96       xfree (sockname);
97
98       if (rc)
99         {
100           /* With no success start a new server.  */
101           if (opt.verbose)
102             log_info (_("no running gpg-agent - starting one\n"));
103           
104           gpgsm_status (ctrl, STATUS_PROGRESS, "starting_agent ? 0 0");
105           
106           if (fflush (NULL))
107             {
108               gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
109               log_error ("error flushing pending output: %s\n",
110                          strerror (errno));
111               return tmperr;
112             }
113           
114           if (!opt.agent_program || !*opt.agent_program)
115             opt.agent_program = GNUPG_DEFAULT_AGENT;
116           if ( !(pgmname = strrchr (opt.agent_program, '/')))
117             pgmname = opt.agent_program;
118           else
119             pgmname++;
120
121           argv[0] = pgmname;
122           argv[1] = "--server";
123           argv[2] = NULL;
124
125           i=0;
126           if (log_get_fd () != -1)
127             no_close_list[i++] = log_get_fd ();
128           no_close_list[i++] = fileno (stderr);
129           no_close_list[i] = -1;
130
131           /* Connect to the agent and perform initial handshaking. */
132           rc = assuan_pipe_connect (&ctx, opt.agent_program, argv,
133                                     no_close_list);
134         }
135     }
136   else
137     {
138       int prot;
139       int pid;
140
141       infostr = xstrdup (infostr);
142       if ( !(p = strchr (infostr, PATHSEP_C)) || p == infostr)
143         {
144           log_error (_("malformed GPG_AGENT_INFO environment variable\n"));
145           xfree (infostr);
146           force_pipe_server = 1;
147           return start_agent (ctrl);
148         }
149       *p++ = 0;
150       pid = atoi (p);
151       while (*p && *p != PATHSEP_C)
152         p++;
153       prot = *p? atoi (p+1) : 0;
154       if (prot != 1)
155         {
156           log_error (_("gpg-agent protocol version %d is not supported\n"),
157                      prot);
158           xfree (infostr);
159           force_pipe_server = 1;
160           return start_agent (ctrl);
161         }
162
163       rc = assuan_socket_connect (&ctx, infostr, pid);
164       xfree (infostr);
165       if (gpg_err_code (rc) == GPG_ERR_ASS_CONNECT_FAILED)
166         {
167           log_error (_("can't connect to the agent - trying fall back\n"));
168           force_pipe_server = 1;
169           return start_agent (ctrl);
170         }
171     }
172
173   if (rc)
174     {
175       log_error ("can't connect to the agent: %s\n", gpg_strerror (rc));
176       return gpg_error (GPG_ERR_NO_AGENT);
177     }
178   agent_ctx = ctx;
179
180   if (DBG_ASSUAN)
181     log_debug ("connection to agent established\n");
182
183   rc = assuan_transact (agent_ctx, "RESET", NULL, NULL, NULL, NULL, NULL, NULL);
184   if (rc)
185     return rc;
186
187   return send_pinentry_environment (agent_ctx, GPG_ERR_SOURCE_DEFAULT,
188                                     opt.display, opt.ttyname, opt.ttytype,
189                                     opt.lc_ctype, opt.lc_messages);
190 }
191
192
193 static int
194 membuf_data_cb (void *opaque, const void *buffer, size_t length)
195 {
196   membuf_t *data = opaque;
197
198   if (buffer)
199     put_membuf (data, buffer, length);
200   return 0;
201 }
202   
203
204
205 \f
206 /* Call the agent to do a sign operation using the key identified by
207    the hex string KEYGRIP. */
208 int
209 gpgsm_agent_pksign (ctrl_t ctrl, const char *keygrip, const char *desc,
210                     unsigned char *digest, size_t digestlen, int digestalgo,
211                     unsigned char **r_buf, size_t *r_buflen )
212 {
213   int rc, i;
214   char *p, line[ASSUAN_LINELENGTH];
215   membuf_t data;
216   size_t len;
217
218   *r_buf = NULL;
219   rc = start_agent (ctrl);
220   if (rc)
221     return rc;
222
223   if (digestlen*2 + 50 > DIM(line))
224     return gpg_error (GPG_ERR_GENERAL);
225
226   rc = assuan_transact (agent_ctx, "RESET", NULL, NULL, NULL, NULL, NULL, NULL);
227   if (rc)
228     return rc;
229
230   snprintf (line, DIM(line)-1, "SIGKEY %s", keygrip);
231   line[DIM(line)-1] = 0;
232   rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
233   if (rc)
234     return rc;
235
236   if (desc)
237     {
238       snprintf (line, DIM(line)-1, "SETKEYDESC %s", desc);
239       line[DIM(line)-1] = 0;
240       rc = assuan_transact (agent_ctx, line,
241                             NULL, NULL, NULL, NULL, NULL, NULL);
242       if (rc)
243         return rc;
244     }
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, NULL, NULL);
251   if (rc)
252     return rc;
253
254   init_membuf (&data, 1024);
255   rc = assuan_transact (agent_ctx, "PKSIGN",
256                         membuf_data_cb, &data, NULL, NULL, NULL, NULL);
257   if (rc)
258     {
259       xfree (get_membuf (&data, &len));
260       return rc;
261     }
262   *r_buf = get_membuf (&data, r_buflen);
263
264   if (!gcry_sexp_canon_len (*r_buf, *r_buflen, NULL, NULL))
265     {
266       xfree (*r_buf); *r_buf = NULL;
267       return gpg_error (GPG_ERR_INV_VALUE);
268     }
269
270   return *r_buf? 0 : out_of_core ();
271 }
272
273
274 /* Call the scdaemon to do a sign operation using the key identified by
275    the hex string KEYID. */
276 int
277 gpgsm_scd_pksign (ctrl_t ctrl, const char *keyid, const char *desc,
278                   unsigned char *digest, size_t digestlen, int digestalgo,
279                   unsigned char **r_buf, size_t *r_buflen )
280 {
281   int rc, i;
282   char *p, line[ASSUAN_LINELENGTH];
283   membuf_t data;
284   size_t len;
285   const char *hashopt;
286   unsigned char *sigbuf;
287   size_t sigbuflen;
288
289   *r_buf = NULL;
290
291   switch(digestalgo)
292     {
293     case GCRY_MD_SHA1:  hashopt = "--hash=sha1"; break;
294     case GCRY_MD_RMD160:hashopt = "--hash=rmd160"; break;
295     case GCRY_MD_MD5:   hashopt = "--hash=md5"; break;
296     case GCRY_MD_SHA256:hashopt = "--hash=sha256"; break;
297     default: 
298       return gpg_error (GPG_ERR_DIGEST_ALGO);
299     }
300
301   rc = start_agent (ctrl);
302   if (rc)
303     return rc;
304
305   if (digestlen*2 + 50 > DIM(line))
306     return gpg_error (GPG_ERR_GENERAL);
307
308   p = stpcpy (line, "SCD SETDATA " );
309   for (i=0; i < digestlen ; i++, p += 2 )
310     sprintf (p, "%02X", digest[i]);
311   rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
312   if (rc)
313     return rc;
314
315   init_membuf (&data, 1024);
316
317   snprintf (line, DIM(line)-1, "SCD PKSIGN %s %s", hashopt, keyid);
318   line[DIM(line)-1] = 0;
319   rc = assuan_transact (agent_ctx, line,
320                         membuf_data_cb, &data, NULL, NULL, NULL, NULL);
321   if (rc)
322     {
323       xfree (get_membuf (&data, &len));
324       return rc;
325     }
326   sigbuf = get_membuf (&data, &sigbuflen);
327
328   /* Create an S-expression from it which is formatted like this:
329      "(7:sig-val(3:rsa(1:sSIGBUFLEN:SIGBUF)))" Fixme: If a card ever
330      creates non-RSA keys we need to change things. */
331   *r_buflen = 21 + 11 + sigbuflen + 4;
332   p = xtrymalloc (*r_buflen);
333   *r_buf = (unsigned char*)p;
334   if (!p)
335     {
336       xfree (sigbuf);
337       return 0;
338     }
339   p = stpcpy (p, "(7:sig-val(3:rsa(1:s" );
340   sprintf (p, "%u:", (unsigned int)sigbuflen);
341   p += strlen (p);
342   memcpy (p, sigbuf, sigbuflen);
343   p += sigbuflen;
344   strcpy (p, ")))");
345   xfree (sigbuf);
346
347   assert (gcry_sexp_canon_len (*r_buf, *r_buflen, NULL, NULL));
348   return  0;
349 }
350
351
352
353 \f
354 /* Handle a CIPHERTEXT inquiry.  Note, we only send the data,
355    assuan_transact talkes care of flushing and writing the end */
356 static int
357 inq_ciphertext_cb (void *opaque, const char *keyword)
358 {
359   struct cipher_parm_s *parm = opaque; 
360   int rc;
361
362   assuan_begin_confidential (parm->ctx);
363   rc = assuan_send_data (parm->ctx, parm->ciphertext, parm->ciphertextlen);
364   assuan_end_confidential (parm->ctx);
365   return rc; 
366 }
367
368
369 /* Call the agent to do a decrypt operation using the key identified by
370    the hex string KEYGRIP. */
371 int
372 gpgsm_agent_pkdecrypt (ctrl_t ctrl, const char *keygrip, const char *desc,
373                        ksba_const_sexp_t ciphertext, 
374                        char **r_buf, size_t *r_buflen )
375 {
376   int rc;
377   char line[ASSUAN_LINELENGTH];
378   membuf_t data;
379   struct cipher_parm_s cipher_parm;
380   size_t n, len;
381   char *p, *buf, *endp;
382   size_t ciphertextlen;
383   
384   if (!keygrip || strlen(keygrip) != 40 || !ciphertext || !r_buf || !r_buflen)
385     return gpg_error (GPG_ERR_INV_VALUE);
386   *r_buf = NULL;
387
388   ciphertextlen = gcry_sexp_canon_len (ciphertext, 0, NULL, NULL);
389   if (!ciphertextlen)
390     return gpg_error (GPG_ERR_INV_VALUE);
391
392   rc = start_agent (ctrl);
393   if (rc)
394     return rc;
395
396   rc = assuan_transact (agent_ctx, "RESET", NULL, NULL, NULL, NULL, NULL, NULL);
397   if (rc)
398     return rc;
399
400   assert ( DIM(line) >= 50 );
401   snprintf (line, DIM(line)-1, "SETKEY %s", keygrip);
402   line[DIM(line)-1] = 0;
403   rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
404   if (rc)
405     return rc;
406
407   if (desc)
408     {
409       snprintf (line, DIM(line)-1, "SETKEYDESC %s", desc);
410       line[DIM(line)-1] = 0;
411       rc = assuan_transact (agent_ctx, line,
412                             NULL, NULL, NULL, NULL, NULL, NULL);
413       if (rc)
414         return rc;
415     }
416
417   init_membuf (&data, 1024);
418   cipher_parm.ctx = agent_ctx;
419   cipher_parm.ciphertext = ciphertext;
420   cipher_parm.ciphertextlen = ciphertextlen;
421   rc = assuan_transact (agent_ctx, "PKDECRYPT",
422                         membuf_data_cb, &data,
423                         inq_ciphertext_cb, &cipher_parm, NULL, NULL);
424   if (rc)
425     {
426       xfree (get_membuf (&data, &len));
427       return rc;
428     }
429
430   put_membuf (&data, "", 1); /* Make sure it is 0 terminated. */
431   buf = get_membuf (&data, &len);
432   if (!buf)
433     return gpg_error (GPG_ERR_ENOMEM);
434   assert (len); /* (we forced Nul termination.)  */
435
436   if (*buf == '(')
437     {
438       if (len < 13 || memcmp (buf, "(5:value", 8) ) /* "(5:valueN:D)\0" */
439         return gpg_error (GPG_ERR_INV_SEXP);
440       len -= 11;   /* Count only the data of the second part. */
441       p = buf + 8; /* Skip leading parenthesis and the value tag. */
442     }
443   else
444     {
445       /* For compatibility with older gpg-agents handle the old style
446          incomplete S-exps. */
447       len--;      /* Do not count the Nul. */
448       p = buf;
449     }
450
451   n = strtoul (p, &endp, 10);
452   if (!n || *endp != ':')
453     return gpg_error (GPG_ERR_INV_SEXP);
454   endp++;
455   if (endp-p+n > len)
456     return gpg_error (GPG_ERR_INV_SEXP); /* Oops: Inconsistent S-Exp. */
457   
458   memmove (buf, endp, n);
459
460   *r_buflen = n;
461   *r_buf = buf;
462   return 0;
463 }
464
465
466
467
468 \f
469 /* Handle a KEYPARMS inquiry.  Note, we only send the data,
470    assuan_transact takes care of flushing and writing the end */
471 static int
472 inq_genkey_parms (void *opaque, const char *keyword)
473 {
474   struct genkey_parm_s *parm = opaque; 
475   int rc;
476
477   rc = assuan_send_data (parm->ctx, parm->sexp, parm->sexplen);
478   return rc; 
479 }
480
481
482 \f
483 /* Call the agent to generate a newkey */
484 int
485 gpgsm_agent_genkey (ctrl_t ctrl,
486                     ksba_const_sexp_t keyparms, ksba_sexp_t *r_pubkey)
487 {
488   int rc;
489   struct genkey_parm_s gk_parm;
490   membuf_t data;
491   size_t len;
492   unsigned char *buf;
493
494   *r_pubkey = NULL;
495   rc = start_agent (ctrl);
496   if (rc)
497     return rc;
498
499   rc = assuan_transact (agent_ctx, "RESET", NULL, NULL, NULL, NULL, NULL, NULL);
500   if (rc)
501     return rc;
502
503   init_membuf (&data, 1024);
504   gk_parm.ctx = agent_ctx;
505   gk_parm.sexp = keyparms;
506   gk_parm.sexplen = gcry_sexp_canon_len (keyparms, 0, NULL, NULL);
507   if (!gk_parm.sexplen)
508     return gpg_error (GPG_ERR_INV_VALUE);
509   rc = assuan_transact (agent_ctx, "GENKEY",
510                         membuf_data_cb, &data, 
511                         inq_genkey_parms, &gk_parm, NULL, NULL);
512   if (rc)
513     {
514       xfree (get_membuf (&data, &len));
515       return rc;
516     }
517   buf = get_membuf (&data, &len);
518   if (!buf)
519     return gpg_error (GPG_ERR_ENOMEM);
520   if (!gcry_sexp_canon_len (buf, len, NULL, NULL))
521     {
522       xfree (buf);
523       return gpg_error (GPG_ERR_INV_SEXP);
524     }
525   *r_pubkey = buf;
526   return 0;
527 }
528
529 \f
530 /* Call the agent to read the public key part for a given keygrip.  If
531    FROMCARD is true, the key is directly read from the current
532    smartcard. In this case HEXKEYGRIP should be the keyID
533    (e.g. OPENPGP.3). */
534 int
535 gpgsm_agent_readkey (ctrl_t ctrl, int fromcard, const char *hexkeygrip,
536                      ksba_sexp_t *r_pubkey)
537 {
538   int rc;
539   membuf_t data;
540   size_t len;
541   unsigned char *buf;
542   char line[ASSUAN_LINELENGTH];
543
544   *r_pubkey = NULL;
545   rc = start_agent (ctrl);
546   if (rc)
547     return rc;
548
549   rc = assuan_transact (agent_ctx, "RESET",NULL, NULL, NULL, NULL, NULL, NULL);
550   if (rc)
551     return rc;
552
553   snprintf (line, DIM(line)-1, "%sREADKEY %s",
554             fromcard? "SCD ":"", hexkeygrip);
555   line[DIM(line)-1] = 0;
556
557   init_membuf (&data, 1024);
558   rc = assuan_transact (agent_ctx, line,
559                         membuf_data_cb, &data, 
560                         NULL, NULL, NULL, NULL);
561   if (rc)
562     {
563       xfree (get_membuf (&data, &len));
564       return rc;
565     }
566   buf = get_membuf (&data, &len);
567   if (!buf)
568     return gpg_error (GPG_ERR_ENOMEM);
569   if (!gcry_sexp_canon_len (buf, len, NULL, NULL))
570     {
571       xfree (buf);
572       return gpg_error (GPG_ERR_INV_SEXP);
573     }
574   *r_pubkey = buf;
575   return 0;
576 }
577
578 \f
579
580 static int
581 istrusted_status_cb (void *opaque, const char *line)
582 {
583   struct rootca_flags_s *flags = opaque;
584
585   if (!strncmp (line, "TRUSTLISTFLAG", 13) && (line[13]==' ' || !line[13]))
586     {
587       for (line += 13; *line == ' '; line++)
588         ;
589       if (!strncmp (line, "relax", 5) && (line[5] == ' ' || !line[5]))
590         flags->relax = 1;
591     }
592   return 0;
593 }
594
595
596
597 /* Ask the agent whether the certificate is in the list of trusted
598    keys.  ROOTCA_FLAGS is guaranteed to be cleared on error. */
599 int
600 gpgsm_agent_istrusted (ctrl_t ctrl, ksba_cert_t cert,
601                        struct rootca_flags_s *rootca_flags)
602 {
603   int rc;
604   char *fpr;
605   char line[ASSUAN_LINELENGTH];
606
607   memset (rootca_flags, 0, sizeof *rootca_flags);
608
609   rc = start_agent (ctrl);
610   if (rc)
611     return rc;
612
613   fpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
614   if (!fpr)
615     {
616       log_error ("error getting the fingerprint\n");
617       return gpg_error (GPG_ERR_GENERAL);
618     }
619
620   snprintf (line, DIM(line)-1, "ISTRUSTED %s", fpr);
621   line[DIM(line)-1] = 0;
622   xfree (fpr);
623
624   rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL,
625                         istrusted_status_cb, rootca_flags);
626   return rc;
627 }
628
629 /* Ask the agent to mark CERT as a trusted Root-CA one */
630 int
631 gpgsm_agent_marktrusted (ctrl_t ctrl, ksba_cert_t cert)
632 {
633   int rc;
634   char *fpr, *dn;
635   char line[ASSUAN_LINELENGTH];
636
637   rc = start_agent (ctrl);
638   if (rc)
639     return rc;
640
641   fpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
642   if (!fpr)
643     {
644       log_error ("error getting the fingerprint\n");
645       return gpg_error (GPG_ERR_GENERAL);
646     }
647
648   dn = ksba_cert_get_issuer (cert, 0);
649   if (!dn)
650     {
651       xfree (fpr);
652       return gpg_error (GPG_ERR_GENERAL);
653     }
654   snprintf (line, DIM(line)-1, "MARKTRUSTED %s S %s", fpr, dn);
655   line[DIM(line)-1] = 0;
656   ksba_free (dn);
657   xfree (fpr);
658
659   rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
660   return rc;
661 }
662
663
664 \f
665 /* Ask the agent whether the a corresponding secret key is available
666    for the given keygrip */
667 int
668 gpgsm_agent_havekey (ctrl_t ctrl, const char *hexkeygrip)
669 {
670   int rc;
671   char line[ASSUAN_LINELENGTH];
672
673   rc = start_agent (ctrl);
674   if (rc)
675     return rc;
676
677   if (!hexkeygrip || strlen (hexkeygrip) != 40)
678     return gpg_error (GPG_ERR_INV_VALUE);
679
680   snprintf (line, DIM(line)-1, "HAVEKEY %s", hexkeygrip);
681   line[DIM(line)-1] = 0;
682
683   rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
684   return rc;
685 }
686
687 \f
688 static int
689 learn_cb (void *opaque, const void *buffer, size_t length)
690 {
691   struct learn_parm_s *parm = opaque;
692   size_t len;
693   char *buf;
694   ksba_cert_t cert;
695   int rc;
696
697   if (parm->error)
698     return 0;
699
700   if (buffer)
701     {
702       put_membuf (parm->data, buffer, length);
703       return 0;
704     }
705   /* END encountered - process what we have */
706   buf = get_membuf (parm->data, &len);
707   if (!buf)
708     {
709       parm->error = gpg_error (GPG_ERR_ENOMEM);
710       return 0;
711     }
712
713
714   /* FIXME: this should go into import.c */
715   rc = ksba_cert_new (&cert);
716   if (rc)
717     {
718       parm->error = rc;
719       return 0;
720     }
721   rc = ksba_cert_init_from_mem (cert, buf, len);
722   if (rc)
723     {
724       log_error ("failed to parse a certificate: %s\n", gpg_strerror (rc));
725       ksba_cert_release (cert);
726       parm->error = rc;
727       return 0;
728     }
729
730   rc = gpgsm_basic_cert_check (cert);
731   if (gpg_err_code (rc) == GPG_ERR_MISSING_CERT)
732     { /* For later use we store it in the ephemeral database. */
733       log_info ("issuer certificate missing - storing as ephemeral\n");
734       keydb_store_cert (cert, 1, NULL);
735     }
736   else if (rc)
737     log_error ("invalid certificate: %s\n", gpg_strerror (rc));
738   else
739     {
740       int existed;
741
742       if (!keydb_store_cert (cert, 0, &existed))
743         {
744           if (opt.verbose > 1 && existed)
745             log_info ("certificate already in DB\n");
746           else if (opt.verbose && !existed)
747             log_info ("certificate imported\n");
748         }
749     }
750
751   ksba_cert_release (cert);
752   init_membuf (parm->data, 4096);
753   return 0;
754 }
755   
756 /* Call the agent to learn about a smartcard */
757 int
758 gpgsm_agent_learn (ctrl_t ctrl)
759 {
760   int rc;
761   struct learn_parm_s learn_parm;
762   membuf_t data;
763   size_t len;
764
765   rc = start_agent (ctrl);
766   if (rc)
767     return rc;
768
769   init_membuf (&data, 4096);
770   learn_parm.error = 0;
771   learn_parm.ctx = agent_ctx;
772   learn_parm.data = &data;
773   rc = assuan_transact (agent_ctx, "LEARN --send",
774                         learn_cb, &learn_parm, 
775                         NULL, NULL, NULL, NULL);
776   xfree (get_membuf (&data, &len));
777   if (rc)
778     return rc;
779   return learn_parm.error;
780 }
781
782 \f
783 /* Ask the agent to change the passphrase of the key identified by
784    HEXKEYGRIP. If DESC is not NULL, display instead of the default
785    description message. */
786 int
787 gpgsm_agent_passwd (ctrl_t ctrl, const char *hexkeygrip, const char *desc)
788 {
789   int rc;
790   char line[ASSUAN_LINELENGTH];
791
792   rc = start_agent (ctrl);
793   if (rc)
794     return rc;
795
796   if (!hexkeygrip || strlen (hexkeygrip) != 40)
797     return gpg_error (GPG_ERR_INV_VALUE);
798
799   if (desc)
800     {
801       snprintf (line, DIM(line)-1, "SETKEYDESC %s", desc);
802       line[DIM(line)-1] = 0;
803       rc = assuan_transact (agent_ctx, line,
804                             NULL, NULL, NULL, NULL, NULL, NULL);
805       if (rc)
806         return rc;
807     }
808
809   snprintf (line, DIM(line)-1, "PASSWD %s", hexkeygrip);
810   line[DIM(line)-1] = 0;
811
812   rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
813   return rc;
814 }
815
816
817 \f
818 /* Ask the agent to pop up a confirmation dialog with the text DESC
819    and an okay and cancel button.  */
820 gpg_error_t
821 gpgsm_agent_get_confirmation (ctrl_t ctrl, const char *desc)
822 {
823   int rc;
824   char line[ASSUAN_LINELENGTH];
825
826   rc = start_agent (ctrl);
827   if (rc)
828     return rc;
829
830   snprintf (line, DIM(line)-1, "GET_CONFIRMATION %s", desc);
831   line[DIM(line)-1] = 0;
832
833   rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
834   return rc;
835 }