First steps towards supporting W32.
[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_syserror ();
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_syserror ();
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 #ifdef _W32_PTH_H
111   log_printf ("unknown under W32");
112 #else
113   if (!(m->mx_state & PTH_MUTEX_INITIALIZED))
114     log_printf ("not_initialized");
115   else if (!(m->mx_state & PTH_MUTEX_LOCKED))
116     log_printf ("not_locked");
117   else
118     log_printf ("locked tid=0x%lx count=%lu", (long)m->mx_owner, m->mx_count);
119 #endif
120 }
121
122
123 /* This function may be called to print information pertaining to the
124    current state of this module to the log. */
125 void
126 app_dump_state (void)
127 {
128   int slot;
129
130   for (slot=0; slot < DIM (lock_table); slot++)
131     if (lock_table[slot].initialized)
132       {
133         log_info ("app_dump_state: slot=%d lock=", slot);
134         dump_mutex_state (&lock_table[slot].lock);
135         if (lock_table[slot].app)
136           {
137             log_printf (" app=%p", lock_table[slot].app);
138             if (lock_table[slot].app->apptype)
139               log_printf (" type=`%s'", lock_table[slot].app->apptype);
140           }
141         if (lock_table[slot].last_app)
142           {
143             log_printf (" lastapp=%p", lock_table[slot].last_app);
144             if (lock_table[slot].last_app->apptype)
145               log_printf (" type=`%s'", lock_table[slot].last_app->apptype);
146           }
147         log_printf ("\n");
148       }
149 }
150
151 /* Check wether the application NAME is allowed.  This does not mean
152    we have support for it though.  */
153 static int
154 is_app_allowed (const char *name)
155 {
156   strlist_t l;
157
158   for (l=opt.disabled_applications; l; l = l->next)
159     if (!strcmp (l->d, name))
160       return 0; /* no */
161   return 1; /* yes */
162 }
163
164
165 /* This may be called to tell this module about a removed card. */
166 void
167 application_notify_card_removed (int slot)
168 {
169   app_t app;
170
171   if (slot < 0 || slot >= DIM (lock_table))
172     return;
173
174   /* FIXME: We are ignoring any error value here.  */
175   lock_reader (slot); 
176
177   /* Deallocate a saved application for that slot, so that we won't
178      try to reuse it.  If there is no saved application, set a flag so
179      that we won't save the current state. */
180   app = lock_table[slot].last_app;
181
182   if (app)
183     {
184       lock_table[slot].last_app = NULL;
185       deallocate_app (app);
186     }
187   unlock_reader (slot); 
188 }
189
190  
191 /* This fucntion is used by the serialno command to check for an
192    application conflict which may appear if the serialno command is
193    used to request a specific application and the connection has
194    already done a select_application. */
195 gpg_error_t
196 check_application_conflict (ctrl_t ctrl, const char *name)
197 {
198   int slot = ctrl->reader_slot;
199   app_t app;
200
201   if (slot < 0 || slot >= DIM (lock_table))
202     return gpg_error (GPG_ERR_INV_VALUE);
203
204   app = lock_table[slot].initialized ? lock_table[slot].app : NULL;
205   if (app && app->apptype && name)
206     if ( ascii_strcasecmp (app->apptype, name))
207         return gpg_error (GPG_ERR_CONFLICT);
208   return 0;
209 }
210
211
212 /* If called with NAME as NULL, select the best fitting application
213    and return a context; otherwise select the application with NAME
214    and return a context.  SLOT identifies the reader device. Returns
215    an error code and stores NULL at R_APP if no application was found
216    or no card is present. */
217 gpg_error_t
218 select_application (ctrl_t ctrl, int slot, const char *name, app_t *r_app)
219 {
220   gpg_error_t err;
221   app_t app = NULL;
222   unsigned char *result = NULL;
223   size_t resultlen;
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 - so the
246      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 WRITEKEY operation.  */
740 gpg_error_t
741 app_writekey (app_t app, ctrl_t ctrl,
742               const char *keyidstr, unsigned int flags,
743               gpg_error_t (*pincb)(void*, const char *, char **),
744               void *pincb_arg,
745               const unsigned char *keydata, size_t keydatalen)
746 {
747   gpg_error_t err;
748
749   if (!app || !keyidstr || !*keyidstr || !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.writekey)
754     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
755   err = lock_reader (app->slot);
756   if (err)
757     return err;
758   err = app->fnc.writekey (app, ctrl, keyidstr, flags,
759                            pincb, pincb_arg, keydata, keydatalen);
760   unlock_reader (app->slot);
761   if (opt.verbose)
762     log_info ("operation writekey result: %s\n", gpg_strerror (err));
763   return err;
764
765 }
766
767
768 /* Perform a SETATTR operation.  */
769 gpg_error_t 
770 app_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags,
771             gpg_error_t (*pincb)(void*, const char *, char **),
772             void *pincb_arg)
773 {
774   gpg_error_t err;
775
776   if (!app || !keynostr || !*keynostr || !pincb)
777     return gpg_error (GPG_ERR_INV_VALUE);
778   if (!app->initialized)
779     return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
780   if (!app->fnc.genkey)
781     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
782   err = lock_reader (app->slot);
783   if (err)
784     return err;
785   err = app->fnc.genkey (app, ctrl, keynostr, flags, 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