This discussion is archived
13 Replies Latest reply: Nov 11, 2012 11:20 PM by Jin RSS

How can I test the Le ?

Jin Newbie
Currently Being Moderated
Although I asked about the Le problem a few of days ago, I could not resolve the Le problem.

I have tested Le on select command, but the card does not reject by SW value:6700
For example: send: 00A4000107xxxxxxxxxxxxxx01
Lc: 07, AID:xxxxxxxxxxxxxx, Le: 01
Response: 9000 not the 6700

I analyzed the Le in the ADPU packet, which is case 4 according to ISO7816-3 and used tools and equipment such as the MP65, ORGA, and ICC SPECTRO.
As a result, the problem is that card cannot take the Le. The Le is ignored if the command excluding Le is correct.
I think the Le is managed by the COS, not the application. That is why the card cannot accept and response it.

My question is how to test it.
Even though I have been changed my environment to JCOP, the result was same.
That means if I fix the code based on JCOP, it cannot guarantee that is correct.
It remains unclear how the Le test should be performed.

I eagerly want to know how to test it, and I would like to know what you generally think about this matter to pass approval test sessions if I leave the matter as it is.

Thank you.
Jin.

글 수정: Jin
  • 1. Re: How can I test the Le ?
    Umer Journeyer
    Currently Being Moderated
    Please post your code and the apdus you send and receive.
  • 2. Re: How can I test the Le ?
    Jin Newbie
    Currently Being Moderated
    private final void returnFci(APDU apdu) throws CardException
         {                         

              short idl = apdu.setIncomingAndReceive();
              byte[] apduBuffer = apdu.getBuffer();
              short le = (short)(apdu.setOutgoing() & (short)0x00ff);
              
              if(apduBuffer[ISO7816.OFFSET_CLA] != CLASS_ISO)
         CardException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);
              
              Util.arrayCopy(fileControlInformation, (short)0, transientData, TD_OFF_FILE_CONTROL_INFORMATION, (short)fileControlInformation.length);

              if     (isApplicationPermanentlyBlocked)
                   ISOException.throwIt(ISO7816.SW_FUNC_NOT_SUPPORTED);

              if((apduBuffer[ISO7816.OFFSET_P1]!=(byte)4) || ((apduBuffer[ISO7816.OFFSET_P2]!=(byte)0)))
                   CardException.throwIt(ISO7816.SW_INCORRECT_P1P2);

              if((apduBuffer[ISO7816.OFFSET_LC] == (byte)0) || (idl == (short)0) ||
                        (apduBuffer[ISO7816.OFFSET_LC] != (byte)idl) ||
                        (le != (short)0))
                        CardException.throwIt(ISO7816.SW_WRONG_LENGTH);
         
              if((apduBuffer[ISO7816.OFFSET_LC] == (byte)0) || (le != (short)0))
                   CardException.throwIt(ISO7816.SW_WRONG_LENGTH);

              AID aidNsicc = JCSystem.getAID();
              byte AIDLength = JCSystem.getAID().getBytes(transientData, TD_OFF_AID);
              if(aidNsicc.equals(apduBuffer, ISO7816.OFFSET_CDATA, (byte)AIDLength) == false)
                   CardException.throwIt(ISO7816.SW_FILE_NOT_FOUND);
         
              sendOutgoingAndSendDataOfArray(apdu,transientData,TD_OFF_FILE_CONTROL_INFORMATION,(short)fileControlInformation.length);

              if     (isApplicationBlocked)
                   ISOException.throwIt(SW_APPLI_BLOCKED);
         }


    public static final void sendOutgoingAndSendDataOfArray(APDU apdu, byte[] dataToSend, short offset, short length)throws CardException
    {
         apdu.setOutgoingLength(length);
         apdu.sendBytesLong(dataToSend,offset,length);
    }



    -------------------------------------------------------
    Test No 0103 : SELECT
    -------------------------------------------------------

    [APDU - Gemplus USB Smart Card Reader 0]
    00 A4 04 00 07 D3 60 00 00 01 00 00 01
    << 6F 42 84 07 D3 60 00 00 01 00 00 A5 37 50 10 4E
    53 49 43 43 53 20 41 54 4D 2F 44 65 62 69 74 87
    01 01 9F 38 03 9F 1A 02 5F 2D 04 69 64 65 6E 9F
    11 01 01 9F 12 06 4E 53 49 43 43 53 BF 0C 05 9F
    4D 02 0B 0A 90 00
    35,822,988ns
  • 3. Re: How can I test the Le ?
    Umer Journeyer
    Currently Being Moderated
    I cannot execute this function in my mind ; )
    if you can post complete sample code then might i can understand what you are looking for. so far i could not get your question. Pardon me please as my level of understanding it little low : )

    Also try to post with [ code ] tags
    private final void returnFci(APDU apdu) throws CardException
    {
    
    short idl = apdu.setIncomingAndReceive();
    byte[] apduBuffer = apdu.getBuffer();
    short le = (short)(apdu.setOutgoing() & (short)0x00ff);
    
    if(apduBuffer[ISO7816.OFFSET_CLA] != CLASS_ISO)
    CardException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);
    
    Util.arrayCopy(fileControlInformation, (short)0, transientData, TD_OFF_FILE_CONTROL_INFORMATION, (short)fileControlInformation.length);
    
    if (isApplicationPermanentlyBlocked)
    ISOException.throwIt(ISO7816.SW_FUNC_NOT_SUPPORTED);
    
    if((apduBuffer[ISO7816.OFFSET_P1]!=(byte)4) || ((apduBuffer[ISO7816.OFFSET_P2]!=(byte)0)))
    CardException.throwIt(ISO7816.SW_INCORRECT_P1P2);
    
    if((apduBuffer[ISO7816.OFFSET_LC] == (byte)0) || (idl == (short)0) ||
    (apduBuffer[ISO7816.OFFSET_LC] != (byte)idl) ||
    (le != (short)0))
    CardException.throwIt(ISO7816.SW_WRONG_LENGTH);
    
    if((apduBuffer[ISO7816.OFFSET_LC] == (byte)0) || (le != (short)0))
    CardException.throwIt(ISO7816.SW_WRONG_LENGTH);
    
    AID aidNsicc = JCSystem.getAID();
    byte AIDLength = JCSystem.getAID().getBytes(transientData, TD_OFF_AID);
    if(aidNsicc.equals(apduBuffer, ISO7816.OFFSET_CDATA, (byte)AIDLength) == false)
    CardException.throwIt(ISO7816.SW_FILE_NOT_FOUND);
    
    sendOutgoingAndSendDataOfArray(apdu,transientData,TD_OFF_FILE_CONTROL_INFORMATION,(short)fileControlInformation.length);
    
    if (isApplicationBlocked)
    ISOException.throwIt(SW_APPLI_BLOCKED);
    }
    
    public static final void sendOutgoingAndSendDataOfArray(APDU apdu, byte[] dataToSend, short offset, short length)throws CardException
    {
    apdu.setOutgoingLength(length);
    apdu.sendBytesLong(dataToSend,offset,length);
    }
  • 4. Re: How can I test the Le ?
    Jin Newbie
    Currently Being Moderated
    00 A4 04 00 07 D3 60 00 00 01 00 00 *01*
    << 9000 (Wrong Le is added, so it must be 6700, not the 9000)

    I analyzed the APDU, and the Le was not taken by card.

    I think the reason why the card responds by SW9000, not the 6700, is type of the command, which is CASE 4(ISO7816-3).

    According to ISO7816-3 Case4S, The short Lc field consists of one byte: C(5) ≠ '00' for encoding Nc from 1 to 255.
    The short Le field consists of one byte: C(n) with any value for encoding Ne from 1 to 256 ('00' means the maximum, 256).
    The command APDU is mapped onto the command TPDU by cutting off the Le field, i.e., C(n).

    In other words, the Le is not sent to the card, so I cannot get the Le value correctly.

    In my opinion, it is not related to the code or application.
    Therefore, I am asking how to test the Le not the fixing error, and what you generally think about this matter to pass approval test sessions if I leave the matter as it is.
  • 5. Re: How can I test the Le ?
    Umer Journeyer
    Currently Being Moderated
    The command you are sending is expecting Le=00 as stated in GP 2.1.1
    The data field of the command shall contain the AID of the Application to be selected. The Lc and data field of
    the SELECT command may be omitted if the Issuer Security Domain is being selected. In this case, Le shall be
    set to '00' and the command is a case 2 command according to ISO/IEC 7816-4.
    If you wanna test the le behavior you will need to test it on some other APDUs.
  • 6. Re: How can I test the Le ?
    Sebastien_Lorquet Journeyer
    Currently Being Moderated
    Hi Jin,

    My colleague is having the same issue with a gemalto card, setOutgoing() always returns zero.

    I suggested to directly read this byte in the apdu buffer at the correct offset.

    This is not a generic solution to manage app APDUs in the world, but for a particular command, the apdu case (1/2/3/4) is known, so one could read Le at the proper place in the buffer.

    I'll tell you if that worked.

    But Jin you did not reply to me. Do you use a contact or contactless interface?

    Regards

    Umer: beware, that's only for the special case "00A4040000" to select the ISD (yeah, you don't need to know the ISD AID, which is cool). In all other situations, SELECT is a case 4 command and Le is valid to request the length of the returned data.
  • 7. Re: How can I test the Le ?
    Jin Newbie
    Currently Being Moderated
    Hi Lorquet

    I am sorry about that.
    I use a contact interface.
    Your solution is interesting for me.
    Please, tell me if that succeeds.

    Thank you,
    Jin
  • 8. Re: How can I test the Le ?
    Adriaan Explorer
    Currently Being Moderated
    We had a similar problem over contact interface on another card (vendor shall remain nameless).

    In the ISO7816-3 spec, you will find Section 12.2.5 for Case4S: it describes how the APDU exchange is sometimes split into two T-APDUs on the transport layer, but on the application layer there is always only one C-APDU and one R-APDU per exchange. In Case 4S.2 and 4S.3 a second T-APDU will be sent to the card, with INS=GET_RESPONSE and P3=Le (or some upper limit).

    Even though this is clear to me, I'm not sure how to modify the applet to deal with the second T-APDU. Magic on the transport layer could be considered the responsibility of the Card Manager, but I have seen how transport layer issues creep into the application layer (at least on the card, if not on the CAD side).

    Any ideas?
  • 9. Re: How can I test the Le ?
    Sebastien_Lorquet Journeyer
    Currently Being Moderated
    Jin, that is why Le gets zero. In contactless mode Le is not used.

    The Le byte is only needed for T=0 contact protocol. In this mode, the length and direction of the transfer must always be know before the bytes are transferred. Sending Le allows the card to check that the coupler UART will expect Le bytes, so if the card does not agree with that Le value, it can send a 6CXX until the length is okay between the card and the coupler.

    In contactless mode (and T=1) there is no need to deal with that. The transfers are wrapped inside packets (I-blocks). The transfer length is not important.

    So what does it means? We're at the APDU level of transaction.

    You don't have to send Le. You just send the command APDU, and the card will reply a response APDU with any length. To check that the length is correct, you just have to check the response length.

    my conclusion is that Le is a low-level protocol part that got lost in higher protocol levels, where it has nothing to do.

    I don't have the results yet, I'll ask tomorrow.

    Regards,
    Sebastien
  • 10. Re: How can I test the Le ?
    Sebastien_Lorquet Journeyer
    Currently Being Moderated
    Adriaan: the second TPDU exchange is managed by the OS, you will not see it.

    In T=0 mode, if you send a case 4 command apdu with Le included, you will get that in the return of setOutgoing().
    It seems that when other protocols are used, Le is not available in this way.

    But the javacard applet will always be able to return as many data as it wants, the applet does not have to care about the return value from setOutgoing().

    The ACTUAL number of returned bytes is defined by the applet with the setOutgoingLength() call.

    This value is used by the card OS to create the response I-block in T=1 or contactless modes, OR to reply with a 6CXX/61XX SW in T=0 mode.

    If the Le from SetOutgoing() matches the number of bytes passed to setOutgoing() the card OS will reply 61XX and expect a GET RESPONSE. The Applet is NOT notified of this. process() is NOT called in this context.

    Then If the Le in get response does not match XX, we have two possible situations according to the card model:
    -some cards reject the call with a new 61XX
    -some cards reply with the requested number of bytes, followed by a 61YY where YY is the number of bytes still remaining

    If the Le from SetOutgoing() does not matches the number of bytes passed to setOutgoing() the card OS will reply 6CXX and expect the SAME APDU with a proper Le=XX. The card reader will have to re-emit the EXACT SAME command with modified Le. The applet is NOT notified about that, process() is NOT called.

    In all cases, if any unexpected apdu is sent in place of get response or a repetition, these steps are cancelled and the new APDU is processed.

    and if a get response is sent when it is unexpected, process() will be called with this apdu.
  • 11. Re: How can I test the Le ?
    Adriaan Explorer
    Currently Being Moderated
    Thanks, that is useful to know.
  • 12. Re: How can I test the Le ?
    Sebastien_Lorquet Journeyer
    Currently Being Moderated
    Jin,

    our test did not work, the buffer does not contain anything past the last command byte.

    This is because the card is using T=1, which confirms all my previous posts.

    ==>> you cannot get Le for a case 4 apdu in protocols other than T=0.

    In our situation this was not a problem, but in the case it's a problem, don't forget that you can get the current protocol with this API: http://www.informatik.uni-augsburg.de/swt/lehre/javacard/JavaCard-2.1-API/javacard.framework.APDU.html#getProtocol%28%29 , and maybe do things differently according to the protocol.

    Regards,
    Sebastien
  • 13. Re: How can I test the Le ?
    Jin Newbie
    Currently Being Moderated
    Lorquet,

    Thank you for your help.
    I confirmed the current protocol with the getProtocol() API again.
    The returned data is 0, so it is T=0.

    Thank you,
    Jin

Legend

  • Correct Answers - 10 points
  • Helpful Answers - 5 points