10

我的问题是,是否可以从小程序本身的代码中锁定小程序,作为从代码中检测到的操作的对策。

显而易见的选择是使用GPSystem.lockCard();它并且它可以工作,但是我想知道是否可以只锁定小程序。我还可以从关联安全域的经过身份验证的会话中锁定小程序本身。但它是否可能来自小程序代码本身。看来,鉴于GPSystem.setCardContentState();使用的方法GPSystem.APPLICATION_LOCKED,所以我也测试了它,但它不起作用。

重读GP卡规范2.2 PDF的描述:

OPEN 应拒绝来自生命周期状态 LOCKED 的任何转换请求;

在我的 Eclipse 中,JavaDoc 说:

OPEN 应拒绝任何向生命周期状态 LOCKED 的转换请求

这里发生了什么?

4

5 回答 5

9

有趣的是,这种机制是如何从 GlobalPlatform Card 规范 2.1.1 演变到 2.2.1(在 2.3 中仍然相同):

  1. 在 GP 2.1.1 中,仅允许发卡机构(卡外实体)或 OPEN(作为“例外”的结果)启动对应用程序的锁定:

    发卡机构具有禁用卡上应用程序的持续执行状态的机制。该机制可以根据 OPEN 处理的异常或使用外部调用的命令从 OPEN 内部调用。发卡机构是唯一可以启动应用程序锁定的实体。

    该方法GPSystem.setCardContentState()被明确定义为只允许对特定于应用程序的生命周期状态(设置最低 3 位之间的值)0x07进行状态更改。0x7F由于APPLICATION_LOCKED后面规范中的常数为0x80设置此状态是不允许的。此方法的注释中也明确说明了这一点:

    • OPEN 应拒绝任何生命周期状态 INSTALLED 或LOCKED的转换请求。

    因此,尝试从应用程序本身将应用程序状态设置为锁定必须在实现 GP 2.1.1 的卡上失败。

    更新(2016-05-20):我在几张 NXP JCOP 卡(声称符合 GP 2.1.1)上对此进行了测试,并且设置了高位设置或任何低 3 位清除的值确实失败了。

  2. 这在 GP 2.2 中发生了变化。现在,允许应用程序锁定自身:

    该卡具有禁用并随后重新启用卡上应用程序的持续执行状态的机制。该机制可以根据 OPEN 处理的异常或使用外部调用的命令从 OPEN 内部调用。具有全局锁定特权的应用程序、应用程序本身或直接或间接关联的安全域是唯一可以启动应用程序锁定的实体。

    GP 卡规范不要求应用程序持有任何特定权限来锁定自身。

    不幸的是,该方法的 API 规范GPSystem.setCardContentState()还不是很清楚。首先,该方法的描述仍然指出,只允许设置最低 3 位之间的0x07值:0x7F

    此方法设置当前小程序上下文的应用程序特定生命周期状态。只要设置了 3 个低位,应用程序特定的生命周期状态范围为 0x07 到 0x7F。

    其次,在作为 GP 卡规范 2.2 文档附录 A 的一部分的 API 文档和 API 导出文件中的 JavaDoc 中存在偏差说明。虽然规范中的注释更改为:

    • OPEN 应拒绝任何转换到生命周期状态 INSTALLED 的请求;
    • OPEN 应拒绝来自生命周期状态LOCKED的任何转换请求;

    API 导出文件(GPSystem.java 和 JavaDoc)中的注释与 GP 2.1.1 中的相同。

    因此,如果此方法是根据规范实现的,它仍应拒绝将应用程序生命周期状态设置为APPLICATION_LOCKED.

    更新 (2016-05-20):我在 NXP J3D081 (JCOP v2.4.2 R2) 卡上进行了测试(声称符合 GP 2.2)。不幸的是,设置设置了高位或清除低 3 位的值会失败。

    不过,也有方法GPRegistryEntry.setState()。此方法的文档指出:

    • 仅当调用应用程序对应于此 GPRegistryEntry 时,才应接受到除 APPLICATION_LOCKED 和 APPLICATION_UNLOCKED 之外的生命周期状态的转换请求;
    • 应用程序应能锁定,不能自行解锁;

    因此,看看以下内容是否适用于使用setCardContentState()失败的同一张卡会很有趣:

    GPSystem.getRegistryEntry(null).setState(GPSystem.APPLICATION_LOCKED);
    

    更新 (2016-05-20):我在 NXP J3D081 (JCOP v2.4.2 R2) 卡上进行了测试(声称符合 GP 2.2)。不幸的是,这也失败了。顺便提一句。null如果或JCSystem.getAID()用作 的参数,似乎没有什么区别getRegistryEntry()

    更新 (2016-06-14):Paul Bastian称,NXP 代表已确认应用程序无法在 JCOP v2.4.x 卡上将自己设置为锁定状态。

    更新(2016-06-06):我在英飞凌 SLE97CNFX 卡(声称符合 GP 2.2.1)上对此进行了测试,它工作正常。我可以使用APPLICATION_LOCKED(0x80) 成功地将状态设置为锁定。然后将状态设置为previous_state | 0x80。尝试设置其他设置了高位的状态值(例如 0x8F)不起作用(正如我预期的那样)。

  3. 在 GP 2.2.1 中,该方法的文档GPSystem.setCardContentState()已更改(再次)。更改说明清楚地表明该方法已更新为现在允许应用程序锁定自身(导出文件版本 1.5。映射到 GP 2.2.1):

    • 导出文件版本 1.5:此方法现在允许与当前小程序上下文关联的应用程序锁定自身。

    方法定义更改为:

    此方法允许与当前小应用程序上下文相关联的应用程序将其状态更改为特定于应用程序的生命周期状态或锁定自身。应用程序无法使用此方法自行解锁。

    传递给该方法的 state 参数的值范围现在显式包括 的值APPLICATION_LOCKED

    bState- 特定于应用程序的生命周期状态(0x07 到 0x7F,设置了 3 个低位),或APPLICATION_LOCKED(0x80)。

    因此,实现 GP 2.2.1 或更高版本的卡最终应该允许应用程序使用该方法将自己的生命周期状态更改为锁定GPSystem.setCardContentState()

    更新(2016-06-06):我在英飞凌 SLE97CNFX 卡(声称符合 GP 2.2.1(或者是 2.3?))上对此进行了测试,并且它有效。我可以使用APPLICATION_LOCKED(0x80) 成功地将状态设置为锁定。然后将状态设置为previous_state | 0x80。尝试设置其他设置了高位的状态值(例如 0x8F)不起作用(正如我预期的那样)。

替代解决方案

在无法将应用程序生命周期设置为 state 的情况下,您可以做些什么来解决问题APPLICATION_LOCKED,即使用特定于应用程序的生命周期状态:

public class LockableApplet extends Applet {

    [... applet installation / instantiation code ...]

    private static final byte APPLICATION_STATE_UNLOCKED = (byte)0x07;
    private static final byte APPLICATION_STATE_LOCKED = (byte)0x7F;

    public boolean select() {
        if (GPSystem.getCardContentState() == APPLICATION_STATE_LOCKED) {
            return false;
        }

        return true;
    }

    public void process(APDU apdu) {
        if (selectingApplet()) {
            return;
        }

        if (GPSystem.getCardContentState() == APPLICATION_STATE_LOCKED) {
            ISOException.throwIt(ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED);
        }

        [... applet logic code ...]

    }   
}

在检测到应该导致您的应用程序被锁定的问题时,您可以通过以下调用锁定小程序:

GPSystem.setCardContentState(APPLICATION_STATE_LOCKED);

您可以稍后通过安全域使用 SET STATUS 命令再次解锁应用程序。

于 2016-05-11T07:24:20.173 回答
5

(买家当心:似乎这种方式根本行不通——见评论)

(在 GlobalPlatform 卡规范 2.2.1 的上下文中)

您必须遵守图 5-2 中描述的应用程序生命周期状态规则(此处适用标记为“5”的箭头)。

正确的方法应该是:

GPSystem.setCardContentState((byte)(GPSystem.getCardContentState() | GPSystem.APPLICATION_LOCKED));

或者

GPSystem.getRegistryEntry(JCSystem.getAID()).setState((byte)(GPSystem.getCardCo‌​ntentState() | GPSystem.APPLICATION_LOCKED))

应用程序的0x80生命周期状态无效。请参见表 11-4(至少必须设置b1和位,可能也设置位)。b2b3

编辑>

(我承认写这个答案完全是基于对 OPEN 保持实体被锁定的原始状态这一事实的记忆)

我对此很好奇,所以我使用以下小程序(摘录)做了一些测试:

public void process(APDU apdu) {
    byte[] buffer = apdu.getBuffer();

    if(selectingApplet()) {
        return;
    }

    short claIns = Util.getShort(buffer, ISO7816.OFFSET_CLA);
    switch(claIns) {
        case (short) 0x8007:
            buffer[0]=GPSystem.getCardContentState();
            if(buffer[0]==buffer[ISO7816.OFFSET_P1]) {
                if(GPSystem.setCardContentState(buffer[ISO7816.OFFSET_P2])) {
                    buffer[1]=0x01;
                } else {
                    buffer[1]=0x00;
                }
            } else {
                buffer[1]=(byte)0xFF;
            }
            buffer[2]=GPSystem.getCardContentState();
            apdu.setOutgoingAndSend((short)0, (short)3);
            return;
        default: {
            ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
            return;
        }
    }
}

以及以下 APDU:

8007070F03 // To test transition into Application Specific State
80070F8F03 // To test my theory
80070F8003 // To test the GPSystem.APPLICATION_LOCKED constant directly

我的一组卡片(Gemalto、Morpho、JCOP - 不幸的是它们都是 GP 2.1.1)的结果符合 Michael Roland 的出色答案和 GP 规范 - 应用程序尝试阻止自身被拒绝。

收到所有 GP 2.1.1 卡的响应 APDU:

8007070F03 -> 07010F9000 // Succeeded in transition from `07` to `0F`
80070F8F03 -> 0F000F9000 // Failed transition from `0F` to `8F`
80070F8003 -> 0F000F9000 // Failed transition from `0F` to `80`

请注意:此工具在解析卡识别数据时对于确定实施的 GP 版本非常有用。

于 2016-05-11T16:53:56.347 回答
3

本身不符合 GP 核心规范。产品符合 GP配置的 GP 要求。GP 配置不是免费的。JCOP 2.4.x 产品符合 GP 2.2.x“现有 GP 2.1.1 在 v2.2.1 上实现的映射指南”配置。顾名思义,此配置用于向后兼容映射。基本上,JCOP 2.4.x 产品只是符合 GP 2.1.1 的产品(具有 GP 2.2.x 的几个特性)。全局锁定权限对于小程序是可选的。

于 2016-06-14T11:40:55.207 回答
3

是的。这是 GlobalPlatform 应用程序的常见和预期操作。您必须使用正确的权限(gp -install -privs CardLock)安装您的应用程序,并且执行此操作的代码是:

GPSystem.setCardContentState(GPSystem.APPLICATION_LOCKED);

您可以稍后解锁应用程序

gp -unlock-applet <aid>
于 2016-05-10T22:42:22.940 回答
2

是的,这很简单:使用一个private static boolean标志并在process(APDU apdu)方法的开头检查它:

public class MiniApplet extends Applet {

    public static void install(byte[] bArray, short bOffset, byte bLength) {
        new MiniApplet();
    }

    protected MiniApplet() {
        register();
    }

    private static final short SW_APPLET_IS_LOCKED = (short) 0x9199; //any error SW
    private static boolean appletLocked = false; //static -> faster access, this flag is checked each call! "private" modifier is VERY important!

    public void process(APDU apdu) {
        if (selectingApplet()) {
            return; //it is a good practice not to throw any exceptions on SELECT command
        }

        if (appletLocked) { 
            ISOException.throwIt(SW_APPLET_IS_LOCKED);
        }

        if (attackDetected()) { //implement your attack detection
            appletLocked = true;
        }
    }   
}
于 2016-05-10T20:29:47.937 回答