2006-04-14 Marcus Brinkmann <marcus@g10code.de>
[gnupg.git] / scd / app.c
1 /* app.c - Application selection.
2  *      Copyright (C) 2003, 2004, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #include <config.h>
22 #include <errno.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 # include <pth.h>
27
28 #include "scdaemon.h"
29 #include "app-common.h"
30 #include "apdu.h"
31 #include "iso7816.h"
32 #include "tlv.h"
33
34 /* This table is used to keep track of locks on a per reader base.
35    The index into the table is the slot number of the reader.  The
36    mutex will be initialized on demand (one of the advantages of a
37    userland threading system). */
38 static struct
39 {
40   int initialized;
41   pth_mutex_t lock;
42   app_t app;        /* Application context in use or NULL. */
43   app_t last_app;   /* Last application object used as this slot or NULL. */
44 } lock_table[10];
45
46
47
48 static void deallocate_app (app_t app);
49
50
51 \f
52 /* Lock the reader SLOT.  This function shall be used right before
53    calling any of the actual application functions to serialize access
54    to the reader.  We do this always even if the reader is not
55    actually used.  This allows an actual connection to assume that it
56    never shares a reader (while performing one command).  Returns 0 on
57    success; only then the unlock_reader function must be called after
58    returning from the handler. */
59 static gpg_error_t 
60 lock_reader (int slot)
61 {
62   gpg_error_t err;
63
64   if (slot < 0 || slot >= DIM (lock_table))
65     return gpg_error (slot<0? GPG_ERR_INV_VALUE : GPG_ERR_RESOURCE_LIMIT);
66
67   if (!lock_table[slot].initialized)
68     {
69       if (!pth_mutex_init (&lock_table[slot].lock))
70         {
71           err = gpg_error_from_errno (errno);
72           log_error ("error initializing mutex: %s\n", strerror (errno));
73           return err;
74         }
75       lock_table[slot].initialized = 1;
76       lock_table[slot].app = NULL;
77       lock_table[slot].last_app = NULL;
78     }
79   
80   if (!pth_mutex_acquire (&lock_table[slot].lock, 0, NULL))
81     {
82       err = gpg_error_from_errno (errno);
83       log_error ("failed to acquire APP lock for slot %d: %s\n",
84                  slot, strerror (errno));
85       return err;
86     }
87
88   return 0;
89 }
90
91 /* Release a lock on the reader.  See lock_reader(). */
92 static void
93 unlock_reader (int slot)
94 {
95   if (slot < 0 || slot >= DIM (lock_table)
96       || !lock_table[slot].initialized)
97     log_bug ("unlock_reader called for invalid slot %d\n", slot);
98
99   if (!pth_mutex_release (&lock_table[slot].lock))
100     log_error ("failed to release APP lock for slot %d: %s\n",
101                slot, strerror (errno));
102
103 }
104
105
106 static void
107 dump_mutex_state (pth_mutex_t *m)
108 {
109   if (!(m->mx_state & PTH_MUTEX_INITIALIZED))
110     log_printf ("not_initialized");
111   else if (!(m->mx_state & PTH_MUTEX_LOCKED))
112     log_printf ("not_locked");
113   else
114     log_printf ("locked tid=0x%lx count=%lu", (long)m->mx_owner, m->mx_count);
115 }
116
117
118 /* This function may be called to print information pertaining to the
119    current state of this module to the log. */
120 void
121 app_dump_state (void)
122 {
123   int slot;
124
125   for (slot=0; slot < DIM (lock_table); slot++)
126     if (lock_table[slot].initialized)
127       {
128         log_info ("app_dump_state: slot=%d lock=", slot);
129         dump_mutex_state (&lock_table[slot].lock);
130         if (lock_table[slot].app)
131           {
132             log_printf (" app=%p", lock_table[slot].app);
133             if (lock_table[slot].app->apptype)
134               log_printf (" type=`%s'", lock_table[slot].app->apptype);
135           }
136         if (lock_table[slot].last_app)
137           {
138             log_printf (" lastapp=%p", lock_table[slot].last_app);
139             if (lock_table[slot].last_app->apptype)
140               log_printf (" type=`%s'", lock_table[slot].last_app->apptype);
141           }
142         log_printf ("\n");
143       }
144 }
145
146 /* Check wether the application NAME is allowed.  This does not mean
147    we have support for it though.  */
148 static int
149 is_app_allowed (const char *name)
150 {
151   strlist_t l;
152
153   for (l=opt.disabled_applications; l; l = l->next)
154     if (!strcmp (l->d, name))
155       return 0; /* no */
156   return 1; /* yes */
157 }
158
159
160 /* This may be called to tell this module about a removed card. */
161 void
162 application_notify_card_removed (int slot)
163 {
164   app_t app;
165
166   if (slot < 0 || slot >= DIM (lock_table))
167     return;
168
169   /* FIXME: We are ignoring any error value here.  */
170   lock_reader (slot); 
171
172   /* Deallocate a saved application for that slot, so that we won't
173      try to reuse it.  If there is no saved application, set a flag so
174      that we won't save the current state. */
175   app = lock_table[slot].last_app;
176
177   if (app)
178     {
179       lock_table[slot].last_app = NULL;
180       deallocate_app (app);
181     }
182   unlock_reader (slot); 
183 }
184
185  
186 /* This fucntion is used by the serialno command to check for an
187    application conflict which may appear if the serialno command is
188    used to request a specific application and the connection has
189    already done a select_application. */
190 gpg_error_t
191 check_application_conflict (ctrl_t ctrl, const char *name)
192 {
193   int slot = ctrl->reader_slot;
194   app_t app;
195
196   if (slot < 0 || slot >= DIM (lock_table))
197     return gpg_error (GPG_ERR_INV_VALUE);
198
199   app = lock_table[slot].initialized ? lock_table[slot].app : NULL;
200   if (app && app->apptype && name)
201     if ( ascii_strcasecmp (app->apptype, name))
202         return gpg_error (GPG_ERR_CONFLICT);
203   return 0;
204 }
205
206
207 /* If called with NAME as NULL, select the best fitting application
208    and return a context; otherwise select the application with NAME
209    and return a context.  SLOT identifies the reader device. Returns
210    an error code and stores NULL at R_APP if no application was found
211    or no card is present. */
212 gpg_error_t
213 select_application (ctrl_t ctrl, int slot, const char *name, app_t *r_app)
214 {
215   gpg_error_t err;
216   app_t app = NULL;
217   unsigned char *result = NULL;
218   size_t resultlen;
219
220   *r_app = NULL;
221
222   err = lock_reader (slot);
223   if (err)
224     return err;
225
226   /* First check whether we already have an application to share. */
227   app = lock_table[slot].initialized ? lock_table[slot].app : NULL;
228   if (app && name)
229     if (!app->apptype || ascii_strcasecmp (app->apptype, name))
230       {
231         unlock_reader (slot);
232         if (app->apptype)
233           log_info ("application `%s' in use by reader %d - can't switch\n",
234                     app->apptype, slot);
235         return gpg_error (GPG_ERR_CONFLICT);
236       }
237
238   /* If we don't have an app, check whether we have a saved
239      application for that slot.  This is useful so that a card does
240      not get reset even if only one session is using the card - so the
241      PIN cache and other cached data are preserved. */
242   if (!app && lock_table[slot].initialized && lock_table[slot].last_app)
243     {
244       app = lock_table[slot].last_app;
245       if (!name || (app->apptype && !ascii_strcasecmp (app->apptype, name)) )
246         {
247           /* Yes, we can reuse this application - either the caller
248              requested an unspecific one or the requested one matches
249              the saved one. */
250           lock_table[slot].app = app;
251           lock_table[slot].last_app = NULL;
252         }
253       else 
254         {
255           /* No, this saved application can't be used - deallocate it. */
256           lock_table[slot].last_app = NULL;
257           deallocate_app (app);
258           app = NULL;
259         }
260     }
261
262   /* If we can reuse an application, bump the reference count and
263      return it.  */
264   if (app)
265     {
266       if (app->slot != slot)
267         log_bug ("slot mismatch %d/%d\n", app->slot, slot);
268       app->slot = slot;
269
270       app->ref_count++;
271       *r_app = app;
272       unlock_reader (slot);
273       return 0; /* Okay: We share that one. */
274     }
275
276   /* Need to allocate a new one.  */
277   app = xtrycalloc (1, sizeof *app);
278   if (!app)
279     {
280       err = gpg_error_from_errno (errno);
281       log_info ("error allocating context: %s\n", gpg_strerror (err));
282       unlock_reader (slot);
283       return err;
284     }
285   app->slot = slot;
286
287
288   /* Fixme: We should now first check whether a card is at all
289      present. */
290
291   /* Try to read the GDO file first to get a default serial number. */
292   err = iso7816_select_file (slot, 0x3F00, 1, NULL, NULL);
293   if (!err)
294     err = iso7816_select_file (slot, 0x2F02, 0, NULL, NULL);
295   if (!err)
296      err = iso7816_read_binary (slot, 0, 0, &result, &resultlen);
297   if (!err)
298     {
299       size_t n;
300       const unsigned char *p;
301
302       p = find_tlv_unchecked (result, resultlen, 0x5A, &n);
303       if (p)
304         resultlen -= (p-result);
305       if (p && n > resultlen && n == 0x0d && resultlen+1 == n)
306         {
307           /* The object it does not fit into the buffer.  This is an
308              invalid encoding (or the buffer is too short.  However, I
309              have some test cards with such an invalid encoding and
310              therefore I use this ugly workaround to return something
311              I can further experiment with. */
312           log_info ("enabling BMI testcard workaround\n");
313           n--;
314         }
315
316       if (p && n <= resultlen)
317         {
318           /* The GDO file is pretty short, thus we simply reuse it for
319              storing the serial number. */
320           memmove (result, p, n);
321           app->serialno = result;
322           app->serialnolen = n;
323           err = app_munge_serialno (app);
324           if (err)
325             goto leave;
326         }
327       else
328         xfree (result);
329       result = NULL;
330     }
331
332   /* For certain error codes, there is no need to try more.  */
333   if (gpg_err_code (err) == GPG_ERR_CARD_NOT_PRESENT)
334     goto leave;
335   
336
337   /* Figure out the application to use.  */
338   err = gpg_error (GPG_ERR_NOT_FOUND);
339
340   if (err && is_app_allowed ("openpgp")
341           && (!name || !strcmp (name, "openpgp")))
342     err = app_select_openpgp (app);
343   if (err && is_app_allowed ("nks") && (!name || !strcmp (name, "nks")))
344     err = app_select_nks (app);
345   if (err && is_app_allowed ("p15") && (!name || !strcmp (name, "p15")))
346     err = app_select_p15 (app);
347   if (err && is_app_allowed ("dinsig") && (!name || !strcmp (name, "dinsig")))
348     err = app_select_dinsig (app);
349   if (err && name)
350     err = gpg_error (GPG_ERR_NOT_SUPPORTED);
351
352  leave:
353   if (err)
354     {
355       if (name)
356         log_info ("can't select application `%s': %s\n",
357                   name, gpg_strerror (err));
358       else
359         log_info ("no supported card application found: %s\n",
360                   gpg_strerror (err));
361       xfree (app);
362       unlock_reader (slot);
363       return err;
364     }
365
366   app->initialized = 1;
367   app->ref_count = 1;
368   lock_table[slot].app = app;
369   *r_app = app;
370   unlock_reader (slot);
371   return 0;
372 }
373
374
375 /* Deallocate the application. */
376 static void
377 deallocate_app (app_t app)
378 {
379   if (app->fnc.deinit)
380     {
381       app->fnc.deinit (app);
382       app->fnc.deinit = NULL;
383     }
384
385   xfree (app->serialno);
386   xfree (app);
387 }
388
389 /* Free the resources associated with the application APP.  APP is
390    allowed to be NULL in which case this is a no-op.  Note that we are
391    using reference counting to track the users of the application and
392    actually deferring the deallocation to allow for a later reuse by
393    a new connection. */
394 void
395 release_application (app_t app)
396 {
397   int slot;
398
399   if (!app)
400     return;
401
402   if (app->ref_count < 1)
403     log_bug ("trying to release an already released context\n");
404   if (--app->ref_count)
405     return;
406
407   /* Move the reference to the application in the lock table. */
408   slot = app->slot;
409   /* FIXME: We are ignoring any error value.  */
410   lock_reader (slot);
411   if (lock_table[slot].app != app)
412     {
413       unlock_reader (slot);
414       log_bug ("app mismatch %p/%p\n", app, lock_table[slot].app);
415       deallocate_app (app);
416       return;
417     }
418
419   if (lock_table[slot].last_app)
420     deallocate_app (lock_table[slot].last_app);
421   lock_table[slot].last_app = lock_table[slot].app;
422   lock_table[slot].app = NULL;
423   unlock_reader (slot);
424 }
425
426
427
428 /* The serial number may need some cosmetics.  Do it here.  This
429    function shall only be called once after a new serial number has
430    been put into APP->serialno. 
431
432    Prefixes we use:
433    
434      FF 00 00 = For serial numbers starting with an FF
435      FF 01 00 = Some german p15 cards return an empty serial number so the
436                 serial number from the EF(TokenInfo) is used instead.
437      
438      All other serial number not starting with FF are used as they are.
439 */
440 gpg_error_t
441 app_munge_serialno (app_t app)
442 {
443   if (app->serialnolen && app->serialno[0] == 0xff)
444     { 
445       /* The serial number starts with our special prefix.  This
446          requires that we put our default prefix "FF0000" in front. */
447       unsigned char *p = xtrymalloc (app->serialnolen + 3);
448       if (!p)
449         return gpg_error (gpg_err_code_from_errno (errno));
450       memcpy (p, "\xff\0", 3);
451       memcpy (p+3, app->serialno, app->serialnolen);
452       app->serialnolen += 3;
453       xfree (app->serialno);
454       app->serialno = p;
455     }
456   return 0;
457 }
458
459
460
461 /* Retrieve the serial number and the time of the last update of the
462    card.  The serial number is returned as a malloced string (hex
463    encoded) in SERIAL and the time of update is returned in STAMP.  If
464    no update time is available the returned value is 0.  Caller must
465    free SERIAL unless the function returns an error.  If STAMP is not
466    of interest, NULL may be passed. */
467 gpg_error_t 
468 app_get_serial_and_stamp (app_t app, char **serial, time_t *stamp)
469 {
470   char *buf, *p;
471   int i;
472
473   if (!app || !serial)
474     return gpg_error (GPG_ERR_INV_VALUE);
475
476   *serial = NULL;
477   if (stamp)
478     *stamp = 0; /* not available */
479
480   buf = xtrymalloc (app->serialnolen * 2 + 1);
481   if (!buf)
482     return gpg_error_from_errno (errno);
483   for (p=buf, i=0; i < app->serialnolen; p +=2, i++)
484     sprintf (p, "%02X", app->serialno[i]);
485   *p = 0;
486   *serial = buf;
487   return 0;
488 }
489
490
491 /* Write out the application specifig status lines for the LEARN
492    command. */
493 gpg_error_t
494 app_write_learn_status (app_t app, CTRL ctrl)
495 {
496   gpg_error_t err;
497
498   if (!app)
499     return gpg_error (GPG_ERR_INV_VALUE);
500   if (!app->initialized)
501     return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
502   if (!app->fnc.learn_status)
503     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
504
505   if (app->apptype)
506     send_status_info (ctrl, "APPTYPE",
507                       app->apptype, strlen (app->apptype), NULL, 0);
508   err = lock_reader (app->slot);
509   if (err)
510     return err;
511   err = app->fnc.learn_status (app, ctrl);
512   unlock_reader (app->slot);
513   return err;
514 }
515
516
517 /* Read the certificate with id CERTID (as returned by learn_status in
518    the CERTINFO status lines) and return it in the freshly allocated
519    buffer put into CERT and the length of the certificate put into
520    CERTLEN. */
521 gpg_error_t
522 app_readcert (app_t app, const char *certid,
523               unsigned char **cert, size_t *certlen)
524 {
525   gpg_error_t err;
526
527   if (!app)
528     return gpg_error (GPG_ERR_INV_VALUE);
529   if (!app->initialized)
530     return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
531   if (!app->fnc.readcert)
532     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
533   err = lock_reader (app->slot);
534   if (err)
535     return err;
536   err = app->fnc.readcert (app, certid, cert, certlen);
537   unlock_reader (app->slot);
538   return err;
539 }
540
541
542 /* Read the key with ID KEYID.  On success a canonical encoded
543    S-expression with the public key will get stored at PK and its
544    length (for assertions) at PKLEN; the caller must release that
545    buffer. On error NULL will be stored at PK and PKLEN and an error
546    code returned.
547
548    This function might not be supported by all applications.  */
549 gpg_error_t
550 app_readkey (app_t app, const char *keyid, unsigned char **pk, size_t *pklen)
551 {
552   gpg_error_t err;
553
554   if (pk)
555     *pk = NULL;
556   if (pklen)
557     *pklen = 0;
558
559   if (!app || !keyid || !pk || !pklen)
560     return gpg_error (GPG_ERR_INV_VALUE);
561   if (!app->initialized)
562     return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
563   if (!app->fnc.readkey)
564     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
565   err = lock_reader (app->slot);
566   if (err)
567     return err;
568   err= app->fnc.readkey (app, keyid, pk, pklen);
569   unlock_reader (app->slot);
570   return err;
571 }
572
573
574 /* Perform a GETATTR operation.  */
575 gpg_error_t 
576 app_getattr (app_t app, CTRL ctrl, const char *name)
577 {
578   gpg_error_t err;
579
580   if (!app || !name || !*name)
581     return gpg_error (GPG_ERR_INV_VALUE);
582   if (!app->initialized)
583     return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
584
585   if (app->apptype && name && !strcmp (name, "APPTYPE"))
586     {
587       send_status_info (ctrl, "APPTYPE",
588                         app->apptype, strlen (app->apptype), NULL, 0);
589       return 0;
590     }
591   if (name && !strcmp (name, "SERIALNO"))
592     {
593       char *serial;
594       time_t stamp;
595       int rc;
596       
597       rc = app_get_serial_and_stamp (app, &serial, &stamp);
598       if (rc)
599         return rc;
600       send_status_info (ctrl, "SERIALNO", serial, strlen (serial), NULL, 0);
601       xfree (serial);
602       return 0;
603     }
604
605   if (!app->fnc.getattr)
606     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
607   err = lock_reader (app->slot);
608   if (err)
609     return err;
610   err =  app->fnc.getattr (app, ctrl, name);
611   unlock_reader (app->slot);
612   return err;
613 }
614
615 /* Perform a SETATTR operation.  */
616 gpg_error_t 
617 app_setattr (app_t app, const char *name,
618              gpg_error_t (*pincb)(void*, const char *, char **),
619              void *pincb_arg,
620              const unsigned char *value, size_t valuelen)
621 {
622   gpg_error_t err;
623
624   if (!app || !name || !*name || !value)
625     return gpg_error (GPG_ERR_INV_VALUE);
626   if (!app->initialized)
627     return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
628   if (!app->fnc.setattr)
629     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
630   err = lock_reader (app->slot);
631   if (err)
632     return err;
633   err = app->fnc.setattr (app, name, pincb, pincb_arg, value, valuelen);
634   unlock_reader (app->slot);
635   return err;
636 }
637
638 /* Create the signature and return the allocated result in OUTDATA.
639    If a PIN is required the PINCB will be used to ask for the PIN; it
640    should return the PIN in an allocated buffer and put it into PIN.  */
641 gpg_error_t 
642 app_sign (app_t app, const char *keyidstr, int hashalgo,
643           gpg_error_t (*pincb)(void*, const char *, char **),
644           void *pincb_arg,
645           const void *indata, size_t indatalen,
646           unsigned char **outdata, size_t *outdatalen )
647 {
648   gpg_error_t err;
649
650   if (!app || !indata || !indatalen || !outdata || !outdatalen || !pincb)
651     return gpg_error (GPG_ERR_INV_VALUE);
652   if (!app->initialized)
653     return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
654   if (!app->fnc.sign)
655     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
656   err = lock_reader (app->slot);
657   if (err)
658     return err;
659   err = app->fnc.sign (app, keyidstr, hashalgo,
660                        pincb, pincb_arg,
661                        indata, indatalen,
662                        outdata, outdatalen);
663   unlock_reader (app->slot);
664   if (opt.verbose)
665     log_info ("operation sign result: %s\n", gpg_strerror (err));
666   return err;
667 }
668
669 /* Create the signature using the INTERNAL AUTHENTICATE command and
670    return the allocated result in OUTDATA.  If a PIN is required the
671    PINCB will be used to ask for the PIN; it should return the PIN in
672    an allocated buffer and put it into PIN.  */
673 gpg_error_t 
674 app_auth (app_t app, const char *keyidstr,
675           gpg_error_t (*pincb)(void*, const char *, char **),
676           void *pincb_arg,
677           const void *indata, size_t indatalen,
678           unsigned char **outdata, size_t *outdatalen )
679 {
680   gpg_error_t err;
681
682   if (!app || !indata || !indatalen || !outdata || !outdatalen || !pincb)
683     return gpg_error (GPG_ERR_INV_VALUE);
684   if (!app->initialized)
685     return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
686   if (!app->fnc.auth)
687     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
688   err = lock_reader (app->slot);
689   if (err)
690     return err;
691   err = app->fnc.auth (app, keyidstr,
692                        pincb, pincb_arg,
693                        indata, indatalen,
694                        outdata, outdatalen);
695   unlock_reader (app->slot);
696   if (opt.verbose)
697     log_info ("operation auth result: %s\n", gpg_strerror (err));
698   return err;
699 }
700
701
702 /* Decrypt the data in INDATA and return the allocated result in OUTDATA.
703    If a PIN is required the PINCB will be used to ask for the PIN; it
704    should return the PIN in an allocated buffer and put it into PIN.  */
705 gpg_error_t 
706 app_decipher (app_t app, const char *keyidstr,
707               gpg_error_t (*pincb)(void*, const char *, char **),
708               void *pincb_arg,
709               const void *indata, size_t indatalen,
710               unsigned char **outdata, size_t *outdatalen )
711 {
712   gpg_error_t err;
713
714   if (!app || !indata || !indatalen || !outdata || !outdatalen || !pincb)
715     return gpg_error (GPG_ERR_INV_VALUE);
716   if (!app->initialized)
717     return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
718   if (!app->fnc.decipher)
719     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
720   err = lock_reader (app->slot);
721   if (err)
722     return err;
723   err = app->fnc.decipher (app, keyidstr,
724                            pincb, pincb_arg,
725                            indata, indatalen,
726                            outdata, outdatalen);
727   unlock_reader (app->slot);
728   if (opt.verbose)
729     log_info ("operation decipher result: %s\n", gpg_strerror (err));
730   return err;
731 }
732
733
734 /* Perform the WRITEKEY operation.  */
735 gpg_error_t
736 app_writekey (app_t app, ctrl_t ctrl,
737               const char *keyidstr, unsigned int flags,
738               gpg_error_t (*pincb)(void*, const char *, char **),
739               void *pincb_arg,
740               const unsigned char *keydata, size_t keydatalen)
741 {
742   gpg_error_t err;
743
744   if (!app || !keyidstr || !*keyidstr || !pincb)
745     return gpg_error (GPG_ERR_INV_VALUE);
746   if (!app->initialized)
747     return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
748   if (!app->fnc.writekey)
749     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
750   err = lock_reader (app->slot);
751   if (err)
752     return err;
753   err = app->fnc.writekey (app, ctrl, keyidstr, flags,
754                            pincb, pincb_arg, keydata, keydatalen);
755   unlock_reader (app->slot);
756   if (opt.verbose)
757     log_info ("operation writekey result: %s\n", gpg_strerror (err));
758   return err;
759
760 }
761
762
763 /* Perform a SETATTR operation.  */
764 gpg_error_t 
765 app_genkey (app_t app, CTRL ctrl, const char *keynostr, unsigned int flags,
766             gpg_error_t (*pincb)(void*, const char *, char **),
767             void *pincb_arg)
768 {
769   gpg_error_t err;
770
771   if (!app || !keynostr || !*keynostr || !pincb)
772     return gpg_error (GPG_ERR_INV_VALUE);
773   if (!app->initialized)
774     return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
775   if (!app->fnc.genkey)
776     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
777   err = lock_reader (app->slot);
778   if (err)
779     return err;
780   err = app->fnc.genkey (app, ctrl, keynostr, flags, pincb, pincb_arg);
781   unlock_reader (app->slot);
782   if (opt.verbose)
783     log_info ("operation genkey result: %s\n", gpg_strerror (err));
784   return err;
785 }
786
787
788 /* Perform a GET CHALLENGE operation.  This fucntion is special as it
789    directly accesses the card without any application specific
790    wrapper. */
791 gpg_error_t
792 app_get_challenge (app_t app, size_t nbytes, unsigned char *buffer)
793 {
794   gpg_error_t err;
795
796   if (!app || !nbytes || !buffer)
797     return gpg_error (GPG_ERR_INV_VALUE);
798   if (!app->initialized)
799     return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
800   err = lock_reader (app->slot);
801   if (err)
802     return err;
803   err = iso7816_get_challenge (app->slot, nbytes, buffer);
804   unlock_reader (app->slot);
805   return err;
806 }
807
808
809
810 /* Perform a CHANGE REFERENCE DATA or RESET RETRY COUNTER operation.  */
811 gpg_error_t 
812 app_change_pin (app_t app, CTRL ctrl, const char *chvnostr, int reset_mode,
813                 gpg_error_t (*pincb)(void*, const char *, char **),
814                 void *pincb_arg)
815 {
816   gpg_error_t err;
817
818   if (!app || !chvnostr || !*chvnostr || !pincb)
819     return gpg_error (GPG_ERR_INV_VALUE);
820   if (!app->initialized)
821     return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
822   if (!app->fnc.change_pin)
823     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
824   err = lock_reader (app->slot);
825   if (err)
826     return err;
827   err = app->fnc.change_pin (app, ctrl, chvnostr, reset_mode,
828                              pincb, pincb_arg);
829   unlock_reader (app->slot);
830   if (opt.verbose)
831     log_info ("operation change_pin result: %s\n", gpg_strerror (err));
832   return err;
833 }
834
835
836 /* Perform a VERIFY operation without doing anything lese.  This may
837    be used to initialze a the PIN cache for long lasting other
838    operations.  Its use is highly application dependent. */
839 gpg_error_t 
840 app_check_pin (app_t app, const char *keyidstr,
841                gpg_error_t (*pincb)(void*, const char *, char **),
842                void *pincb_arg)
843 {
844   gpg_error_t err;
845
846   if (!app || !keyidstr || !*keyidstr || !pincb)
847     return gpg_error (GPG_ERR_INV_VALUE);
848   if (!app->initialized)
849     return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
850   if (!app->fnc.check_pin)
851     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
852   err = lock_reader (app->slot);
853   if (err)
854     return err;
855   err = app->fnc.check_pin (app, keyidstr, pincb, pincb_arg);
856   unlock_reader (app->slot);
857   if (opt.verbose)
858     log_info ("operation check_pin result: %s\n", gpg_strerror (err));
859   return err;
860 }
861