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