简体   繁体   中英

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. I refactored a bit and inserted an OwnerPIN object to my Applet. And now I can write the Applet once, but the second time, the deletion does not work anymore. 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. Is it connected to my OwnerPIN object?

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 . They are always there, even after the Applet instance is uninstalled and garbage collected. 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 .

If you cannot avoid it, use AppletEvent interface:

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.

First of all please download the GlobalPlatformPro tool. (It's free and if you are working in Windows platform, then gp.exe is enough for your case.)

After downloading try these commands in the command-line:

List you installed applets and their packages 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).

The 0102030405 and 010203040503 in the results are Pack AID and App AID of your program in my card.

Deleting the package by alone, without deleting its applet:

If I try to delete the package without deleting its applet, then it fails and I receive the same error that you receive:

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.
  2. Delete the package with all of its dependencies(including the applet).

Deleting the package and the applet simultaneously:

I choose the second solution (a parameter -deletedeps added to the delete command):

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:

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.

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)

Anyway, if in the first step (Listing installed applets) you faced with the 0x6985 error, that means your keys are not correct. For example if I put a random number for the key parameter in the command the I will face this result:

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 . Typically after 10 wrong tries, your card will be locked and the lock life cycle is irreversible.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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