SC - Smartcard Library

SCARD.002 (Initial)
T J Hudson tjh@cryptsoft.com
13 November 1997


Table of Contents


1. Smartcard Functions

sio also comes with a number of Smartcard related functions. To use these you need to also include sct0.h


2. Low-level interface

Low-level functions for reseting the smartcard and getting the ATR and scanning for the right communication settings.

2.1. SCT0_Reset

int SCT0_Reset(SIO_INFO *s);

Reset the Smartcard - should respond with ATR

2.2. SCT0_GetATR

int SCT0_GetATR(SIO_INFO *s,char *buf,int bufsize);

Request ATR from smartcard. SCT0_GetATR calls SCT0_Reset to perform a standard Smartcard reset.

2.3. SCT0_ScanForATR

int SCT0_ScanForATR(SIO_INFO *s,char *buf, int bufsize);

Try all communication settings until a valid ATR is returned. Using this function you can rapidly locate what parameter combination is required for any Smartcard.

SCT0_ScanForATR returns the length of the ATR (or 0 if no valid setting is found). The valid ATR is copied into buf assuming that there is enough space.

2.4. SCT0_ScanClasses

int SCT0_ScanClasses(SIO_INFO *s, char *classlist);

Scan for valid command classes. classlist should be an array of 256 chars (one for each class) and on return each index in the array will be set to 1 if the Smartcard responded indicating that the class was valid or 0 if an error was reported.

2.5. SCT0_ScanInstructions

int SCT0_ScanInstructions(SIO_INFO *s,char theclass,char *inslist);

Scan for valid instructions in a particular class. inslist should be an array of 256 chars (one for each instruction) and on return each index in the array will be set to 1 if the instruction is valid or 0 if it is not.


Note: some instructions (not many) may be valid without any parameters and in which case they will be executed during this scan.

2.6. SCT0_ScanFiles

int SCT0_ScanFiles(SIO_INFO *s,char theclass,char thefile,char *filelist);

Scan for all files by FileID that start with the given byte of thefile. filelist should be an array of 256 chars (one for each file) and on return each index in the array will be set to 1 if the file thefileindex exists or 0 if it does not.


3. Structures

3.1. SC_ATR

The SC_ATR structure holds a more easily manipulated version of the card ATR. Use SC_DecodeATR to convert from a buffer holding the ATR into the SC_ATR structure.

/* the ATR can be at most 1+32 characters ... we store the raw data
 * in "data" and the decoded data in the rest of the fields pulled
 * appart so that we don't have to mess with ATR logic to get at
 * the fields. There is redundant information naturally.
 */
typedef struct {
  unsigned char data[32+1];
  int data_count;

  unsigned char TS;
  unsigned char T0;

  int TCK;
  unsigned char TCK_sent;  /* transmitted TCK */
  unsigned char TCK_calc;  /* calculated TCK */

  /* there are limits to how many of TA[i] you can have but
   * is this documented somewhere - I'm assuming that 3 is
   * the max for any of the chars
   *
   * note: entry[0] in each of these is ignored so that
   *       TA1 is stored in TA[1] (not TA[0]) so that
   *       the code matches the documentation
   */
  unsigned char TA[1+3];
  int TA_count;
  unsigned char TB[1+3];
  int TB_count;
  unsigned char TC[1+3];
  int TC_count;

  /* we don't store TD bytes as there isn't anything in them
   * that is of interest except the transmission protocol currently
   * in use which we extract separately - however I might just be
   * wrong as there are cards that can support lots of different
   * protocols which are probably indicated via multiple TD bytes
   */

  /* historical bytes are implicitly limited by the bounds of
   * the total message size
   */
  char historical[32];
  int historical_count;

  /* now for the redundant interpretation of the above data */
  int direct_convention;
  int inverse_convention;

  /* transmission protocol extracted from TD bytes */
  int transmission_protocol;

} SC_ATR;

3.2. SC_CMD

typedef struct {
  unsigned char CLA;    /* class */
  unsigned char INS;    /* instruction */
  unsigned char P1;     /* parameter 1 */
  unsigned char P2;     /* parameter 2 */
  int Lc;               /* Length command - length of data */
  int Le;               /* Length expected - expected result length */
  char data[SC_MAX_DATA_LEN];       /* command data */
} SC_CMD;

3.3. SC_RSP

typedef struct {
  unsigned char SW1;
  unsigned char SW2;
  int len;
  char data[SC_MAX_DATA_LEN];
  int rsp_code;      /* interpreted code */
} SC_RSP;


Note: rsp_code is the card-independant interpretation of SW1 and SW2 in the form of one of the SC_RSP_* defines.


4. API

SIO *sio;
SC_STATE *sc;
SLOG *log;
SC_CMD cmd;
SC_RSP rsp;
char uout[SC_MAX_HEX_DATA_LEN];

sc=SC_Init(sio,SC_READER_DUMBMOUSE,SC_CARD_CRYPTOFLEX,1,log);
if (sc!=NULL) {
  /* select the MF the hard way */
  /* c0 a4 is SelectFile on a Cryptoflex */
  cmd.CLA=0xc0;
  cmd.INS=0xa4;
  cmd.P1=0x00;
  cmd.P2=0x00;
  cmd.len=0x02;
  cmd.data[0]=0x3f;
  cmd.data[1]=0x00;

  /* use the low-level interface */
  if (SC_DoCommand(sc,SC_DIR_IN,&cmd,&rsp) {
    /* it worked ... now we have to compose a GetResponse command
     * to get at the interesting data related to the file
     */
  }

  /* or use the ASCII form */
  if (SC_DoAsciiCommand(sc,SC_DIR_IN,"c0a40000023f00",uout)) {
    /* again ... we have to do a GetResponse manually */
  }

  /* or use the higher-level interface which is what really should
   * be used in preference to any of the other interfaces for any
   * application level-coding
   */
  if (SC_Execute(sc,"SelectFile 3f00",uout,1)) {
    /* this will do the select file command and then call getresponse
     * as well (as chaining is switched on) to get the extended result
     * if the command succeeded and then call the parsing routines to
     * decode the output structure into a variable list
     */

     /* display some of the interesting information */
     printf("FREE_SPACE: %s\n",SC_GetVar(sc,"FREE_SPACE"));
     printf("FILE_STATUS: %s\n",SC_GetVar(sc,"FILE_STATUS"));
  }

  SC_Final(sc);
}

4.1. SC_GetVersion

Get the version of the library.

int SC_GetVersion(int *vmajor, int *vminor);
#define SC_VERSION_MAJOR        1
#define SC_VERSION_MINOR        2

4.2. SC_DecodeATR

To decode a buffer holding an ATR into the

SC_ATR *SC_DecodeATR(char *buf,int len);

4.3. SC_ATR2Text

To convert a decode ATR in SC_ATR into a (potentially) user-meaningful textual description.

char *SC_ATR2Text(SC_ATR *atr,int flag);

4.4. SC_Init

Start a session with a given card in a given reader.

SC_STATE *SC_Init(SIO_INFO *s,int reader_type,
                    int card_type, int probe,
                  SLOG *log);

4.5. SC_Final

Finish with a session.

int SC_Final(SC_STATE *sc);

4.6. SC_SetLog

Specify where logging information is to be sent.

int SC_SetLog(SC_STATE *sc,SLOG *slog);

4.7. SC_ErrorCode2String

Convert from a numeric error code into the error token. The last error that occurs is detailed in the error_code field of the SC_STATE structure.

char *SC_ErrorCode2String(int err);

4.8. SC_DoCommand

Send an ISO 7816 command to smartcard and get a response.

int SC_DoCommand(SC_STATE *sc,int direction, SC_CMD *uin, SC_RSP *uout);

4.9. SC_DoAsciiCommand

Send an ISO 7816 command formatted in hexadecimal ASCII format and get a response.

int SC_DoAsciiCommand(SC_STATE *sc,int direction,char *uin,char *uout);

4.10. SC_ExecuteCommand

int SC_ExecuteCommand(SC_STATE *sc,char *cmd,char *uout,int chain);

5. Library structure

Internally things are structured so that there are well-defined (but not well-documented) abstraction layers.

 slog.c - logging interface
 sio.c - all the serial communication stuff
 sc.c - smartcard library interface
 sct0.c - ISO low-level scanning stuff
 sccards.c - higher-level command interface

Reader specific information is contained in sc.c for getting the ATR and for submitting commands to the reader and getting the responses.

ISO 7816 command parsing (turning a command into a byte stream and sending it to a card) is also in sc.c.

Parsing of ISO 7816 messages and error codes is handled in sccards.c where the ASCII command interface is assembled from table-driven card-specific command sets.

Each card has a separate file containing the supported commands.

 sc_cflex.c - Schlumberger Cryptoflex
 sc_dx.c - Philips DX

Commands can be chained together (usually for calling GET_RESPONSE on the success of a command).

The structured data returned from commands can be parsed into easily accessed variables (and later will be mapped in a card independant manner).