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