Changeset 1174 for trunk/src


Ignore:
Timestamp:
11/24/09 15:49:02 (2 years ago)
Author:
s
Message:

Modify Rutoken S binary interfaces by Aktiv Co. (accordance with http://www.opensc-project.org/opensc/changeset/3865) (Rutoken S+OpenCT+PCSC-Lite+rdesktop works now)

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/ifd/ifd-rutoken.c

    r1152 r1174  
    99#include <unistd.h> 
    1010#include <string.h> 
     11#include <stdlib.h> 
    1112 
    1213#define MAX_BUF_T0_LEN  256 
     
    362363} 
    363364 
     365static void swap_pair(unsigned char *buf, size_t len) 
     366{ 
     367        size_t i; 
     368        unsigned char tmp; 
     369 
     370        for (i = 0; i + 1 < len; i += 2) { 
     371                tmp = buf[i]; 
     372                buf[i] = buf[i + 1]; 
     373                buf[i + 1] = tmp; 
     374        } 
     375} 
     376 
     377static void swap_four(unsigned char *buf, size_t len) 
     378{ 
     379        size_t i; 
     380        unsigned char tmp; 
     381 
     382        for (i = 0; i + 3 < len; i += 4) { 
     383                tmp = buf[i]; 
     384                buf[i] = buf[i + 3]; 
     385                buf[i + 3] = tmp; 
     386 
     387                swap_pair(&buf[i + 1], 2); 
     388        } 
     389} 
     390 
     391static int read_tag(unsigned char *buf, size_t buf_len, 
     392                unsigned char tag_in, unsigned char *out, size_t out_len) 
     393{ 
     394        unsigned char tag; 
     395        size_t taglen, i = 0; 
     396 
     397        while (i + 2 <= buf_len) { 
     398                tag = buf[i]; 
     399                taglen = buf[i + 1]; 
     400                i += 2; 
     401                if (taglen + i > buf_len) 
     402                        return -1; 
     403                if (tag == tag_in) { 
     404                        if (taglen != out_len) 
     405                                return -1; 
     406                        memcpy(out, buf + i, out_len); 
     407                        return 0; 
     408                } 
     409                i += taglen; 
     410        } 
     411        return -1; 
     412} 
     413 
     414static int convert_doinfo_to_rtprot(void *data, size_t data_len) 
     415{ 
     416        unsigned char dohdr[32] = { 0 }; 
     417        unsigned char secattr[40], data_a5[0xff]; 
     418        unsigned char *p = data; 
     419        size_t i, data_a5_len; 
     420 
     421        if (read_tag(p, data_len, 0x80, &dohdr[0], 2) == 0) { 
     422                swap_pair(&dohdr[0], 2); 
     423                ifd_debug(6, "tag 0x80 (file size) = %02x %02x", dohdr[0], dohdr[1]); 
     424        } 
     425        data_a5_len = dohdr[1] & 0xff; 
     426        if (read_tag(p, data_len, 0xA5, data_a5, data_a5_len) == 0) 
     427                ifd_debug(6, "tag 0xA5 = %s", ct_hexdump(data_a5, data_a5_len)); 
     428        else 
     429                data_a5_len = 0; 
     430        if (data_len < sizeof(dohdr) + data_a5_len) { 
     431                ifd_debug(6, "data_len = %u", data_len); 
     432                return -1; 
     433        } 
     434        if (read_tag(p, data_len, 0x83, &dohdr[2], 2) == 0) 
     435                ifd_debug(6, "tag 0x83 (Type,ID) = %02x %02x", dohdr[2], dohdr[3]); 
     436        if (read_tag(p, data_len, 0x85, &dohdr[4], 3) == 0) 
     437                ifd_debug(6, "tag 0x85 (Opt,Flags,MaxTry) = %02x %02x %02x", 
     438                                dohdr[4], dohdr[5], dohdr[6]); 
     439        if (read_tag(p, data_len, 0x86, secattr, sizeof(secattr)) == 0) { 
     440                i = 17; 
     441                memcpy(dohdr + i, secattr, 8); 
     442                for (i += 8, p = &secattr[8]; i < sizeof(dohdr); ++i, p += 4) 
     443                        dohdr[i] = *p; 
     444                ifd_debug(6, "tag 0x86 = %s", ct_hexdump(&dohdr[17], 15)); 
     445        } 
     446        memcpy(data, dohdr, sizeof(dohdr)); 
     447        memcpy((unsigned char*)data + sizeof(dohdr), data_a5, data_a5_len); 
     448        return sizeof(dohdr) + data_a5_len; 
     449} 
     450 
     451static int convert_fcp_to_rtprot(void *data, size_t data_len) 
     452{ 
     453        unsigned char rtprot[32] = { 0 }; 
     454        unsigned char secattr[40]; 
     455        unsigned char *p = data; 
     456        size_t i; 
     457 
     458        if (data_len < sizeof(rtprot)) { 
     459                ifd_debug(6, "data_len = %u", data_len); 
     460                return -1; 
     461        } 
     462        /* 0x62 - FCP */ 
     463        if (p[0] != 0x62  ||  (size_t)p[1] + 2 > data_len) { 
     464                ifd_debug(6, "Tag = %02x  len = %u", p[0], p[1]); 
     465                return -1; 
     466        } 
     467        p += 2; 
     468        data_len -= 2; 
     469        /* file type */ 
     470        if (read_tag(p, data_len, 0x82, &rtprot[4], 2) != 0) 
     471                return -1; 
     472        ifd_debug(6, "tag 0x82 (file type) = %02x %02x", rtprot[4], rtprot[5]); 
     473        /* file id */ 
     474        if (read_tag(p, data_len, 0x83, &rtprot[6], 2) != 0) 
     475                return -1; 
     476        swap_pair(&rtprot[6], 2); 
     477        ifd_debug(6, "tag 0x83 (file id) = %02x %02x", rtprot[6], rtprot[7]); 
     478        /* file size */ 
     479        if (read_tag(p, data_len, 0x81, &rtprot[0], 2) == 0) { 
     480                swap_pair(&rtprot[0], 2); 
     481                ifd_debug(6, "tag 0x81 (complete file size) = %02x %02x", 
     482                                rtprot[0], rtprot[1]); 
     483        } 
     484        if (read_tag(p, data_len, 0x80, &rtprot[2], 2) == 0) { 
     485                swap_pair(&rtprot[2], 2); 
     486                ifd_debug(6, "tag 0x80 (file size) = %02x %02x", rtprot[2], rtprot[3]); 
     487        } 
     488        if (read_tag(p, data_len, 0x86, secattr, sizeof(secattr)) == 0) { 
     489                i = 17; 
     490                memcpy(rtprot + i, secattr, 8); 
     491                for (i += 8, p = &secattr[8]; i < sizeof(rtprot); ++i, p += 4) 
     492                        rtprot[i] = *p; 
     493                ifd_debug(6, "tag 0x86 = %s", ct_hexdump(&rtprot[17], 15)); 
     494        } 
     495        memcpy(data, rtprot, sizeof(rtprot)); 
     496        return sizeof(rtprot); 
     497} 
     498 
     499static int convert_rtprot_to_doinfo(void *data, size_t data_len) 
     500{ 
     501        unsigned char doinfo[0xff] = { 0 }; 
     502        unsigned char *pdata = data; 
     503        size_t i, doinfo_len = 0; 
     504 
     505        if (data_len < 32) { 
     506                ifd_debug(6, "data_len = %u", data_len); 
     507                return -1; 
     508        } 
     509        if (pdata[0] != 0 && pdata[0] < sizeof(doinfo) - 4 - 4 - 5 - 42 - 2) { 
     510                /* Tag 0x80 */ 
     511                doinfo[doinfo_len++] = 0x80; 
     512                doinfo[doinfo_len++] = 2; 
     513                memcpy(doinfo + doinfo_len, pdata, 2); 
     514                swap_pair(doinfo + doinfo_len, 2); 
     515                doinfo_len += 2; 
     516        } 
     517        /* Tag 0x83 */ 
     518        doinfo[doinfo_len++] = 0x83; 
     519        doinfo[doinfo_len++] = 2; 
     520        doinfo[doinfo_len++] = pdata[2]; 
     521        doinfo[doinfo_len++] = pdata[3]; 
     522 
     523        /* Tag 0x85 */ 
     524        doinfo[doinfo_len++] = 0x85; 
     525        doinfo[doinfo_len++] = 3; 
     526        doinfo[doinfo_len++] = pdata[4]; 
     527        doinfo[doinfo_len++] = pdata[5]; 
     528        doinfo[doinfo_len++] = pdata[6]; 
     529 
     530        /* Tag 0x86 */ 
     531        doinfo[doinfo_len++] = 0x86; 
     532        doinfo[doinfo_len++] = 40; 
     533        memcpy(doinfo + doinfo_len, pdata + 17, 8); 
     534        doinfo_len += 8; 
     535        for (i = 0; i < 7 && doinfo_len + 3 < sizeof(doinfo); ++i, doinfo_len += 4) 
     536                doinfo[doinfo_len] = pdata[17 + 8 + i]; 
     537        doinfo_len += 4; /* for reserved */ 
     538        if (pdata[0] != 0 && pdata[0] + doinfo_len + 2 < sizeof(doinfo)) { 
     539                /* Tag 0xA5 */ 
     540                if (data_len - 32 < pdata[0]) { 
     541                        ifd_debug(6, "for tag 0xA5 incorrect data_len = %u", data_len); 
     542                        return -1; 
     543                } 
     544                doinfo[doinfo_len++] = 0xA5; 
     545                doinfo[doinfo_len++] = pdata[0]; 
     546                memcpy(doinfo + doinfo_len, pdata + 32, pdata[0]); 
     547                doinfo_len += pdata[0]; 
     548        } 
     549        ifd_debug(6, "doinfo = %s", ct_hexdump(doinfo, doinfo_len)); 
     550        memcpy(data, doinfo, doinfo_len); 
     551        return doinfo_len; 
     552} 
     553 
     554static int convert_rtprot_to_fcp(void *data, size_t data_len) 
     555{ 
     556        unsigned char fcp[63] = { 
     557                0x62, sizeof(fcp) - 2, 
     558                0x81, 2, 0, 0, 
     559                0x80, 2, 0, 0, 
     560                0x82, 2, 0, 0, 
     561                0x83, 2, 0, 0, 
     562                0x8A, 1, 0, 
     563                0x86, 40 
     564        }; 
     565        unsigned char *p = data; 
     566        size_t i; 
     567 
     568        if (data_len < sizeof(fcp)) { 
     569                ifd_debug(6, "data_len = %u", data_len); 
     570                return -1; 
     571        } 
     572        /* Tag 0x81 */ 
     573        memcpy(fcp + 4, p, 2); 
     574        swap_pair(fcp + 4, 2); 
     575        /* Tag 0x80 */ 
     576        memcpy(fcp + 8, p + 2, 2); 
     577        swap_pair(fcp + 8, 2); 
     578        /* Tag 0x82 */ 
     579        memcpy(fcp + 12, p + 4, 2); 
     580        /* Tag 0x83 */ 
     581        memcpy(fcp + 16, p + 6, 2); 
     582        swap_pair(fcp + 16, 2); 
     583        /* Tag 0x8A */ 
     584        fcp[20] = p[8]; 
     585 
     586        /* Tag 0x86 */ 
     587        memcpy(fcp + 23, p + 17, 8); 
     588        for (i = 0; i < 7 && sizeof(fcp) > 23 + 8 + i * 4; ++i) 
     589                fcp[23 + 8 + i * 4] = p[17 + 8 + i]; 
     590        ifd_debug(6, "fcp = %s", ct_hexdump(fcp, sizeof(fcp))); 
     591        memcpy(data, fcp, sizeof(fcp)); 
     592        return sizeof(fcp); 
     593} 
     594 
    364595static int rutoken_transparent( ifd_reader_t * reader, int dad, 
    365596                const void *sbuf, size_t slen, 
    366597                void *rbuf, size_t rlen) 
    367598{ 
    368         int rrecv = 0; 
     599        unsigned char sw[2], *send_buf_trn = NULL; 
     600        const void *send_buf = sbuf; 
     601        int len, rrecv = -1, iscase4 = 0; 
    369602        ifd_iso_apdu_t iso; 
     603 
    370604        ifd_debug(6, "buffer %s rlen = %d", ct_hexdump(sbuf, slen), rlen); 
    371605        if ( ifd_iso_apdu_parse(sbuf, slen, &iso) < 0) 
    372606                return -1; 
    373607        ifd_debug(6, "iso.le = %d", iso.le); 
     608 
     609        if (iso.cla == 0 && slen > 5) { 
     610                send_buf_trn = malloc(slen); 
     611                if (!send_buf_trn) { 
     612                        ifd_debug(5, "out of memory (slen = %u)", slen); 
     613                        return IFD_ERROR_NO_MEMORY; 
     614                } 
     615                memcpy(send_buf_trn, sbuf, slen); 
     616                /* select file, delete file */ 
     617                if (iso.ins == 0xa4 || iso.ins == 0xe4) 
     618                        swap_pair(send_buf_trn + 5, slen - 5); 
     619                /* create file */ 
     620                else if (iso.ins == 0xe0) { 
     621                        len = convert_fcp_to_rtprot(send_buf_trn + 5, slen - 5); 
     622                        ifd_debug(6, "convert_fcp_to_rtprot = %i", len); 
     623                        if (len > 0) { 
     624                                slen = len + 5; 
     625                                send_buf_trn[4] = len; /* replace le */ 
     626                        } 
     627                } 
     628                /* create_do, key_gen */ 
     629                else if (iso.ins == 0xda && iso.p1 == 1 
     630                                && (iso.p2 == 0x65 || iso.p2 == 0x62)) { 
     631                        len = convert_doinfo_to_rtprot(send_buf_trn + 5, slen - 5); 
     632                        ifd_debug(6, "convert_doinfo_to_rtprot = %i", len); 
     633                        if (len > 0) { 
     634                                slen = len + 5; 
     635                                send_buf_trn[4] = len; /* replace le */ 
     636                        } 
     637                } 
     638                ifd_debug(6, "le = %u", send_buf_trn[4]); 
     639                send_buf = send_buf_trn; 
     640        } 
    374641        switch(iso.cse){ 
     642                case    IFD_APDU_CASE_2S: 
     643                case    IFD_APDU_CASE_3S: 
     644                        if (iso.cla == 0 && iso.ins == 0xa4) 
     645                                iscase4 = 1; /* FIXME: */ 
    375646                case    IFD_APDU_CASE_1: 
    376                 case    IFD_APDU_CASE_2S: 
    377                 case    IFD_APDU_CASE_3S: 
    378                         return rutoken_send_tpducomand(reader, dad, sbuf, slen,  
    379                                         rbuf, rlen, 0); 
     647                        rrecv = rutoken_send_tpducomand(reader, dad, send_buf, slen, 
     648                                        rbuf, rlen, iscase4); 
    380649                        break; 
    381650                case    IFD_APDU_CASE_4S: 
    382651                        // make send case 4 command 
    383                         rrecv = rutoken_send_tpducomand(reader, dad, sbuf, slen-1,  
     652                        rrecv = rutoken_send_tpducomand(reader, dad, send_buf, slen-1, 
    384653                                        rbuf, rlen, 1); 
    385                         return rrecv; 
    386654                        break; 
    387655                default: 
    388656                        break; 
    389657        } 
    390         return -1; 
     658        if (send_buf_trn) 
     659                free(send_buf_trn); 
     660 
     661        if (rrecv > 0 && (size_t)rrecv >= sizeof(sw)) { 
     662                memcpy(sw, (unsigned char*)rbuf + rrecv - sizeof(sw), sizeof(sw)); 
     663                if (sw[0] != 0x90 || sw[1] != 0) 
     664                        /* do nothing */; 
     665                /* select file */ 
     666                else if (iso.cla == 0 && iso.ins == 0xa4 
     667                                && rrecv == sizeof(sw) + 32 /* size rtprot */) { 
     668                        len = convert_rtprot_to_fcp(rbuf, rlen); 
     669                        ifd_debug(6, "convert_rtprot_to_fcp = %i", len); 
     670                        if (len > 0) { 
     671                                rrecv = -1; 
     672                                if (rlen >= len + sizeof(sw)) { 
     673                                        memcpy((unsigned char*)rbuf+len, sw, sizeof(sw)); 
     674                                        rrecv = len + sizeof(sw); 
     675                                } 
     676                        } 
     677                } 
     678                /* get_do_info */ 
     679                else if (iso.cla == 0x80 && iso.ins == 0x30 
     680                                && (size_t)rrecv >= sizeof(sw) + 32 /* size rtprot */) { 
     681                        len = convert_rtprot_to_doinfo(rbuf, rlen); 
     682                        ifd_debug(6, "convert_rtprot_to_doinfo = %i", len); 
     683                        if (len > 0) { 
     684                                rrecv = -1; 
     685                                if (rlen >= len + sizeof(sw)) { 
     686                                        memcpy((unsigned char*)rbuf+len, sw, sizeof(sw)); 
     687                                        rrecv = len + sizeof(sw); 
     688                                } 
     689                        } 
     690                } 
     691                else if (iso.cla == 0 && iso.ins == 0xca && iso.p1 == 1) { 
     692                        /* get_serial, get_free_mem */ 
     693                        if (iso.p2 == 0x81 || iso.p2 == 0x8a) 
     694                                swap_four(rbuf, rrecv - sizeof(sw)); 
     695                        /* get_current_ef */ 
     696                        else if (iso.p2 == 0x11) 
     697                                swap_pair(rbuf, rrecv - sizeof(sw)); 
     698                } 
     699        } 
     700        return rrecv; 
    391701} 
    392702 
Note: See TracChangeset for help on using the changeset viewer.