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