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