简体   繁体   English

无法删除Java Card applet

[英]Cannot delete Java Card applet

I am quite new to Java Card but after some reading, my first Applet is working quite well.....until today. 我是Java Card的新手,但经过一些阅读,我的第一个Applet工作得很好.....直到今天。 I refactored a bit and inserted an OwnerPIN object to my Applet. 我重构了一下并将一个OwnerPIN对象插入到我的Applet中。 And now I can write the Applet once, but the second time, the deletion does not work anymore. 现在我可以编写Applet一次,但第二次,删除不再起作用了。 Here is my output: 这是我的输出:

Java Card 2.2.2 Class File Converter, Version 1.3
Copyright 2005 Sun Microsystems, Inc. All rights reserved. Use is subject to license terms.
mode_201
gemXpressoPro
enable_timer
establish_context
command time: 16 ms
card_connect
command time: 187 ms
select -AID A000000018434D00
command time: 78 ms
open_sc -security 1 -keyind 0 -keyver 0 -key 47454d5850524553534f53414d504c45 -keyDerivation visa2
command time: 328 ms
delete -AID  0102030405060708090000
delete() returns 0x80206985 (6985: Command not allowed - Conditions of use not satisfied.)
command time: 31 ms
delete -AID  01020304050607080900
delete() returns 0x80206985 (6985: Command not allowed - Conditions of use not satisfied.)
command time: 47 ms
get_status -element e0


List of applets (AID state privileges)
a000000018434d00 1 9e
a0000000620001 1 0
a0000000620002 1 0
a0000000620003 1 0
a0000000620101 1 0
a000000062010101 1 0
a0000000620102 1 0
a0000000620201 1 0
a0000000620209 1 0
a0000000620202 1 0
a000000018100109 1 0
a00000001810010b 1 0
a00000001810010a 1 0
a0000000030000 1 0
a000000018100106 1 0
a000000018100201 1 0
a000000018100101 1 0
a00000015100 1 0
a000000018100108 1 0
a0000000181001ff 1 0
a000000018100501 1 0
a000000018100502 1 0
a000000018100401 1 0
5365637572697479 1 0
a0000000035350 1 0
01020304050607080900 1 0
0102030405060708090000 7 0
command time: 187 ms
install -file mycap.cap -sdAID A000000018434D00 -nvCodeLimit 4096 -instParam 2265
install_for_load() returns 0x80206985 (6985: Command not allowed - Conditions of use not satisfied.)

update As requested, parts of my code: 更新根据要求,我的部分代码:

public class MyApplet extends Applet
{

   private static final byte MY_CLA = (byte)0xB0;

  ...
    private final static byte VERIFY_INS = (byte)0x40;
 ...
    private final static byte NEED_VERIFICATION_INS = (byte)0x47;
    private final static byte GET_INSTALL_PARAMS_INS = (byte)0x50;
    private final static byte GET_REMAINING_PIN_TRIES_INS = (byte)0x60;

    private final static byte PIN_TRY_LIMIT = (byte)0x03;
    private final static byte MAX_PIN_SIZE = (byte)0x08;

    // signal that the PIN verification failed
    private final static short SW_VERIFICATION_FAILED = 0x6300;
    private final static short SW_PIN_VERIFICATION_REQUIRED = 0x6301;

   ...
    private static byte[] testdata;
    private OwnerPIN m_pin;
    private byte[] m_array;
    private short m_offset;
    private byte m_length;

    private MyApplet(byte[] bArray, short bOffset, byte bLength)
    {
       ...
        m_pin = new OwnerPIN(PIN_TRY_LIMIT, MAX_PIN_SIZE);
        // m_array = bArray;
        // m_offset = bOffset;
        // m_length = bLength;
        register();
    }

    public boolean select()
    {
        if (m_pin.getTriesRemaining() == 0)
        {
            return false;
        }
        return true;
    }

    public void deselect()
    {
        m_pin.resetAndUnblock();
    }

    private void adminRest()
    {
        m_pin.resetAndUnblock();
        return;
    }


    private void getInstallParams(APDU apdu)
    {
        try
        {
            byte[] buffer = apdu.getBuffer();
            // inform the JCRE that the applet has data to return
            short le = apdu.setOutgoing();
            // set the actual number of the outgoing data bytes
            apdu.setOutgoingLength(((short)testdata.length));
            apdu.sendBytesLong(testdata, (short)0, (short)testdata.length);

        }
        catch (APDUException e)
        {
            // TODO Auto-generated catch block
        }
        catch (TransactionException e)
        {
            // TODO Auto-generated catch block
        }
        catch (ArrayIndexOutOfBoundsException e)
        {
            // TODO Auto-generated catch block
        }
        catch (NullPointerException e)
        {
            // TODO Auto-generated catch block
        }
    }

    /**
     * Get number of remaining pin tries
     * 
     * @param apdu
     */
    private void getPinTriesRemaining(APDU apdu)
    {
        try
        {
            byte[] buffer = apdu.getBuffer();
            // inform the JCRE that the applet has data to return
            apdu.setOutgoing();
            // set the actual number of the outgoing data bytes
            apdu.setOutgoingLength((byte)2);

            // write the PinTriesRemaining into the APDU buffer at the offset 0
            Util.setShort(buffer, (short)0, m_pin.getTriesRemaining());

            // send the 2-byte balance at the offset
            // 0 in the apdu buffer
            apdu.sendBytes((short)0, (short)2);
        }
        catch (APDUException e)
        {
            // TODO Auto-generated catch block
        }
        catch (TransactionException e)
        {
            // TODO Auto-generated catch block
        }
        catch (ArrayIndexOutOfBoundsException e)
        {
            // TODO Auto-generated catch block
        }
        catch (NullPointerException e)
        {
            // TODO Auto-generated catch block
        }

    } // end of getPinTriesRemaining method

    /**
     * Verification method to verify the PIN
     * 
     * @param apdu
     */
    private void verify(APDU apdu)
    {

        byte[] buffer = apdu.getBuffer();

        // receive the PIN data for validation.
        byte byteRead = (byte)(apdu.setIncomingAndReceive());

        // check pin
        // the PIN data is read into the APDU buffer
        // starting at the offset ISO7816.OFFSET_CDATA
        // the PIN data length = byteRead
        if (!m_pin.check(buffer, ISO7816.OFFSET_CDATA, byteRead))
        {
            ISOException.throwIt(SW_VERIFICATION_FAILED);
        }

    } // end of verify method

    /**
     * Installs the applet.
     *
     * @param bArray array with installation parameters.
     * @param bOffset offset into array.
     * @param bLength the length of the parameters.
     */
    public static void install(byte[] bArray, short bOffset, byte bLength)
    {
        testdata = new byte[bLength];
        Util.arrayCopy(bArray, (short)0, testdata, (short)0, bLength);
        new MyApplet(bArray, bOffset, bLength);
    }


    /**
     * Processes an incoming APDU.
     *
     * @param apdu the APDU.
     */
    public void process(APDU apdu)
    {

        byte l_transferredBuffer[] = apdu.getBuffer();
        // Get the CLA; mask out the logical-channel info.
        l_transferredBuffer[ISO7816.OFFSET_CLA] = (byte)(l_transferredBuffer[ISO7816.OFFSET_CLA] & (byte)0xFC);
        if ((l_transferredBuffer[ISO7816.OFFSET_CLA] == 0) && (l_transferredBuffer[ISO7816.OFFSET_INS] == (byte)(0xA4)))
        {
            ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);
        }
        if (l_transferredBuffer[ISO7816.OFFSET_CLA] != MY_CLA)
        {
            ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);
        }

        byte l_ins = l_transferredBuffer[ISO7816.OFFSET_INS];

      ...
        else if (l_ins == VERIFY_INS)
        {
            verify(apdu);
        }
        ...
        else if (l_ins == NEED_VERIFICATION_INS)
        {
            isNeedVerification(apdu, l_transferredBuffer);
        }
        else if (l_ins == GET_INSTALL_PARAMS_INS)
        {
            getInstallParams(apdu);
        }
        else if (l_ins == GET_REMAINING_PIN_TRIES_INS)
        {
            getPinTriesRemaining(apdu);
        }
        else
        {
            ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
        }
    }

    private void isNeedVerification(APDU apdu, byte[] buffer)
    {
        // The structure for the response request is
        // ---------------------
        // | response |
        // | 1 byte |
        // ---------------------
        getRequest(apdu, buffer);
        byte[] l_needVerificationResponse = new byte[1];
        boolean l_validated = m_pin.isValidated();
        if (l_validated)
        {
            l_needVerificationResponse[0] = 1;
        }
        else
        {
            l_needVerificationResponse[0] = 0;
        }
        apdu.setOutgoing();
        apdu.setOutgoingLength((short)l_needVerificationResponse.length);
        apdu.sendBytesLong(l_needVerificationResponse, (short)0, (short)l_needVerificationResponse.length);
    }

    private byte[] getRequest(APDU apdu, byte[] transferredBuffer)
    {
        short l_setIncomingAndReceive = apdu.setIncomingAndReceive();
        byte[] request = new byte[l_setIncomingAndReceive];
        for (short i = 0; i < request.length; i++)
        {
            short l_j = (short)(ISO7816.OFFSET_CDATA + i);
            request[i] = transferredBuffer[l_j];
        }
        return request;
    }
... 
}

Is my card blocked? 我的卡被封了吗? I can see that my AID runs in state 7...what does that mean. 我可以看到我的AID在状态7中运行......这是什么意思。 Is it connected to my OwnerPIN object? 它是否连接到我的OwnerPIN对象?

Thanks for your help! 谢谢你的帮助! Jan 一月

The problematic line is this one: 问题是这一行:

private static byte[] testdata;

Remember, static references to persistent objects are EVIL AND DANGEROUS . 请记住,对持久对象的static引用是邪恶的和危险的 They are always there, even after the Applet instance is uninstalled and garbage collected. 即使在卸载Applet实例并收集垃圾后,它们也始终存在。 That is why the referenced object (byte array in your case) is never garbage collected, the persistent memory is never released and thus the deletion command fails. 这就是为什么引用的对象(在你的情况下为字节数组)永远不会被垃圾收集,持久性内存永远不会释放,因此删除命令失败。

If you can avoid using static references, do so . 如果可以避免使用static引用, 请执行此操作

If you cannot avoid it, use AppletEvent interface: 如果你无法避免它,请使用AppletEvent接口:

public final class MyApplet extends Applet implements AppletEvent {

    private static byte[] testdata;
    ...

    //This method is called in the moment of uninstallation
    public final void uninstall() {
        testData = null; //release the reference --> testData can be GC
    }
    ...

}

I installed your applet on two different JavaCards and then I deleted it and installed it again and again successfully. 我在两个不同的JavaCards上安装了你的applet,然后我将其删除并再次成功安装。

First of all please download the GlobalPlatformPro tool. 首先,请下载GlobalPlatformPro工具。 (It's free and if you are working in Windows platform, then gp.exe is enough for your case.) (它是免费的,如果您在Windows平台上工作,那么gp.exe足以满足您的需求。)

After downloading try these commands in the command-line: 下载后,在命令行中尝试以下命令:

List you installed applets and their packages AID: 列出你安装的applet及其包AID:

G:\BasicTestTools\SmartCardTools>gp -key 404142434445464748494a4b4c4d4e4f -list
AID: A000000151000000 (|....Q...|)
     ISD OP_READY: Security Domain, Card lock, Card terminate, Default selected, CVM (PIN) management

AID: 010203040503 (|......|)
     App SELECTABLE: (none)

AID: A0000001515350 (|....QSP|)
     ExM LOADED: (none)
     A000000151535041 (|....QSPA|)

AID: 0102030405 (|.....|)
     ExM LOADED: (none)
     010203040503 (|......|)

Note that in the above output, those AIDs that are marked with App , are applets and those AIDs that are marked with ExM are Executable Modules (Packages). 请注意,在上面的输出中,那些用App标记的AID是applet,而那些用ExM标记的ExM可执行模块 (Packages)。

The 0102030405 and 010203040503 in the results are Pack AID and App AID of your program in my card. 结果中的0102030405010203040503是我的卡中程序的Pack AID和App AID。

Deleting the package by alone, without deleting its applet: 单独删除包,而不删除其applet:

If I try to delete the package without deleting its applet, then it fails and I receive the same error that you receive: 如果我尝试删除包而不删除其applet,则它会失败并且我收到您收到的相同错误:

G:\BasicTestTools\SmartCardTools>gp -key 404142434445464748494a4b4c4d4e4f -delete 0102030405
Could not delete AID: 0102030405
TIP: Maybe try with --deletedeps
pro.javacard.gp.GPException: Deletion failed SW: 6985
        at pro.javacard.gp.GlobalPlatform.check(GlobalPlatform.java:1092)
        at pro.javacard.gp.GlobalPlatform.deleteAID(GlobalPlatform.java:867)
        at pro.javacard.gp.GPTool.main(GPTool.java:390)

There are two ways to delete it: 有两种方法可以删除它:

  1. Delete the applet first and then delete the packages. 首先删除applet,然后删除包。
  2. Delete the package with all of its dependencies(including the applet). 删除包含其所有依赖项(包括applet)的包。

Deleting the package and the applet simultaneously: 同时删除包和applet:

I choose the second solution (a parameter -deletedeps added to the delete command): 我选择第二个解决方案(一个参数-deletedeps添加到delete命令):

G:\BasicTestTools\SmartCardTools>gp -key 404142434445464748494a4b4c4d4e4f -delete 0102030405 -deletedeps

G:\BasicTestTools\SmartCardTools>gp -key 404142434445464748494a4b4c4d4e4f -list
AID: A000000151000000 (|....Q...|)
     ISD OP_READY: Security Domain, Card lock, Card terminate, Default selected, CVM (PIN) management

AID: A0000001515350 (|....QSP|)
     ExM LOADED: (none)
     A000000151535041 (|....QSPA|)

Installing the same applet with the same AIDs for the Package and the Applet again: 再次使用相同的AID为Package和Applet安装相同的applet:

As you see, your package and the applet are deleted. 如您所见,您的包和小程序将被删除。 Now I install it again: 现在我再次安装它:

G:\BasicTestTools\SmartCardTools>gp -key 404142434445464748494a4b4c4d4e4f -install C:\NetBeansProjects\test2\dist\test2.cap

G:\BasicTestTools\SmartCardTools>gp -key 404142434445464748494a4b4c4d4e4f -list
AID: A000000151000000 (|....Q...|)
     ISD OP_READY: Security Domain, Card lock, Card terminate, Default selected, CVM (PIN) management

AID: 010203040503 (|......|)
     App SELECTABLE: (none)

AID: A0000001515350 (|....QSP|)
     ExM LOADED: (none)
     A000000151535041 (|....QSPA|)

AID: 0102030405 (|.....|)
     ExM LOADED: (none)
     010203040503 (|......|)

Well, As you see the applet installed successfully again. 好吧,正如您看到applet再次成功安装。

Note that you must replace my card's authentication keys with your card's authentication keys(I mean replace 404142...4f with your card's keys) 请注意,您必须使用卡的身份验证密钥替换我的卡的身份验证密钥(我的意思是用您的卡的密钥替换404142...4f

Anyway, if in the first step (Listing installed applets) you faced with the 0x6985 error, that means your keys are not correct. 无论如何,如果在第一步(列出已安装的applet)中遇到0x6985错误,则表示您的密钥不正确。 For example if I put a random number for the key parameter in the command the I will face this result: 例如,如果我在命令中为key参数添加一个随机数,我将面对这个结果:

G:\BasicTestTools\SmartCardTools>gp -key 00112233445566778899aabbccddeeff -list
pro.javacard.gp.GPException: STRICT WARNING: Card cryptogram invalid!
Card: 7F9CFF3D61110EF2
Host: 9EE2CDBF4A088053
!!! DO NOT RE-TRY THE SAME COMMAND/KEYS OR YOU MAY BRICK YOUR CARD !!!
        at pro.javacard.gp.GlobalPlatform.printStrictWarning(GlobalPlatform.java:184)
        at pro.javacard.gp.GlobalPlatform.openSecureChannel(GlobalPlatform.java:515)
        at pro.javacard.gp.GPTool.main(GPTool.java:371)

And as it indicate in the output, you have limited tries for the value of key . 正如它在输出中指出的那样,你对key的值的尝试有限。 Typically after 10 wrong tries, your card will be locked and the lock life cycle is irreversible. 通常在10次错误尝试后,您的卡将被锁定并且锁定生命周期不可逆转。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM