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