Thanks for the input Karsten. Much appreciated. Tripp Hyde
-----Original Message----- From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] Behalf Of Karsten Ohme Sent: Monday, November 21, 2005 12:40 PM To: MUSCLE Subject: Re: [Muscle] Data and 61XX Tripp Hyde wrote: > Hello, I'm curious what Musclecard does in the following case. If > you want to retrieve data from the card that's greater than the size > of a transmission packet (say 256 bytes), the card sends back '61XX' > where XX indicates how much data is left. You can continue sending > GET RESPONSES to the card until you get all the data. However, after > searching through 7816-3 and 7816-4 I can't seem to find the answer > for the following case: > > What if you specify an Lc byte that is smaller than the amount of > data that could be returned. Does the card return a '6CXX' error, > does it return that smaller amount of data + '9000', or does it > return that smaller amount of data + '61XX' where XX is the amount of > data left? Or is this left open to the interpretation of the > application designer? The return codes are specified by the Java Card specification. But they are conforming to ISO 7816-4. I quote from Java Card RE Specification Chapter 9, I hope this is the case you are asking: // Lr < Le // 1. The card sends <0x61,Lr> completion status bytes // 2. The CAD sends GET RESPONSE command with Le = Lr. // 3. The card sends Lr bytes of output data using the standard T=0 <INS> or <~INS> // procedure byte mechanism. // 4. The card sends <SW1,SW2> completion status on completion of the // Applet.process method. // Lr > Le // 1. The card sends Le bytes of output data using the standard T=0 <INS> or // <~INS> procedure byte mechanism. // 2. The card sends <0x61,(Lr-Le)> completion status bytes // 3. The CAD sends GET RESPONSE command with new Le <= Lr. // 4. The card sends (new) Le bytes of output data using the standard T=0 <INS> or // <~INS> procedure byte mechanism. // 5. Repeat steps 2-4 as necessary to send the remaining output data bytes (Lr) as // required. // 6. The card sends <SW1,SW2> completion status on completion of the // Applet.process method. > > I'm just trying to figure out how others interpret this case. > Thanks. You can sneak through the code below, this should handle all cases correctly. Karsten static LONG send_APDU(OPGP_CARD_INFO cardInfo, GP211_SECURITY_INFO *secInfo, PBYTE capdu, DWORD capduLength, PBYTE rapdu, PDWORD rapduLength) { LONG result; // modified for managing all 4 cases with automatic APDU chaining // when necessary... BYTE apduCommand[261]; DWORD caseAPDU; DWORD apduCommandLength = 261; BYTE lc; BYTE le; BYTE la; DWORD i; DWORD offset = 0; PBYTE responseData = NULL; DWORD responseDataLength = *rapduLength; LOG_START(_T("send_APDU")); responseData = (PBYTE)malloc(sizeof(BYTE)*responseDataLength); if (traceEnable) { _ftprintf(traceFile, _T("--> ")); for (i=0; i<capduLength; i++) { _ftprintf(traceFile, _T("%02X"), capdu[i]); } _ftprintf(traceFile, _T("\n")); } // main transmission block // wrap command result = wrap_command(capdu, capduLength, apduCommand, &apduCommandLength, secInfo); if ( OPGP_ERROR_SUCCESS != result) { goto end; } apduCommand[0] |= cardInfo.logicalChannel; // if T=1 or else T=0 if (cardInfo.protocol == OPGP_CARD_PROTOCOL_T1) { // T=1 transmition result = SCardTransmit(cardInfo.cardHandle, SCARD_PCI_T1, apduCommand, apduCommandLength, NULL, responseData, &responseDataLength ); if ( SCARD_S_SUCCESS != result) { goto end; } // if ( SCARD_S_SUCCESS != result) offset += responseDataLength - 2; } else { // Determine which type of Exchange between the reader if (apduCommandLength == 4) { // Case 1 short caseAPDU = 1; } else if (apduCommandLength == 5) { // Case 2 short caseAPDU = 2; le = apduCommand[4]; } else { lc = apduCommand[4]; if ((convertByte(lc) + 5) == apduCommandLength) { // Case 3 short caseAPDU = 3; } else if ((convertByte(lc) + 5 + 1) == apduCommandLength) { // Case 4 short caseAPDU = 4; le = apduCommand[apduCommandLength - 1]; apduCommandLength--; } else { { result = OPGP_ERROR_UNRECOGNIZED_APDU_COMMAND; goto end; } } } // if (Determine which type of Exchange) // T=0 transmition (first command) responseDataLength = *rapduLength; result = SCardTransmit(cardInfo.cardHandle, SCARD_PCI_T0, apduCommand, apduCommandLength, NULL, responseData, &responseDataLength ); if ( SCARD_S_SUCCESS != result) { goto end; } // if ( SCARD_S_SUCCESS != result) offset += responseDataLength - 2; // main switch block for cases 2 and 4 switch (caseAPDU) { case 2: { while ((responseData[responseDataLength + offset - 2] == 0x61) || (responseData[responseDataLength + offset - 2] == 0x6c)) { //Le is not accepted by the card and the card indicates the available length La. //The response TPDU from the card indicates that the command is aborted due to //a wrong length and that the right length is La: (SW1='6C' and SW2 codes La). if (responseData[responseDataLength + offset - 2] == 0x6c) { la = responseData[responseDataLength + offset - 1]; apduCommand[apduCommandLength-1] = la; // P3 // T=0 transmition (command w/ La) responseDataLength = *rapduLength - offset; result = SCardTransmit(cardInfo.cardHandle, SCARD_PCI_T0, apduCommand, apduCommandLength, NULL, responseData+offset, &responseDataLength ); if ( SCARD_S_SUCCESS != result) { goto end; } // If La is greater that Le, then the response TPDU is mapped // onto the response APDU by keeping only the first Le bytes // of the body and the status bytes SW1-SW2. if (convertByte(le) < convertByte(la)) { memmove(responseData+offset+convertByte(le), responseData+offset+responseDataLength-2, 2); offset += convertByte(le); break; } // if (convertByte(le) < convertByte(la)) offset += responseDataLength - 2; le = la; continue; } // if (6C) // Java Card specific. Java Card RE Specification Chapter 9 // if (61) if (responseData[responseDataLength + offset - 2] == 0x61) { // Lr < Le // 1. The card sends <0x61,Lr> completion status bytes // 2. The CAD sends GET RESPONSE command with Le = Lr. // 3. The card sends Lr bytes of output data using the standard T=0 <INS> or <~INS> // procedure byte mechanism. // 4. The card sends <SW1,SW2> completion status on completion of the // Applet.process method. // Lr > Le // 1. The card sends Le bytes of output data using the standard T=0 <INS> or // <~INS> procedure byte mechanism. // 2. The card sends <0x61,(Lr-Le)> completion status bytes // 3. The CAD sends GET RESPONSE command with new Le <= Lr. // 4. The card sends (new) Le bytes of output data using the standard T=0 <INS> or // <~INS> procedure byte mechanism. // 5. Repeat steps 2-4 as necessary to send the remaining output data bytes (Lr) as // required. // 6. The card sends <SW1,SW2> completion status on completion of the // Applet.process method. // These two cases behave the same way la = responseData[responseDataLength + offset - 1]; apduCommand[0] = 0x00;; apduCommand[1] = 0xC0; // INS (Get Response) apduCommand[2] = 0x00; // P1 apduCommand[3] = 0x00; // P2 apduCommand[4] = la; apduCommandLength = 5; le = la; // T=0 transmition (command w/ La) responseDataLength = *rapduLength - offset; result = SCardTransmit(cardInfo.cardHandle, SCARD_PCI_T0, apduCommand, apduCommandLength, NULL, responseData+offset, &responseDataLength ); if ( SCARD_S_SUCCESS != result) { goto end; } // if ( SCARD_S_SUCCESS != result) offset += responseDataLength - 2; continue; } // if (61) } // while (61) || (6c) break; } // case 2 case 4: { /* Note: Some smartcard are not fully compatible with ISO normatives in case short 4. So when a card returns a 0x9000 to inform a good transfer of the APDU command then the terminal have to terminate the transaction and it shall return the sw1 sw2 to the user. In the case of fully ISO, the terminal sends a get response to extract the "le" bytes requested inside the APDU command. */ // if 61 etc. if (responseData[responseDataLength + offset - 2] == 0x61 || responseData[responseDataLength + offset - 2] == 0x90 || responseData[responseDataLength + offset - 2] == 0x9F) { apduCommand[0] = 0x00; apduCommand[1] = 0xC0; // INS (Get Response) apduCommand[2] = 0x00; // P1 apduCommand[3] = 0x00; // P2 apduCommandLength = 5; // Default Case Le is requested in the get response apduCommand[4] = le; // P3 // verify if we have La < Le in the case of sw2 = 0x61 or 0x9f if (responseData[responseDataLength + offset - 2] != 0x90) { if (convertByte(responseData[responseDataLength + offset - 1]) < convertByte(le)) { // La is requested in the get response apduCommand[4] = responseData[responseDataLength + offset - 1]; le = responseData[responseDataLength + offset - 1]; } } // T=0 transmission (command w/ Le or La) responseDataLength = *rapduLength - offset; result = SCardTransmit(cardInfo.cardHandle, SCARD_PCI_T0, apduCommand, apduCommandLength, NULL, responseData+offset, &responseDataLength ); if ( SCARD_S_SUCCESS != result) { goto end; } // if ( SCARD_S_SUCCESS != result) offset += responseDataLength - 2; } // if (61 etc.) while ((responseData[responseDataLength + offset - 2] == 0x61) || (responseData[responseDataLength + offset - 2] == 0x6c) || (responseData[responseDataLength + offset - 2] == 0x9f)) { // if (6c) if (responseData[responseDataLength + offset - 2] == 0x6c) { la = responseData[responseDataLength + offset - 1]; apduCommand[apduCommandLength -1] = la; // P3 // T=0 transmition (command w/ La) responseDataLength = *rapduLength - offset; result = SCardTransmit(cardInfo.cardHandle, SCARD_PCI_T0, apduCommand, apduCommandLength, NULL, responseData+offset, &responseDataLength ); if ( SCARD_S_SUCCESS != result) { goto end; } // If La is greater that Le, then the response TPDU is mapped // onto the response APDU by keeping only the first Le bytes // of the body and the status bytes SW1-SW2. if (convertByte(le) < convertByte(la)) { memmove(responseData+offset+convertByte(le), responseData+offset+responseDataLength-2, 2); offset += convertByte(le); break; } // if (convertByte(le) < convertByte(la)) offset += responseDataLength - 2; le = la; continue; } // if (6c) // if (61) || (9f) if ((responseData[responseDataLength + offset - 2] == 0x61) || (responseData[responseDataLength + offset - 2] == 0x9f)) { // Lr < Le // 1. The card sends <0x61,Lr> completion status bytes // 2. The CAD sends GET RESPONSE command with Le = Lr. // 3. The card sends Lr bytes of output data using the standard T=0 <INS> or <~INS> // procedure byte mechanism. // 4. The card sends <SW1,SW2> completion status on completion of the // Applet.process method. // Lr > Le // 1. The card sends Le bytes of output data using the standard T=0 <INS> or // <~INS> procedure byte mechanism. // 2. The card sends <0x61,(Lr-Le)> completion status bytes // 3. The CAD sends GET RESPONSE command with new Le <= Lr. // 4. The card sends (new) Le bytes of output data using the standard T=0 <INS> or // <~INS> procedure byte mechanism. // 5. Repeat steps 2-4 as necessary to send the remaining output data bytes (Lr) as // required. // 6. The card sends <SW1,SW2> completion status on completion of the // Applet.process method. la = responseData[responseDataLength + offset - 1]; apduCommand[0] = 0x00; apduCommand[1] = 0xC0; // INS (Get Response) apduCommand[2] = 0x00; // P1 apduCommand[3] = 0x00; // P2 apduCommand[4] = la; apduCommandLength = 5; le = la; // T=0 transmition (command w/ La) responseDataLength = *rapduLength - offset; result = SCardTransmit(cardInfo.cardHandle, SCARD_PCI_T0, apduCommand, apduCommandLength, NULL, responseData+offset, &responseDataLength ); if ( SCARD_S_SUCCESS != result) { goto end; } offset += responseDataLength - 2; continue; } // if (61) || (9f) } // while (61) || (6c) || (9f) break; } // case 4 } // switch (main switch block for cases 2 and 4) } // if (if T=1 or else T=0) // if the case 3 command is actually a case 4 command and the cards wants to responds something. if (responseData[responseDataLength + offset - 2] == 0x61) { la = responseData[responseDataLength + offset - 1]; apduCommand[0] = 0x00;; apduCommand[1] = 0xC0; // INS (Get Response) apduCommand[2] = 0x00; // P1 apduCommand[3] = 0x00; // P2 apduCommand[4] = la; apduCommandLength = 5; le = la; // T=0 transmition (command w/ La) responseDataLength = *rapduLength - offset; result = SCardTransmit(cardInfo.cardHandle, cardInfo.protocol == OPGP_CARD_PROTOCOL_T0 ? SCARD_PCI_T0 : SCARD_PCI_T1, apduCommand, apduCommandLength, NULL, responseData+offset, &responseDataLength ); if ( SCARD_S_SUCCESS != result) { goto end; } // if ( SCARD_S_SUCCESS != result) offset += responseDataLength - 2; } // if (61) memcpy(rapdu, responseData, offset + 2); *rapduLength = offset + 2; if (traceEnable) { _ftprintf(traceFile, _T("<-- ")); for (i=0; i<*rapduLength; i++) { _ftprintf(traceFile, _T("%02X"), rapdu[i]); } _ftprintf(traceFile, _T("\n")); } if (rapdu[*rapduLength-2] != 0x90 || rapdu[*rapduLength-1] != 0x00) { result = (OPGP_ISO7816_ERROR_PREFIX | (rapdu[*rapduLength-2] << 8)) | rapdu[*rapduLength-1]; goto end; } { result = OPGP_ERROR_SUCCESS; goto end; } end: if (responseData) free(responseData); LOG_END(_T("send_APDU"), result); return result; } > > Tripp > > _______________________________________________ Muscle mailing list > [email protected] > http://lists.drizzle.com/mailman/listinfo/muscle _______________________________________________ Muscle mailing list [email protected] http://lists.drizzle.com/mailman/listinfo/muscle _______________________________________________ Muscle mailing list [email protected] http://lists.drizzle.com/mailman/listinfo/muscle
