Exemplo n.º 1
0
        /// <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)));
        }
Exemplo n.º 2
0
        /// <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));
        }
Exemplo n.º 3
0
        /// <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))));
        }
Exemplo n.º 4
0
        /// <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));
        }
Exemplo n.º 5
0
        /// <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));
        }
Exemplo n.º 6
0
        /// <summary>
        /// Process GENERATE RANDOM instruction (CC2)
        /// <para>
        /// C-APDU: <code>00 C4 00 00 08</code>
        /// </para>
        /// </summary>
        /// <param name="apdu"></param>
        /// <returns></returns>
        private IFakeCardFeedback ProcessGenerateRandom(CommandAPDU apdu)
        {
            byte[] apduBuffer = apdu.GetBuffer();
            short  le         = apdu.SetOutgoing();

            // verify that Le='08'
            if (le != 8)
            {
                // if not => error
                ISOException.throwIt(JavaCard.ISO7816.SW_WRONG_LENGTH);
            }

            // generate 8 random bytes
            var rndGen = new RNGCryptoServiceProvider();

            rndGen.GetBytes(apduBuffer, 0, 8);
            // and send it!
            return(apdu.SetOutgoingAndSend(0, 8));
        }
Exemplo n.º 7
0
        /// <summary>
        /// Process READ BINARY instruction (CC2)
        /// <para>
        /// C-APDU: <code>00 B0 {P1-P2: offset} {Le}</code>
        /// </para>
        /// <para>
        /// R-APDU when an EF is selected: <code>{data in EF}</code>
        /// </para>
        /// <para>
        /// R-APDU when no EF is selected: <code>{headers of EF in current DF}</code>
        /// </para>
        /// </summary>
        /// <param name="apdu"></param>
        /// <returns></returns>
        private IFakeCardFeedback ProcessRead(CommandAPDU apdu)
        {
            short le        = apdu.SetOutgoing(); // in BYTES
            short wordCount = (short)((short)(le + 3) / 4);

            byte[] buffer = JCSystem.makeTransientByteArray((short)(wordCount * 4), JCSystem.CLEAR_ON_DESELECT);
            short  offset;

            if (_currentEF != null)
            {
                // an EF is selected ==> read binary
                offset = Util.getShort(apdu.GetBuffer(), JavaCard.ISO7816.OFFSET_P1); // in WORDS

                byte[] header = JCSystem.makeTransientByteArray(8, JCSystem.CLEAR_ON_DESELECT);
                _currentEF.GetHeader(header, 0);
                _headerParser.Parse(header, 0, 8);
                offset += (short)(_currentEF.Read(offset, buffer, 0, wordCount, _headerParser.fileType == HeaderParser.FILETYPE_EFSZ) << 2);
            }
            else
            {
                // no EF selected ==> DIR
                offset = 0;
                byte currentChildNumber = 0;
                File fileChild          = _currentDF.GetChild(currentChildNumber);
                // get header of each file in current DF
                while (fileChild != null && offset < le)
                {
                    fileChild.GetHeader(buffer, offset);
                    offset   += (short)(fileChild.GetHeaderSize() << 2);
                    fileChild = _currentDF.GetChild(++currentChildNumber);
                }
            }

            // Pad with FF
            Util.arrayFillNonAtomic(buffer, offset, (short)(le - offset), (byte)MemoryState.Free);

            // and send data!
            apdu.SetOutgoingLength(le);
            return(apdu.SendBytesLong(buffer, 0, le));
        }
Exemplo n.º 8
0
        /// <summary>
        /// Process WRITE BINARY instruction (CC3)
        /// <para>
        /// C-APDU: <code>00 B0 {offset} {Lc} {data} </code>
        /// </para>
        /// <list type="table">
        ///     <item>
        ///         <term>offset</term>
        ///         <description>offset of first word of the file coded by P1 P2 (WORDS) to be written.</description>
        ///     </item>
        ///     <item>
        ///         <term>data</term>
        ///         <description>data to be written in file.</description>
        ///     </item>
        /// </list>
        /// </summary>
        /// <param name="apdu"></param>
        /// <returns></returns>
        private IFakeCardFeedback ProcessWrite(CommandAPDU apdu)
        {
            // TODO: check ==> security of current EF

            byte[] apduBuffer = apdu.GetBuffer();
            apdu.SetIncomingAndReceive();

            short offset    = Util.getShort(apduBuffer, JavaCard.ISO7816.OFFSET_P1); // in WORDS
            short length    = APDUHelpers.getIncomingLength(apdu);                   // in BYTES
            short wordCount = (short)((short)(length + 3) / 4);                      // length in WORDS

            // availability check
            VerifyOutOfFile(offset, wordCount);
            if (!_currentEF.IsAvailable(offset, wordCount))
            {
                ISOException.throwIt(JavaCard.ISO7816.SW_WRONG_LENGTH);
            }

            // copy data in a buffer
            byte[] buffer    = JCSystem.makeTransientByteArray((short)(wordCount * 4), JCSystem.CLEAR_ON_DESELECT);
            short  udcOffset = APDUHelpers.getOffsetCdata(apdu);

            Util.arrayCopyNonAtomic(apduBuffer, udcOffset, buffer, 0, length);

            // complete words with FF in buffer
            short iMax = (short)(wordCount * 4);

            for (short i = length; i < iMax; i++)
            {
                buffer[i] = 0xFF;
            }

            // and write data to file
            _currentEF.Write(buffer, 0, offset, wordCount);

            return(FakeCardFeedback.FromSuccess(unchecked ((short)0x9000)));
        }