梳理 Java Card API 流程

参考文档
mermaid官方文档

学习目标:以支持扩展APDU为导向,熟悉 Java Card API 流程。

学习向导:站在 Java Card Applet 开发者的角度,把 命令接收流程返回响应数据流程以及如何调用API给理清楚。

第一步 通读文档

将文档大概看一遍之后,知道 javacard.framework.APDU 的 API 与传输协议无关(用文档的话说就是,applet 可以使用相同的APDU接口,而不管所使用的基础协议是 T=0 还是 T=1),还知道状态机用于表示基于调用的方法和数据传输状态的APDU对象的各种处理状态。除此之外,又定义了与协议相关的接口和枚举常量。

俗话说万事开头难,入门可以先从软柿子开始捏,我的学习路线是:先搞明白状态机各个状态的定义以及状态切换,然后把状态机的状态与API进行关联,接着分协议类型T0和T1,最后再分 ISO7816、SWP和SPI之类的。

当然了,想要将上述节点都拿下并梳理清楚之间关系,就我目前而言,难度至少5颗星,不是简单看看就能理解的,所以这篇文章主要还是用于记录我的学习过程以及各个里程段做个记忆存档。

第二步 攻克 状态机

APDU对象的状态机有正常状态和异常状态两种,正常状态又分输入状态和输出状态。

graph LR APDU对象 --> 正常状态 正常状态 --> 输入状态 正常状态 --> 输出状态 APDU对象 --> 异常状态

输入状态按顺序从左往右排列可分为INITIAL、PARTIAL_INCOMING和FULL_INCOMING。

graph LR A[刚接收到命令标头] --> B[正在接收中] B --> C[命令接收已完成]

同样地,输出状态按顺序从左往右排列可分为OUTGOING、OUTGOING_LENGTH_KNOWN、PARTIAL_OUTGOING和FULL_OUTGOING。

graph LR A[设置传输方向为输出] --> B[设置输出长度] B --> C[正在输出中] C --> D[响应数据输出已完成]

异常状态有IO_ERROR、NO_T0_GETRESPONSE、NO_T0_REISSUE和T1_IFD_ABORT四种,此时我暂不关心它们。

接着,排除与协议相关的接口后,就得到与APDU相关的接口:

修饰符和类型 API
byte[] getBuffer()
static byte getCurrentAPDU()
static byte[] getCurrentAPDUBuffer()
byte getCurrentState()
static short getInBlockSize()
short getIncomingLength()
short getOffsetCdata()
static short getOutBlockSize()
short receiveBytes(short bOff)
void sendBytes(short bOff, short len)
void sendBytesLong(byte[] outData, short bOff, short len)
short setIncomingAndReceive()
short setOutgoing()
void setOutgoingAndSend(short bOff, short len)
void setOutgoingLength(short len)
short setOutgoingNoChaining()

然后将它们分为辅助和功能两类API,因为辅助类API中,只有getCurrentState()是跟状态机关联,但它不会影响状态机的变化,所以就单独将功能类API拎出来:

修饰符和类型 API
short receiveBytes(short bOff)
void sendBytes(short bOff, short len)
void sendBytesLong(byte[] outData, short bOff, short len)
short setIncomingAndReceive()
short setOutgoing()
void setOutgoingAndSend(short bOff, short len)
void setOutgoingLength(short len)
short setOutgoingNoChaining()

结合文档,梳理 APDU API 切换状态机状态的流程,并进行关联。

  1. receiveBytes 和 setIncomingAndReceive 具有相同的状态机切换过程。
graph LR A[输入命令数据] --> B[已全部接收] B -- 设置APDU对象状态 --> D[FULL_INCOMING] A --> E[尚未完全接收] E -- 设置APDU对象状态 --> F[PARTIAL_INCOMING]
  1. sendBytes 和 sendBytesLong 具有相同的状态机切换过程。
graph LR A[输出响应数据] --> B[已全部输出] A --> C[尚未完全输出] B -- 设置APDU对象状态 --> D[PARTIAL_OUTGOING] C -- 设置APDU对象状态 --> E[FULL_OUTGOING]
  1. setOutgoingAndSend 适用于较短的数据长度,只有一个状态可以设置。
graph LR A[输出响应数据] --> B[已全部输出] B -- 设置APDU对象状态 --> C[FULL_OUTGOING]
  1. setOutgoing 和 setOutgoingNoChaining 具有相同的状态机切换状态过程。
graph LR A[准备输出响应数据] -- 设置APDU对象状态 --> B[OUTGOING]
  1. setOutgoingLength 只设置响应数据的实际长度。
graph LR A[准备输出响应数据] -- 设置APDU对象状态 --> B[OUTGOING_LENGTH_KNOWN]
posted @ 2020-08-17 10:42  sunck  阅读(754)  评论(0编辑  收藏  举报