/// <summary> /// Process DELETE FILE instruction (E4) /// <para> /// C-APDU: <code>00 E4 00 00 02 {fid}</code> /// </para> /// </summary> /// <param name="apdu"></param> /// <returns></returns> private IFakeCardFeedback ProcessDeleteFile(CommandAPDU apdu) { byte[] buffer = apdu.GetBuffer(); _ = apdu.SetIncomingAndReceive(); short udcOffset = APDUHelpers.getOffsetCdata(apdu); short lc = APDUHelpers.getIncomingLength(apdu); if (lc != 2) { ISOException.throwIt(JavaCard.ISO7816.SW_WRONG_P1P2); } short fid = Util.getShort(buffer, udcOffset); if (_currentDF.DeleteFile(fid) == false) { ISOException.throwIt(JavaCard.ISO7816.SW_FILE_NOT_FOUND); } if (_currentEF != null && fid == _currentEF.GetFileId()) { _currentEF = null; } return(apdu.SetOutgoingAndSend(0, 0)); }
/// <summary> /// Process the GET CHALLENGE of an EMV transaction. /// </summary> /// <returns>Last status word.</returns> public UInt16 GetChallenge() { BeforeGetChallengeEvent.Raise(this, new EmvEventArgs()); // Clear previous challenge _iccChallenge = null; // Execute GET CHALLENGE var cAPDU = new CommandAPDU(0x00, 0x84, 0x00, 0x00, 0); var crp = new CommandResponsePair(cAPDU); crp.Transmit(_cardChannel); _lastStatusWord = crp.RApdu.StatusWord; // If GET RESPONSE needed, do it if (crp.RApdu.Sw1 == 0x61) { crp = new CommandResponsePair(new GetResponseCommand(crp.RApdu.Sw2)); _lastStatusWord = crp.RApdu.StatusWord; } // Finally, store result if (crp.RApdu.StatusWord == 0x9000) { _iccChallenge = crp.RApdu.Udr; } AfterGetChallengeEvent.Raise(this, new EmvEventArgs()); return(_lastStatusWord); }
/// <summary> /// Process the VERIFY PIN phase of an EMV transaction. /// </summary> /// <param name="pinBlock">PIN Block.</param> /// <returns>Last status word.</returns> public UInt16 VerifyPin(PINBlock pinBlock) { BeforeVerifyPinEvent.Raise(this, new EmvEventArgs()); byte p2 = 0x00; if (pinBlock is PlaintextPINBlock) { p2 = 0x80; } // Execute the VERIFY instruction var cAPDU = new CommandAPDU(0x00, 0x20, 0x00, p2, (UInt32)pinBlock.PinBlock.Length, pinBlock.PinBlock); var crp = new CommandResponsePair(cAPDU); crp.Transmit(_cardChannel); _lastStatusWord = crp.RApdu.StatusWord; _verifyPinStatusWord = _lastStatusWord; if (_lastStatusWord != 0x9000) { Tvr.CardholderVerificationFailed = true; } AfterVerifyPinEvent.Raise(this, new EmvEventArgs()); return(_lastStatusWord); }
/// <inheritdoc /> public IFakeCardFeedback ExecuteCommand(CommandAPDU cApdu) { if (cApdu.BinaryCommand.Length < 5) { return(FakeCardFeedback.FromError(ErrorCode.CommDataLost)); } if (cApdu.IsCc2 && cApdu.Cla == 0x00 && cApdu.Ins == 0xC0) { return(ProcessGetResponse(cApdu)); } ClearUdrToBeRetrieved(); IFakeCardFeedback response; try { response = _fakeCard.ExecuteCommand(cApdu); } catch (ISOException isoException) { return(FakeCardFeedback.FromSuccess(isoException.getReason())); } if (response.RApdu.Udr.Length == 0 || cApdu.IsCc2) { return(response); } StoreUdrToBeRetrieved(response.RApdu.Udr, cApdu.Ins); return(FakeCardFeedback.FromSuccess((short)response.RApdu.StatusWord)); }
/// <summary> /// Process ERASE instruction (CC3) /// <para> /// C-APDU: <code>00 0E {offset} {Lc} {length} </code> /// </para> /// <list type="table"> /// <item> /// <term>offset</term> /// <description>offset of first word of the file coded by P1 P2 (WORDS) to be erased.</description> /// </item> /// <item> /// <term>length</term> /// <description>number of words to be erased.</description> /// </item> /// </list> /// </summary> /// <param name="apdu"></param> /// <returns></returns> private IFakeCardFeedback ProcessErase(CommandAPDU apdu) { // TODO: check ==> security of current EF byte[] apduBuffer = apdu.GetBuffer(); apdu.SetIncomingAndReceive(); // Check if Lc ==2 short lc = APDUHelpers.getIncomingLength(apdu); if (lc != 2) { ISOException.throwIt(JavaCard.ISO7816.SW_WRONG_LENGTH); } short offset = Util.getShort(apduBuffer, JavaCard.ISO7816.OFFSET_P1); // in WORDS short udcOffset = APDUHelpers.getOffsetCdata(apdu); short length = Util.getShort(apduBuffer, udcOffset); // in WORDS VerifyOutOfFile(offset, length); _currentEF.Erase(offset, length); return(FakeCardFeedback.FromSuccess(unchecked ((short)0x9000))); }
private void TransmitToCard(CommandAPDU command) { try { var crp = new CommandResponsePair(command); var errorCode = crp.Transmit(SharedData.CardChannel); if (errorCode != ErrorCode.Success) { LogFailure($"ErrorCode={errorCode}"); } else if (crp.RApdu.StatusWord != 0x9000) { LogFailure($"SW={crp.RApdu.StatusWord:X4}"); } else { LogSuccess(); } } catch (Exception exception) { LogException(exception); } }
private static void ExecuteCrpFSearch(short offset) { PrintHeader($"FSEARCH @{offset:X4}"); var cApdu = new CommandAPDU($"00A0{offset:X4}00"); ExecuteCrp(cApdu); }
private static void ExecuteCrpErase(short offset, short length) { PrintHeader($"ERASE {length:X4} word(s) @{offset:X4}"); var cApdu = new CommandAPDU($"000E{offset:X4}02{length:X4}"); ExecuteCrp(cApdu); }
private static void ExecuteCrpGenerateRandom() { PrintHeader("GENERATE RANDOM"); var cApdu = new CommandAPDU(0x00, 0xC4, 0x00, 0x00, 0x08); ExecuteCrp(cApdu); }
private static void ExecuteCrpGetResponse(byte le) { PrintHeader($"GET RESPONSE {le:X4} bytes"); var cApdu = new CommandAPDU($"00C00000{le:X2}"); ExecuteCrp(cApdu); }
private static void ExecuteCrpRead(short offset, byte le) { PrintHeader($"READ {le:X2} word(s) @{offset:X4}"); var cApdu = new CommandAPDU($"00B0{offset:X4}{le:X2}"); ExecuteCrp(cApdu); }
/// <summary> /// MasterCard cAPDU. /// Process the COMPUTE CRYPTOGRAPHIC CHECKSUM phase of a MasterCard transaction. /// </summary> /// <returns>Last status word.</returns> public UInt16 ComputeCryptographicChecksum() { BeforeComputeCryptographicChecksumEvent.Raise(this, new EmvEventArgs()); // If UDOL 9F69 is not supplied in records, then use default UDOL = 9F6A04 byte[] udolDataValue = null; var tlvAll = new List <TlvData>(); foreach (var record in _tlvRecords) { tlvAll.Add(record); if (record.HasTag(0x9F69)) { var udol = new DataObjectList(record.GetTag(0x9F69).Value); tlvAll.AddRange(TlvTerminalData); udolDataValue = udol.BuildData(tlvAll); } } if (udolDataValue == null) { var tmp = ""; var seed = new Random(10000).Next(); var rndNumbers = new Random(seed); for (var i = 0; i < 8; i++) { var rndNumber = rndNumbers.Next(10); tmp += rndNumber.ToString(CultureInfo.InvariantCulture); } udolDataValue = tmp.FromHexa(); } // Execute COMPUTE CRYPTOGRAPHIC CHECKSUM var cAPDU = new CommandAPDU(0x80, 0x2A, 0x8E, 0x80, (uint)udolDataValue.Length, udolDataValue, 0); var crp = new CommandResponsePair(cAPDU); crp.Transmit(_cardChannel); _lastStatusWord = crp.RApdu.StatusWord; // If GET RESPONSE needed, do it if (crp.RApdu.Sw1 == 0x61) { _tlvCryptographicChecksum = new TlvData(); crp = new CommandResponsePair(new GetResponseCommand(crp.RApdu.Sw2)); crp.Transmit(_cardChannel); _lastStatusWord = crp.RApdu.StatusWord; } // Finally, store result if (crp.RApdu.StatusWord == 0x9000) { _tlvCryptographicChecksum = new TlvData(crp.RApdu.Udr); } AfterComputeCryptographicChecksumEvent.Raise(this, new EmvEventArgs()); return(_lastStatusWord); }
private static void ExecuteCrpCreateFile(string fileIdentifier, string fileControlInformation) { PrintHeader($"CREATE FILE {fileIdentifier}"); var lc = $"{(fileIdentifier.Length + fileControlInformation.Length) / 2:X2}"; var cApdu = new CommandAPDU($"00E00040{lc}{fileIdentifier}{fileControlInformation}"); ExecuteCrp(cApdu); }
private static void ExecuteCrpDeleteFile(string fileIdentifier) { PrintHeader($"DELETE FILE {fileIdentifier}"); var lc = $"{fileIdentifier.Length / 2:X2}"; var cApdu = new CommandAPDU($"00E40040{lc}{fileIdentifier}"); ExecuteCrp(cApdu); }
private void selectApplet() { myReader = new Reader(); myReader.Connect(read); apdu = new CommandAPDU(0x00, 0xA4, 0x04, 0x00, AID, (byte)AID.Length); resApdu = myReader.Transmit(apdu); reponse_texBox.AppendText(resApdu.SW1.ToString("X2") + resApdu.SW2.ToString("X2")); }
private static void ExecuteCrpWrite(short offset, string udc) { var lc = udc.Length / 2; PrintHeader($"WRITE {lc:X2} word(s) @{offset:X4}"); var cApdu = new CommandAPDU($"00D0{offset:X4}{lc:X2}{udc}"); ExecuteCrp(cApdu); }
public void GenerateRandomWithWrongLeShouldFail(int le) { var fakeCard = CreateFakeCard(); var generateRandomApdu = new CommandAPDU($"00 C4 00 00 {le:X2}"); var feedbackToGenerateRandom = fakeCard.ExecuteCommand(generateRandomApdu); Assert.AreEqual(ErrorCode.Success, feedbackToGenerateRandom.ErrorCode); Assert.AreEqual(0x6700, feedbackToGenerateRandom.RApdu.StatusWord); Assert.AreEqual(0, feedbackToGenerateRandom.RApdu.Udr.Length); }
private ResponseAPDU Transmit(CommandAPDU commandAdpu, int bufferSize) { if (commandAdpu == null) { throw new ArgumentNullException(nameof(commandAdpu)); } var result = _connection.Transmit(commandAdpu.Adpu, bufferSize); return(new ResponseAPDU(result)); }
private ResponseAPDU SendCommand(BeIDCommandAPDU command, int p1, int p2, int le) { if (command == null) { throw new ArgumentNullException(nameof(command)); } var commandAdpu = new CommandAPDU(command.Cla, command.Ins, p1, p2, le); return(Transmit(commandAdpu, BUFFER_SIZE)); }
public void GenerateRandomWithRightLeShouldSucceed() { var fakeCard = CreateFakeCard(); var generateRandomApdu = new CommandAPDU($"00 C4 00 00 08"); var feedbackToGenerateRandom = fakeCard.ExecuteCommand(generateRandomApdu); Assert.AreEqual(ErrorCode.Success, feedbackToGenerateRandom.ErrorCode); Assert.AreEqual(0x9000, feedbackToGenerateRandom.RApdu.StatusWord); Assert.AreEqual(8, feedbackToGenerateRandom.RApdu.Udr.Length); }
/// <summary> /// Process SELECT instruction (CC4). /// <para> /// C-APDU: <code>00 A4 00 00 02 {FID} {Le}</code> /// </para> /// <para> /// R-APDU: <code>{offset} {size} {header}</code> /// </para> /// <list type="table"> /// <item> /// <term>offset</term> /// <description>offset of first word of the file, 2 bytes (WORDS).</description> /// </item> /// <item> /// <term>size</term> /// <description>size of the body of the file (WORDS).</description> /// </item> /// </list> /// </summary> /// <param name="apdu"></param> /// <returns></returns> private IFakeCardFeedback ProcessSelect(CommandAPDU apdu) { byte[] buffer = apdu.GetBuffer(); apdu.SetIncomingAndReceive(); short udcOffset = APDUHelpers.getOffsetCdata(apdu); short lc = (short)apdu.Lc; if (lc != 2) { ISOException.throwIt(JavaCard.ISO7816.SW_WRONG_LENGTH); } short fid = Util.getShort(buffer, udcOffset); File file; if (fid == 0x3F00) { file = _masterFile; } else { file = _currentDF.FindFileByFileId(fid); } if (file == null) { ISOException.throwIt(JavaCard.ISO7816.SW_FILE_NOT_FOUND); } // Update current DF / EF if (file.IsDF()) { _currentDF = (DedicatedFile)file; _currentEF = null; } else { _currentEF = (ElementaryFile)file; } // Build and send R-APDU short headerSize = file.GetHeaderSize(); Util.setShort(buffer, 0, (short)(file._inParentBodyOffset >> 2)); Util.setShort(buffer, 2, (short)(file.GetLength() - headerSize)); file.GetHeader(buffer, 4); // TODO Automagically adds 9000 return(apdu.SetOutgoingAndSend(0, (short)(4 + (headerSize << 2)))); }
/// <summary> /// Process the INTERNAL AUTHENTICATION of an EMV transaction. /// </summary> /// <param name="unpredictableNumber">Unpredictable number.</param> /// <returns>Last status word.</returns> public UInt16 InternalAuthenticate(byte[] unpredictableNumber) { BeforeInternalAuthenticateEvent.Raise(this, new EmvEventArgs()); _tlvInternalAuthenticateUnpredictableNumber = new TlvData(0x9F37, 0x04, unpredictableNumber); // Build DDOL data byte[] ddolDataValue; if (Ddol != null) { // Use DDOL to build data var tlvAll = new List <TlvData> { TlvFci, TlvProcessingOptions, _tlvInternalAuthenticateUnpredictableNumber }; tlvAll.AddRange(TlvRecords); tlvAll.AddRange(TlvTerminalData); ddolDataValue = Ddol.BuildData(tlvAll); } else { ddolDataValue = new byte[0]; } // Execute GET PROCESSING OPTIONS var cAPDU = new CommandAPDU(0x00, 0x88, 0x00, 0x00, (uint)ddolDataValue.Length, ddolDataValue, 0); var crp = new CommandResponsePair(cAPDU); crp.Transmit(_cardChannel); _lastStatusWord = crp.RApdu.StatusWord; // If GET RESPONSE needed, do it if (crp.RApdu.Sw1 == 0x61) { _tlvSignedDynamicApplicationResponse = new TlvData(); crp = new CommandResponsePair(new GetResponseCommand(crp.RApdu.Sw2)); crp.Transmit(_cardChannel); _lastStatusWord = crp.RApdu.StatusWord; } // Finally, store result if (crp.RApdu.StatusWord == 0x9000) { _tlvSignedDynamicApplicationResponse = new TlvData(crp.RApdu.Udr); } AfterInternalAuthenticateEvent.Raise(this, new EmvEventArgs()); return(_lastStatusWord); }
/// <summary> /// process a GET RESPONSE command after a successful FSEARCH. /// </summary> /// <param name="cApdu"></param> /// <returns></returns> private IFakeCardFeedback ProcessGetResponseAfterFSearch(CommandAPDU cApdu) { if (cApdu.Le != 0x08) { return(FakeCardFeedback.FromSuccess(JavaCard.ISO7816.SW_WRONG_LENGTH)); } var rApduBytes = GetRApduBytesWithRetrievedUdr((short)cApdu.Le); ClearUdrToBeRetrieved(); return(FakeCardFeedback.FromSuccess(rApduBytes)); }
/// <summary> /// Process the GET PROCESSING OPTIONS phase of an EMV transaction. /// </summary> /// <returns>Last status word.</returns> public UInt16 GetProcessingOptions() { BeforeGetProcessingOptionsEvent.Raise(this, new EmvEventArgs()); // If PDOL 9F38 is not supplied in FCI, then used 8300 as UDC; if supplied: build the PDOL in tag 83 L V byte[] pdolDataValue; if (TlvFci.HasTag(0x9F38)) { // Use PDOL to build tag 83 value var pdol = new DataObjectList(TlvFci.GetTag(0x9F38).Value); var tlvAll = new List <TlvData> { TlvFci }; tlvAll.AddRange(TlvTerminalData); pdolDataValue = pdol.BuildData(tlvAll); } else { pdolDataValue = new byte[0]; } // Build tag 83 with computed value var tlvPdolData = new TlvData(0x83, (uint)pdolDataValue.Length, pdolDataValue); // Execute GET PROCESSING OPTIONS var cAPDU = new CommandAPDU(0x80, 0xA8, 0x00, 0x00, tlvPdolData.Length + 2, tlvPdolData.ToByteArray(), 0); var crp = new CommandResponsePair(cAPDU); crp.Transmit(_cardChannel); _lastStatusWord = crp.RApdu.StatusWord; // If GET RESPONSE needed, do it if (crp.RApdu.Sw1 == 0x61) { _tlvProcessingOptions = new TlvData(); crp = new CommandResponsePair(new GetResponseCommand(crp.RApdu.Sw2)); crp.Transmit(_cardChannel); _lastStatusWord = crp.RApdu.StatusWord; } // Finally, store result if (crp.RApdu.StatusWord == 0x9000) { _tlvProcessingOptions = new TlvData(crp.RApdu.Udr); } AfterGetProcessingOptionsEvent.Raise(this, new EmvEventArgs()); return(_lastStatusWord); }
public void ReadMFShouldSucceed() { var fakeCard = CreateFakeCard(); var readApdu = new CommandAPDU("00 B0 00 00 40"); var feedbackToRead = fakeCard.ExecuteCommand(readApdu); Assert.AreEqual(ErrorCode.Success, feedbackToRead.ErrorCode); Assert.AreEqual(0x9000, feedbackToRead.RApdu.StatusWord); var filler = new byte[0x40 - 24]; Array.Fill(filler, (byte)0xFF); Assert.AreEqual($"17 FF 06 E4 1F 6C 05 70 0E 2F F5 CE 0E 10 03 DF 7F 00 00 22 FF FF FE 62 {filler.ToHexa()}", feedbackToRead.RApdu.Udr.ToHexa()); }
/// <summary> /// Process FSEARCH instruction (CC2). /// <para> /// C-APDU: <code>00 B0 {P1-P2: offset} 04</code> /// </para> /// <para> /// R-APDU when an EF is selected: <code>{offset} {number of word in current EF} {looked-up word}</code> /// </para> /// <para> /// R-APDU when no EF is selected: <code>{offset} {number of word in current DF} {looked-up word}</code> /// </para> /// </summary> /// <param name="apdu"></param> /// <returns></returns> private IFakeCardFeedback ProcessFSearch(CommandAPDU apdu) { // get offset byte[] buffer = apdu.GetBuffer(); short offset = Util.getShort(buffer, JavaCard.ISO7816.OFFSET_P1); // in WORDS // get le short le = apdu.SetOutgoing(); // in BYTES if (le != 0) { ISOException.throwIt(JavaCard.ISO7816.SW_WRONG_LENGTH); } short wordCount; short offsetFound = offset; // check that there is a current EF if (_currentEF != null) { wordCount = (short)(_currentEF.GetLength() - _currentEF.GetHeaderSize()); while (!(_currentEF.IsAvailable(offsetFound, 1) || offsetFound == wordCount)) { offsetFound++; } } else { wordCount = (short)(_currentDF.GetLength() - _currentDF.GetHeaderSize()); while (!(_currentDF.IsAvailable(offsetFound, 1) || offsetFound == wordCount)) { offsetFound++; } } // check that there is still some empty space if (offsetFound == wordCount) { ISOException.throwIt(Constants.SW_DATA_NOT_FOUND); } // copy answer in buffer Util.setShort(buffer, 0, offsetFound); Util.setShort(buffer, 2, wordCount); Util.arrayFillNonAtomic(buffer, 4, 4, (byte)MemoryState.Free); // and send it! return(apdu.SetOutgoingAndSend(0, 8)); }
private ResponseAPDU SendCommand(BeIDCommandAPDU command, byte[] data) { if (command == null) { throw new ArgumentNullException(nameof(command)); } if (data == null) { throw new ArgumentNullException(nameof(data)); } var commandAdpu = new CommandAPDU(command.Cla, command.Ins, command.P1, command.P2, data); return(Transmit(commandAdpu, BUFFER_SIZE)); }
/// <summary> /// Process CREATE FILE instruction (E0) /// <para> /// C-APDU: <code>00 E0 {offset} {Lc} {header}</code> /// </para> /// <list type="table"> /// <item> /// <term>offset</term> /// <description>offset of first word of the file coded by P1 P2 (WORDS).</description> /// </item> /// <item> /// <term>header</term> /// <description>header of the new file, must be word aligned.</description> /// </item> /// </list> /// </summary> /// <param name="apdu"></param> /// <returns></returns> private IFakeCardFeedback ProcessCreateFile(CommandAPDU apdu) { byte[] buffer = apdu.GetBuffer(); apdu.SetIncomingAndReceive(); short headerOffset = APDUHelpers.getOffsetCdata(apdu); short headerLength = APDUHelpers.getIncomingLength(apdu); if (headerLength < 4) { ISOException.throwIt(JavaCard.ISO7816.SW_DATA_INVALID); } short offset = Util.getShort(buffer, JavaCard.ISO7816.OFFSET_P1); if (!_headerParser.Parse(buffer, headerOffset, (short)(headerOffset + headerLength))) { ISOException.throwIt(JavaCard.ISO7816.SW_DATA_INVALID); } short size = (short)(_headerParser.bodyLength + (short)(_headerParser.headerLength >> 2)); File file = null; switch (_headerParser.fileType) { case HeaderParser.FILETYPE_DF: file = _currentDF.CreateDedicatedFile(offset, size, buffer, headerOffset, headerLength); break; case HeaderParser.FILETYPE_EFSZ: case HeaderParser.FILETYPE_EFWZ: file = _currentDF.CreateElementaryFile(offset, size, buffer, headerOffset, headerLength); break; default: ISOException.throwIt(JavaCard.ISO7816.SW_CONDITIONS_NOT_SATISFIED); break; } if (file == null) { ISOException.throwIt(JavaCard.ISO7816.SW_DATA_INVALID); } return(apdu.SetOutgoingAndSend(0, 0)); }
public void FSearchInMasterFileShouldFindFreeWordAt0035(int searchOffset, string expectedFoundOffset) { var fakeCard = CreateFakeCard(); var fSearchApdu = new CommandAPDU($"00 A0 {searchOffset:X4} 00"); var feedbackToFSearch = fakeCard.ExecuteCommand(fSearchApdu); Assert.AreEqual(ErrorCode.Success, feedbackToFSearch.ErrorCode); Assert.AreEqual(0x9000, feedbackToFSearch.RApdu.StatusWord); Assert.AreEqual(0, feedbackToFSearch.RApdu.Udr.Length); var getResponseApdu = new CommandAPDU("00 C0 00 00 08"); var feedbackToGetResponse = fakeCard.ExecuteCommand(getResponseApdu); Assert.AreEqual(ErrorCode.Success, feedbackToGetResponse.ErrorCode); Assert.AreEqual(0x9000, feedbackToGetResponse.RApdu.StatusWord); Assert.AreEqual($"{expectedFoundOffset} 02 9F FF FF FF FF", feedbackToGetResponse.RApdu.Udr.ToHexa()); }
public void SelectMFWithWrongLeShouldFailOnGetResponse(int le) { var fakeCard = CreateFakeCard(); var selectApdu = new CommandAPDU("00 A4 00 00 02 3F 00"); var feedbackToSelect = fakeCard.ExecuteCommand(selectApdu); Assert.AreEqual(ErrorCode.Success, feedbackToSelect.ErrorCode); Assert.AreEqual(0x9000, feedbackToSelect.RApdu.StatusWord); Assert.AreEqual(0, feedbackToSelect.RApdu.Udr.Length); var getResponseApdu = new CommandAPDU($"00 C0 00 00 {le:X2}"); var feedbackToGetResponse = fakeCard.ExecuteCommand(getResponseApdu); Assert.AreEqual(ErrorCode.Success, feedbackToGetResponse.ErrorCode); Assert.AreEqual(0x6700, feedbackToGetResponse.RApdu.StatusWord); Assert.AreEqual(0, feedbackToGetResponse.RApdu.Udr.Length); }