Changeset 526 for branches

Show
Ignore:
Timestamp:
07/09/04 19:20:24 (5 years ago)
Author:
aj
Message:

This patch introduces host files to CTAPI. The implementation is not
complete, but enough to compile and run code to read out German health
insurance cards. It should not break existing code, but of course
testing is encouraged. (fix by Michael Haardt)

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • branches/openct-0.6/src/ctapi/ctapi.c

    r411 r526  
    99#endif 
    1010#include <stdlib.h> 
     11#include <string.h> 
    1112#include <openct/openct.h> 
    1213#include <openct/ifd.h> 
     
    1516#include <openct/conf.h> 
    1617#include <openct/error.h> 
     18 
    1719#include "ctapi.h" 
    18  
    19 static struct CardTerminal 
    20 { 
    21         unsigned short ctn; 
    22         ct_handle *h; 
    23         ct_lock_handle lock; 
    24         struct CardTerminal *next; 
    25 } *cardTerminals; 
    2620 
    2721/* 
     
    4842} 
    4943 
    50 static int 
    51 ctapi_reset(ct_handle *h, char p1, char p2, 
     44struct CardTerminal; 
     45 
     46struct CardTerminalFile 
     47{ 
     48        unsigned int id; 
     49        int (*gen)(struct CardTerminal *ct, ct_buf_t *buf, off_t start, size_t length, size_t *size); 
     50        struct CardTerminalFile *dir[20]; 
     51}; 
     52 
     53static struct CardTerminal 
     54{ 
     55        unsigned short ctn; 
     56        ct_handle *h; 
     57        unsigned int slots; 
     58        ct_lock_handle lock; 
     59        unsigned char sync; 
     60        struct CardTerminalFile mf; 
     61        struct CardTerminalFile ctcf; 
     62        struct CardTerminalFile ctdir; 
     63        struct CardTerminalFile iccdir[16]; 
     64        struct CardTerminalFile hostcf; 
     65        struct CardTerminalFile hoststatus; 
     66        struct CardTerminalFile *cwd; 
     67        struct CardTerminal *next; 
     68} *cardTerminals; 
     69 
     70static int 
     71put(ct_buf_t *buf, 
     72        off_t *start, size_t *length, size_t *size, const unsigned char *data, size_t data_len) 
     73{ 
     74        *size+=data_len; 
     75        while (data_len--) { 
     76                if (*start==0) { 
     77                        if (*length>0) { 
     78                                if (buf!=(ct_buf_t*)0 && ct_buf_put(buf,data,1)<0) 
     79                                        return -1; 
     80                                ++data; 
     81                                --(*length); 
     82                        } 
     83                } 
     84                else --(*start); 
     85        } 
     86        return 0; 
     87} 
     88 
     89static int 
     90dir(struct CardTerminal *ct, 
     91        ct_buf_t *buf, off_t start, size_t length, size_t *size) 
     92{ 
     93        struct CardTerminalFile **entry; 
     94 
     95        if (size!=(size_t*)0) 
     96                *size=0; 
     97        for (entry=&ct->cwd->dir[0]; *entry; ++entry) { 
     98                char r[5]; 
     99                int rc; 
     100 
     101                r[0]=((*entry)->id>>8)&0xff; 
     102                r[1]=((*entry)->id)&0xff; 
     103                r[2]=0x01; 
     104                r[3]=0x00; 
     105                r[4]=0x00; 
     106                if ((rc=put(buf,&start,&length,size,r,5))<0) return rc; 
     107        } 
     108        return 0; 
     109} 
     110 
     111static int 
     112ctcf(struct CardTerminal *ct, 
     113        ct_buf_t *buf, off_t start, size_t length, size_t *size) 
     114{ 
     115        return 0; 
     116} 
     117 
     118static int 
     119hostcf(struct CardTerminal *ct, 
     120        ct_buf_t *buf, off_t start, size_t length, size_t *size) 
     121{ 
     122        char data[2]; 
     123        const char *version="OpenCT"; 
     124        int rc; 
     125 
     126        if (size!=(size_t*)0) *size=0; 
     127        data[0]=0x01; 
     128        data[1]=strlen(version); 
     129        if ((rc=put(buf,&start,&length,size,data,2))<0) 
     130                return rc; 
     131        if ((rc=put(buf,&start,&length,size,version,strlen(version)))<0) 
     132                return rc; 
     133        return 0; 
     134} 
     135 
     136static int 
     137hoststatus(struct CardTerminal *ct, 
     138        ct_buf_t *buf, off_t start, size_t length, size_t *size) 
     139{ 
     140        return 0; 
     141} 
     142 
     143static int 
     144CardTerminalFile_read(struct CardTerminal *ct, 
     145        ct_buf_t *buf, off_t offset, size_t len) 
     146{ 
     147        int rc; 
     148        size_t size; 
     149 
     150        if ((rc=ct->cwd->gen(ct,buf,offset,len,&size))<0) 
     151                return rc; 
     152        if (offset>size) { 
     153                return ctapi_error(buf,0x6b00); 
     154        } 
     155        else if (offset+len>=size) { 
     156                if (ctapi_put_sw(buf,0x9000)<0) return ctapi_error(buf,CTBCS_SW_BAD_LENGTH); 
     157                return 0; 
     158        } 
     159        else 
     160        { 
     161                if (ctapi_put_sw(buf,0x6282)<0) return ctapi_error(buf,CTBCS_SW_BAD_LENGTH); 
     162                else return 0; 
     163        } 
     164} 
     165 
     166static int 
     167CardTerminalFile_select(struct CardTerminal *ct, 
     168        int id, ct_buf_t *buf) 
     169{ 
     170        struct CardTerminalFile *cur=(struct CardTerminalFile*)0; 
     171        char r[12]={ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x00 }; 
     172        size_t size=0; 
     173 
     174        if (id==0x3f00) 
     175                cur=&ct->mf; 
     176        else if (id==0xff10) 
     177                cur=&ct->hostcf; 
     178        else if (id==0xff11) 
     179                cur=&ct->hoststatus; 
     180        else { 
     181                struct CardTerminalFile **entry; 
     182 
     183                for (entry=&ct->cwd->dir[0]; *entry && (*entry)->id!=id; ++entry); 
     184                cur=*entry; 
     185        }   
     186        if (cur==(struct CardTerminalFile*)0) 
     187                return ctapi_error(buf, 0x6a82); 
     188        ct->cwd=cur; 
     189        ct->cwd->gen(ct,(ct_buf_t*)0,0,1024,&size); 
     190        r[2]=r[0]=size>>8; 
     191        r[3]=r[1]=size&0xff; 
     192        r[4]=ct->cwd->dir[0]!=(struct CardTerminalFile*)0?0x88:0x08; 
     193        return ct_buf_put(buf,r,12); 
     194} 
     195 
     196static int 
     197ctapi_reset(struct CardTerminal *ct, char p1, char p2, 
    52198                ct_buf_t *rbuf, 
    53199                time_t timeout, const char *message) 
     
    60206        case CTBCS_UNIT_INTERFACE1: 
    61207        case CTBCS_UNIT_INTERFACE2: 
    62                 rc = ct_card_reset(h, p1 - CTBCS_UNIT_INTERFACE1, 
     208                rc = ct_card_reset(ct->h, p1 - CTBCS_UNIT_INTERFACE1, 
    63209                                atr, sizeof(atr)); 
    64210                break; 
     
    76222        if (rc < 0) 
    77223                return ERR_TRANS; 
     224 
     225        if (rc == 4) 
     226                ct->sync |= 1 << (p1 - CTBCS_UNIT_INTERFACE1); 
     227        else 
     228                ct->sync &= ~(1 << (p1 - CTBCS_UNIT_INTERFACE1)); 
    78229         
    79230        switch (p2 & 0xF) { 
     
    100251 */ 
    101252static int 
    102 ctapi_request_icc(ct_handle *h, char p1, char p2, 
     253ctapi_request_icc(struct CardTerminal *ct, char p1, char p2, 
    103254                ct_buf_t *sbuf, ct_buf_t *rbuf) 
    104255{ 
     
    121272        } 
    122273 
    123         /* XXX use ct_tlv_* functions */ 
    124274        while (ct_buf_avail(sbuf)) { 
    125275                unsigned char   type, len, val; 
     
    145295 
    146296        /* ctapi_reset does all the rest of the work */ 
    147         return ctapi_reset(h, p1, p2, rbuf, timeout, message); 
     297        return ctapi_reset(ct, p1, p2, rbuf, timeout, message); 
    148298 
    149299bad_length: 
     
    183333 */ 
    184334static int 
    185 ctapi_control(ct_handle *h, 
     335ctapi_control(struct CardTerminal *ct, 
    186336                const unsigned char *cmd, size_t cmd_len, 
    187337                void *rsp, size_t rsp_len) 
     
    190340        int             rc; 
    191341        int le = 0; 
     342        unsigned char id[2]; 
    192343 
    193344        if (rsp_len < 2) 
     
    214365        if (le == 0) le = 256; 
    215366 
    216         if (cmd[0] != CTBCS_CLA) { 
    217                 ct_error("Bad CTBCS APDU, cla=0x%02x", cmd[0]); 
    218                 ctapi_error(&rbuf, CTBCS_SW_BAD_CLASS); 
    219                 goto out; 
    220         } 
    221  
    222         switch (cmd[1]) { 
    223         case CTBCS_INS_RESET: /* old reset command */ 
    224         case 0x10:            /* new reset command */ 
    225                 rc = ctapi_reset(h, cmd[2], cmd[3], &rbuf, 0, NULL); 
    226                 break; 
    227         case CTBCS_INS_REQUEST_ICC: 
    228                 rc = ctapi_request_icc(h, cmd[2], cmd[3], &sbuf, &rbuf); 
    229                 break; 
    230         case CTBCS_INS_STATUS: 
    231                 rc = ctapi_status(h, &rbuf); 
    232                 break; 
    233         default: 
    234                 ct_error("Bad CTBCS APDU, ins=0x%02x", cmd[1]); 
    235                 rc = ctapi_error(&rbuf, CTBCS_SW_BAD_INS); 
     367        switch ((cmd[0]<<8)|cmd[1]) { 
     368                case (CTBCS_CLA<<8)|CTBCS_INS_RESET: /* compatibility reset command */ 
     369                case (CTBCS_CLA<<8)|0x10:            /* native reset command */ 
     370                        rc = ctapi_reset(ct, cmd[2], cmd[3], &rbuf, 0, NULL); 
     371                        break; 
     372                case (CTBCS_CLA<<8)|CTBCS_INS_REQUEST_ICC: 
     373                        rc = ctapi_request_icc(ct, cmd[2], cmd[3], &sbuf, &rbuf); 
     374                        break; 
     375                case (CTBCS_CLA<<8)|CTBCS_INS_STATUS: 
     376                        rc = ctapi_status(ct->h, &rbuf); 
     377                        break; 
     378                case (0x00<<8)|0xb0: 
     379                        rc = CardTerminalFile_read(ct, &rbuf, (cmd[2]<<8)|cmd[3], le); 
     380                        break; 
     381                case (0x00<<8)|0xa4: 
     382                        if (cmd[4]!=2 || ct_buf_get(&sbuf, id, 2)==-1) { 
     383                                ct_error("Bad SELECT FILE ID"); 
     384                                rc = ctapi_error(&rbuf, CTBCS_SW_BAD_CLASS); 
     385                        } else 
     386                                rc = CardTerminalFile_select(ct, (id[0]<<8)|id[1],&rbuf); 
     387                        break; 
     388                default: 
     389                        if (cmd[0]!=CTBCS_CLA && cmd[0]!=0x00) { 
     390                                ct_error("Bad CTBCS APDU, cla=0x%02x", cmd[0]); 
     391                                rc = ctapi_error(&rbuf, CTBCS_SW_BAD_CLASS); 
     392                        } 
     393                        else { 
     394                                ct_error("Bad CTBCS APDU, ins=0x%02x", cmd[1]); 
     395                                rc = ctapi_error(&rbuf, CTBCS_SW_BAD_INS); 
     396                        } 
    236397        } 
    237398 
     
    240401 
    241402        if (ct_buf_avail(&rbuf) > le + 2) 
    242                 ctapi_error(&rbuf, CTBCS_SW_BAD_LENGTH); 
    243  
    244 out:    return ct_buf_avail(&rbuf); 
     403                return ctapi_error(&rbuf, CTBCS_SW_BAD_LENGTH); 
     404 
     405        return ct_buf_avail(&rbuf); 
     406} 
     407 
     408/* 
     409 * Handle card transactions 
     410 */ 
     411static int 
     412ctapi_transact(struct CardTerminal *ct, int nslot, 
     413                const char *cmd, size_t cmd_len, 
     414                void *rsp, size_t rsp_len) 
     415{ 
     416        static const unsigned char select_kvk[11]={ 0x00, 0xa4, 0x04, 0x00, 0x06, 0xd2, 0x80, 0x00, 0x00, 0x01, 0x01 }; 
     417        static const unsigned char read_binary[2]={ 0x00, 0xb0 }; 
     418        ct_buf_t        sbuf, rbuf; 
     419        int             rc; 
     420        int le = 0; 
     421 
     422        ct_buf_set(&sbuf, (void *) cmd, cmd_len); 
     423        ct_buf_init(&rbuf, rsp, rsp_len); 
     424 
     425        if (cmd_len == 4) 
     426        { 
     427                le = 0; 
     428                ct_buf_get(&sbuf, NULL, 4); 
     429        } 
     430        else if (cmd_len == 5+(unsigned char)cmd[4]) 
     431        { 
     432                le = 0; 
     433                ct_buf_get(&sbuf, NULL, 5); 
     434        } 
     435        else 
     436        { 
     437                le = (unsigned char)cmd[4]; 
     438                ct_buf_get(&sbuf, NULL, 5); 
     439        } 
     440        if (le == 0) le = 256; 
     441 
     442        if (cmd_len == 11 && memcmp(cmd, select_kvk, 11)==0) { 
     443                rc = 0; 
     444                if (rc < 0) 
     445                        return rc; 
     446                if (ctapi_put_sw(&rbuf, 0x9000) < 0) 
     447                        return ctapi_error(&rbuf, CTBCS_SW_BAD_LENGTH); 
     448                return ct_buf_avail(&rbuf); 
     449        } 
     450        else if ((ct->sync & (1 << nslot)) && cmd_len >= 5 && memcmp(cmd, read_binary, 2)==0) { 
     451                unsigned char buf[256]; 
     452 
     453                if ((rc = ct_card_read_memory(ct->h, nslot, (((unsigned char)cmd[2])<<8)|((unsigned char)cmd[3]), buf, le)) < 0) 
     454{ 
     455#if 0 
     456printf("rc is %d\n",rc); 
     457#endif 
     458                        return rc; 
     459} 
     460                if (ct_buf_put(&rbuf, buf, rc) < 0 
     461                 || ctapi_put_sw(&rbuf, 0x9000) < 0) 
     462                        return ctapi_error(&rbuf, CTBCS_SW_BAD_LENGTH); 
     463                return ct_buf_avail(&rbuf); 
     464        } 
     465        else 
     466                return ct_card_transact(ct->h, 0, 
     467                        cmd, cmd_len, rsp, rsp_len); 
    245468} 
    246469 
    247470/* 
    248471 * Initialize card terminal #N. 
    249  * As all the terminals are configured by libifd internally, 
    250  * we ignore the port number 
    251472 */ 
    252473char 
     
    255476        struct CardTerminal *ct; 
    256477        ct_handle *h; 
     478        ct_info_t info; 
    257479        ct_lock_handle lock; 
    258  
    259         if ((ct=(struct CardTerminal *) malloc(sizeof(struct CardTerminal)))==(struct CardTerminal*)0) 
     480        int i; 
     481 
     482        if ((ct=malloc(sizeof(struct CardTerminal)))==(struct CardTerminal*)0) 
    260483                return ERR_MEMORY; 
    261484        if (!(h = ct_reader_connect(pn))) { 
     
    263486                return ERR_INVALID; 
    264487        } 
    265         if (ct_card_lock(h, 0, IFD_LOCK_EXCLUSIVE, &lock) < 0) { 
    266                 free(ct); 
    267                 return ERR_HTSI; 
    268         } 
     488        memset(ct,0,sizeof(struct CardTerminal)); 
    269489        ct->ctn=ctn; 
    270490        ct->h=h; 
     
    272492        ct->next=cardTerminals; 
    273493        cardTerminals=ct; 
     494        ct->cwd=&ct->mf; 
     495        ct_reader_info(pn,&info); 
     496        ct->mf.id=0x3f00; 
     497        ct->mf.gen=dir; 
     498        ct->mf.dir[0]=&ct->mf; 
     499        ct->mf.dir[1]=&ct->ctcf; 
     500        ct->mf.dir[2]=&ct->ctdir; 
     501        for (i=0; i<info.ct_slots; ++i) { 
     502                ct->mf.dir[3+i]=&ct->iccdir[i]; 
     503        } 
     504        ct->ctcf.id=0x0020; 
     505        ct->ctcf.gen=ctcf; 
     506        ct->ctcf.dir[0]=&ct->mf; 
     507        ct->ctdir.id=0x7f60; 
     508        ct->ctdir.gen=dir; 
     509        ct->ctdir.dir[0]=&ct->mf; 
     510        for (i=0; i<info.ct_slots; ++i) { 
     511                ct->iccdir[i].id=0x7f70+i; 
     512                ct->iccdir[i].gen=dir; 
     513                ct->iccdir[i].dir[0]=&ct->iccdir[i]; 
     514        } 
     515        ct->hostcf.id=0xff10; 
     516        ct->hostcf.gen=hostcf; 
     517        ct->hostcf.dir[0]=&ct->hostcf; 
     518        ct->hoststatus.id=0xff11; 
     519        ct->hoststatus.gen=hoststatus; 
     520        ct->hoststatus.dir[0]=&ct->hoststatus; 
     521        if (ct_card_lock(h, 0, IFD_LOCK_EXCLUSIVE, &lock) < 0) { 
     522                CT_close(ctn); 
     523                return ERR_HTSI; 
     524        } 
    274525        return OK; 
    275526} 
     
    307558 
    308559#if 0 
    309                 ct_debug("CT_data(dad=%d lc=%u lr=%u cmd=%s", 
    310                                 *dad, lc, *lr, ct_hexdump(cmd, lc)); 
     560        ct_debug("CT_data(dad=%d lc=%u lr=%u cmd=%s", 
     561                *dad, lc, *lr, ct_hexdump(cmd, lc)); 
    311562#endif 
    312563 
    313564        switch (*dad) { 
    314565                case CTAPI_DAD_ICC1: 
    315                         rc = ct_card_transact((*ct)->h, 0, 
    316                                 cmd, (size_t)lc, rsp, (size_t)*lr); 
     566                        rc = ctapi_transact(*ct, 0, cmd, lc, rsp, *lr); 
    317567                        break; 
    318568                case CTAPI_DAD_ICC2: 
    319                         rc = ct_card_transact((*ct)->h, 1, 
    320                                 cmd, (size_t)lc, rsp, (size_t)*lr); 
     569                        rc = ctapi_transact(*ct, 1, cmd, lc, rsp, *lr); 
    321570                        break; 
    322571                case CTAPI_DAD_CT: 
    323                         rc = ctapi_control((*ct)->h, 
     572                        rc = ctapi_control(*ct, 
    324573                                cmd, lc, rsp, *lr); 
    325574                        break;