* keyserver.c (keyserver_spawn): Use the full 64-bit keyid in the INFO
[gnupg.git] / g10 / iso7816.c
1 /* iso7816.c - ISO 7816 commands
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 #if GNUPG_MAJOR_VERSION == 1
28 /* This is used with GnuPG version < 1.9.  The code has been source
29    copied from the current GnuPG >= 1.9  and is maintained over
30    there. */
31 #include "options.h"
32 #include "errors.h"
33 #include "memory.h"
34 #include "util.h"
35 #include "i18n.h"
36 #else /* GNUPG_MAJOR_VERSION != 1 */
37 #include "scdaemon.h"
38 #endif /* GNUPG_MAJOR_VERSION != 1 */
39
40 #include "iso7816.h"
41 #include "apdu.h"
42
43
44 #define CMD_SELECT_FILE 0xA4
45 #define CMD_VERIFY      0x20
46 #define CMD_CHANGE_REFERENCE_DATA 0x24
47 #define CMD_RESET_RETRY_COUNTER   0x2C
48 #define CMD_GET_DATA    0xCA
49 #define CMD_PUT_DATA    0xDA
50 #define CMD_PSO         0x2A
51 #define CMD_INTERNAL_AUTHENTICATE 0x88
52 #define CMD_GENERATE_KEYPAIR      0x47
53 #define CMD_GET_CHALLENGE         0x84
54
55 static gpg_error_t
56 map_sw (int sw)
57 {
58   gpg_err_code_t ec;
59
60   switch (sw)
61     {
62     case SW_EEPROM_FAILURE: ec = GPG_ERR_HARDWARE; break;
63     case SW_WRONG_LENGTH:   ec = GPG_ERR_INV_VALUE; break;
64     case SW_CHV_WRONG:      ec = GPG_ERR_BAD_PIN; break;
65     case SW_CHV_BLOCKED:    ec = GPG_ERR_PIN_BLOCKED; break;
66     case SW_USE_CONDITIONS: ec = GPG_ERR_USE_CONDITIONS; break;
67     case SW_NOT_SUPPORTED:  ec = GPG_ERR_NOT_SUPPORTED; break;
68     case SW_BAD_PARAMETER:  ec = GPG_ERR_INV_VALUE; break;
69     case SW_REF_NOT_FOUND:  ec = GPG_ERR_NO_OBJ; break;
70     case SW_BAD_P0_P1:      ec = GPG_ERR_INV_VALUE; break;
71     case SW_INS_NOT_SUP:    ec = GPG_ERR_CARD; break;
72     case SW_CLA_NOT_SUP:    ec = GPG_ERR_CARD; break;
73     case SW_SUCCESS:        ec = 0; break;
74
75     case SW_HOST_OUT_OF_CORE: ec = GPG_ERR_ENOMEM; break;
76     case SW_HOST_INV_VALUE:   ec = GPG_ERR_INV_VALUE; break;
77     case SW_HOST_INCOMPLETE_CARD_RESPONSE: ec = GPG_ERR_CARD; break;
78     default:
79       if ((sw & 0x010000))
80         ec = GPG_ERR_GENERAL; /* Should not happen. */
81       else if ((sw & 0xff00) == SW_MORE_DATA)
82         ec = 0; /* This should actually never been seen here. */
83       else
84         ec = GPG_ERR_CARD;
85     }
86   return gpg_error (ec);
87 }
88
89 /* This function is specialized version of the SELECT FILE command.
90    SLOT is the card and reader as created for example by
91    apdu_open_reader (), AID is a buffer of size AIDLEN holding the
92    requested application ID.  The function can't be used to enumerate
93    AIDs and won't return the AID on success.  The return value is 0
94    for okay or GNUPG error code.  Note that ISO error codes are
95    internally mapped. */
96 gpg_error_t
97 iso7816_select_application (int slot, const char *aid, size_t aidlen)
98 {
99   int sw;
100
101   sw = apdu_send_simple (slot, 0x00, CMD_SELECT_FILE, 4, 0, aidlen, aid);
102   return map_sw (sw);
103 }
104
105
106 /* Perform a VERIFY command on SLOT using the card holder verification
107    vector CHVNO with a CHV of lenght CHVLEN.  Returns 0 on success. */
108 gpg_error_t
109 iso7816_verify (int slot, int chvno, const char *chv, size_t chvlen)
110 {
111   int sw;
112
113   sw = apdu_send_simple (slot, 0x00, CMD_VERIFY, 0, chvno, chvlen, chv);
114   return map_sw (sw);
115 }
116
117 /* Perform a CHANGE_REFERENCE_DATA command on SLOT for the card holder
118    verification vector CHVNO.  If the OLDCHV is NULL (and OLDCHVLEN
119    0), a "change reference data" is done, otherwise an "exchange
120    reference data".  The new reference data is expected in NEWCHV of
121    length NEWCHVLEN.  */
122 gpg_error_t
123 iso7816_change_reference_data (int slot, int chvno,
124                                const char *oldchv, size_t oldchvlen,
125                                const char *newchv, size_t newchvlen)
126 {
127   int sw;
128   char *buf;
129
130   if ((!oldchv && oldchvlen)
131       || (oldchv && !oldchvlen)
132       || !newchv || !newchvlen )
133     return gpg_error (GPG_ERR_INV_VALUE);
134
135   buf = xtrymalloc (oldchvlen + newchvlen);
136   if (!buf)
137     return out_of_core ();
138   if (oldchvlen)
139     memcpy (buf, oldchv, oldchvlen);
140   memcpy (buf+oldchvlen, newchv, newchvlen);
141
142   sw = apdu_send_simple (slot, 0x00, CMD_CHANGE_REFERENCE_DATA,
143                          oldchvlen? 0 : 1, chvno, oldchvlen+newchvlen, buf);
144   xfree (buf);
145   return map_sw (sw);
146
147 }
148
149 gpg_error_t
150 iso7816_reset_retry_counter (int slot, int chvno,
151                              const char *newchv, size_t newchvlen)
152 {
153   int sw;
154
155   if (!newchv || !newchvlen )
156     return gpg_error (GPG_ERR_INV_VALUE);
157
158   sw = apdu_send_simple (slot, 0x00, CMD_RESET_RETRY_COUNTER,
159                          2, chvno, newchvlen, newchv);
160   return map_sw (sw);
161 }
162
163
164 /* Perform a GET DATA command requesting TAG and storing the result in
165    a newly allocated buffer at the address passed by RESULT.  Return
166    the length of this data at the address of RESULTLEN. */
167 gpg_error_t
168 iso7816_get_data (int slot, int tag,
169                   unsigned char **result, size_t *resultlen)
170 {
171   int sw;
172
173   if (!result || !resultlen)
174     return gpg_error (GPG_ERR_INV_VALUE);
175   *result = NULL;
176   *resultlen = 0;
177
178   sw = apdu_send (slot, 0x00, CMD_GET_DATA,
179                   ((tag >> 8) & 0xff), (tag & 0xff), -1, NULL,
180                   result, resultlen);
181   if (sw != SW_SUCCESS)
182     {
183       /* Make sure that pending buffers are released. */
184       xfree (*result);
185       *result = NULL;
186       *resultlen = 0;
187       return map_sw (sw);
188     }
189
190   return 0;
191 }
192
193
194 /* Perform a PUT DATA command on card in SLOT.  Write DATA of length
195    DATALEN to TAG. */
196 gpg_error_t
197 iso7816_put_data (int slot, int tag,
198                   const unsigned char *data, size_t datalen)
199 {
200   int sw;
201
202   sw = apdu_send_simple (slot, 0x00, CMD_PUT_DATA,
203                          ((tag >> 8) & 0xff), (tag & 0xff),
204                          datalen, data);
205   return map_sw (sw);
206 }
207
208
209 /* Perform the security operation COMPUTE DIGITAL SIGANTURE.  On
210    success 0 is returned and the data is availavle in a newly
211    allocated buffer stored at RESULT with its length stored at
212    RESULTLEN. */
213 gpg_error_t
214 iso7816_compute_ds (int slot, const unsigned char *data, size_t datalen,
215                     unsigned char **result, size_t *resultlen)
216 {
217   int sw;
218
219   if (!data || !datalen || !result || !resultlen)
220     return gpg_error (GPG_ERR_INV_VALUE);
221   *result = NULL;
222   *resultlen = 0;
223
224   sw = apdu_send (slot, 0x00, CMD_PSO, 0x9E, 0x9A, datalen, data,
225                   result, resultlen);
226   if (sw != SW_SUCCESS)
227     {
228       /* Make sure that pending buffers are released. */
229       xfree (*result);
230       *result = NULL;
231       *resultlen = 0;
232       return map_sw (sw);
233     }
234
235   return 0;
236 }
237
238
239 /* Perform the security operation DECIPHER.  On
240    success 0 is returned and the plaintext is available in a newly
241    allocated buffer stored at RESULT with its length stored at
242    RESULTLEN. */
243 gpg_error_t
244 iso7816_decipher (int slot, const unsigned char *data, size_t datalen,
245                   unsigned char **result, size_t *resultlen)
246 {
247   int sw;
248   unsigned char *buf;
249
250   if (!data || !datalen || !result || !resultlen)
251     return gpg_error (GPG_ERR_INV_VALUE);
252   *result = NULL;
253   *resultlen = 0;
254
255   /* We need to prepend the padding indicator. */
256   buf = xtrymalloc (datalen + 1);
257   if (!buf)
258     return out_of_core ();
259   *buf = 0; /* Padding indicator. */
260   memcpy (buf+1, data, datalen);
261   sw = apdu_send (slot, 0x00, CMD_PSO, 0x80, 0x86, datalen+1, buf,
262                   result, resultlen);
263   xfree (buf);
264   if (sw != SW_SUCCESS)
265     {
266       /* Make sure that pending buffers are released. */
267       xfree (*result);
268       *result = NULL;
269       *resultlen = 0;
270       return map_sw (sw);
271     }
272
273   return 0;
274 }
275
276
277 gpg_error_t
278 iso7816_internal_authenticate (int slot,
279                                const unsigned char *data, size_t datalen,
280                                unsigned char **result, size_t *resultlen)
281 {
282   int sw;
283
284   if (!data || !datalen || !result || !resultlen)
285     return gpg_error (GPG_ERR_INV_VALUE);
286   *result = NULL;
287   *resultlen = 0;
288
289   sw = apdu_send (slot, 0x00, CMD_INTERNAL_AUTHENTICATE, 0, 0,
290                   datalen, data,  result, resultlen);
291   if (sw != SW_SUCCESS)
292     {
293       /* Make sure that pending buffers are released. */
294       xfree (*result);
295       *result = NULL;
296       *resultlen = 0;
297       return map_sw (sw);
298     }
299
300   return 0;
301 }
302
303
304 static gpg_error_t
305 do_generate_keypair (int slot, int readonly,
306                   const unsigned char *data, size_t datalen,
307                   unsigned char **result, size_t *resultlen)
308 {
309   int sw;
310
311   if (!data || !datalen || !result || !resultlen)
312     return gpg_error (GPG_ERR_INV_VALUE);
313   *result = NULL;
314   *resultlen = 0;
315
316   sw = apdu_send (slot, 0x00, CMD_GENERATE_KEYPAIR, readonly? 0x81:0x80, 0,
317                   datalen, data,  result, resultlen);
318   if (sw != SW_SUCCESS)
319     {
320       /* Make sure that pending buffers are released. */
321       xfree (*result);
322       *result = NULL;
323       *resultlen = 0;
324       return map_sw (sw);
325     }
326
327   return 0;
328 }
329
330
331 gpg_error_t
332 iso7816_generate_keypair (int slot,
333                           const unsigned char *data, size_t datalen,
334                           unsigned char **result, size_t *resultlen)
335 {
336   return do_generate_keypair (slot, 0, data, datalen, result, resultlen);
337 }
338
339
340 gpg_error_t
341 iso7816_read_public_key (int slot,
342                           const unsigned char *data, size_t datalen,
343                           unsigned char **result, size_t *resultlen)
344 {
345   return do_generate_keypair (slot, 1, data, datalen, result, resultlen);
346 }
347
348
349
350 gpg_error_t
351 iso7816_get_challenge (int slot, int length, unsigned char *buffer)
352 {
353   int sw;
354   unsigned char *result;
355   size_t resultlen, n;
356
357   if (!buffer || length < 1)
358     return gpg_error (GPG_ERR_INV_VALUE);
359
360   do
361     {
362       result = NULL;
363       n = length > 254? 254 : length;
364       sw = apdu_send_le (slot, 0x00, CMD_GET_CHALLENGE, 0, 0, -1, NULL,
365                          n,
366                          &result, &resultlen);
367       if (sw != SW_SUCCESS)
368         {
369           /* Make sure that pending buffers are released. */
370           xfree (result);
371           return map_sw (sw);
372         }
373       if (resultlen > n)
374         resultlen = n;
375       memcpy (buffer, result, resultlen);
376       buffer += resultlen;
377       length -= resultlen;
378       xfree (result);
379     }
380   while (length > 0);
381
382   return 0;
383 }