文章目录
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;
}
传输层
/*
* 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;
}