UICC 之 USIM 详解全系列——USIM Demo详解

USIM Demo详解

文件结构

在这里插入图片描述

UICC的TLV解码目前只实现了对Application selection response的解码,后续其它命令的TLV解码都以’_tlv’结尾。

函数调用关系如下图:
在这里插入图片描述


核心code讲解

核心Code主要有两个函数,分别对应于应用层业务处理和传输层命令处理过程

应用层

/*
 * Description:这个函数位于UICC应用层,用于组装APDU并发送到传输层
 * Params:
 * 			usim :实例化后的USIM对象
 * 			r_apdu_p :用于传输APDU response
 */
static int _send_apdu(usim_t* usim,r_apdu_t* r_apdu_p /* out */)
{
    
    
	//history_pool中记录着将要发送的APDU,通过get_latest_item函数
	//获取将要发送的APDU
    apdu_t* _apdu_p = (apdu_t*)get_latest_item(usim->history_pool);
    //打印即将发送的APDU,用于调试目的
    _display_one_apdu(_apdu_p);
    //发送到传输层
    if(0 == usim->send_apdu_usim(GTE_APDU_HEAD(_apdu_p),_apdu_p->apdu_size))
        return 0;
    //根据APDU response 判断下一步的行动
    switch(r_tpdu.r_tpdu[r_tpdu.r_tpdu_size-2]) //SW1
    {
    
    
        case 0x61: {
    
    
            //send GET RESPONSE command
            uint8_t _xx = GTE_APDU_LE(_apdu_p) < r_tpdu.r_tpdu[r_tpdu.r_tpdu_size - 1]?
                         GTE_APDU_LE(_apdu_p):r_tpdu.r_tpdu[r_tpdu.r_tpdu_size - 1];
			//将GET RESPONSE command放入history_pool
            insert_history_item(usim->history_pool,
                                (uint8_t *) _new_apdu_command(0x00, 0xC0,
                                                              0x00, 0x00,
                                                              INVALID_LC, NULL,
                                                              _xx/* SW2 */),
                                NULL);
            //递归执行_send_apdu
            if (0 == _send_apdu(usim, r_apdu_p /* out */))
                return 0;
            break;
        }
        case 0x6C: {
    
    
            //resend previous command header
            //获取上一条发送的APDU
            apdu_t* _apdu_previous = (apdu_t*)get_latest_item(usim->history_pool);
			//修改Le字段,并将修改后的“previous command”插入history_pool
            insert_history_item(usim->history_pool,
                                (uint8_t *) _new_apdu_command(_apdu_previous->CLA,
                                                              _apdu_previous->INC,
                                                              _apdu_previous->P1,
                                                              _apdu_previous->P2,
                                                              INVALID_LC,
                                                              NULL,
                                                              r_tpdu.r_tpdu[r_tpdu.r_tpdu_size-1]/* SW2 */),
                                NULL);
            if (0 == _send_apdu(usim, r_apdu_p /* out */))
                return 0;
            break;
        }
        case 0x62:
        case 0x63:
        case 0x91:
        case 0x92:
            //for Case4 (特殊情况处理,此时直接将Le置为0x00)
            if(_apdu_p->has_Lc == _HAS_LC &&
                _apdu_p->has_Le == _HAS_LE)
            {
    
    
                //decode status words
                _decode_status_words(r_tpdu.r_tpdu[r_tpdu.r_tpdu_size-2],
                                     r_tpdu.r_tpdu[r_tpdu.r_tpdu_size-1]);
                //_display_one_apdu(_apdu_p);
                insert_history_item(usim->history_pool,
                                    (uint8_t *) _new_apdu_command(0x00, 0xC0,
                                                                  0x00, 0x00,
                                                                  INVALID_LC, NULL,
                                                                  0x00/* SW2 */),
                                    NULL);
                if (0 == _send_apdu(usim, r_apdu_p /* out */))
                    return 0;
                break;
            }
        default:
            //decode status words
            _decode_status_words(r_tpdu.r_tpdu[r_tpdu.r_tpdu_size-2],
                                 r_tpdu.r_tpdu[r_tpdu.r_tpdu_size-1]);
            //_display_one_apdu(_apdu_p);
            assert(r_apdu_p != NULL);
            memset(r_apdu_p , 0 , sizeof(r_apdu_t));
            r_apdu_p->r_apdu_size = r_tpdu.r_tpdu_size - 2; //substrate SW1|SW2
            r_apdu_p->r_apdu = (uint8_t*)malloc(r_apdu_p->r_apdu_size);
            assert(r_apdu_p->r_apdu != NULL);
            memcpy(r_apdu_p->r_apdu, r_tpdu.r_tpdu , r_apdu_p->r_apdu_size);
            r_apdu_p->sw1 = r_tpdu.r_tpdu[r_tpdu.r_tpdu_size-2];
            r_apdu_p->sw2 = r_tpdu.r_tpdu[r_tpdu.r_tpdu_size-1];
            break;
    }
    return 1;
}

点击获取完整code

传输层

/*
 * Description : 将TPDU发送到数据链路层并根据数据链路层的反馈信息进行相应的处理
 * Params:
 * 			apdu_p:应用层commnad
 * 			apdu_size:command长度
 */
int send_apdu_usim(uint8_t* apdu_p , uint8_t apdu_size)
{
    
    
    uint8_t enable_usim = 0;//random value
    uint32_t  data_size = 0;
    uint8_t *data=NULL;

    uint8_t response_data[260]={
    
    0};
    uint32_t res_size=0;

    uint8_t hasLe=0;
    uint8_t hasLc=0;

    //send command header size to usim
    fpga_write(apdu_p , 5/*in Byte*/); //CLS INS P1 P2 P3

    //get response(data size and data)
    fpga_read(response_data, &res_size);

re_decode:

	//对应协议中“INS [Le Bytes of data] SW1 SW2”的Case
    if(res_size > 3) 
    {
    
    
        hasLe = 0;
        //判断APDU中是否存在Le字段
        if(apdu_size > 4)
        {
    
    
            if(hasLc == 1)
            {
    
    
                if((apdu_size-5-apdu_p[4]) == 1) hasLe = 1;
                else hasLe = 0;
            }
            else
                hasLe = 1;
        }
        //if apdu_size > Le , return Le bytes of data
        if(hasLe && (apdu_p[apdu_size-1] != 0)
        && (res_size-2-1)>apdu_p[apdu_size-1]) 
            r_tpdu.r_tpdu_size = apdu_p[apdu_size-1]+2;
        else
            r_tpdu.r_tpdu_size = res_size-1;
        memset(r_tpdu.r_tpdu , 0 , sizeof(r_tpdu.r_tpdu));
        memcpy(r_tpdu.r_tpdu,response_data+1,r_tpdu.r_tpdu_size);
    }
    else if(res_size == 1 && response_data[0]==apdu_p[1]) // return INS
    {
    
    
        hasLc = 1;

        //send data part of APDU
        fpga_write(apdu_p+5 , apdu_p[4]/*in Byte*/);

        //get response(data size and data)
        fpga_read(response_data, &res_size);

        goto re_decode;
    }
    else if(res_size == 2) //only SW1 SW2
    {
    
    
        r_tpdu.r_tpdu_size = res_size;
        memset(r_tpdu.r_tpdu , 0 , sizeof(r_tpdu.r_tpdu));
        //拷贝数据,将结果反馈给应用层
        memcpy(r_tpdu.r_tpdu,response_data,r_tpdu.r_tpdu_size);
    }
    else
    {
    
    
        printf("Error:undefined action.\n");
        return 0;
    }


    return 1;
}

点击获取完整code


返回系列目录

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_31985307/article/details/114808641