~ubuntu-branches/ubuntu/dapper/gnupg2/dapper

« back to all changes in this revision

Viewing changes to g10/iso7816.c

  • Committer: Bazaar Package Importer
  • Author(s): Andreas Mueller
  • Date: 2005-03-29 10:30:32 UTC
  • Revision ID: james.westby@ubuntu.com-20050329103032-sj42n2ain3ipx310
Tags: upstream-1.9.15
ImportĀ upstreamĀ versionĀ 1.9.15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* iso7816.c - ISO 7816 commands
 
2
 *      Copyright (C) 2003, 2004 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
 * $Id: iso7816.c,v 1.3.2.11 2004/10/20 08:54:45 wk Exp $
 
21
 */
 
22
 
 
23
#include <config.h>
 
24
#include <errno.h>
 
25
#include <stdio.h>
 
26
#include <stdlib.h>
 
27
#include <string.h>
 
28
 
 
29
#if defined(GNUPG_SCD_MAIN_HEADER)
 
30
#include GNUPG_SCD_MAIN_HEADER
 
31
#elif GNUPG_MAJOR_VERSION == 1
 
32
/* This is used with GnuPG version < 1.9.  The code has been source
 
33
   copied from the current GnuPG >= 1.9  and is maintained over
 
34
   there. */
 
35
#include "options.h"
 
36
#include "errors.h"
 
37
#include "memory.h"
 
38
#include "util.h"
 
39
#include "i18n.h"
 
40
#else /* GNUPG_MAJOR_VERSION != 1 */
 
41
#include "scdaemon.h"
 
42
#endif /* GNUPG_MAJOR_VERSION != 1 */
 
43
 
 
44
#include "iso7816.h"
 
45
#include "apdu.h"
 
46
 
 
47
 
 
48
#define CMD_SELECT_FILE 0xA4
 
49
#define CMD_VERIFY      0x20
 
50
#define CMD_CHANGE_REFERENCE_DATA 0x24
 
51
#define CMD_RESET_RETRY_COUNTER   0x2C
 
52
#define CMD_GET_DATA    0xCA
 
53
#define CMD_PUT_DATA    0xDA
 
54
#define CMD_MSE         0x22
 
55
#define CMD_PSO         0x2A
 
56
#define CMD_INTERNAL_AUTHENTICATE 0x88
 
57
#define CMD_GENERATE_KEYPAIR      0x47
 
58
#define CMD_GET_CHALLENGE         0x84
 
59
#define CMD_READ_BINARY 0xB0
 
60
#define CMD_READ_RECORD 0xB2
 
61
 
 
62
static gpg_error_t
 
63
map_sw (int sw)
 
64
{
 
65
  gpg_err_code_t ec;
 
66
 
 
67
  switch (sw)
 
68
    {
 
69
    case SW_EEPROM_FAILURE: ec = GPG_ERR_HARDWARE; break;
 
70
    case SW_WRONG_LENGTH:   ec = GPG_ERR_INV_VALUE; break;
 
71
    case SW_CHV_WRONG:      ec = GPG_ERR_BAD_PIN; break;
 
72
    case SW_CHV_BLOCKED:    ec = GPG_ERR_PIN_BLOCKED; break;
 
73
    case SW_USE_CONDITIONS: ec = GPG_ERR_USE_CONDITIONS; break;
 
74
    case SW_NOT_SUPPORTED:  ec = GPG_ERR_NOT_SUPPORTED; break;
 
75
    case SW_BAD_PARAMETER:  ec = GPG_ERR_INV_VALUE; break;
 
76
    case SW_FILE_NOT_FOUND: ec = GPG_ERR_ENOENT; break;
 
77
    case SW_RECORD_NOT_FOUND:ec= GPG_ERR_NOT_FOUND; break;
 
78
    case SW_REF_NOT_FOUND:  ec = GPG_ERR_NO_OBJ; break;
 
79
    case SW_BAD_P0_P1:      ec = GPG_ERR_INV_VALUE; break;
 
80
    case SW_INS_NOT_SUP:    ec = GPG_ERR_CARD; break;
 
81
    case SW_CLA_NOT_SUP:    ec = GPG_ERR_CARD; break;
 
82
    case SW_SUCCESS:        ec = 0; break;
 
83
 
 
84
    case SW_HOST_OUT_OF_CORE: ec = GPG_ERR_ENOMEM; break;
 
85
    case SW_HOST_INV_VALUE:   ec = GPG_ERR_INV_VALUE; break;
 
86
    case SW_HOST_INCOMPLETE_CARD_RESPONSE: ec = GPG_ERR_CARD; break;
 
87
    case SW_HOST_NOT_SUPPORTED: ec = GPG_ERR_NOT_SUPPORTED; break;
 
88
    case SW_HOST_LOCKING_FAILED: ec = GPG_ERR_BUG; break;
 
89
    case SW_HOST_BUSY:           ec = GPG_ERR_EBUSY; break;
 
90
    case SW_HOST_NO_CARD:        ec = GPG_ERR_CARD_NOT_PRESENT; break;
 
91
    case SW_HOST_CARD_INACTIVE:  ec = GPG_ERR_CARD_RESET; break;
 
92
    case SW_HOST_CARD_IO_ERROR:  ec = GPG_ERR_EIO; break;
 
93
    case SW_HOST_GENERAL_ERROR:  ec = GPG_ERR_GENERAL; break;
 
94
    case SW_HOST_NO_READER:      ec = GPG_ERR_ENODEV; break;
 
95
    case SW_HOST_ABORTED:        ec = GPG_ERR_CANCELED; break;
 
96
 
 
97
    default:
 
98
      if ((sw & 0x010000))
 
99
        ec = GPG_ERR_GENERAL; /* Should not happen. */
 
100
      else if ((sw & 0xff00) == SW_MORE_DATA)
 
101
        ec = 0; /* This should actually never been seen here. */
 
102
      else
 
103
        ec = GPG_ERR_CARD;
 
104
    }
 
105
  return gpg_error (ec);
 
106
}
 
107
 
 
108
/* Map a status word from the APDU layer to a gpg-error code.  */
 
109
gpg_error_t
 
110
iso7816_map_sw (int sw)
 
111
{
 
112
  /* All APDU functions should return 0x9000 on success but for
 
113
     historical reasons of the implementation some return 0 to
 
114
     indicate success.  We allow for that here. */
 
115
  return sw? map_sw (sw) : 0;
 
116
}
 
117
 
 
118
 
 
119
/* This function is specialized version of the SELECT FILE command.
 
120
   SLOT is the card and reader as created for example by
 
121
   apdu_open_reader (), AID is a buffer of size AIDLEN holding the
 
122
   requested application ID.  The function can't be used to enumerate
 
123
   AIDs and won't return the AID on success.  The return value is 0
 
124
   for okay or a GPG error code.  Note that ISO error codes are
 
125
   internally mapped. */
 
126
gpg_error_t
 
127
iso7816_select_application (int slot, const char *aid, size_t aidlen)
 
128
{
 
129
  int sw;
 
130
  sw = apdu_send_simple (slot, 0x00, CMD_SELECT_FILE, 4, 0, aidlen, aid);
 
131
  return map_sw (sw);
 
132
}
 
133
 
 
134
 
 
135
gpg_error_t
 
136
iso7816_select_file (int slot, int tag, int is_dir,
 
137
                     unsigned char **result, size_t *resultlen)
 
138
{
 
139
  int sw, p0, p1;
 
140
  unsigned char tagbuf[2];
 
141
 
 
142
  tagbuf[0] = (tag >> 8) & 0xff;
 
143
  tagbuf[1] = tag & 0xff;
 
144
 
 
145
  if (result || resultlen)
 
146
    {
 
147
      *result = NULL;
 
148
      *resultlen = 0;
 
149
      return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
 
150
    }
 
151
  else
 
152
    {
 
153
      p0 = (tag == 0x3F00)? 0: is_dir? 1:2;
 
154
      p1 = 0x0c; /* No FC return. */
 
155
      sw = apdu_send_simple (slot, 0x00, CMD_SELECT_FILE,
 
156
                             p0, p1, 2, tagbuf );
 
157
      return map_sw (sw);
 
158
    }
 
159
 
 
160
  return 0;
 
161
}
 
162
 
 
163
 
 
164
/* This is a private command currently only working for TCOS cards. */
 
165
gpg_error_t
 
166
iso7816_list_directory (int slot, int list_dirs,
 
167
                        unsigned char **result, size_t *resultlen)
 
168
{
 
169
  int sw;
 
170
 
 
171
  if (!result || !resultlen)
 
172
    return gpg_error (GPG_ERR_INV_VALUE);
 
173
  *result = NULL;
 
174
  *resultlen = 0;
 
175
 
 
176
  sw = apdu_send (slot, 0x80, 0xAA, list_dirs? 1:2, 0, -1, NULL,
 
177
                  result, resultlen);
 
178
  if (sw != SW_SUCCESS)
 
179
    {
 
180
      /* Make sure that pending buffers are released. */
 
181
      xfree (*result);
 
182
      *result = NULL;
 
183
      *resultlen = 0;
 
184
    }
 
185
  return map_sw (sw);
 
186
}
 
187
 
 
188
 
 
189
 
 
190
/* Perform a VERIFY command on SLOT using the card holder verification
 
191
   vector CHVNO with a CHV of lenght CHVLEN.  Returns 0 on success. */
 
192
gpg_error_t
 
193
iso7816_verify (int slot, int chvno, const char *chv, size_t chvlen)
 
194
{
 
195
  int sw;
 
196
 
 
197
  sw = apdu_send_simple (slot, 0x00, CMD_VERIFY, 0, chvno, chvlen, chv);
 
198
  return map_sw (sw);
 
199
}
 
200
 
 
201
/* Perform a CHANGE_REFERENCE_DATA command on SLOT for the card holder
 
202
   verification vector CHVNO.  If the OLDCHV is NULL (and OLDCHVLEN
 
203
   0), a "change reference data" is done, otherwise an "exchange
 
204
   reference data".  The new reference data is expected in NEWCHV of
 
205
   length NEWCHVLEN.  */
 
206
gpg_error_t
 
207
iso7816_change_reference_data (int slot, int chvno,
 
208
                               const char *oldchv, size_t oldchvlen,
 
209
                               const char *newchv, size_t newchvlen)
 
210
{
 
211
  int sw;
 
212
  char *buf;
 
213
 
 
214
  if ((!oldchv && oldchvlen)
 
215
      || (oldchv && !oldchvlen)
 
216
      || !newchv || !newchvlen )
 
217
    return gpg_error (GPG_ERR_INV_VALUE);
 
218
 
 
219
  buf = xtrymalloc (oldchvlen + newchvlen);
 
220
  if (!buf)
 
221
    return gpg_error (gpg_err_code_from_errno (errno));
 
222
  if (oldchvlen)
 
223
    memcpy (buf, oldchv, oldchvlen);
 
224
  memcpy (buf+oldchvlen, newchv, newchvlen);
 
225
 
 
226
  sw = apdu_send_simple (slot, 0x00, CMD_CHANGE_REFERENCE_DATA,
 
227
                         oldchvlen? 0 : 1, chvno, oldchvlen+newchvlen, buf);
 
228
  xfree (buf);
 
229
  return map_sw (sw);
 
230
 
 
231
}
 
232
 
 
233
gpg_error_t
 
234
iso7816_reset_retry_counter (int slot, int chvno,
 
235
                             const char *newchv, size_t newchvlen)
 
236
{
 
237
  int sw;
 
238
 
 
239
  if (!newchv || !newchvlen )
 
240
    return gpg_error (GPG_ERR_INV_VALUE);
 
241
 
 
242
  sw = apdu_send_simple (slot, 0x00, CMD_RESET_RETRY_COUNTER,
 
243
                         2, chvno, newchvlen, newchv);
 
244
  return map_sw (sw);
 
245
}
 
246
 
 
247
 
 
248
/* Perform a GET DATA command requesting TAG and storing the result in
 
249
   a newly allocated buffer at the address passed by RESULT.  Return
 
250
   the length of this data at the address of RESULTLEN. */
 
251
gpg_error_t
 
252
iso7816_get_data (int slot, int tag,
 
253
                  unsigned char **result, size_t *resultlen)
 
254
{
 
255
  int sw;
 
256
 
 
257
  if (!result || !resultlen)
 
258
    return gpg_error (GPG_ERR_INV_VALUE);
 
259
  *result = NULL;
 
260
  *resultlen = 0;
 
261
 
 
262
  sw = apdu_send (slot, 0x00, CMD_GET_DATA,
 
263
                  ((tag >> 8) & 0xff), (tag & 0xff), -1, NULL,
 
264
                  result, resultlen);
 
265
  if (sw != SW_SUCCESS)
 
266
    {
 
267
      /* Make sure that pending buffers are released. */
 
268
      xfree (*result);
 
269
      *result = NULL;
 
270
      *resultlen = 0;
 
271
      return map_sw (sw);
 
272
    }
 
273
 
 
274
  return 0;
 
275
}
 
276
 
 
277
 
 
278
/* Perform a PUT DATA command on card in SLOT.  Write DATA of length
 
279
   DATALEN to TAG. */
 
280
gpg_error_t
 
281
iso7816_put_data (int slot, int tag,
 
282
                  const unsigned char *data, size_t datalen)
 
283
{
 
284
  int sw;
 
285
 
 
286
  sw = apdu_send_simple (slot, 0x00, CMD_PUT_DATA,
 
287
                         ((tag >> 8) & 0xff), (tag & 0xff),
 
288
                         datalen, data);
 
289
  return map_sw (sw);
 
290
}
 
291
 
 
292
/* Manage Security Environment.  This is a weird operation and there
 
293
   is no easy abstraction for it.  Furthermore, some card seem to have
 
294
   a different interpreation of 7816-8 and thus we resort to let the
 
295
   caller decide what to do. */
 
296
gpg_error_t
 
297
iso7816_manage_security_env (int slot, int p1, int p2,
 
298
                             const unsigned char *data, size_t datalen)
 
299
{
 
300
  int sw;
 
301
 
 
302
  if (p1 < 0 || p1 > 255 || p2 < 0 || p2 > 255 || !data || !datalen)
 
303
    return gpg_error (GPG_ERR_INV_VALUE);
 
304
 
 
305
  sw = apdu_send_simple (slot, 0x00, CMD_MSE, p1, p2, datalen, data);
 
306
  return map_sw (sw);
 
307
}
 
308
 
 
309
 
 
310
/* Perform the security operation COMPUTE DIGITAL SIGANTURE.  On
 
311
   success 0 is returned and the data is availavle in a newly
 
312
   allocated buffer stored at RESULT with its length stored at
 
313
   RESULTLEN. */
 
314
gpg_error_t
 
315
iso7816_compute_ds (int slot, const unsigned char *data, size_t datalen,
 
316
                    unsigned char **result, size_t *resultlen)
 
317
{
 
318
  int sw;
 
319
 
 
320
  if (!data || !datalen || !result || !resultlen)
 
321
    return gpg_error (GPG_ERR_INV_VALUE);
 
322
  *result = NULL;
 
323
  *resultlen = 0;
 
324
 
 
325
  sw = apdu_send (slot, 0x00, CMD_PSO, 0x9E, 0x9A, datalen, data,
 
326
                  result, resultlen);
 
327
  if (sw != SW_SUCCESS)
 
328
    {
 
329
      /* Make sure that pending buffers are released. */
 
330
      xfree (*result);
 
331
      *result = NULL;
 
332
      *resultlen = 0;
 
333
      return map_sw (sw);
 
334
    }
 
335
 
 
336
  return 0;
 
337
}
 
338
 
 
339
 
 
340
/* Perform the security operation DECIPHER.  PADIND is the padding
 
341
   indicator to be used.  It should be 0 if no padding is required, a
 
342
   value of -1 suppresses the padding byte.  On success 0 is returned
 
343
   and the plaintext is available in a newly allocated buffer stored
 
344
   at RESULT with its length stored at RESULTLEN. */
 
345
gpg_error_t
 
346
iso7816_decipher (int slot, const unsigned char *data, size_t datalen,
 
347
                  int padind, unsigned char **result, size_t *resultlen)
 
348
{
 
349
  int sw;
 
350
  unsigned char *buf;
 
351
 
 
352
  if (!data || !datalen || !result || !resultlen)
 
353
    return gpg_error (GPG_ERR_INV_VALUE);
 
354
  *result = NULL;
 
355
  *resultlen = 0;
 
356
 
 
357
  if (padind >= 0)
 
358
    {
 
359
      /* We need to prepend the padding indicator. */
 
360
      buf = xtrymalloc (datalen + 1);
 
361
      if (!buf)
 
362
        return gpg_error (gpg_err_code_from_errno (errno));
 
363
 
 
364
      *buf = padind; /* Padding indicator. */
 
365
      memcpy (buf+1, data, datalen);
 
366
      sw = apdu_send (slot, 0x00, CMD_PSO, 0x80, 0x86, datalen+1, buf,
 
367
                      result, resultlen);
 
368
      xfree (buf);
 
369
    }
 
370
  else
 
371
    {
 
372
      sw = apdu_send (slot, 0x00, CMD_PSO, 0x80, 0x86, datalen, data,
 
373
                      result, resultlen);
 
374
    }
 
375
  if (sw != SW_SUCCESS)
 
376
    {
 
377
      /* Make sure that pending buffers are released. */
 
378
      xfree (*result);
 
379
      *result = NULL;
 
380
      *resultlen = 0;
 
381
      return map_sw (sw);
 
382
    }
 
383
 
 
384
  return 0;
 
385
}
 
386
 
 
387
 
 
388
gpg_error_t
 
389
iso7816_internal_authenticate (int slot,
 
390
                               const unsigned char *data, size_t datalen,
 
391
                               unsigned char **result, size_t *resultlen)
 
392
{
 
393
  int sw;
 
394
 
 
395
  if (!data || !datalen || !result || !resultlen)
 
396
    return gpg_error (GPG_ERR_INV_VALUE);
 
397
  *result = NULL;
 
398
  *resultlen = 0;
 
399
 
 
400
  sw = apdu_send (slot, 0x00, CMD_INTERNAL_AUTHENTICATE, 0, 0,
 
401
                  datalen, data,  result, resultlen);
 
402
  if (sw != SW_SUCCESS)
 
403
    {
 
404
      /* Make sure that pending buffers are released. */
 
405
      xfree (*result);
 
406
      *result = NULL;
 
407
      *resultlen = 0;
 
408
      return map_sw (sw);
 
409
    }
 
410
 
 
411
  return 0;
 
412
}
 
413
 
 
414
 
 
415
static gpg_error_t
 
416
do_generate_keypair (int slot, int readonly,
 
417
                  const unsigned char *data, size_t datalen,
 
418
                  unsigned char **result, size_t *resultlen)
 
419
{
 
420
  int sw;
 
421
 
 
422
  if (!data || !datalen || !result || !resultlen)
 
423
    return gpg_error (GPG_ERR_INV_VALUE);
 
424
  *result = NULL;
 
425
  *resultlen = 0;
 
426
 
 
427
  sw = apdu_send (slot, 0x00, CMD_GENERATE_KEYPAIR, readonly? 0x81:0x80, 0,
 
428
                  datalen, data,  result, resultlen);
 
429
  if (sw != SW_SUCCESS)
 
430
    {
 
431
      /* Make sure that pending buffers are released. */
 
432
      xfree (*result);
 
433
      *result = NULL;
 
434
      *resultlen = 0;
 
435
      return map_sw (sw);
 
436
    }
 
437
 
 
438
  return 0;
 
439
}
 
440
 
 
441
 
 
442
gpg_error_t
 
443
iso7816_generate_keypair (int slot,
 
444
                          const unsigned char *data, size_t datalen,
 
445
                          unsigned char **result, size_t *resultlen)
 
446
{
 
447
  return do_generate_keypair (slot, 0, data, datalen, result, resultlen);
 
448
}
 
449
 
 
450
 
 
451
gpg_error_t
 
452
iso7816_read_public_key (int slot,
 
453
                          const unsigned char *data, size_t datalen,
 
454
                          unsigned char **result, size_t *resultlen)
 
455
{
 
456
  return do_generate_keypair (slot, 1, data, datalen, result, resultlen);
 
457
}
 
458
 
 
459
 
 
460
 
 
461
gpg_error_t
 
462
iso7816_get_challenge (int slot, int length, unsigned char *buffer)
 
463
{
 
464
  int sw;
 
465
  unsigned char *result;
 
466
  size_t resultlen, n;
 
467
 
 
468
  if (!buffer || length < 1)
 
469
    return gpg_error (GPG_ERR_INV_VALUE);
 
470
 
 
471
  do
 
472
    {
 
473
      result = NULL;
 
474
      n = length > 254? 254 : length;
 
475
      sw = apdu_send_le (slot, 0x00, CMD_GET_CHALLENGE, 0, 0, -1, NULL,
 
476
                         n,
 
477
                         &result, &resultlen);
 
478
      if (sw != SW_SUCCESS)
 
479
        {
 
480
          /* Make sure that pending buffers are released. */
 
481
          xfree (result);
 
482
          return map_sw (sw);
 
483
        }
 
484
      if (resultlen > n)
 
485
        resultlen = n;
 
486
      memcpy (buffer, result, resultlen);
 
487
      buffer += resultlen;
 
488
      length -= resultlen;
 
489
      xfree (result);
 
490
    }
 
491
  while (length > 0);
 
492
 
 
493
  return 0;
 
494
}
 
495
 
 
496
/* Perform a READ BINARY command requesting a maximum of NMAX bytes
 
497
   from OFFSET.  With NMAX = 0 the entire file is read. The result is
 
498
   stored in a newly allocated buffer at the address passed by RESULT.
 
499
   Returns the length of this data at the address of RESULTLEN. */
 
500
gpg_error_t
 
501
iso7816_read_binary (int slot, size_t offset, size_t nmax,
 
502
                     unsigned char **result, size_t *resultlen)
 
503
{
 
504
  int sw;
 
505
  unsigned char *buffer;
 
506
  size_t bufferlen;
 
507
  int read_all = !nmax;
 
508
  size_t n;
 
509
 
 
510
  if (!result || !resultlen)
 
511
    return gpg_error (GPG_ERR_INV_VALUE);
 
512
  *result = NULL;
 
513
  *resultlen = 0;
 
514
 
 
515
  /* We can only encode 15 bits in p0,p1 to indicate an offset. Thus
 
516
     we check for this limit. */
 
517
  if (offset > 32767)
 
518
    return gpg_error (GPG_ERR_INV_VALUE);
 
519
 
 
520
  do
 
521
    {
 
522
      buffer = NULL;
 
523
      bufferlen = 0;
 
524
      /* Fixme: Either the ccid driver or the TCOS cards have problems
 
525
         with an Le of 0. */
 
526
      if (read_all || nmax > 254)
 
527
        n = 254;
 
528
      else
 
529
        n = nmax;
 
530
      sw = apdu_send_le (slot, 0x00, CMD_READ_BINARY,
 
531
                         ((offset>>8) & 0xff), (offset & 0xff) , -1, NULL,
 
532
                         n, &buffer, &bufferlen);
 
533
 
 
534
      if (sw != SW_SUCCESS && sw != SW_EOF_REACHED)
 
535
        {
 
536
          /* Make sure that pending buffers are released. */
 
537
          xfree (buffer);
 
538
          xfree (*result);
 
539
          *result = NULL;
 
540
          *resultlen = 0;
 
541
          return map_sw (sw);
 
542
        }
 
543
      if (*result) /* Need to extend the buffer. */
 
544
        {
 
545
          unsigned char *p = xtryrealloc (*result, *resultlen + bufferlen);
 
546
          if (!p)
 
547
            {
 
548
              gpg_error_t err = gpg_error_from_errno (errno);
 
549
              xfree (buffer);
 
550
              xfree (*result);
 
551
              *result = NULL;
 
552
              *resultlen = 0;
 
553
              return err;
 
554
            }
 
555
          *result = p;
 
556
          memcpy (*result + *resultlen, buffer, bufferlen);
 
557
          *resultlen += bufferlen;
 
558
          xfree (buffer);
 
559
          buffer = NULL;
 
560
        }
 
561
      else /* Transfer the buffer into our result. */
 
562
        {
 
563
          *result = buffer;
 
564
          *resultlen = bufferlen;
 
565
        }
 
566
      offset += bufferlen;
 
567
      if (offset > 32767)
 
568
        break; /* We simply truncate the result for too large
 
569
                  files. */
 
570
      if (nmax > bufferlen)
 
571
        nmax -= bufferlen;
 
572
      else
 
573
        nmax = 0;
 
574
    }
 
575
  while ((read_all && sw != SW_EOF_REACHED) || (!read_all && nmax));
 
576
  
 
577
  return 0;
 
578
}
 
579
 
 
580
/* Perform a READ RECORD command. RECNO gives the record number to
 
581
   read with 0 indicating the current record.  RECCOUNT must be 1 (not
 
582
   all cards support reading of more than one record).  SHORT_EF
 
583
   should be 0 to read the current EF or contain a short EF. The
 
584
   result is stored in a newly allocated buffer at the address passed
 
585
   by RESULT.  Returns the length of this data at the address of
 
586
   RESULTLEN. */
 
587
gpg_error_t
 
588
iso7816_read_record (int slot, int recno, int reccount, int short_ef,
 
589
                     unsigned char **result, size_t *resultlen)
 
590
{
 
591
  int sw;
 
592
  unsigned char *buffer;
 
593
  size_t bufferlen;
 
594
 
 
595
  if (!result || !resultlen)
 
596
    return gpg_error (GPG_ERR_INV_VALUE);
 
597
  *result = NULL;
 
598
  *resultlen = 0;
 
599
 
 
600
  /* We can only encode 15 bits in p0,p1 to indicate an offset. Thus
 
601
     we check for this limit. */
 
602
  if (recno < 0 || recno > 255 || reccount != 1
 
603
      || short_ef < 0 || short_ef > 254 )
 
604
    return gpg_error (GPG_ERR_INV_VALUE);
 
605
 
 
606
  buffer = NULL;
 
607
  bufferlen = 0;
 
608
  /* Fixme: Either the ccid driver of the TCOS cards have problems
 
609
     with an Le of 0. */
 
610
  sw = apdu_send_le (slot, 0x00, CMD_READ_RECORD,
 
611
                     recno, 
 
612
                     short_ef? short_ef : 0x04,
 
613
                     -1, NULL,
 
614
                     254, &buffer, &bufferlen);
 
615
 
 
616
  if (sw != SW_SUCCESS && sw != SW_EOF_REACHED)
 
617
    {
 
618
      /* Make sure that pending buffers are released. */
 
619
      xfree (buffer);
 
620
      xfree (*result);
 
621
      *result = NULL;
 
622
      *resultlen = 0;
 
623
      return map_sw (sw);
 
624
    }
 
625
  *result = buffer;
 
626
  *resultlen = bufferlen;
 
627
  
 
628
  return 0;
 
629
}
 
630