JavaCard共享接口方法无法访问传入数据的问题排查
问题背景
作为JavaCard小程序开发新手,尝试通过Shareable接口实现跨Applet方法调用,但遇到异常:发送APDU指令00 11 00 00时,返回6F00 (SW_UNKNOWN),预期是SW_CONDITIONS_NOT_SATISFIED;但如果不在checkNumber方法中操作传入的数组,能正常返回SW_WRONG_DATA。
代码实现
共享接口定义(Configurations.java)
public interface Configuration extends Shareable { public void checkNumber(byte[] number); }
提供共享接口的SourceApplet
// sourceapplet.java public void checkNumber(byte[] number) { short numberLength = (short)number.length; if (numberLength < 6) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } ISOException.throwIt(ISO7816.SW_WRONG_DATA); }
调用接口的TargetApplet
// targetapplet.java public final class TargetApplet extends Applet implements MultiSelectable { private static final byte INS_TEST_CHECK_NUMBER = (byte) 0x11; private AID checkNumberAppletAID; private TargetApplet() { // 初始化checkNumberApplet的AID byte[] aidBytes = {(byte) 0xB2, 0x86, 0x00, 0x00, 0x00, 0x01}; checkNumberAppletAID = JCSystem.lookupAID(aidBytes, (short)0, (byte) aidBytes.length); if (checkNumberAppletAID == null) { ISOException.throwIt(ISO7816.SW_FILE_NOT_FOUND); // 未找到小程序 } } public void process(APDU apdu) { final byte[] buffer = apdu.getBuffer(); final byte ins = buffer[ISO7816.OFFSET_INS]; switch (ins) { case INS_TEST_CHECK_NUMBER: processCheckNumber(apdu); break; default: ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED); } } private void processCheckNumber(APDU apdu) { Configuration config = (Configuration) JCSystem.getAppletShareableInterfaceObject(checkNumberAppletAID, (byte) 0x00); if (config == null) { ISOException.throwIt(ISO7816.SW_APPLET_SELECT_FAILED); } byte[] number = new byte[]{1,2,3,4}; // byte[] number = new byte[] {(byte) '1', (byte) '2', (byte) '3', (byte) '4'}; config.checkNumber(number); } }
尝试的解决方案及结果
更新1:更换内存类型
- 使用瞬态内存:在TargetApplet中用
JCSystem.makeTransientByteArray创建数组,结果仍异常。 - 使用持久化内存:在TargetApplet中用
new byte[4]创建数组,结果仍异常。
更新2:添加异常捕获
在SourceApplet的checkNumber方法中添加try-catch:
public void checkNumber(byte[] number) { try { short numberLength = (short)number.length; if (numberLength < 6) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } } catch (ISOException e) { ISOException.throwIt(e.getReason()); } catch (SecurityException e) { ISOException.throwIt(ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED); } }
现在返回6982 SW_SECURITY_STATUS_NOT_SATISFIED。
疑问
- 问题根源是什么?如何解决?
- TargetApplet中传入的number数组是否存在问题?
解答
问题原因
JavaCard的安全沙箱机制限制了跨Applet访问内存:当SourceApplet尝试访问TargetApplet创建的数组的length属性时,会触发SecurityException。不同Applet拥有独立的内存空间,默认不允许直接访问对方对象的内部属性(包括数组长度)。未捕获该异常时,会返回通用错误6F00;捕获后则返回自定义的6982。
解决方案
修改共享接口设计,由调用方(TargetApplet)主动传入数组长度,避免跨Applet访问对象内部属性:
- 更新共享接口
// Configurations.java public interface Configuration extends Shareable { public void checkNumber(byte[] number, short length); }
- 修改SourceApplet实现
public void checkNumber(byte[] number, short length) { if (length < 6) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } ISOException.throwIt(ISO7816.SW_WRONG_DATA); }
- 修改TargetApplet调用逻辑
private void processCheckNumber(APDU apdu) { Configuration config = (Configuration) JCSystem.getAppletShareableInterfaceObject(checkNumberAppletAID, (byte) 0x00); if (config == null) { ISOException.throwIt(ISO7816.SW_APPLET_SELECT_FAILED); } byte[] number = new byte[]{1,2,3,4}; config.checkNumber(number, (short)number.length); }
原理说明
JavaCard的Shareable接口仅允许跨Applet调用方法,但方法参数中对象的内部属性访问受沙箱限制。通过主动传入数组长度,避开了跨Applet访问对象内部属性的操作,符合安全规范,同时能实现预期的业务逻辑。
内容的提问来源于stack exchange,提问作者Preeti
相关产品推荐
相关产品推荐

