Example #1
0
        private ResponseApdu RetransmitOnInsufficientBuffer(CommandApdu commandApdu, ResponseApdu responseApdu,
                                                            out SCardPCI receivePci)
        {
            int receiveBufferLength;
            var resendCmdApdu = (CommandApdu)commandApdu.Clone();

            if (responseApdu.SW2 == 0)
            {
                resendCmdApdu.Le    = 0;       // 256
                receiveBufferLength = 256 + 2; // 2 bytes for status word
            }
            else
            {
                resendCmdApdu.Le    = responseApdu.SW2;
                receiveBufferLength = responseApdu.SW2 + 2; // 2 bytes for status word
            }

            var receiveBuffer = new byte[receiveBufferLength];

            receivePci = new SCardPCI();

            try {
                var sendBuffer = resendCmdApdu.ToArray();

                // Shall we wait until we re-send we APDU/TPDU?
                if (RetransmitWaitTime > 0)
                {
                    Thread.Sleep(RetransmitWaitTime);
                }

                // send Command APDU again with new Le value
                return(SimpleTransmit(
                           sendBuffer,
                           sendBuffer.Length,
                           resendCmdApdu.Case,
                           resendCmdApdu.Protocol,
                           receivePci,
                           receiveBuffer,
                           receiveBufferLength));
            } catch (WinErrorInsufficientBufferException ex) {
                throw new InvalidApduException(
                          $"Retransmission failed because of unsufficient buffer. Le={resendCmdApdu.Le}", ex);
            } catch (InvalidOperationException ex) {
                throw new InvalidApduException(
                          $"Got SW1={responseApdu.SW1:X}. Retransmission failed because of an invalid APDU.",
                          resendCmdApdu, ex);
            }
        }
Example #2
0
        public virtual Response Transmit(CommandApdu cmdApdu)
        {
            if (cmdApdu == null)
                throw new ArgumentNullException("cmdApdu");

            // prepare send buffer (Check Command APDU and convert it to an byte array)
            byte[] sendbuf;
            try
            {
                sendbuf = cmdApdu.ToArray();
            }
            catch (InvalidOperationException ex)
            {
                throw new InvalidApduException("Invalid APDU.", cmdApdu, ex);
            }
            catch (Exception ex)
            {
                throw ex;
            }

            // create Response object
            Response resp = new Response();

            // prepare receive buffer (Response APDU)
            byte[] recvbuf = null;
            int recvbuflen = cmdApdu.ExpectedResponseLength; // expected size that shall be returned
            recvbuf = new byte[recvbuflen];

            ResponseApdu respApdu = null;
            SCardPCI recvPci = new SCardPCI();

            respApdu = _SimpleTransmit(
                sendbuf,
                sendbuf.Length,
                cmdApdu.Case,       // ISO case used by the Command APDU
                cmdApdu.Protocol,   // Protocol used by the Command APDU
                recvPci,
                ref recvbuf,
                ref recvbuflen);

            /* Check status word SW1SW2:
             *
             * 1. 0x6cxx -> Set response buffer size Le <- SW2
             * 2. AND/OR 0x61xx -> More data can be read with GET RESPONSE
             */

            // Case 1: SW1=0x6c, Previous Le/P3 not accepted -> Set le = SW2
            if (respApdu.SW1 == (byte)SW1Code.ErrorP3Incorrect)
            {
                CommandApdu resendCmdApdu = (CommandApdu)cmdApdu.Clone();
                if (respApdu.SW2 == 0)
                {
                    resendCmdApdu.Le = 0; // 256
                    recvbuflen = 256 + 2;           // 2 bytes for status word
                }
                else
                {
                    resendCmdApdu.Le = respApdu.SW2;
                    recvbuflen = respApdu.SW2 + 2;  // 2 bytes for status word
                }

                recvbuf = new byte[recvbuflen];
                recvPci = new SCardPCI();

                try
                {
                    sendbuf = resendCmdApdu.ToArray();

                    // Shall we wait until we re-send we APDU/TPDU?
                    if (_retransmitWaitTime > 0)
                        Thread.Sleep(_retransmitWaitTime);

                    // send Command APDU again with new Le value
                    respApdu = _SimpleTransmit(
                        sendbuf,
                        sendbuf.Length,
                        resendCmdApdu.Case,
                        resendCmdApdu.Protocol,
                        recvPci,
                        ref recvbuf,
                        ref recvbuflen);
                }
                catch (InvalidOperationException ex)
                {
                    throw new InvalidApduException("Got SW1=0x6c. Retransmission failed because of an invalid APDU.", resendCmdApdu, ex);
                }
            }

            // Case 2: SW1=0x61, More data available -> GET RESPONSE
            if (respApdu.SW1 == (byte)SW1Code.NormalDataResponse)
            {
                /* The transmission system shall issue a GET RESPONSE command APDU (or TPDU)
                 * to the card by assigning the minimum of SW2 and Le to parameter Le (or P3)).
                 * Le = min(Le,SW2)
                 */
                int _le = (cmdApdu.Le < respApdu.SW2) ? cmdApdu.Le : respApdu.SW2;

                do
                {
                    // add the last ResponseAPDU to the Response object
                    resp.AddResponseApdu(respApdu);
                    resp.AddRecvPci(recvPci);

                    CommandApdu getResponseApdu = _constructGetResponseApdu(ref _le);

                    if (_le == 0)
                        recvbuflen = 256 + 2; // 2 bytes for status word
                    else
                        recvbuflen = _le + 2; // 2 bytes for status word

                    recvbuf = new byte[recvbuflen];

                    try
                    {
                        sendbuf = getResponseApdu.ToArray();

                        // Shall we wait until we re-send we APDU/TPDU?
                        if (_retransmitWaitTime > 0)
                            Thread.Sleep(_retransmitWaitTime);

                        // send Command APDU again with new Le value
                        respApdu = _SimpleTransmit(
                            sendbuf,
                            sendbuf.Length,
                            getResponseApdu.Case,
                            getResponseApdu.Protocol,
                            recvPci,
                            ref recvbuf,
                            ref recvbuflen);
                    }
                    catch (InvalidOperationException ex)
                    {
                        throw new InvalidApduException("Got SW1=0x61. Retransmission failed because of an invalid GET RESPONSE APDU.", getResponseApdu, ex);
                    }

                    // In case there is more data available.
                    _le = respApdu.SW2;
                } while (
                    // More data available.
                    respApdu.SW1 == (byte)SW1Code.NormalDataResponse

                    ||

                    // Warning condition: data may be corrupted. Iso7816-4 7.1.5
                    (respApdu.SW1 == (byte)SW1Code.WarningNVDataNotChanged &&
                     respApdu.SW2 == (byte)0x81)
                    );
            }

            resp.AddResponseApdu(respApdu);
            resp.AddRecvPci(recvPci);

            return resp;
        }
Example #3
0
        /// <summary>Transmits the specified command APDU.</summary>
        /// <param name="commandApdu">The command APDU.</param>
        /// <returns>A response containing one ore more <see cref="ResponseApdu" />.</returns>
        public virtual Response Transmit(CommandApdu commandApdu)
        {
            if (commandApdu == null)
            {
                throw new ArgumentNullException("commandApdu");
            }

            // prepare send buffer (Check Command APDU and convert it to an byte array)
            byte[] sendBuffer;
            try {
                sendBuffer = commandApdu.ToArray();
            } catch (InvalidOperationException exception) {
                throw new InvalidApduException("Invalid APDU.", commandApdu, exception);
            }

            // create Response object
            var response = new Response();

            // prepare receive buffer (Response APDU)
            var receiveBufferLength = commandApdu.ExpectedResponseLength; // expected size that shall be returned
            var receiveBuffer       = new byte[receiveBufferLength];

            var receivePci = new SCardPCI();

            var responseApdu = SimpleTransmit(
                sendBuffer,
                sendBuffer.Length,
                commandApdu.Case,     // ISO case used by the Command APDU
                commandApdu.Protocol, // Protocol used by the Command APDU
                receivePci,
                ref receiveBuffer,
                ref receiveBufferLength);

            /* Check status word SW1SW2:
             *
             * 1. 0x6cxx -> Set response buffer size Le <- SW2
             * 2. AND/OR 0x61xx -> More data can be read with GET RESPONSE
             */

            if (responseApdu.SW1 == (byte)SW1Code.ErrorP3Incorrect)
            {
                // Case 1: SW1=0x6c, Previous Le/P3 not accepted -> Set le = SW2
                var resendCmdApdu = (CommandApdu)commandApdu.Clone();
                if (responseApdu.SW2 == 0)
                {
                    resendCmdApdu.Le    = 0;       // 256
                    receiveBufferLength = 256 + 2; // 2 bytes for status word
                }
                else
                {
                    resendCmdApdu.Le    = responseApdu.SW2;
                    receiveBufferLength = responseApdu.SW2 + 2; // 2 bytes for status word
                }

                receiveBuffer = new byte[receiveBufferLength];
                receivePci    = new SCardPCI();

                try {
                    sendBuffer = resendCmdApdu.ToArray();

                    // Shall we wait until we re-send we APDU/TPDU?
                    if (RetransmitWaitTime > 0)
                    {
                        Thread.Sleep(RetransmitWaitTime);
                    }

                    // send Command APDU again with new Le value
                    responseApdu = SimpleTransmit(
                        sendBuffer,
                        sendBuffer.Length,
                        resendCmdApdu.Case,
                        resendCmdApdu.Protocol,
                        receivePci,
                        ref receiveBuffer,
                        ref receiveBufferLength);
                } catch (InvalidOperationException ex) {
                    throw new InvalidApduException("Got SW1=0x6c. Retransmission failed because of an invalid APDU.",
                                                   resendCmdApdu, ex);
                }
            }

            if (responseApdu.SW1 == (byte)SW1Code.NormalDataResponse)
            {
                // Case 2: SW1=0x61, More data available -> GET RESPONSE

                /* The transmission system shall issue a GET RESPONSE command APDU (or TPDU)
                 * to the card by assigning the minimum of SW2 and Le to parameter Le (or P3)).
                 * Le = min(Le,SW2)
                 */
                var le = (commandApdu.Le < responseApdu.SW2)
                    ? commandApdu.Le
                    : responseApdu.SW2;

                do
                {
                    // add the last ResponseAPDU to the Response object
                    response.Add(responseApdu);
                    response.Add(receivePci);

                    var getResponseApdu = ConstructGetResponseApdu(ref le);

                    if (le == 0)
                    {
                        receiveBufferLength = 256 + 2; // 2 bytes for status word
                    }
                    else
                    {
                        receiveBufferLength = le + 2; // 2 bytes for status word
                    }

                    receiveBuffer = new byte[receiveBufferLength];

                    try {
                        sendBuffer = getResponseApdu.ToArray();

                        // Shall we wait until we re-send we APDU/TPDU?
                        if (RetransmitWaitTime > 0)
                        {
                            Thread.Sleep(RetransmitWaitTime);
                        }

                        // send Command APDU again with new Le value
                        responseApdu = SimpleTransmit(
                            sendBuffer,
                            sendBuffer.Length,
                            getResponseApdu.Case,
                            getResponseApdu.Protocol,
                            receivePci,
                            ref receiveBuffer,
                            ref receiveBufferLength);
                    } catch (InvalidOperationException ex) {
                        throw new InvalidApduException(
                                  "Got SW1=0x61. Retransmission failed because of an invalid GET RESPONSE APDU.",
                                  getResponseApdu, ex);
                    }

                    // In case there is more data available.
                    le = responseApdu.SW2;
                } while (
                    // More data available.
                    responseApdu.SW1 == (byte)SW1Code.NormalDataResponse ||
                    // Warning condition: data may be corrupted. Iso7816-4 7.1.5
                    (responseApdu.SW1 == (byte)SW1Code.WarningNVDataNotChanged && responseApdu.SW2 == 0x81));
            }

            response.Add(responseApdu);
            response.Add(receivePci);

            return(response);
        }