Use bin2hex if possible.
[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   (void)m;
110   log_printf ("unknown under W32");
111 #else
112   if (!(m->mx_state & PTH_MUTEX_INITIALIZED))
113     log_printf ("not_initialized");
114   else if (!(m->mx_state & PTH_MUTEX_LOCKED))
115     log_printf ("not_locked");
116   else
117     log_printf ("locked tid=0x%lx count=%lu", (long)m->mx_owner, m->mx_count);
118 #endif
119 }
120
121
122 /* This function may be called to print information pertaining to the
123    current state of this module to the log. */
124 void
125 app_dump_state (void)
126 {
127   int slot;
128
129   for (slot=0; slot < DIM (lock_table); slot++)
130     if (lock_table[slot].initialized)
131       {
132         log_info ("app_dump_state: slot=%d lock=", slot);
133         dump_mutex_state (&lock_table[slot].lock);
134         if (lock_table[slot].app)
135           {
136             log_printf (" app=%p", lock_table[slot].app);
137             if (lock_table[slot].app->apptype)
138               log_printf (" type=`%s'", lock_table[slot].app->apptype);
139           }
140         if (lock_table[slot].last_app)
141           {
142             log_printf (" lastapp=%p", lock_table[slot].last_app);
143             if (lock_table[slot].last_app->apptype)
144               log_printf (" type=`%s'", lock_table[slot].last_app->apptype);
145           }
146         log_printf ("\n");
147       }
148 }
149
150 /* Check wether the application NAME is allowed.  This does not mean
151    we have support for it though.  */
152 static int
153 is_app_allowed (const char *name)
154 {
155   strlist_t l;
156
157   for (l=opt.disabled_applications; l; l = l->next)
158     if (!strcmp (l->d, name))
159       return 0; /* no */
160   return 1; /* yes */
161 }
162
163
164 /* This may be called to tell this module about a removed card. */
165 void
166 application_notify_card_removed (int slot)
167 {
168   app_t app;
169
170   if (slot < 0 || slot >= DIM (lock_table))
171     return;
172
173   /* FIXME: We are ignoring any error value here.  */
174   lock_reader (slot); 
175
176   /* Deallocate a saved application for that slot, so that we won't
177      try to reuse it.  If there is no saved application, set a flag so
178      that we won't save the current state. */
179   app = lock_table[slot].last_app;
180
181   if (app)
182     {
183       lock_table[slot].last_app = NULL;
184       deallocate_app (app);
185     }
186   unlock_reader (slot); 
187 }
188
189  
190 /* This function is used by the serialno command to check for an
191    application conflict which may appear if the serialno command is
192    used to request a specific application and the connection has
193    already done a select_application. */
194 gpg_error_t
195 check_application_conflict (ctrl_t ctrl, const char *name)
196 {
197   int slot = ctrl->reader_slot;
198   app_t app;
199
200   if (slot < 0 || slot >= DIM (lock_table))
201     return gpg_error (GPG_ERR_INV_VALUE);
202
203   app = lock_table[slot].initialized ? lock_table[slot].app : NULL;
204   if (app && app->apptype && name)
205     if ( ascii_strcasecmp (app->apptype, name))
206         return gpg_error (GPG_ERR_CONFLICT);
207   return 0;
208 }
209
210
211 /* If called with NAME as NULL, select the best fitting application
212    and return a context; otherwise select the application with NAME
213    and return a context.  SLOT identifies the reader device. Returns
214    an error code and stores NULL at R_APP if no application was found
215    or no card is present. */
216 gpg_error_t
217 select_application (ctrl_t ctrl, int slot, const char *name, app_t *r_app)
218 {
219   gpg_error_t err;
220   app_t app = NULL;
221   unsigned char *result = NULL;
222   size_t resultlen;
223
224   (void)ctrl;
225
226   *r_app = NULL;
227
228   err = lock_reader (slot);
229   if (err)
230     return err;
231
232   /* First check whether we already have an application to share. */
233   app = lock_table[slot].initialized ? lock_table[slot].app : NULL;
234   if (app && name)
235     if (!app->apptype || ascii_strcasecmp (app->apptype, name))
236       {
237         unlock_reader (slot);
238         if (app->apptype)
239           log_info ("application `%s' in use by reader %d - can't switch\n",
240                     app->apptype, slot);
241         return gpg_error (GPG_ERR_CONFLICT);
242       }
243
244   /* If we don't have an app, check whether we have a saved
245      application for that slot.  This is useful so that a card does
246      not get reset even if only one session is using the card - this
247      way the PIN cache and other cached data are preserved.  */
248   if (!app && lock_table[slot].initialized && lock_table[slot].last_app)
249     {
250       app = lock_table[slot].last_app;
251       if (!name || (app->apptype && !ascii_strcasecmp (app->apptype, name)) )
252         {
253           /* Yes, we can reuse this application - either the caller
254              requested an unspecific one or the requested one matches
255              the saved one. */
256           lock_table[slot].app = app;
257           lock_table[slot].last_app = NULL;
258         }
259       else 
260         {
261           /* No, this saved application can't be used - deallocate it. */
262           lock_table[slot].last_app = NULL;
263           deallocate_app (app);
264           app = NULL;
265         }
266     }
267
268   /* If we can reuse an application, bump the reference count and
269      return it.  */
270   if (app)
271     {
272       if (app->slot != slot)
273         log_bug ("slot mismatch %d/%d\n", app->slot, slot);
274       app->slot = slot;
275
276       app->ref_count++;
277       *r_app = app;
278       unlock_reader (slot);
279       return 0; /* Okay: We share that one. */
280     }
281
282   /* Need to allocate a new one.  */
283   app = xtrycalloc (1, sizeof *app);
284   if (!app)
285     {
286       err = gpg_error_from_syserror ();
287       log_info ("error allocating context: %s\n", gpg_strerror (err));
288       unlock_reader (slot);
289       return err;
290     }
291   app->slot = slot;
292
293
294   /* Fixme: We should now first check whether a card is at all
295      present. */
296
297   /* Try to read the GDO file first to get a default serial number. */
298   err = iso7816_select_file (slot, 0x3F00, 1, NULL, NULL);
299   if (!err)
300     err = iso7816_select_file (slot, 0x2F02, 0, NULL, NULL);
301   if (!err)
302      err = iso7816_read_binary (slot, 0, 0, &result, &resultlen);
303   if (!err)
304     {
305       size_t n;
306       const unsigned char *p;
307
308       p = find_tlv_unchecked (result, resultlen, 0x5A, &n);
309       if (p)
310         resultlen -= (p-result);
311       if (p && n > resultlen && n == 0x0d && resultlen+1 == n)
312         {
313           /* The object it does not fit into the buffer.  This is an
314              invalid encoding (or the buffer is too short.  However, I
315              have some test cards with such an invalid encoding and
316              therefore I use this ugly workaround to return something
317              I can further experiment with. */
318           log_info ("enabling BMI testcard workaround\n");
319           n--;
320         }
321
322       if (p && n <= resultlen)
323         {
324           /* The GDO file is pretty short, thus we simply reuse it for
325              storing the serial number. */
326           memmove (result, p, n);
327           app->serialno = result;
328           app->serialnolen = n;
329           err = app_munge_serialno (app);
330           if (err)
331             goto leave;
332         }
333       else
334         xfree (result);
335       result = NULL;
336     }
337
338   /* For certain error codes, there is no need to try more.  */
339   if (gpg_err_code (err) == GPG_ERR_CARD_NOT_PRESENT)
340     goto leave;
341   
342
343   /* Figure out the application to use.  */
344   err = gpg_error (GPG_ERR_NOT_FOUND);
345
346   if (err && is_app_allowed ("openpgp")
347           && (!name || !strcmp (name, "openpgp")))
348     err = app_select_openpgp (app);
349   if (err && is_app_allowed ("nks") && (!name || !strcmp (name, "nks")))
350     err = app_select_nks (app);
351   if (err && is_app_allowed ("p15") && (!name || !strcmp (name, "p15")))
352     err = app_select_p15 (app);
353   if (err && is_app_allowed ("dinsig") && (!name || !strcmp (name, "dinsig")))
354     err = app_select_dinsig (app);
355   if (err && name)
356     err = gpg_error (GPG_ERR_NOT_SUPPORTED);
357
358  leave:
359   if (err)
360     {
361       if (name)
362         log_info ("can't select application `%s': %s\n",
363                   name, gpg_strerror (err));
364       else
365         log_info ("no supported card application found: %s\n",
366                   gpg_strerror (err));
367       xfree (app);
368       unlock_reader (slot);
369       return err;
370     }
371
372   app->initialized = 1;
373   app->ref_count = 1;
374   lock_table[slot].app = app;
375   *r_app = app;
376   unlock_reader (slot);
377   return 0;
378 }
379
380
381 /* Deallocate the application. */
382 static void
383 deallocate_app (app_t app)
384 {
385   if (app->fnc.deinit)
386     {
387       app->fnc.deinit (app);
388       app->fnc.deinit = NULL;
389     }
390
391   xfree (app->serialno);
392   xfree (app);
393 }
394
395 /* Free the resources associated with the application APP.  APP is
396    allowed to be NULL in which case this is a no-op.  Note that we are
397    using reference counting to track the users of the application and
398    actually deferring the deallocation to allow for a later reuse by
399    a new connection. */
400 void
401 release_application (app_t app)
402 {
403   int slot;
404
405   if (!app)
406     return;
407
408   if (app->ref_count < 1)
409     log_bug ("trying to release an already released context\n");
410   if (--app->ref_count)
411     return;
412
413   /* Move the reference to the application in the lock table. */
414   slot = app->slot;
415   /* FIXME: We are ignoring any error value.  */
416   lock_reader (slot);
417   if (lock_table[slot].app != app)
418     {
419       unlock_reader (slot);
420       log_bug ("app mismatch %p/%p\n", app, lock_table[slot].app);
421       deallocate_app (app);
422       return;
423     }
424
425   if (lock_table[slot].last_app)
426     deallocate_app (lock_table[slot].last_app);
427   lock_table[slot].last_app = lock_table[slot].app;
428   lock_table[slot].app = NULL;
429   unlock_reader (slot);
430 }
431
432
433
434 /* The serial number may need some cosmetics.  Do it here.  This
435    function shall only be called once after a new serial number has
436    been put into APP->serialno. 
437
438    Prefixes we use:
439    
440      FF 00 00 = For serial numbers starting with an FF
441      FF 01 00 = Some german p15 cards return an empty serial number so the
442                 serial number from the EF(TokenInfo) is used instead.
443      
444      All other serial number not starting with FF are used as they are.
445 */
446 gpg_error_t
447 app_munge_serialno (app_t app)
448 {
449   if (app->serialnolen && app->serialno[0] == 0xff)
450     { 
451       /* The serial number starts with our special prefix.  This
452          requires that we put our default prefix "FF0000" in front. */
453       unsigned char *p = xtrymalloc (app->serialnolen + 3);
454       if (!p)
455         return gpg_error (gpg_err_code_from_errno (errno));
456       memcpy (p, "\xff\0", 3);
457       memcpy (p+3, app->serialno, app->serialnolen);
458       app->serialnolen += 3;
459       xfree (app->serialno);
460       app->serialno = p;
461     }
462   return 0;
463 }
464
465
466
467 /* Retrieve the serial number and the time of the last update of the
468    card.  The serial number is returned as a malloced string (hex
469    encoded) in SERIAL and the time of update is returned in STAMP.  If
470    no update time is available the returned value is 0.  Caller must
471    free SERIAL unless the function returns an error.  If STAMP is not
472    of interest, NULL may be passed. */
473 gpg_error_t 
474 app_get_serial_and_stamp (app_t app, char **serial, time_t *stamp)
475 {
476   char *buf;
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 = bin2hex (app->serialno, app->serialnolen, NULL);
486   if (!buf)
487     return gpg_error_from_syserror ();
488
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 WRITECERT operation.  */
738 gpg_error_t
739 app_writecert (app_t app, ctrl_t ctrl,
740               const char *certidstr,
741               gpg_error_t (*pincb)(void*, const char *, char **),
742               void *pincb_arg,
743               const unsigned char *data, size_t datalen)
744 {
745   gpg_error_t err;
746
747   if (!app || !certidstr || !*certidstr || !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.writecert)
752     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
753   err = lock_reader (app->slot);
754   if (err)
755     return err;
756   err = app->fnc.writecert (app, ctrl, certidstr,
757                             pincb, pincb_arg, data, datalen);
758   unlock_reader (app->slot);
759   if (opt.verbose)
760     log_info ("operation writecert result: %s\n", gpg_strerror (err));
761   return err;
762 }
763
764
765 /* Perform the WRITEKEY operation.  */
766 gpg_error_t
767 app_writekey (app_t app, ctrl_t ctrl,
768               const char *keyidstr, unsigned int flags,
769               gpg_error_t (*pincb)(void*, const char *, char **),
770               void *pincb_arg,
771               const unsigned char *keydata, size_t keydatalen)
772 {
773   gpg_error_t err;
774
775   if (!app || !keyidstr || !*keyidstr || !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.writekey)
780     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
781   err = lock_reader (app->slot);
782   if (err)
783     return err;
784   err = app->fnc.writekey (app, ctrl, keyidstr, flags,
785                            pincb, pincb_arg, keydata, keydatalen);
786   unlock_reader (app->slot);
787   if (opt.verbose)
788     log_info ("operation writekey result: %s\n", gpg_strerror (err));
789   return err;
790 }
791
792
793 /* Perform a SETATTR operation.  */
794 gpg_error_t 
795 app_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags,
796             time_t createtime,
797             gpg_error_t (*pincb)(void*, const char *, char **),
798             void *pincb_arg)
799 {
800   gpg_error_t err;
801
802   if (!app || !keynostr || !*keynostr || !pincb)
803     return gpg_error (GPG_ERR_INV_VALUE);
804   if (!app->initialized)
805     return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
806   if (!app->fnc.genkey)
807     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
808   err = lock_reader (app->slot);
809   if (err)
810     return err;
811   err = app->fnc.genkey (app, ctrl, keynostr, flags, 
812                          createtime, pincb, pincb_arg);
813   unlock_reader (app->slot);
814   if (opt.verbose)
815     log_info ("operation genkey result: %s\n", gpg_strerror (err));
816   return err;
817 }
818
819
820 /* Perform a GET CHALLENGE operation.  This fucntion is special as it
821    directly accesses the card without any application specific
822    wrapper. */
823 gpg_error_t
824 app_get_challenge (app_t app, size_t nbytes, unsigned char *buffer)
825 {
826   gpg_error_t err;
827
828   if (!app || !nbytes || !buffer)
829     return gpg_error (GPG_ERR_INV_VALUE);
830   if (!app->initialized)
831     return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
832   err = lock_reader (app->slot);
833   if (err)
834     return err;
835   err = iso7816_get_challenge (app->slot, nbytes, buffer);
836   unlock_reader (app->slot);
837   return err;
838 }
839
840
841
842 /* Perform a CHANGE REFERENCE DATA or RESET RETRY COUNTER operation.  */
843 gpg_error_t 
844 app_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr, int reset_mode,
845                 gpg_error_t (*pincb)(void*, const char *, char **),
846                 void *pincb_arg)
847 {
848   gpg_error_t err;
849
850   if (!app || !chvnostr || !*chvnostr || !pincb)
851     return gpg_error (GPG_ERR_INV_VALUE);
852   if (!app->initialized)
853     return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
854   if (!app->fnc.change_pin)
855     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
856   err = lock_reader (app->slot);
857   if (err)
858     return err;
859   err = app->fnc.change_pin (app, ctrl, chvnostr, reset_mode,
860                              pincb, pincb_arg);
861   unlock_reader (app->slot);
862   if (opt.verbose)
863     log_info ("operation change_pin result: %s\n", gpg_strerror (err));
864   return err;
865 }
866
867
868 /* Perform a VERIFY operation without doing anything lese.  This may
869    be used to initialze a the PIN cache for long lasting other
870    operations.  Its use is highly application dependent. */
871 gpg_error_t 
872 app_check_pin (app_t app, const char *keyidstr,
873                gpg_error_t (*pincb)(void*, const char *, char **),
874                void *pincb_arg)
875 {
876   gpg_error_t err;
877
878   if (!app || !keyidstr || !*keyidstr || !pincb)
879     return gpg_error (GPG_ERR_INV_VALUE);
880   if (!app->initialized)
881     return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
882   if (!app->fnc.check_pin)
883     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
884   err = lock_reader (app->slot);
885   if (err)
886     return err;
887   err = app->fnc.check_pin (app, keyidstr, pincb, pincb_arg);
888   unlock_reader (app->slot);
889   if (opt.verbose)
890     log_info ("operation check_pin result: %s\n", gpg_strerror (err));
891   return err;
892 }
893