* gpg.sgml: Document "addcardkey" and "keytocard".
[gnupg.git] / g10 / cardglue.c
1 /* cardglue.c - mainly dispatcher for card related functions.
2  * Copyright (C) 2003, 2004 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 #ifndef ENABLE_CARD_SUPPORT
23 #error  not configured for card support.
24 #endif
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <errno.h>
29 #include <stdarg.h>
30 #include <assert.h>
31
32 #include "options.h"
33 #include "packet.h"
34 #include "errors.h"
35 #include "memory.h"
36 #include "util.h"
37 #include "main.h"
38 #include "status.h"
39 #include "ttyio.h"
40 #include "i18n.h"
41
42 #include "cardglue.h"
43 #include "apdu.h"
44 #include "app-common.h"
45
46 struct ctrl_ctx_s {
47   int (*status_cb)(void *opaque, const char *line);
48   void *status_cb_arg;
49 };
50
51
52 static char *default_reader_port;
53 static APP current_app;
54
55
56
57 /* Create a serialno/fpr string from the serial number and the secret
58    key.  caller must free the returned string.  There is no error
59    return. [Taken from 1.9's keyid.c]*/
60 char *
61 serialno_and_fpr_from_sk (const unsigned char *sn, size_t snlen,
62                           PKT_secret_key *sk)
63 {
64   unsigned char fpr[MAX_FINGERPRINT_LEN];
65   size_t fprlen;
66   char *buffer, *p;
67   int i;
68   
69   fingerprint_from_sk (sk, fpr, &fprlen);
70   buffer = p = xmalloc (snlen*2 + 1 + fprlen*2 + 1);
71   for (i=0; i < snlen; i++, p+=2)
72     sprintf (p, "%02X", sn[i]);
73   *p++ = '/';
74   for (i=0; i < fprlen; i++, p+=2)
75     sprintf (p, "%02X", fpr[i]);
76   *p = 0;
77   return buffer;
78 }
79
80
81 /* Send a line with status information via assuan and escape all given
82    buffers. The variable elements are pairs of (char *, size_t),
83    terminated with a (NULL, 0). */
84 void
85 send_status_info (CTRL ctrl, const char *keyword, ...)
86 {
87   va_list arg_ptr;
88   const unsigned char *value;
89   size_t valuelen;
90   char buf[950], *p;
91   size_t n;
92   
93   va_start (arg_ptr, keyword);
94
95   p = buf; 
96   n = 0;
97   valuelen = strlen (keyword);
98   for ( ; valuelen && n < DIM (buf)-2; n++, valuelen--, keyword++)
99     *p++ = *keyword;
100
101   while ( (value = va_arg (arg_ptr, const unsigned char *)) )
102     {
103       valuelen = va_arg (arg_ptr, size_t);
104       if (!valuelen)
105         continue; /* empty buffer */
106       if (n)
107         {
108           *p++ = ' ';
109           n++;
110         }
111       for ( ; valuelen && n < DIM (buf)-2; n++, valuelen--, value++)
112         {
113           if (*value < ' ' || *value == '+')
114             {
115               sprintf (p, "%%%02X", *value);
116               p += 3;
117             }
118           else if (*value == ' ')
119             *p++ = '+';
120           else
121             *p++ = *value;
122         }
123     }
124   *p = 0;
125   ctrl->status_cb (ctrl->status_cb_arg, buf);
126
127   va_end (arg_ptr);
128 }
129
130
131 void gcry_md_hash_buffer (int algo, void *digest,
132                           const void *buffer, size_t length)
133 {
134   MD_HANDLE h = md_open (algo, 0);
135   if (!h)
136     BUG();
137   md_write (h, (byte *) buffer, length);
138   md_final (h);
139   memcpy (digest, md_read (h, algo), md_digest_length (algo));
140   md_close (h);
141 }
142
143
144 /* This is a limited version of the one in 1.9 but it should be
145    sufficient here. */
146 void
147 log_printf (const char *fmt, ...)
148 {
149   va_list arg_ptr;
150
151   va_start (arg_ptr, fmt);
152   vfprintf (log_stream (), fmt, arg_ptr);
153   va_end (arg_ptr);
154 }
155
156
157
158 /* Print a hexdump of BUFFER.  With TEXT of NULL print just the raw
159    dump, with TEXT just an empty string, print a trailing linefeed,
160    otherwise print an entire debug line. */
161 void
162 log_printhex (const char *text, const void *buffer, size_t length)
163 {
164   if (text && *text)
165     log_debug ("%s ", text);
166   if (length)
167     {
168       const unsigned char *p = buffer;
169       log_printf ("%02X", *p);
170       for (length--, p++; length--; p++)
171         log_printf (" %02X", *p);
172     }
173   if (text)
174     log_printf ("\n");
175 }
176
177
178
179 void
180 app_set_default_reader_port (const char *portstr)
181 {
182   xfree (default_reader_port);
183   default_reader_port = portstr? xstrdup (portstr): NULL;
184 }
185
186
187 void
188 card_set_reader_port (const char *portstr)
189 {
190   app_set_default_reader_port (portstr);
191 }
192
193
194 /* Retrieve the serial number and the time of the last update of the
195    card.  The serial number is returned as a malloced string (hex
196    encoded) in SERIAL and the time of update is returned in STAMP.  If
197    no update time is available the returned value is 0.  Caller must
198    free SERIAL unless the function returns an error. */
199 int 
200 app_get_serial_and_stamp (APP app, char **serial, time_t *stamp)
201 {
202   unsigned char *buf, *p;
203   int i;
204
205   if (!app || !serial || !stamp)
206     return gpg_error (GPG_ERR_INV_VALUE);
207
208   *serial = NULL;
209   *stamp = 0; /* not available */
210
211   buf = xtrymalloc (app->serialnolen * 2 + 1);
212   if (!buf)
213     return gpg_error_from_errno (errno);
214   for (p=buf, i=0; i < app->serialnolen; p +=2, i++)
215     sprintf (p, "%02X", app->serialno[i]);
216   *p = 0;
217   *serial = buf;
218   return 0;
219 }
220
221
222
223
224
225
226 /* Release the card info structure. */
227 void 
228 agent_release_card_info (struct agent_card_info_s *info)
229 {
230   if (!info)
231     return;
232
233   xfree (info->serialno); info->serialno = NULL;
234   xfree (info->disp_name); info->disp_name = NULL;
235   xfree (info->disp_lang); info->disp_lang = NULL;
236   xfree (info->pubkey_url); info->pubkey_url = NULL;
237   xfree (info->login_data); info->login_data = NULL;
238   info->fpr1valid = info->fpr2valid = info->fpr3valid = 0;
239   info->cafpr1valid = info->cafpr2valid = info->cafpr3valid = 0;
240 }
241
242
243 /* Open the current card and select the openpgp application.  Return
244    an APP context handle to be used for further procesing or NULL on
245    error or if no OpenPGP application exists.*/
246 static APP
247 open_card (void)
248 {
249   int slot = -1;
250   int rc;
251   APP app;
252   int did_shutdown = 0;
253
254   card_close ();
255
256   
257  retry:
258   if (did_shutdown)
259     apdu_reset (slot);
260   else
261     {
262       slot = apdu_open_reader (default_reader_port);
263       if (slot == -1)
264         {
265           log_error ("card reader not available\n");
266           return NULL;
267         }
268     }
269
270   app = xcalloc (1, sizeof *app);
271   app->slot = slot;
272   rc = app_select_openpgp (app);
273   if (rc && !opt.batch)
274     {
275       write_status_text (STATUS_CARDCTRL, "1");
276       
277       did_shutdown = !!apdu_shutdown_reader (slot);
278
279       if ( cpr_get_answer_okay_cancel ("cardctrl.insert_card.okay",
280            _("Please insert the card and hit return or enter 'c' to cancel: "),
281                                        1) )
282         {
283           if (!did_shutdown)
284             apdu_close_reader (slot);
285           xfree (app);
286           goto retry;
287         }
288     }
289   if (rc)
290     {
291       log_info ("selecting openpgp failed: %s\n", gpg_strerror (rc));
292       apdu_close_reader (slot);
293       xfree (app);
294       return NULL;
295     }
296
297   app->initialized = 1;
298   current_app = app;
299   if (is_status_enabled () )
300     {
301       int i;
302       char *p, *buf;
303
304       buf = xmalloc (5 + app->serialnolen * 2 + 1);
305       p = stpcpy (buf, "3 ");
306       for (i=0; i < app->serialnolen; p +=2, i++)
307         sprintf (p, "%02X", app->serialno[i]);
308       write_status_text (STATUS_CARDCTRL, buf);
309       xfree (buf);
310     }
311
312   return app;
313 }
314
315 void
316 card_close (void)
317 {
318   if (current_app)
319     {
320       APP app = current_app;
321       current_app = NULL;
322
323       apdu_close_reader (app->slot);
324       xfree (app);
325     }
326 }
327
328
329 /* Check that the serial number of the current card (as described by
330    APP) matches SERIALNO.  If there is no match and we are not in
331    batch mode, present a prompt to insert the desired card.  The
332    function return 0 is the present card is okay, -1 if the user
333    selected to insert a new card or an error value.  Note that the
334    card context will be closed in all cases except for 0 as return
335    value and if it was possible to merely shutdown the reader. */
336 static int
337 check_card_serialno (APP app, const char *serialno)
338 {
339   const char *s;
340   int ask = 0;
341   int n;
342   
343   for (s = serialno, n=0; *s != '/' && hexdigitp (s); s++, n++)
344     ;
345   if (n != 32)
346     {
347       log_error ("invalid serial number in keyring detected\n");
348       return gpg_error (GPG_ERR_INV_ID);
349     }
350   if (app->serialnolen != 16)
351     ask = 1;
352   for (s = serialno, n=0; !ask && n < 16; s += 2, n++)
353     if (app->serialno[n] != xtoi_2 (s))
354       ask = 1;
355   if (ask)
356     {
357       char buf[5+32+1];
358       int did_shutdown = 0;
359
360       if (current_app && !apdu_shutdown_reader (current_app->slot))
361         did_shutdown = 1;
362       else
363         card_close ();
364       tty_printf (_("Please remove the current card and "
365                     "insert the one with the serial number:\n"
366                     "   %.*s\n"), 32, serialno);
367
368       sprintf (buf, "1 %.32s", serialno);
369       write_status_text (STATUS_CARDCTRL, buf);
370
371       if ( cpr_get_answer_okay_cancel ("cardctrl.change_card.okay",
372                           _("Hit return when ready "
373                             "or enter 'c' to cancel: "),
374                                        1) )
375         {
376           card_close ();
377           return -1;
378         }
379       if (did_shutdown)
380         apdu_reset (current_app->slot);
381       else
382         card_close ();
383       return gpg_error (GPG_ERR_INV_ID);
384     }
385   return 0;
386 }
387
388
389
390 /* Return a new malloced string by unescaping the string S.  Escaping
391    is percent escaping and '+'/space mapping.  A binary nul will
392    silently be replaced by a 0xFF.  Function returns NULL to indicate
393    an out of memory status. */
394 static char *
395 unescape_status_string (const unsigned char *s)
396 {
397   char *buffer, *d;
398
399   buffer = d = xmalloc (strlen (s)+1);
400   while (*s)
401     {
402       if (*s == '%' && s[1] && s[2])
403         { 
404           s++;
405           *d = xtoi_2 (s);
406           if (!*d)
407             *d = '\xff';
408           d++;
409           s += 2;
410         }
411       else if (*s == '+')
412         {
413           *d++ = ' ';
414           s++;
415         }
416       else
417         *d++ = *s++;
418     }
419   *d = 0; 
420   return buffer;
421 }
422
423 /* Take a 20 byte hexencoded string and put it into the the provided
424    20 byte buffer FPR in binary format. */
425 static int
426 unhexify_fpr (const char *hexstr, unsigned char *fpr)
427 {
428   const char *s;
429   int n;
430
431   for (s=hexstr, n=0; hexdigitp (s); s++, n++)
432     ;
433   if (*s || (n != 40))
434     return 0; /* no fingerprint (invalid or wrong length). */
435   n /= 2;
436   for (s=hexstr, n=0; *s; s += 2, n++)
437     fpr[n] = xtoi_2 (s);
438   return 1; /* okay */
439 }
440
441 /* Take the serial number from LINE and return it verbatim in a newly
442    allocated string.  We make sure that only hex characters are
443    returned. */
444 static char *
445 store_serialno (const char *line)
446 {
447   const char *s;
448   char *p;
449
450   for (s=line; hexdigitp (s); s++)
451     ;
452   p = xmalloc (s + 1 - line);
453   memcpy (p, line, s-line);
454   p[s-line] = 0;
455   return p;
456 }
457
458
459
460 static int
461 learn_status_cb (void *opaque, const char *line)
462 {
463   struct agent_card_info_s *parm = opaque;
464   const char *keyword = line;
465   int keywordlen;
466   int i;
467
468   for (keywordlen=0; *line && !spacep (line); line++, keywordlen++)
469     ;
470   while (spacep (line))
471     line++;
472
473   if (keywordlen == 8 && !memcmp (keyword, "SERIALNO", keywordlen))
474     {
475       xfree (parm->serialno);
476       parm->serialno = store_serialno (line);
477     }
478   else if (keywordlen == 9 && !memcmp (keyword, "DISP-NAME", keywordlen))
479     {
480       xfree (parm->disp_name);
481       parm->disp_name = unescape_status_string (line);
482     }
483   else if (keywordlen == 9 && !memcmp (keyword, "DISP-LANG", keywordlen))
484     {
485       xfree (parm->disp_lang);
486       parm->disp_lang = unescape_status_string (line);
487     }
488   else if (keywordlen == 8 && !memcmp (keyword, "DISP-SEX", keywordlen))
489     {
490       parm->disp_sex = *line == '1'? 1 : *line == '2' ? 2: 0;
491     }
492   else if (keywordlen == 10 && !memcmp (keyword, "PUBKEY-URL", keywordlen))
493     {
494       xfree (parm->pubkey_url);
495       parm->pubkey_url = unescape_status_string (line);
496     }
497   else if (keywordlen == 10 && !memcmp (keyword, "LOGIN-DATA", keywordlen))
498     {
499       xfree (parm->login_data);
500       parm->login_data = unescape_status_string (line);
501     }
502   else if (keywordlen == 11 && !memcmp (keyword, "SIG-COUNTER", keywordlen))
503     {
504       parm->sig_counter = strtoul (line, NULL, 0);
505     }
506   else if (keywordlen == 10 && !memcmp (keyword, "CHV-STATUS", keywordlen))
507     {
508       char *p, *buf;
509
510       buf = p = unescape_status_string (line);
511       if (buf)
512         {
513           while (spacep (p))
514             p++;
515           parm->chv1_cached = atoi (p);
516           while (*p && !spacep (p))
517             p++;
518           while (spacep (p))
519             p++;
520           for (i=0; *p && i < 3; i++)
521             {
522               parm->chvmaxlen[i] = atoi (p);
523               while (*p && !spacep (p))
524                 p++;
525               while (spacep (p))
526                 p++;
527             }
528           for (i=0; *p && i < 3; i++)
529             {
530               parm->chvretry[i] = atoi (p);
531               while (*p && !spacep (p))
532                 p++;
533               while (spacep (p))
534                 p++;
535             }
536           xfree (buf);
537         }
538     }
539   else if (keywordlen == 7 && !memcmp (keyword, "KEY-FPR", keywordlen))
540     {
541       int no = atoi (line);
542       while (* line && !spacep (line))
543         line++;
544       while (spacep (line))
545         line++;
546       if (no == 1)
547         parm->fpr1valid = unhexify_fpr (line, parm->fpr1);
548       else if (no == 2)
549         parm->fpr2valid = unhexify_fpr (line, parm->fpr2);
550       else if (no == 3)
551         parm->fpr3valid = unhexify_fpr (line, parm->fpr3);
552     }
553   else if (keywordlen == 6 && !memcmp (keyword, "CA-FPR", keywordlen))
554     {
555       int no = atoi (line);
556       while (*line && !spacep (line))
557         line++;
558       while (spacep (line))
559         line++;
560       if (no == 1)
561         parm->cafpr1valid = unhexify_fpr (line, parm->cafpr1);
562       else if (no == 2)
563         parm->cafpr2valid = unhexify_fpr (line, parm->cafpr2);
564       else if (no == 3)
565         parm->cafpr3valid = unhexify_fpr (line, parm->cafpr3);
566     }
567
568   return 0;
569 }
570
571
572 /* Return card info. */
573 int 
574 agent_learn (struct agent_card_info_s *info)
575 {
576   APP app;
577   int rc;
578   struct ctrl_ctx_s ctrl;
579   time_t stamp;
580   char *serial;
581   
582   app = current_app? current_app : open_card ();
583   if (!app)
584     return gpg_error (GPG_ERR_CARD);
585
586   memset (info, 0, sizeof *info);
587   memset (&ctrl, 0, sizeof ctrl);
588   ctrl.status_cb = learn_status_cb;
589   ctrl.status_cb_arg = info;
590
591   rc = app_get_serial_and_stamp (app, &serial, &stamp);
592   if (!rc)
593     {
594       send_status_info (&ctrl, "SERIALNO", serial, strlen(serial), NULL, 0);
595       xfree (serial);
596       rc = app->fnc.learn_status (app, &ctrl);
597     }
598
599   return rc;
600 }
601
602 /* Get an attribite from the card. Make sure info is initialized. */
603 int 
604 agent_scd_getattr (const char *name, struct agent_card_info_s *info)
605 {
606   APP app;
607   struct ctrl_ctx_s ctrl;
608
609   app = current_app? current_app : open_card ();
610   if (!app)
611     return gpg_error (GPG_ERR_CARD);
612
613   ctrl.status_cb = learn_status_cb;
614   ctrl.status_cb_arg = info;
615   return app->fnc.getattr (app, &ctrl, name);
616 }
617
618
619
620 static int 
621 pin_cb (void *opaque, const char *info, char **retstr)
622 {
623   char *value;
624   int canceled;
625   int isadmin = (info && strstr (info, "dmin"));
626
627
628   *retstr = NULL;
629   log_debug ("asking for PIN '%s'\n", info);
630
631   value = ask_passphrase (info, 
632                           isadmin? "passphrase.adminpin.ask"
633                                  : "passphrase.pin.ask", 
634                           isadmin?  _("Enter Admin PIN: ") : _("Enter PIN: "),
635                           &canceled);
636   if (!value && canceled)
637     return -1;
638   else if (!value)
639     return G10ERR_GENERAL;
640
641   *retstr = value;
642   return 0;
643 }
644
645
646
647 /* Send a SETATTR command to the SCdaemon. */
648 int 
649 agent_scd_setattr (const char *name,
650                    const unsigned char *value, size_t valuelen)
651 {
652   APP app;
653
654   app = current_app? current_app : open_card ();
655   if (!app)
656     return gpg_error (GPG_ERR_CARD);
657
658   return app->fnc.setattr (app, name, pin_cb, NULL, value, valuelen);
659 }
660
661
662 static int
663 genkey_status_cb (void *opaque, const char *line)
664 {
665   struct agent_card_genkey_s *parm = opaque;
666   const char *keyword = line;
667   int keywordlen;
668
669   log_debug ("got status line `%s'\n", line);
670   for (keywordlen=0; *line && !spacep (line); line++, keywordlen++)
671     ;
672   while (spacep (line))
673     line++;
674
675   if (keywordlen == 7 && !memcmp (keyword, "KEY-FPR", keywordlen))
676     {
677       parm->fprvalid = unhexify_fpr (line, parm->fpr);
678     }
679   if (keywordlen == 8 && !memcmp (keyword, "KEY-DATA", keywordlen))
680     {
681       MPI a;
682       const char *name = line;
683       char *buf;
684
685       while (*line && !spacep (line))
686         line++;
687       while (spacep (line))
688         line++;
689
690       buf = xmalloc ( 2 + strlen (line) + 1);
691       strcpy (stpcpy (buf, "0x"), line);
692       a = mpi_alloc (300);
693       if( mpi_fromstr (a, buf) )
694         log_error ("error parsing received key data\n");
695       else if (*name == 'n' && spacep (name+1))
696         parm->n = a;
697       else if (*name == 'e' && spacep (name+1))
698         parm->e = a;
699       else
700         {
701           log_info ("unknown parameter name in received key data\n");
702           mpi_free (a);
703         }
704       xfree (buf);
705     }
706   else if (keywordlen == 14 && !memcmp (keyword,"KEY-CREATED-AT", keywordlen))
707     {
708       parm->created_at = (u32)strtoul (line, NULL, 10);
709     }
710
711   return 0;
712 }
713
714 /* Send a GENKEY command to the SCdaemon. */
715 int 
716 agent_scd_genkey (struct agent_card_genkey_s *info, int keyno, int force)
717 {
718   APP app;
719   char keynostr[20];
720   struct ctrl_ctx_s ctrl;
721
722   app = current_app? current_app : open_card ();
723   if (!app)
724     return gpg_error (GPG_ERR_CARD);
725
726   memset (info, 0, sizeof *info);
727   sprintf (keynostr, "%d", keyno);
728   ctrl.status_cb = genkey_status_cb;
729   ctrl.status_cb_arg = info;
730
731   return app->fnc.genkey (app, &ctrl, keynostr,
732                            force? 1:0,
733                            pin_cb, NULL);
734 }
735
736 /* Send a PKSIGN command to the SCdaemon. */
737 int 
738 agent_scd_pksign (const char *serialno, int hashalgo,
739                   const unsigned char *indata, size_t indatalen,
740                   unsigned char **r_buf, size_t *r_buflen)
741 {
742   APP app;
743   int rc;
744
745   *r_buf = NULL;
746   *r_buflen = 0;
747  retry:
748   app = current_app? current_app : open_card ();
749   if (!app)
750     return gpg_error (GPG_ERR_CARD);
751
752   /* Check that the card's serialnumber is as required.*/
753   rc = check_card_serialno (app, serialno);
754   if (rc == -1)
755     goto retry;
756   if (rc)
757     return rc;
758
759   return app->fnc.sign (app, serialno, hashalgo,
760                         pin_cb, NULL,
761                         indata, indatalen,
762                         r_buf, r_buflen);
763 }
764
765
766 /* Send a PKDECRYPT command to the SCdaemon. */
767 int 
768 agent_scd_pkdecrypt (const char *serialno,
769                      const unsigned char *indata, size_t indatalen,
770                      unsigned char **r_buf, size_t *r_buflen)
771 {
772   APP app;
773   int rc;
774
775   *r_buf = NULL;
776   *r_buflen = 0;
777  retry:
778   app = current_app? current_app : open_card ();
779   if (!app)
780     return gpg_error (GPG_ERR_CARD);
781
782   /* Check that the card's serialnumber is as required.*/
783   rc = check_card_serialno (app, serialno);
784   if (rc == -1)
785     goto retry;
786   if (rc)
787     return rc;
788
789   return app->fnc.decipher (app, serialno, 
790                             pin_cb, NULL,
791                             indata, indatalen,
792                             r_buf, r_buflen);
793 }
794
795 /* Change the PIN of an OpenPGP card or reset the retry counter. */
796 int 
797 agent_scd_change_pin (int chvno)
798 {
799   APP app;
800   char chvnostr[20];
801   int reset = 0;
802
803   reset = (chvno >= 100);
804   chvno %= 100;
805
806   app = current_app? current_app : open_card ();
807   if (!app)
808     return gpg_error (GPG_ERR_CARD);
809
810   sprintf (chvnostr, "%d", chvno);
811   return app->fnc.change_pin (app, NULL, chvnostr, reset,
812                               pin_cb, NULL);
813 }
814
815 /* Perform a CHECKPIN operation.  SERIALNO should be the serial
816    number of the card - optionally followed by the fingerprint;
817    however the fingerprint is ignored here. */
818 int
819 agent_scd_checkpin (const char *serialnobuf)
820 {
821   APP app;
822
823   app = current_app? current_app : open_card ();
824   if (!app)
825     return gpg_error (GPG_ERR_CARD);
826
827   return app->fnc.check_pin (app, serialnobuf, pin_cb, NULL);
828 }
829
830
831 /* Wrapper to call the store key helper function of app-openpgp.c.  */
832 int 
833 agent_openpgp_storekey (int keyno,
834                         unsigned char *template, size_t template_len,
835                         time_t created_at,
836                         const unsigned char *m, size_t mlen,
837                         const unsigned char *e, size_t elen)
838 {
839   APP app;
840
841   app = current_app? current_app : open_card ();
842   if (!app)
843     return gpg_error (GPG_ERR_CARD);
844
845   return app_openpgp_storekey (app, keyno, template, template_len,
846                                created_at, m, mlen, e, elen,
847                                pin_cb, NULL);
848 }