* Always use 'dynload.h' instead of 'dlfcn.h'.
[gnupg.git] / scd / app.c
1 /* app.c - Application selection.
2  *      Copyright (C) 2003 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #include <config.h>
22 #include <errno.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26
27
28 #include "scdaemon.h"
29 #include "app-common.h"
30 #include "apdu.h"
31 #include "iso7816.h"
32 #include "dynload.h"
33
34 static char *default_reader_port;
35
36 void
37 app_set_default_reader_port (const char *portstr)
38 {
39   xfree (default_reader_port);
40   default_reader_port = portstr? xstrdup (portstr): NULL;
41 }
42
43
44 /* The select the best fitting application and return a context.
45    Returns NULL if no application was found or no card is present. */
46 APP
47 select_application (void)
48 {
49   int slot;
50   int rc;
51   APP app;
52
53   slot = apdu_open_reader (default_reader_port);
54   if (slot == -1)
55     {
56       log_error ("card reader not available\n");
57       return NULL;
58     }
59
60   app = xtrycalloc (1, sizeof *app);
61   if (!app)
62     {
63       rc = out_of_core ();
64       log_info ("error allocating context: %s\n", gpg_strerror (rc));
65       /*apdu_close_reader (slot);*/
66       return NULL;
67     }
68
69   app->slot = slot;
70   rc = app_select_openpgp (app, &app->serialno, &app->serialnolen);
71   if (rc)
72     {
73 /*        apdu_close_reader (slot); */
74       log_info ("selecting openpgp failed: %s\n", gpg_strerror (rc));
75       xfree (app);
76       return NULL;
77     }
78
79   app->initialized = 1;
80   return app;
81 }
82
83
84
85 /* Retrieve the serial number and the time of the last update of the
86    card.  The serial number is returned as a malloced string (hex
87    encoded) in SERIAL and the time of update is returned in STAMP.  If
88    no update time is available the returned value is 0.  Caller must
89    free SERIAL unless the function returns an error. */
90 int 
91 app_get_serial_and_stamp (APP app, char **serial, time_t *stamp)
92 {
93   unsigned char *buf, *p;
94   int i;
95
96   if (!app || !serial || !stamp)
97     return gpg_error (GPG_ERR_INV_VALUE);
98
99   *serial = NULL;
100   *stamp = 0; /* not available */
101
102   buf = xtrymalloc (app->serialnolen * 2 + 1);
103   if (!buf)
104     return gpg_error_from_errno (errno);
105   for (p=buf, i=0; i < app->serialnolen; p +=2, i++)
106     sprintf (p, "%02X", app->serialno[i]);
107   *p = 0;
108   *serial = buf;
109   return 0;
110 }
111
112
113 /* Write out the application specifig status lines for the LEARN
114    command. */
115 int
116 app_write_learn_status (APP app, CTRL ctrl)
117 {
118   if (!app)
119     return gpg_error (GPG_ERR_INV_VALUE);
120   if (!app->initialized)
121     return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
122   if (!app->fnc.learn_status)
123     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
124   return app->fnc.learn_status (app, ctrl);
125 }
126
127
128 /* Perform a SETATTR operation.  */
129 int 
130 app_setattr (APP app, const char *name,
131              int (*pincb)(void*, const char *, char **),
132              void *pincb_arg,
133              const unsigned char *value, size_t valuelen)
134 {
135   if (!app || !name || !*name || !value)
136     return gpg_error (GPG_ERR_INV_VALUE);
137   if (!app->initialized)
138     return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
139   if (!app->fnc.setattr)
140     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
141   return app->fnc.setattr (app, name, pincb, pincb_arg, value, valuelen);
142 }
143
144 /* Create the signature and return the allocated result in OUTDATA.
145    If a PIN is required the PINCB will be used to ask for the PIN; it
146    should return the PIN in an allocated buffer and put it into PIN.  */
147 int 
148 app_sign (APP app, const char *keyidstr, int hashalgo,
149           int (pincb)(void*, const char *, char **),
150           void *pincb_arg,
151           const void *indata, size_t indatalen,
152           unsigned char **outdata, size_t *outdatalen )
153 {
154   int rc;
155
156   if (!app || !indata || !indatalen || !outdata || !outdatalen || !pincb)
157     return gpg_error (GPG_ERR_INV_VALUE);
158   if (!app->initialized)
159     return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
160   if (!app->fnc.sign)
161     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
162   rc = app->fnc.sign (app, keyidstr, hashalgo,
163                       pincb, pincb_arg,
164                       indata, indatalen,
165                       outdata, outdatalen);
166   if (opt.verbose)
167     log_info ("operation sign result: %s\n", gpg_strerror (rc));
168   return rc;
169 }
170
171 /* Create the signature using the INTERNAL AUTHENTICATE command and
172    return the allocated result in OUTDATA.  If a PIN is required the
173    PINCB will be used to ask for the PIN; it should return the PIN in
174    an allocated buffer and put it into PIN.  */
175 int 
176 app_auth (APP app, const char *keyidstr,
177           int (pincb)(void*, const char *, char **),
178           void *pincb_arg,
179           const void *indata, size_t indatalen,
180           unsigned char **outdata, size_t *outdatalen )
181 {
182   int rc;
183
184   if (!app || !indata || !indatalen || !outdata || !outdatalen || !pincb)
185     return gpg_error (GPG_ERR_INV_VALUE);
186   if (!app->initialized)
187     return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
188   if (!app->fnc.auth)
189     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
190   rc = app->fnc.auth (app, keyidstr,
191                       pincb, pincb_arg,
192                       indata, indatalen,
193                       outdata, outdatalen);
194   if (opt.verbose)
195     log_info ("operation auth result: %s\n", gpg_strerror (rc));
196   return rc;
197 }
198
199
200 /* Decrypt the data in INDATA and return the allocated result in OUTDATA.
201    If a PIN is required the PINCB will be used to ask for the PIN; it
202    should return the PIN in an allocated buffer and put it into PIN.  */
203 int 
204 app_decipher (APP app, const char *keyidstr,
205               int (pincb)(void*, const char *, char **),
206               void *pincb_arg,
207               const void *indata, size_t indatalen,
208               unsigned char **outdata, size_t *outdatalen )
209 {
210   int rc;
211
212   if (!app || !indata || !indatalen || !outdata || !outdatalen || !pincb)
213     return gpg_error (GPG_ERR_INV_VALUE);
214   if (!app->initialized)
215     return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
216   if (!app->fnc.decipher)
217     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
218   rc = app->fnc.decipher (app, keyidstr,
219                           pincb, pincb_arg,
220                           indata, indatalen,
221                           outdata, outdatalen);
222   if (opt.verbose)
223     log_info ("operation decipher result: %s\n", gpg_strerror (rc));
224   return rc;
225 }
226
227
228 /* Perform a SETATTR operation.  */
229 int 
230 app_genkey (APP app, CTRL ctrl, const char *keynostr, unsigned int flags,
231             int (*pincb)(void*, const char *, char **),
232             void *pincb_arg)
233 {
234   int rc;
235
236   if (!app || !keynostr || !*keynostr || !pincb)
237     return gpg_error (GPG_ERR_INV_VALUE);
238   if (!app->initialized)
239     return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
240   if (!app->fnc.genkey)
241     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
242   rc = app->fnc.genkey (app, ctrl, keynostr, flags, pincb, pincb_arg);
243   if (opt.verbose)
244     log_info ("operation genkey result: %s\n", gpg_strerror (rc));
245   return rc;
246 }
247
248
249 /* Perform a GET CHALLENGE operation.  This fucntion is special as it
250    directly accesses the card without any application specific
251    wrapper. */
252 int
253 app_get_challenge (APP app, size_t nbytes, unsigned char *buffer)
254 {
255   if (!app || !nbytes || !buffer)
256     return gpg_error (GPG_ERR_INV_VALUE);
257   if (!app->initialized)
258     return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
259   return iso7816_get_challenge (app->slot, nbytes, buffer);
260 }
261
262
263
264 /* Perform a CHANGE REFERENCE DATA or RESET RETRY COUNTER operation.  */
265 int 
266 app_change_pin (APP app, CTRL ctrl, const char *chvnostr, int reset_mode,
267                 int (*pincb)(void*, const char *, char **),
268                 void *pincb_arg)
269 {
270   int rc;
271
272   if (!app || !chvnostr || !*chvnostr || !pincb)
273     return gpg_error (GPG_ERR_INV_VALUE);
274   if (!app->initialized)
275     return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
276   if (!app->fnc.change_pin)
277     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
278   rc = app->fnc.change_pin (app, ctrl, chvnostr, reset_mode, pincb, pincb_arg);
279   if (opt.verbose)
280     log_info ("operation change_pin result: %s\n", gpg_strerror (rc));
281   return rc;
282 }
283
284
285
286
287
288