* keyring.c: Make some strings translatable.
[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 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   if (is_status_enabled())
632     write_status_text (STATUS_NEED_PASSPHRASE_PIN,
633                        isadmin? "OPENPGP 3" : "OPENPGP 1");
634
635   value = ask_passphrase (info, 
636                           isadmin? "passphrase.adminpin.ask"
637                                  : "passphrase.pin.ask", 
638                           isadmin?  _("Enter Admin PIN: ") : _("Enter PIN: "),
639                           &canceled);
640   if (!value && canceled)
641     return -1;
642   else if (!value)
643     return G10ERR_GENERAL;
644
645   *retstr = value;
646   return 0;
647 }
648
649
650
651 /* Send a SETATTR command to the SCdaemon. */
652 int 
653 agent_scd_setattr (const char *name,
654                    const unsigned char *value, size_t valuelen)
655 {
656   APP app;
657
658   app = current_app? current_app : open_card ();
659   if (!app)
660     return gpg_error (GPG_ERR_CARD);
661
662   return app->fnc.setattr (app, name, pin_cb, NULL, value, valuelen);
663 }
664
665
666 static int
667 genkey_status_cb (void *opaque, const char *line)
668 {
669   struct agent_card_genkey_s *parm = opaque;
670   const char *keyword = line;
671   int keywordlen;
672
673   log_debug ("got status line `%s'\n", line);
674   for (keywordlen=0; *line && !spacep (line); line++, keywordlen++)
675     ;
676   while (spacep (line))
677     line++;
678
679   if (keywordlen == 7 && !memcmp (keyword, "KEY-FPR", keywordlen))
680     {
681       parm->fprvalid = unhexify_fpr (line, parm->fpr);
682     }
683   if (keywordlen == 8 && !memcmp (keyword, "KEY-DATA", keywordlen))
684     {
685       MPI a;
686       const char *name = line;
687       char *buf;
688
689       while (*line && !spacep (line))
690         line++;
691       while (spacep (line))
692         line++;
693
694       buf = xmalloc ( 2 + strlen (line) + 1);
695       strcpy (stpcpy (buf, "0x"), line);
696       a = mpi_alloc (300);
697       if( mpi_fromstr (a, buf) )
698         log_error ("error parsing received key data\n");
699       else if (*name == 'n' && spacep (name+1))
700         parm->n = a;
701       else if (*name == 'e' && spacep (name+1))
702         parm->e = a;
703       else
704         {
705           log_info ("unknown parameter name in received key data\n");
706           mpi_free (a);
707         }
708       xfree (buf);
709     }
710   else if (keywordlen == 14 && !memcmp (keyword,"KEY-CREATED-AT", keywordlen))
711     {
712       parm->created_at = (u32)strtoul (line, NULL, 10);
713     }
714
715   return 0;
716 }
717
718 /* Send a GENKEY command to the SCdaemon. */
719 int 
720 agent_scd_genkey (struct agent_card_genkey_s *info, int keyno, int force)
721 {
722   APP app;
723   char keynostr[20];
724   struct ctrl_ctx_s ctrl;
725
726   app = current_app? current_app : open_card ();
727   if (!app)
728     return gpg_error (GPG_ERR_CARD);
729
730   memset (info, 0, sizeof *info);
731   sprintf (keynostr, "%d", keyno);
732   ctrl.status_cb = genkey_status_cb;
733   ctrl.status_cb_arg = info;
734
735   return app->fnc.genkey (app, &ctrl, keynostr,
736                            force? 1:0,
737                            pin_cb, NULL);
738 }
739
740 /* Send a PKSIGN command to the SCdaemon. */
741 int 
742 agent_scd_pksign (const char *serialno, int hashalgo,
743                   const unsigned char *indata, size_t indatalen,
744                   unsigned char **r_buf, size_t *r_buflen)
745 {
746   APP app;
747   int rc;
748
749   *r_buf = NULL;
750   *r_buflen = 0;
751  retry:
752   app = current_app? current_app : open_card ();
753   if (!app)
754     return gpg_error (GPG_ERR_CARD);
755
756   /* Check that the card's serialnumber is as required.*/
757   rc = check_card_serialno (app, serialno);
758   if (rc == -1)
759     goto retry;
760   if (rc)
761     return rc;
762
763   return app->fnc.sign (app, serialno, hashalgo,
764                         pin_cb, NULL,
765                         indata, indatalen,
766                         r_buf, r_buflen);
767 }
768
769
770 /* Send a PKDECRYPT command to the SCdaemon. */
771 int 
772 agent_scd_pkdecrypt (const char *serialno,
773                      const unsigned char *indata, size_t indatalen,
774                      unsigned char **r_buf, size_t *r_buflen)
775 {
776   APP app;
777   int rc;
778
779   *r_buf = NULL;
780   *r_buflen = 0;
781  retry:
782   app = current_app? current_app : open_card ();
783   if (!app)
784     return gpg_error (GPG_ERR_CARD);
785
786   /* Check that the card's serialnumber is as required.*/
787   rc = check_card_serialno (app, serialno);
788   if (rc == -1)
789     goto retry;
790   if (rc)
791     return rc;
792
793   return app->fnc.decipher (app, serialno, 
794                             pin_cb, NULL,
795                             indata, indatalen,
796                             r_buf, r_buflen);
797 }
798
799 /* Change the PIN of an OpenPGP card or reset the retry counter. */
800 int 
801 agent_scd_change_pin (int chvno)
802 {
803   APP app;
804   char chvnostr[20];
805   int reset = 0;
806
807   reset = (chvno >= 100);
808   chvno %= 100;
809
810   app = current_app? current_app : open_card ();
811   if (!app)
812     return gpg_error (GPG_ERR_CARD);
813
814   sprintf (chvnostr, "%d", chvno);
815   return app->fnc.change_pin (app, NULL, chvnostr, reset,
816                               pin_cb, NULL);
817 }
818
819 /* Perform a CHECKPIN operation.  SERIALNO should be the serial
820    number of the card - optionally followed by the fingerprint;
821    however the fingerprint is ignored here. */
822 int
823 agent_scd_checkpin (const char *serialnobuf)
824 {
825   APP app;
826
827   app = current_app? current_app : open_card ();
828   if (!app)
829     return gpg_error (GPG_ERR_CARD);
830
831   return app->fnc.check_pin (app, serialnobuf, pin_cb, NULL);
832 }
833
834
835 /* Wrapper to call the store key helper function of app-openpgp.c.  */
836 int 
837 agent_openpgp_storekey (int keyno,
838                         unsigned char *template, size_t template_len,
839                         time_t created_at,
840                         const unsigned char *m, size_t mlen,
841                         const unsigned char *e, size_t elen)
842 {
843   APP app;
844
845   app = current_app? current_app : open_card ();
846   if (!app)
847     return gpg_error (GPG_ERR_CARD);
848
849   return app_openpgp_storekey (app, keyno, template, template_len,
850                                created_at, m, mlen, e, elen,
851                                pin_cb, NULL);
852 }