Andreas Jellinghaus wrote:

> sounds great, please post your code for review.

Here's what I have, as one attachment in "svn diff" format with the
minor changes and one file card-acos5.c with the rest.

I made sure the indentation on the minor changes matched the files that
were being changed.  The card-acos5.c ended up with whatever a stock
version of emacs on FC6 comes up with, which seems to be 2-space
indentation.  If people would prefer card-acos5.c to match the other
files in this respect, let me know and I'll try and beat emacs into
submission.

Any other comments welcome, of course.

        -- Ian
Index: src/libopensc/ctx.c
===================================================================
--- src/libopensc/ctx.c (revision 3125)
+++ src/libopensc/ctx.c (working copy)
@@ -76,6 +76,7 @@
 #ifdef HAVE_OPENSSL
        { "PIV-II",(void *) sc_get_piv_driver },
 #endif
+       { "acos5",      (void *(*)(void)) sc_get_acos5_driver },
        /* The default driver should be last, as it handles all the
         * unrecognized cards. */
        { "default",    (void *(*)(void)) sc_get_default_driver },
Index: src/libopensc/Makefile.am
===================================================================
--- src/libopensc/Makefile.am   (revision 3125)
+++ src/libopensc/Makefile.am   (working copy)
@@ -29,7 +29,7 @@
        card-cardos.c card-tcos.c card-emv.c card-default.c \
        card-mcrd.c card-starcos.c card-openpgp.c card-jcop.c \
        card-oberthur.c card-belpic.c card-atrust-acos.c \
-       card-incrypto34.c card-piv.c card-muscle.c \
+       card-incrypto34.c card-piv.c card-muscle.c card-acos5.c \
        \
        pkcs15-openpgp.c pkcs15-infocamere.c pkcs15-starcert.c \
        pkcs15-tcos.c pkcs15-esteid.c pkcs15-postecert.c pkcs15-gemsafe.c \
Index: src/libopensc/opensc.h
===================================================================
--- src/libopensc/opensc.h      (revision 3125)
+++ src/libopensc/opensc.h      (working copy)
@@ -1177,6 +1177,7 @@
 extern sc_card_driver_t *sc_get_incrypto34_driver(void);
 extern sc_card_driver_t *sc_get_piv_driver(void);
 extern sc_card_driver_t *sc_get_muscle_driver(void);
+extern sc_card_driver_t *sc_get_acos5_driver(void);
 
 #ifdef __cplusplus
 }
/*
 * card-acos5.c: Support for ACS ACOS5 cards.
 *
 * Copyright (C) 2007  Ian A. Young<[EMAIL PROTECTED]>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include <string.h>
#include "internal.h"
#include "cardctl.h"

static struct sc_atr_table acos5_atrs[] = {
  { "3b:be:18:00:00:41:05:10:00:00:00:00:00:00:00:00:00:90:00", NULL, NULL, 
SC_CARD_TYPE_TEST_BASE, 0, NULL },
  { NULL, NULL, NULL, 0, 0, NULL }
};

static struct sc_card_operations *iso_ops;
static struct sc_card_operations acos5_ops;
static struct sc_card_driver acos5_drv = {
  "ACS ACOS5 card",
  "acos5",
  &acos5_ops,
  NULL, 0, NULL
};

static int
acos5_match_card(sc_card_t *card)
{
  int i;

  i = _sc_match_atr(card, acos5_atrs, &card->type);
  if (i < 0)
    return 0;
  return 1;
}

static int acos5_init(sc_card_t *card)
{
  card->max_recv_size = 128;
  card->max_send_size = 128;
  return SC_SUCCESS;
}

static int acos5_finish(sc_card_t *card)
{
  return SC_SUCCESS;
}

static int acos5_select_file_by_path(sc_card_t *card,
                                     const sc_path_t *in_path,
                                     sc_file_t **file_out)
{
  int in_len = in_path->len;
  const u8 *in_pos = in_path->value;

  sc_path_t path;
  path.len = 2; /* one component at a time */
  path.type = SC_PATH_TYPE_FILE_ID;

  /*
   * Check parameters.
   */
  if (in_len%2 != 0)
    return SC_ERROR_INVALID_ARGUMENTS;

  /*
   * File ID by file ID...
   */
  while (in_len) {
    int result;
    memcpy(path.value, in_pos, 2);
    result = iso_ops->select_file(card, &path, file_out);
    if (result != SC_SUCCESS) return result;
    in_len -= 2;
    in_pos += 2;
  }
  return SC_SUCCESS;
}

static int acos5_select_file(sc_card_t *card,
                             const sc_path_t *in_path,
                             sc_file_t **file_out)
{
  switch (in_path->type) {

  case SC_PATH_TYPE_PATH:
    return acos5_select_file_by_path(card, in_path, file_out);

  default:
    return iso_ops->select_file(card, in_path, file_out);
  }
}

static int
acos5_get_serialnr(sc_card_t *card, sc_serial_number_t *serial)
{
  int r;
  u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
  sc_apdu_t apdu;

  /*
   * Check arguments.
   */
  if (!serial)
    return SC_ERROR_INVALID_ARGUMENTS;

  /*
   * Return a cached serial number, if we have one.
   */
  if (card->serialnr.len) {
    memcpy(serial, &card->serialnr, sizeof(*serial));
    return SC_SUCCESS;
  }

  /*
   * Fetch serial number using GET CARD INFO.
   */
  sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0x14, 0, 0);
  apdu.cla |= 0x80;
  apdu.resp = rbuf;
  apdu.resplen = sizeof(rbuf);
  apdu.le = 6;
  r = sc_transmit_apdu(card, &apdu);
  SC_TEST_RET(card->ctx, r, "APDU transmit failed");
  if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00)
    return SC_ERROR_INTERNAL;

  /*
   * Cache serial number.
   */
  memcpy(card->serialnr.value, apdu.resp, apdu.resplen);
  card->serialnr.len = apdu.resplen;

  /*
   * Copy and return serial number.
   */
  memcpy(serial, &card->serialnr, sizeof(*serial));
  return SC_SUCCESS;
}

static int
acos5_card_ctl(sc_card_t *card, unsigned long cmd, void *ptr)
{
  switch (cmd) {

  case SC_CARDCTL_GET_SERIALNR:
    return acos5_get_serialnr(card, (sc_serial_number_t *)ptr);

  default:
    return SC_ERROR_NOT_SUPPORTED;
  }
}

static int acos5_list_files(sc_card_t *card, u8 *buf, size_t buflen)
{
  sc_apdu_t apdu;
  int r;
  size_t count;
  u8 *bufp = buf;       /* pointer into buf */
  int fno = 0;          /* current file index */

  /*
   * Check parameters.
   */
  if (!buf || (buflen&1))
    return SC_ERROR_INVALID_ARGUMENTS;

  /*
   * Use CARD GET INFO to fetch the number of files under the
   * curently selected DF.
   */
  sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x14, 0x01, 0x00);
  apdu.cla |= 0x80;
  r = sc_transmit_apdu(card, &apdu);
  SC_TEST_RET(card->ctx, r, "APDU transmit failed");
  if (apdu.sw1 != 0x90)
    return SC_ERROR_INTERNAL;
  count = apdu.sw2;

  while (count--) {
    u8 info[8];

    /*
     * Truncate the scan if no more room left in output buffer.
     */
    if (buflen == 0) break;

    sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0x14, 0x02, fno++);
    apdu.cla |= 0x80;
    apdu.resp = info;
    apdu.resplen = sizeof(info);
    apdu.le = sizeof(info);
    r = sc_transmit_apdu(card, &apdu);
    SC_TEST_RET(card->ctx, r, "APDU transmit failed");
    if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00)
      return SC_ERROR_INTERNAL;

    *bufp++ = info[2];
    *bufp++ = info[3];
    buflen -= 2;
  }

  return (bufp - buf);
}

static struct sc_card_driver *
sc_get_driver(void)
{
  struct sc_card_driver *iso_drv = sc_get_iso7816_driver();

  iso_ops = iso_drv->ops;
  acos5_ops = *iso_ops;

  acos5_ops.match_card  = acos5_match_card;
  acos5_ops.init                = acos5_init;
  acos5_ops.finish      = acos5_finish;
  acos5_ops.select_file = acos5_select_file;
  acos5_ops.card_ctl    = acos5_card_ctl;
  acos5_ops.list_files  = acos5_list_files;

  return &acos5_drv;
}

struct sc_card_driver *sc_get_acos5_driver(void)
{
  return sc_get_driver();
}
_______________________________________________
opensc-devel mailing list
[email protected]
http://www.opensc-project.org/mailman/listinfo/opensc-devel

Reply via email to