如何通过响应apdu发送长于256的字节

时间:2018-05-27 20:05:56

标签: digital-signature javacard apdu

请看以下代码:

private void send_certificate (APDU apdu) {


if(!pin.isValidated())ISOException.throwIt(SW_PIN_VERIFICATION_REQUIRED);
else{


    apdu.setOutgoing();
    apdu.setOutgoingLength((short)certificate.length);
    apdu.sendBytesLong(certificate,(short)0,(short)certificate.length);
}

}

证书是javacard applet中的一个字节数组,其长度大于256.如何在不获取APDUException.BAD_LENGTH的情况下发送它?

此外,在发送此字节数组时,如何从主机应用程序中检索此字节数组? 我在主机应用程序中尝试以下操作:

CommandAPDU card_cert;
        ResponseAPDU resp4;
        card_cert =  new CommandAPDU(IDENTITY_CARD_CLA, SEND_CERTIFICATE, 0x00, 0x00);
        resp4 = c.transmit(card_cert);
        if(resp4.getSW()==0x9000) {
            byte [] response = resp4.getData();
            String certf= DatatypeConverter.printHexBinary(response);
            System.out.println("CERTIFICATE:" + certf + "--"+response.length);
            System.out.println(" signature to be verivied: " + DatatypeConverter.printHexBinary(card_signature));
            CertificateFactory certFac = CertificateFactory.getInstance("X.509");
            InputStream is = new ByteArrayInputStream(response);
            X509Certificate cert = ( X509Certificate ) certFac .generateCertificate( is ) ;
            Signature signature = Signature.getInstance("SHA1withRSA");
            signature.initVerify(cert.getPublicKey());

        signature.update(card_signature);
        if(card_signature !=null) {
            boolean ok =signature.verify(card_signature);
            if(ok==true)System.out.println("verification completed" ); 
    }
        }

当然,if(resp4.getSW()==0x9000)之后没有任何内容执行,因为证书未成功发送到主机应用程序。如何实现这一目标?

在我的applet类实现ExtendedLength之后,我在send_certificate()方法中执行了以下操作:

    private void send_certificate (APDU apdu) {
    if(!pin.isValidated())ISOException.throwIt(SW_PIN_VERIFICATION_REQUIRED);
    else{ byte[] buffer = apdu.getBuffer();
          short LE = apdu.setOutgoing();
           short toSend = (short)certificate.length;
           short cert_offset =0;
           short len =240;           
           if (LE != toSend) {
              apdu.setOutgoingLength(toSend);
           } 
           while (toSend > 0) {                
               Util.arrayCopyNonAtomic(certificate, cert_offset, apdu.getBuffer(), (short)0, len);
                       apdu.sendBytes((short) 0, len);
                       toSend -= len;
                       cert_offset += len;
          }
    }   
}

这不起作用:因响应代码28416而失败。

1 个答案:

答案 0 :(得分:1)

您应该确保您的Java Card实现和阅读器都支持扩展长度。可能是这些实现已经抛出了阻碍使用全尺寸扩展长度的障碍:例如,实现可能(错误地)限制APDU的大小。

读者可能要求ATR指示延长的长度。 NFC芯片因未正确实现扩展长度而臭名昭着(而Android因其未启用功能而臭名昭着)。这可能不是您的问题,因为状态字似乎是由卡生成的。

Java Card的代码有错误,应该始终使用setOutgoingLength()。在调用此方法时,您的代码似乎已抛出异常,因此我希望平台不支持您尝试发送的大小。除此之外,使用sendBytesLong的初始代码看起来也是正确的。当然,您的Applet应该实现ExtendedLength标记接口。

请注意,6F00(您的状态代码,对于那些使用十六进制,而不是十进制)可能由卡上生成的任何未处理的运行时异常生成。因此,请确保在尝试解决问题时不会在其他位置创建问题。

遗憾的是,扩展长度是一个雷区。我们现在在2018年,智能卡世界似乎仍然无法发送32 / 64Ki -1字节或以上。是时候用我认为有意义的东西替换ISO / IEC 7816-4了。