Home | History | Annotate | Download | only in cts
      1 /*
      2  * Copyright (C) 2018 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 /* Contributed by Orange */
     18 
     19 package android.omapi.cts;
     20 
     21 import static org.junit.Assert.*;
     22 import static org.junit.Assume.assumeTrue;
     23 
     24 import org.junit.After;
     25 import org.junit.Before;
     26 import org.junit.Test;
     27 
     28 import java.io.IOException;
     29 import java.nio.ByteBuffer;
     30 import java.util.ArrayList;
     31 import java.util.Arrays;
     32 import java.util.NoSuchElementException;
     33 import java.util.Timer;
     34 import java.util.TimerTask;
     35 import java.util.concurrent.Executor;
     36 import java.util.concurrent.TimeoutException;
     37 
     38 import android.content.pm.PackageManager;
     39 import android.se.omapi.Channel;
     40 import android.se.omapi.Reader;
     41 import android.se.omapi.SEService;
     42 import android.se.omapi.SEService.OnConnectedListener;
     43 import android.se.omapi.Session;
     44 import android.support.test.InstrumentationRegistry;
     45 
     46 import com.android.compatibility.common.util.PropertyUtil;
     47 
     48 public class OmapiTest {
     49 
     50     private final static String UICC_READER_PREFIX = "SIM";
     51     private final static String ESE_READER_PREFIX = "eSE";
     52     private final static String SD_READER_PREFIX = "SD";
     53     private final static byte[] SELECTABLE_AID =
     54             new byte[]{(byte) 0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64,
     55                     0x72, 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x31};
     56     private final static byte[] LONG_SELECT_RESPONSE_AID =
     57             new byte[]{(byte) 0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64,
     58                     0x72, 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x32};
     59     private final static byte[] NON_SELECTABLE_AID =
     60             new byte[]{(byte) 0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64,
     61                     0x72, 0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, (byte) 0xFF};
     62 
     63     /* MANAGE open/close and SELECT AID */
     64     private final static byte[][] ILLEGAL_COMMANDS_TRANSMIT = new byte[][]{{0x00, 0x70, 0x00, 0x00},
     65             {0x00, 0x70, (byte) 0x80, 0x00},
     66             {0x00, (byte) 0xA4, 0x04, 0x04, 0x10, 0x4A, 0x53,
     67                     0x52, 0x31, 0x37, 0x37, 0x54, 0x65, 0x73,
     68                     0x74, 0x65, 0x72, 0x20, 0x31, 0x2E, 0x30}
     69     };
     70 
     71     /* OMAPI APDU Test case 1 and 3 */
     72     private final static byte[][] NO_DATA_APDU = new byte[][]{{0x00, 0x06, 0x00, 0x00},
     73             {(byte) 0x80, 0x06, 0x00, 0x00},
     74             {(byte) 0xA0, 0x06, 0x00, 0x00},
     75             {(byte) 0x94, 0x06, 0x00, 0x00},
     76             {0x00, 0x0A, 0x00, 0x00, 0x01, (byte) 0xAA},
     77             {(byte) 0x80, 0x0A, 0x00, 0x00, 0x01, (byte) 0xAA},
     78             {(byte) 0xA0, 0x0A, 0x00, 0x00, 0x01, (byte) 0xAA},
     79             {(byte) 0x94, 0x0A, 0x00, 0x00, 0x01, (byte) 0xAA}
     80     };
     81     /* OMAPI APDU Test case 2 and 4 */
     82     private final static byte[][] DATA_APDU = new byte[][]{{0x00, 0x08, 0x00, 0x00, 0x00},
     83             {(byte) 0x80, 0x08, 0x00, 0x00, 0x00},
     84             {(byte) 0xA0, 0x08, 0x00, 0x00, 0x00},
     85             {(byte) 0x94, 0x08, 0x00, 0x00, 0x00},
     86             {0x00, (byte) 0xC0, 0x00, 0x00, 0x01, (byte) 0xAA, 0x00},
     87             {(byte) 0x80, (byte) 0xC0, 0x00, 0x00, 0x01, (byte) 0xAA, 0x00},
     88             {(byte) 0xA0, (byte) 0xC0, 0x00, 0x00, 0x01, (byte) 0xAA, 0x00},
     89             {(byte) 0x94, (byte) 0xC0, 0x00, 0x00, 0x01, (byte) 0xAA, 0x00}
     90     };
     91 
     92     private final static byte[] CHECK_SELECT_P2_APDU = new byte[]{0x00, (byte) 0xF4, 0x00, 0x00};
     93 
     94     /* OMAPI APDU Test case 1 and 3 */
     95     private final static byte[][] SW_62xx_NO_DATA_APDU =
     96             new byte[][]{{0x00, (byte) 0xF3, 0x00, 0x06},
     97                     {0x00, (byte) 0xF3, 0x00, 0x0A, 0x01, (byte) 0xAA}
     98             };
     99     /* OMAPI APDU Test case 2 and 4 */
    100     private final static byte[] SW_62xx_DATA_APDU = new byte[]{0x00, (byte) 0xF3, 0x00, 0x08, 0x00};
    101     private final static byte[] SW_62xx_VALIDATE_DATA_APDU =
    102             new byte[]{0x00, (byte) 0xF3, 0x00, 0x0C, 0x01, (byte) 0xAA, 0x00};
    103     private final static byte[][] SW_62xx =
    104             new byte[][]{{0x62, 0x00}, {0x62, (byte) 0x81}, {0x62, (byte) 0x82},
    105                     {0x62, (byte) 0x83},
    106                     {0x62, (byte) 0x85}, {0x62, (byte) 0xF1}, {0x62, (byte) 0xF2},
    107                     {0x63, (byte) 0xF1},
    108                     {0x63, (byte) 0xF2}, {0x63, (byte) 0xC2}, {0x62, 0x02}, {0x62, (byte) 0x80},
    109                     {0x62, (byte) 0x84}, {0x62, (byte) 0x86}, {0x63, 0x00}, {0x63, (byte) 0x81}
    110             };
    111     private final static byte[][] SEGMENTED_RESP_APDU = new byte[][]{
    112             //Get response Case2 61FF+61XX with answer length (P1P2) of 0x0800, 2048 bytes
    113             {0x00, (byte) 0xC2, 0x08, 0x00, 0x00},
    114             //Get response Case4 61FF+61XX with answer length (P1P2) of 0x0800, 2048 bytes
    115             {0x00, (byte) 0xC4, 0x08, 0x00, 0x02, 0x12, 0x34, 0x00},
    116             //Get response Case2 6100+61XX with answer length (P1P2) of 0x0800, 2048 bytes
    117             {0x00, (byte) 0xC6, 0x08, 0x00, 0x00},
    118             //Get response Case4 6100+61XX with answer length (P1P2) of 0x0800, 2048 bytes
    119             {0x00, (byte) 0xC8, 0x08, 0x00, 0x02, 0x12, 0x34, 0x00},
    120             //Test device buffer capacity 7FFF data
    121             {0x00, (byte) 0xC2, (byte) 0x7F, (byte) 0xFF, 0x00},
    122             //Get response 6CFF+61XX with answer length (P1P2) of 0x0800, 2048 bytes
    123             {0x00, (byte) 0xCF, 0x08, 0x00, 0x00},
    124             //Get response with another CLA  with answer length (P1P2) of 0x0800, 2048 bytes
    125             {(byte) 0x94, (byte) 0xC2, 0x08, 0x00, 0x00}
    126     };
    127     private final long SERVICE_CONNECTION_TIME_OUT = 3000;
    128     private SEService seService;
    129     private Object serviceMutex = new Object();
    130     private Timer connectionTimer;
    131     private ServiceConnectionTimerTask mTimerTask = new ServiceConnectionTimerTask();
    132     private boolean connected = false;
    133     private final OnConnectedListener mListener = new OnConnectedListener() {
    134                 @Override
    135                 public void onConnected() {
    136                     synchronized (serviceMutex) {
    137                         connected = true;
    138                         serviceMutex.notify();
    139                     }
    140                 }
    141             };
    142 
    143     class SynchronousExecutor implements Executor {
    144         public void execute(Runnable r) {
    145             r.run();
    146         }
    147     }
    148 
    149     private boolean supportsHardware() {
    150         final PackageManager pm = InstrumentationRegistry.getContext().getPackageManager();
    151         boolean lowRamDevice = PropertyUtil.propertyEquals("ro.config.low_ram", "true");
    152         return !lowRamDevice || (lowRamDevice && pm.hasSystemFeature("android.hardware.type.watch"));
    153     }
    154 
    155     private void assertGreaterOrEqual(long greater, long lesser) {
    156         assertTrue("" + greater + " expected to be greater than or equal to " + lesser,
    157                 greater >= lesser);
    158     }
    159 
    160     @Before
    161     public void setUp() throws Exception {
    162         assumeTrue(supportsHardware());
    163         seService = new SEService(InstrumentationRegistry.getContext(), new SynchronousExecutor(), mListener);
    164         connectionTimer = new Timer();
    165         connectionTimer.schedule(mTimerTask, SERVICE_CONNECTION_TIME_OUT);
    166     }
    167 
    168     @After
    169     public void tearDown() throws Exception {
    170         if (seService != null && seService.isConnected()) {
    171             seService.shutdown();
    172             connected = false;
    173         }
    174     }
    175 
    176     private void waitForConnection() throws TimeoutException {
    177         synchronized (serviceMutex) {
    178             if (!connected) {
    179                 try {
    180                     serviceMutex.wait();
    181                 } catch (InterruptedException e) {
    182                     e.printStackTrace();
    183                 }
    184             }
    185             if (!connected) {
    186                 throw new TimeoutException(
    187                         "Service could not be connected after " + SERVICE_CONNECTION_TIME_OUT
    188                                 + " ms");
    189             }
    190             if (connectionTimer != null) {
    191                 connectionTimer.cancel();
    192             }
    193         }
    194     }
    195 
    196     /** Tests getReaders API */
    197     @Test
    198     public void testGetReaders() {
    199         try {
    200             waitForConnection();
    201             Reader[] readers = seService.getReaders();
    202 
    203             for (Reader reader : readers) {
    204                 assertTrue(reader.isSecureElementPresent());
    205                 String name = reader.getName();
    206                 if (!(name.startsWith(UICC_READER_PREFIX) || name.startsWith(ESE_READER_PREFIX)
    207                         || name.startsWith(SD_READER_PREFIX))) {
    208                     fail("Incorrect Reader name");
    209                 }
    210                 assertNotNull("getseService returned null", reader.getSEService());
    211             }
    212         } catch (Exception e) {
    213             fail("Unexpected Exception " + e);
    214         }
    215     }
    216 
    217     /** Tests getATR API */
    218     @Test
    219     public void testATR() {
    220         try {
    221             waitForConnection();
    222             Reader[] readers = seService.getReaders();
    223             ArrayList<Reader> uiccReaders = new ArrayList<Reader>();
    224             if (readers != null && readers.length > 0) {
    225                 for (int i = 0; i < readers.length; i++) {
    226                     if (readers[i].getName().startsWith(UICC_READER_PREFIX)) {
    227                         uiccReaders.add(readers[i]);
    228                     }
    229                 }
    230 
    231                 for (Reader reader : uiccReaders) {
    232                     Session session = null;
    233                     try {
    234                         session = reader.openSession();
    235                     } catch (IOException e) {
    236                         e.printStackTrace();
    237                     }
    238                     assertNotNull("Could not open session", session);
    239                     byte[] atr = session.getATR();
    240                     session.close();
    241                     assertNotNull("ATR is Null", atr);
    242                 }
    243             }
    244         } catch (Exception e) {
    245             fail("Unexpected Exception " + e);
    246         }
    247     }
    248 
    249     /** Tests OpenBasicChannel API when aid is null */
    250     @Test
    251     public void testOpenBasicChannelNullAid() {
    252         try {
    253             waitForConnection();
    254             Reader[] readers = seService.getReaders();
    255 
    256             for (Reader reader : readers) {
    257                 Session session = reader.openSession();
    258                 assertNotNull("Could not open session", session);
    259                 Channel channel = session.openBasicChannel(null, (byte)0x00);
    260                 if (reader.getName().startsWith(UICC_READER_PREFIX)) {
    261                     assertNull("Basic channel on UICC can be opened", channel);
    262                 } else {
    263                     assertNotNull("Basic Channel cannot be opened", channel);
    264                 }
    265                 if (channel != null) {
    266                     channel.close();
    267                 }
    268                 session.close();
    269             }
    270         } catch (Exception e) {
    271             fail("Unexpected Exception " + e);
    272         }
    273     }
    274 
    275     /** Tests OpenBasicChannel API when aid is provided */
    276     @Test
    277     public void testOpenBasicChannelNonNullAid() {
    278         try {
    279             waitForConnection();
    280             Reader[] readers = seService.getReaders();
    281 
    282             for (Reader reader : readers) {
    283                 Session session = reader.openSession();
    284                 assertNotNull("Could not open session", session);
    285                 Channel channel = session.openBasicChannel(SELECTABLE_AID, (byte)0x00);
    286                 if (reader.getName().startsWith(UICC_READER_PREFIX)) {
    287                     assertNull("Basic channel on UICC can be opened", channel);
    288                 } else {
    289                     assertNotNull("Basic Channel cannot be opened", channel);
    290                 }
    291                 if (channel != null) {
    292                     channel.close();
    293                 }
    294                 session.close();
    295             }
    296         } catch (Exception e) {
    297             fail("Unexpected Exception " + e);
    298         }
    299     }
    300 
    301     /** Tests Select API */
    302     @Test
    303     public void testSelectableAid() {
    304         testSelectableAid(SELECTABLE_AID);
    305     }
    306 
    307     @Test
    308     public void testLongSelectResponse() {
    309         byte[] selectResponse = testSelectableAid(LONG_SELECT_RESPONSE_AID);
    310         if (selectResponse == null) {
    311             return;
    312         }
    313         assertTrue("Select Response is not complete", verifyBerTlvData(selectResponse));
    314     }
    315 
    316 
    317     private byte[] testSelectableAid(byte[] aid) {
    318         try {
    319             waitForConnection();
    320             Reader[] readers = seService.getReaders();
    321 
    322             for (Reader reader : readers) {
    323                 assertTrue(reader.isSecureElementPresent());
    324                 Session session = reader.openSession();
    325                 assertNotNull("Null Session", session);
    326                 Channel channel = session.openLogicalChannel(aid, (byte)0x00);
    327                 assertNotNull("Null Channel", channel);
    328                 byte[] selectResponse = channel.getSelectResponse();
    329                 assertNotNull("Null Select Response", selectResponse);
    330                 assertGreaterOrEqual(selectResponse.length, 2);
    331                 assertEquals(selectResponse[selectResponse.length - 1] & 0xFF, 0x00);
    332                 assertEquals(selectResponse[selectResponse.length - 2] & 0xFF, 0x90);
    333                 channel.close();
    334                 session.close();
    335                 return selectResponse;
    336             }
    337         } catch (Exception e) {
    338             fail("Unexpected Exception " + e);
    339         }
    340         return null;
    341     }
    342 
    343     /** Tests if NoSuchElementException in Select */
    344     @Test
    345     public void testWrongAid() {
    346         try {
    347             waitForConnection();
    348             Reader[] readers = seService.getReaders();
    349             for (Reader reader : readers) {
    350                 testNonSelectableAid(reader, NON_SELECTABLE_AID);
    351             }
    352         } catch (TimeoutException e) {
    353             fail("unexpected exception " + e);
    354         }
    355     }
    356 
    357     private void testNonSelectableAid(Reader reader, byte[] aid) {
    358         boolean exception = false;
    359         Session session = null;
    360         try {
    361             assertTrue(reader.isSecureElementPresent());
    362             session = reader.openSession();
    363             assertNotNull("null session", session);
    364             Channel channel = session.openLogicalChannel(aid, (byte)0x00);
    365         } catch (NoSuchElementException e) {
    366             exception = true;
    367             if (session != null) {
    368                 session.close();
    369             }
    370         } catch (Exception e) {
    371             fail("unexpected exception " + e);
    372         }
    373         assertTrue(exception);
    374     }
    375 
    376     /** Tests if Security Exception in Transmit */
    377     @Test
    378     public void testSecurityExceptionInTransmit() {
    379         boolean exception = false;
    380         Session session;
    381         Channel channel;
    382         try {
    383             waitForConnection();
    384             Reader[] readers = seService.getReaders();
    385 
    386             for (Reader reader : readers) {
    387                 assertTrue(reader.isSecureElementPresent());
    388                 session = reader.openSession();
    389                 assertNotNull("null session", session);
    390                 channel = session.openLogicalChannel(SELECTABLE_AID, (byte)0x00);
    391                 assertNotNull("Null Channel", channel);
    392                 byte[] selectResponse = channel.getSelectResponse();
    393                 assertNotNull("Null Select Response", selectResponse);
    394                 assertGreaterOrEqual(selectResponse.length, 2);
    395                 assertEquals(selectResponse[selectResponse.length - 1] & 0xFF, 0x00);
    396                 assertEquals(selectResponse[selectResponse.length - 2] & 0xFF, 0x90);
    397                 for (byte[] cmd : ILLEGAL_COMMANDS_TRANSMIT) {
    398                     try {
    399                         exception = false;
    400                         byte[] response = channel.transmit(cmd);
    401                     } catch (SecurityException e) {
    402                         exception = true;
    403                     }
    404                     assertTrue(exception);
    405                 }
    406                 channel.close();
    407                 session.close();
    408             }
    409         } catch (Exception e) {
    410             fail("unexpected exception " + e);
    411         }
    412     }
    413 
    414     private byte[] internalTransmitApdu(Reader reader, byte[] apdu) {
    415         try {
    416             assertTrue(reader.isSecureElementPresent());
    417             Session session = reader.openSession();
    418             assertNotNull("null session", session);
    419             Channel channel = session.openLogicalChannel(SELECTABLE_AID, (byte)0x00);
    420             assertNotNull("Null Channel", channel);
    421             byte[] selectResponse = channel.getSelectResponse();
    422             assertNotNull("Null Select Response", selectResponse);
    423             assertGreaterOrEqual(selectResponse.length, 2);
    424             byte[] transmitResponse = channel.transmit(apdu);
    425             channel.close();
    426             session.close();
    427             return transmitResponse;
    428         } catch (Exception e) {
    429             fail("unexpected exception " + e);
    430         }
    431         return null;
    432     }
    433 
    434     /**
    435      * Tests Transmit API for all readers.
    436      *
    437      * Checks the return status and verifies the size of the
    438      * response.
    439      */
    440     @Test
    441     public void testTransmitApdu() {
    442         try {
    443             waitForConnection();
    444             Reader[] readers = seService.getReaders();
    445 
    446             for (Reader reader : readers) {
    447                 for (byte[] apdu : NO_DATA_APDU) {
    448                     byte[] response = internalTransmitApdu(reader, apdu);
    449                     assertEquals(response.length, 2);
    450                     assertEquals(response[response.length - 1] & 0xFF, 0x00);
    451                     assertEquals(response[response.length - 2] & 0xFF, 0x90);
    452                 }
    453 
    454                 for (byte[] apdu : DATA_APDU) {
    455                     byte[] response = internalTransmitApdu(reader, apdu);
    456                     /* 256 byte data and 2 bytes of status word */
    457                     assertEquals(response.length, 258);
    458                     assertEquals(response[response.length - 1] & 0xFF, 0x00);
    459                     assertEquals(response[response.length - 2] & 0xFF, 0x90);
    460                 }
    461             }
    462         } catch (Exception e) {
    463             fail("unexpected exception " + e);
    464         }
    465     }
    466 
    467     /**
    468      * Tests if underlying implementations returns the correct Status Word
    469      *
    470      * TO verify that :
    471      * - the device does not modify the APDU sent to the Secure Element
    472      * - the warning code is properly received by the application layer as SW answer
    473      * - the verify that the application layer can fetch the additionnal data (when present)
    474      */
    475     @Test
    476     public void testStatusWordTransmit() {
    477         try {
    478             waitForConnection();
    479             Reader[] readers = seService.getReaders();
    480 
    481             for (Reader reader : readers) {
    482                 for (byte[] apdu : SW_62xx_NO_DATA_APDU) {
    483                     for (byte i = 0x00; i < SW_62xx.length; i++) {
    484                         apdu[2] = (byte)(i+1);
    485                         byte[] response = internalTransmitApdu(reader, apdu);
    486                         byte[] SW = SW_62xx[i];
    487                         assertEquals(response[response.length - 1], SW[1]);
    488                         assertEquals(response[response.length - 2], SW[0]);
    489                     }
    490                 }
    491 
    492                 for (byte i = 0x00; i < SW_62xx.length; i++) {
    493                     byte[] apdu = SW_62xx_DATA_APDU;
    494                     apdu[2] = (byte)(i+1);
    495                     byte[] response = internalTransmitApdu(reader, apdu);
    496                     byte[] SW = SW_62xx[i];
    497                     assertGreaterOrEqual(response.length, 3);
    498                     assertEquals(response[response.length - 1], SW[1]);
    499                     assertEquals(response[response.length - 2], SW[0]);
    500                 }
    501 
    502                 for (byte i = 0x00; i < SW_62xx.length; i++) {
    503                     byte[] apdu = SW_62xx_VALIDATE_DATA_APDU;
    504                     apdu[2] = (byte)(i+1);
    505                     byte[] response = internalTransmitApdu(reader, apdu);
    506                     assertGreaterOrEqual(response.length, apdu.length + 2);
    507                     byte[] responseSubstring = Arrays.copyOfRange(response, 0, apdu.length);
    508                     apdu[0] = 0x01;
    509                     assertTrue(Arrays.equals(responseSubstring, apdu));
    510                     byte[] SW = SW_62xx[i];
    511                     assertEquals(response[response.length - 1], SW[1]);
    512                     assertEquals(response[response.length - 2], SW[0]);
    513                 }
    514             }
    515         } catch (Exception e) {
    516             fail("unexpected exception " + e);
    517         }
    518     }
    519 
    520     /** Test if the responses are segmented by the underlying implementation */
    521     @Test
    522     public void testSegmentedResponseTransmit() {
    523         try {
    524             waitForConnection();
    525             Reader[] readers = seService.getReaders();
    526 
    527             for (Reader reader : readers) {
    528                 for (byte[] apdu : SEGMENTED_RESP_APDU) {
    529                     byte[] response = internalTransmitApdu(reader, apdu);
    530                     byte[] b = { 0x00, 0x00, apdu[2], apdu[3] };
    531                     ByteBuffer wrapped = ByteBuffer.wrap(b);
    532                     int expectedLength = wrapped.getInt();
    533                     assertEquals(response.length, expectedLength + 2);
    534                     assertEquals(response[response.length - 1] & 0xFF, 0x00);
    535                     assertEquals(response[response.length - 2] & 0xFF, 0x90);
    536                     assertEquals(response[response.length - 3] & 0xFF, 0xFF);
    537                 }
    538             }
    539         } catch (Exception e) {
    540             fail("unexpected exception " + e);
    541         }
    542     }
    543 
    544     /** Test the P2 value of the select command sent by the underlying implementation */
    545     @Test
    546     public void testP2Value() {
    547         try {
    548             waitForConnection();
    549             Reader[] readers = seService.getReaders();
    550 
    551             for (Reader reader : readers) {
    552                 byte[] response = internalTransmitApdu(reader, CHECK_SELECT_P2_APDU);
    553                 assertGreaterOrEqual(response.length, 3);
    554                 assertEquals(response[response.length - 1] & 0xFF, 0x00);
    555                 assertEquals(response[response.length - 2] & 0xFF, 0x90);
    556                 assertEquals(response[response.length - 3] & 0xFF, 0x00);
    557             }
    558         } catch (Exception e) {
    559           fail("unexpected exception " + e);
    560         }
    561     }
    562 
    563     /**
    564      * Verifies TLV data
    565      * @param tlv
    566      * @return true if the data is tlv formatted, false otherwise
    567      */
    568     private static boolean verifyBerTlvData(byte[] tlv){
    569         if (tlv == null || tlv.length == 0) {
    570             throw new RuntimeException("Invalid tlv, null");
    571         }
    572         int i = 0;
    573         if ((tlv[i++] & 0x1F) == 0x1F) {
    574             // extra byte for TAG field
    575             i++;
    576         }
    577 
    578         int len = tlv[i++] & 0xFF;
    579         if (len > 127) {
    580             // more than 1 byte for length
    581             int bytesLength = len-128;
    582             len = 0;
    583             for(int j = bytesLength; j > 0; j--) {
    584                 len += (len << 8) + (tlv[i++] & 0xFF);
    585             }
    586         }
    587         // Additional 2 bytes for the SW
    588         return (tlv.length == (i+len+2));
    589     }
    590 
    591     class ServiceConnectionTimerTask extends TimerTask {
    592         @Override
    593         public void run() {
    594             synchronized (serviceMutex) {
    595                 serviceMutex.notifyAll();
    596             }
    597         }
    598     }
    599 }
    600