在两种不同的情况下初始化更新给定的 6985 和 61xx。

10

我有一个Java卡,并编写了一个发送APDU到Java卡的小代码。当我发送Init_Update命令时,我会收到0x6985的响应,类似于:

我有一张java卡并写了发送APDU到java卡的代码。在这里当我发送Init_Update命令时,我收到类似于0x6985的响应:

CMD -> 80 50 00 00 08 11 22 33 44 55 66 77 88
RES <- 6985

但当我使用其他工具发送此命令时,它会给出所需的结果,例如:

Transmit: 80 50 00 00 08    []
  11 22 33 44 55 66 77 88                            ."3DUfw.
Card answered: 61 1C

我的Java代码在我拥有的其他Java卡上能够正常工作。有人可以告诉我这种不同行为的原因吗?

// full java code


     public static void main(String[] args) {
            // TODO code application logic here
            try
            {

        factory = TerminalFactory.getDefault();
                    terminals = factory.terminals().list(); 
                terminal = terminals.get(0);
                card = terminal.connect("*");
                    channel =card.getBasicChannel();

                    CommandAPDU cmdAPDU;
                     ResponseAPDU response;
                    byte[] select_isd = {(byte) 0x00,(byte) 0xA4,(byte) 0x04,(byte) 0x00,(byte) 0x08,(byte) 0xA0,(byte) 0x00,
                                         (byte) 0x00,(byte) 0x00,(byte) 0x03,(byte) 0x00,(byte) 0x00,(byte) 0x00 };
                    cmdAPDU = new CommandAPDU(select_isd);
                     response = channel.transmit(cmdAPDU);
                    byte[] INIT_UPDATE = {(byte) 0x80,(byte) 0x50,(byte) 0x00,(byte) 0x00,(byte) 0x08,(byte) 0x11,(byte) 0x22,
                                          (byte) 0x33,(byte) 0x44,(byte) 0x55,(byte) 0x66,(byte) 0x77,(byte) 0x88 };
                     cmdAPDU = new CommandAPDU(INIT_UPDATE);
                     response = channel.transmit(cmdAPDU);
 }
        catch( Exception ex)
        {

        }
    }

其他工具日志看起来像:

Card opened
12 bytes ATR received:
3B 68 00 00 00 73 C8 40 00 00 90 00

Transmit: 00 A4 04 00 08    [SELECT FILE]
  A0 00 00 00 03 00 00 00                            ........
Card answered: 61 12

Transmit: 00 C0 00 00 12    [GET RESPONSE]
Card answered: 90 00
  6F 10 84 08 A0 00 00 00 03 00 00 00 A5 04 9F 65    o..............e
  01 FF                                              ..

Transmit: 80 50 00 00 08    []
  11 22 33 44 55 66 77 88                            ."3DUfw.
Card answered: 61 1C

但是当我运行我的Java代码时,INIT_UPDATE命令返回6985。

如果需要其他信息,请告诉我。

==新添加的内容=== 我尝试在JCOP shell中运行我的脚本,我的脚本类似于:

/mode trace=on
/terminal 
/atr
/send 80CAA08D05
/send 802E000014B555C94B0B2368B4840201808502032288020060
/send 80D8000000
/atr
/send 80500000081122334455667788

我已经得到了所需的结果。我试着在Java中实现它,我的新Java代码看起来像:

=====新更新的JAVA代码===

factory = TerminalFactory.getDefault();
         terminals = factory.terminals().list(); 
         terminal = terminals.get(0);

         card = terminal.connect("*");
         channel =card.getBasicChannel();

         CommandAPDU cmdAPDU;
         ResponseAPDU response;
         byte[] x = { (byte) 0x80, (byte) 0xCA, (byte) 0xA0,(byte) 0x8D,(byte)0x05};
         byte[] y = {    remove command for security reasons};
         byte[] z = {     (byte) 0x80, (byte) 0xD8, (byte) 0x00, (byte) 0x00, (byte) 0x00}; // it set default key


           cmdAPDU = new CommandAPDU(x);
         response = channel.transmit(cmdAPDU);
                System.out.println(response.toString());

                  cmdAPDU = new CommandAPDU(y);
         response = channel.transmit(cmdAPDU);
                System.out.println(response.toString());

                           cmdAPDU = new CommandAPDU(z);
         response = channel.transmit(cmdAPDU);
                System.out.println(response.toString());

                   card.disconnect(true);
                    card = terminal.connect("*");
                   channel =card.getBasicChannel();


         byte[] INIT_UPDATE = {(byte) 0x80,(byte) 0x50,(byte) 0x00,(byte) 0x00,(byte) 0x08,(byte) 0x11,(byte) 0x22,(byte) 0x33,(byte) 0x44,(byte) 0x55,(byte) 0x66,(byte) 0x77,(byte) 0x88 };

         cmdAPDU = new CommandAPDU(INIT_UPDATE);
        response = channel.transmit(cmdAPDU);

2
在发送初始化更新之前,您是否选择了ISD?或者在发送初始化更新之前先发送ATR。 - Anurag Sharma
如果可能的话,请添加您代码的这一部分。 - Ebrahim Ghasemi
611C 表示有 0x1C = 28 字节需要读取。你应该使用 GET RESPONSE 命令(00 C0 00 00 XX)响应 61XX,以获取你的响应数据。 - vojta
@Abraham,代码已编辑,请检查。 - Arjun
1
@abraham 我的卡是双界面卡,但我的读卡器只支持接触式,我正在使用接触式场景测试我的Java代码... - Arjun
显示剩余12条评论
5个回答

7
6985的意思是使用条件不满足。由于您到目前为止没有使用任何密钥,这可能意味着卡被锁定或终止。


611C是用于通过T=0发送的APDU的状态字。T=0不能在同一APDU中处理命令和响应(也称为“ISO case 4”),因此需要使用GET RESPONSE来处理ISO case 4命令。要么第一个应用程序将其隐藏起来处理(就像Java Card本身一样)-将两个APDU组合在一起-要么它创建一个T=1连接而不是T=0连接。
这与6985状态字关系不大,因为您预计会在处理INITIALIZE UPDATE命令的业务逻辑之前产生此警告-只有在可以生成输出时才会处理该命令。

其实我的卡没有被锁定,因为在其他工具中它会给出611C的响应。你是对的,javax.smartcard.io处理内部获取响应,所以我们不需要担心。我很担心我的Java代码为什么会返回6985与这张卡片一起。 - Arjun
@Maarten Bodewes:抱歉不同意您的观点:69 85 表示“未满足使用条件”,而security.conditions not satisfied则由69 82表示。 - guidot
@guidit 谢谢,我进行了实质性的编辑。原回答存在一些错误,但回答的主旨保持不变。 - Maarten Bodewes
@Maarten: 很抱歉与您意见不合:如果卡终止或锁定,则已初始化的更新命令永远不会返回6985。 根据规范映射指南GP v2.1.1在v2.2.1下的第6.5.5节:如果终止卡,则返回“6D00”响应。根据GP2.2.1规范,Initialized Update命令可以与卡生命周期状态(CLCS)Locked一起使用,因为如果您通过Secure会话(SCP02)将CLCS从Secure移动到Locked,然后从Locked状态将CLCS移回Secured状态,则需要通过InitUpdate和External Authenticate命令建立安全会话。 - Bhanu

4
  1. 对于SW '6985'

根据规范现有GP v2.1.1实现在v2.2.1上的映射指南:第6.5.2节:

"如果在发出此命令(初始化更新命令)的逻辑通道之外的逻辑通道上当前存在安全通道,则返回'6985'响应。"

请确认当Initialize Update命令失败并返回6985时,是否符合此行为。

  1. 对于SW '611C'

如果信息过长无法放入单个响应数据字段,则卡片将返回信息开头,并将SW1-SW2设置为“61XX”。然后,后续的GET RESPONSE提供'XX'字节的信息。该过程可以重复进行,直到卡片发送SW1-SW2设置为“9000”。

在这种情况下,您需要使用P3为1C的GET RESPONSE命令,卡片将返回1C字节的数据。


我们如何处理安全通道类的事情,只需发送80 50 00 00 08 11 22 33 44 55 66 77 88即可。 - Arjun
@Rohit:80 50 00 00 08 11 22 33 44 55 66 77 88 只是初始化更新命令,它与外部认证命令一起用于启动安全会话(SCP02 会话)。由于某些原因,Initialized Update 命令可能会返回 6985,其中之一就是如果在一个逻辑通道上支持逻辑通道并且安全域上有活动的安全会话,则如果您尝试在另一个逻辑通道上启动同一安全域上的安全会话(通过发送 Initialized Update 命令),则 Initialized Update 命令将返回 6985。 - Bhanu
检查在发送初始化更新命令的安全域上是否当前处于安全会话状态,并且是否存在其他逻辑通道。最好通过管理通道命令(请参阅全局平台规范)关闭所有其他逻辑通道,然后检查您的情况。 - Bhanu
Initialized Update命令可能会出现6985的其他原因包括:1-如果安全域(发出Initialized Update命令的安全域)上不存在SCP02密钥集。 SCP02密钥集从20到2F。请检查密钥集是否存在。 2-如果安全域(发出Initialized Update命令的安全域)没有SCP功能(请参阅UICC配置规范,并查看SD安装参数中的标签“81”),请交叉检查SCP功能。 - Bhanu
我发现代码相当简单,只需在同一通道上获取基本通道并传输INIT_update。很抱歉,您想让我做更多的事情不清楚。供您参考,我尝试使用Jcop shell脚本进行了尝试,我的脚本如下:/mode trace=on /terminal /atr /send 80CAA08D05 /send 802E000014xxxxxxxxxx... /send 80D8000000 /atr #INITUPDATE /send 80500000081122334455667788 它可以正常工作并给出61xx。 - Arjun

0

请问您能否也尝试一下这个程序?

 public static void main(String[] args) {
     try{
         factory = TerminalFactory.getDefault();
         terminals = factory.terminals().list(); 
         terminal = terminals.get(0);

         card = terminal.connect("*");
         channel =card.getBasicChannel();

         CommandAPDU cmdAPDU1;
         CommandAPDU cmdAPDU2;
         ResponseAPDU response1;
         ResponseAPDU response2;

         byte[] select_isd = {(byte) 0x00,(byte) 0xA4,(byte) 0x04,(byte) 0x00,(byte) 0x08,(byte) 0xA0,(byte) 0x00,(byte) 0x00,(byte) 0x00,(byte) 0x03,(byte) 0x00,(byte) 0x00,(byte) 0x00 };
         byte[] INIT_UPDATE = {(byte) 0x80,(byte) 0x50,(byte) 0x00,(byte) 0x00,(byte) 0x08,(byte) 0x11,(byte) 0x22,(byte) 0x33,(byte) 0x44,(byte) 0x55,(byte) 0x66,(byte) 0x77,(byte) 0x88 };

         cmdAPDU1 = new CommandAPDU(select_isd);
         cmdAPDU2 = new CommandAPDU(INIT_UPDATE);
         response1 = channel.transmit(cmdAPDU1);
         response2 = channel.transmit(cmdAPDU2);
         }
     catch( Exception ex)
     {

     }
}

我担心在transmit方法之间使用new CommandAPDU会重置卡片和读卡器之间的连接。

更新:

如果上述程序返回相同的错误,请尝试使用以下程序:

public static void main(String[] args) {
     try{
         factory = TerminalFactory.getDefault();
         terminals = factory.terminals().list(); 
         terminal = terminals.get(0);

         card = terminal.connect("*");
         channel =card.getBasicChannel();

         CommandAPDU cmdAPDU;
         ResponseAPDU response;


         byte[] select_isd = {(byte) 0x00,(byte) 0xA4,(byte) 0x04,(byte) 0x00,(byte) 0x08,(byte) 0xA0,(byte) 0x00,(byte) 0x00,(byte) 0x00,(byte) 0x03,(byte) 0x00,(byte) 0x00,(byte) 0x00 };
         byte[] get_response={(byte)0x00,(byte)0xC0 ,(byte)0x00 ,(byte)0x00 ,(byte)0x12};
         byte[] INIT_UPDATE = {(byte) 0x80,(byte) 0x50,(byte) 0x00,(byte) 0x00,(byte) 0x08,(byte) 0x11,(byte) 0x22,(byte) 0x33,(byte) 0x44,(byte) 0x55,(byte) 0x66,(byte) 0x77,(byte) 0x88 };

         cmdAPDU = new CommandAPDU(select_isd);
         response = channel.transmit(cmdAPDU);

         cmdAPDU = new CommandAPDU(get_response);
         response = channel.transmit(cmdAPDU);

         cmdAPDU = new CommandAPDU(INIT_UPDATE);
         response = channel.transmit(cmdAPDU);

         }
     catch( Exception ex)
     {

     }
}

热切期待您的回复。

更新-2:

我认为尝试编写Python脚本可以找出问题所在。您也可以尝试一下:

>>> from smartcard.System import readers
>>> from smartcard.util import toHexString
>>>
>>> r=readers()
#if you have more than one reader or a dual interface reader, put the right index in the below line instead of `0`
>>> connection = r[0].createConnection()
>>> connection.connect()
>>>
>>> SELECT = [0xA0, 0xA4, 0x04, 0x00, 0x08 , 0xA0 , 0x00 , 0x00 , 0x00 , 0x03 , 0x00 , 0x00 , 0x00 ]
>>> GET_RESPONSE = [ 0x00, 0xC0, 0x00, 0x00, 0x12]
>>> INIT_UPDATE= [0x80, 0x50, 0x00, 0x00, 0x08, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88]
>>>
>>> data, sw1, sw2 = connection.transmit( SELECT)
>>> print "%s %x %x" % (data, sw1, sw2)
>>>
#if the sw1 and sw2 of above command is not `0x6112`, don't send GET_RESPOSE command.
>>> data, sw1, sw2 = connection.transmit( GET_RESPONSE)
>>> print "%s %x %x" % (data, sw1, sw2)    
>>>
>>> data, sw1, sw2 = connection.transmit( INIT_UPDATE)
>>> print "%s %x %x" % (data, sw1, sw2)

请注意,上述脚本适用于Python 2.7,您还必须安装PySCard

感谢您的建议。但是您的第一个示例返回ResponseAPDU:20字节,SW = 9000 ResponseAPDU:2字节,SW = 6985,第二个示例返回ResponseAPDU:20字节,SW = 9000 ResponseAPDU:2字节,SW = 6f00 ResponseAPDU:2字节,SW = 6985。 - Arjun
这是非常奇怪的行为。我不知道为什么会发生这种情况。 - Arjun
@rohitamitpathak,能否请您尝试一下我在“更新-2”部分中添加的Python脚本呢?谢谢。 - Ebrahim Ghasemi
我尝试使用Jcop shell脚本,我的脚本如下:/mode trace=on /terminal /atr /send 80CAA08D05/send 802E000014xxxxxxxxxx.../send 80D8000000/atr#INITUPDATE /send 80500000081122334455667788 它正常工作并返回61xx。 - Arjun

0
问题在于必须在INITIAL UPDATE之后立即执行EXTERNAL UPDATE命令。如果收到61nn响应并发送C0命令以从INITIAL UPDATE中检索剩余数据,则EXTERNAL AUTH命令将失败,指示“未满足访问条件”[6982];然后,您至少有两个可能的选择来解决此问题:
  1. 将读卡器连接到T = 1协议模式

lResult=SCardConnect( *pphContext, tszReaderName, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T1,//<--FORCE TO SCARD_PROTOCOL_T1, pphCard, &dwActiveProtocol) )); //<--VERIFY THAT THIS VALUE IS SETTED TO 2 调整引擎APDU发送器以使用T1协议接收响应中的信息,避免使用getResp命令。

{00 C0 00 00 nn}

(我假设这样做没问题,我仍在进行中)如果您想使用T0协议,则必须重新发送两次INITIAL UPDATE命令,第一次是为了使用C0命令从响应中获取数据。第二次尝试将重新建立安全通道,以使用C0 Apdu命令。在这里,可能需要一些机制来管理通道命令,以关闭其他通道(参见https://globalplatform.org/wp-content/uploads/2018/06/GPC_Specification-2.2.1.pdf第11.7段),因为您可能会收到一个6985作为响应,并且您的智能卡似乎无法执行INITIAL UPDATE而没有错误。

0
您可以使用BusHound捕获一些APDU,然后在发送命令期间比较和分析两个工具之间的差异。

我尝试过但没有找到一个可以发送我的命令的地方,例如:- 80 50 00 00 08 11 22 33 44 55 66 77 88。 - Arjun

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接