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.accesscontrol3.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.util.Timer;
     29 import java.util.TimerTask;
     30 import java.util.concurrent.Executor;
     31 import java.util.concurrent.TimeoutException;
     32 
     33 import android.content.pm.PackageManager;
     34 import android.os.RemoteException;
     35 import android.se.omapi.Channel;
     36 import android.se.omapi.Reader;
     37 import android.se.omapi.SEService;
     38 import android.se.omapi.SEService.OnConnectedListener;
     39 import android.se.omapi.Session;
     40 import android.support.test.InstrumentationRegistry;
     41 
     42 import com.android.compatibility.common.util.PropertyUtil;
     43 
     44 public class AccessControlTest {
     45     private final static String UICC_READER_PREFIX = "SIM";
     46     private final static String ESE_READER_PREFIX = "eSE";
     47     private final static String SD_READER_PREFIX = "SD";
     48 
     49     private final static byte[] AID_40 = new byte[] { (byte) 0xA0, 0x00, 0x00,
     50         0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
     51         0x53, 0x40 };
     52     private final static byte[] AID_41 = new byte[] { (byte) 0xA0, 0x00, 0x00,
     53         0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
     54         0x53, 0x41 };
     55     private final static byte[] AID_42 = new byte[] { (byte) 0xA0, 0x00, 0x00,
     56         0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
     57         0x53, 0x42 };
     58     private final static byte[] AID_43 = new byte[] { (byte) 0xA0, 0x00, 0x00,
     59         0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
     60         0x53, 0x43 };
     61     private final static byte[] AID_44 = new byte[] { (byte) 0xA0, 0x00, 0x00,
     62         0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
     63         0x53, 0x44 };
     64     private final static byte[] AID_45 = new byte[] { (byte) 0xA0, 0x00, 0x00,
     65         0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
     66         0x53, 0x45 };
     67     private final static byte[] AID_46 = new byte[] { (byte) 0xA0, 0x00, 0x00,
     68         0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
     69         0x53, 0x46 };
     70     private final static byte[] AID_47 = new byte[] { (byte) 0xA0, 0x00, 0x00,
     71         0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
     72         0x53, 0x47 };
     73     private final static byte[] AID_48 = new byte[] { (byte) 0xA0, 0x00, 0x00,
     74         0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
     75         0x53, 0x48 };
     76     private final static byte[] AID_49 = new byte[] { (byte) 0xA0, 0x00, 0x00,
     77         0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
     78         0x53, 0x49 };
     79     private final static byte[] AID_4A = new byte[] { (byte) 0xA0, 0x00, 0x00,
     80         0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
     81         0x53, (byte) 0x4A };
     82     private final static byte[] AID_4B = new byte[] { (byte) 0xA0, 0x00, 0x00,
     83         0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
     84         0x53, (byte) 0x4B };
     85     private final static byte[] AID_4C = new byte[] { (byte) 0xA0, 0x00, 0x00,
     86         0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
     87         0x53, (byte) 0x4C };
     88     private final static byte[] AID_4D = new byte[] { (byte) 0xA0, 0x00, 0x00,
     89         0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
     90         0x53, (byte) 0x4D };
     91     private final static byte[] AID_4E = new byte[] { (byte) 0xA0, 0x00, 0x00,
     92         0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
     93         0x53, (byte) 0x4E };
     94     private final static byte[] AID_4F = new byte[] { (byte) 0xA0, 0x00, 0x00,
     95         0x04, 0x76, 0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x43, 0x54,
     96         0x53, (byte) 0x4F };
     97 
     98     private final static byte[][] AUTHORIZED_AID = new byte[][] { AID_40,
     99         AID_41, AID_45, AID_46 };
    100     private final static byte[][] UNAUTHORIZED_AID = new byte[][] { AID_42,
    101         AID_43, AID_44, AID_47, AID_48, AID_49, AID_4A, AID_4B, AID_4C, AID_4D, AID_4E,
    102         AID_4F };
    103 
    104     /* Authorized APDU for AID_40 */
    105     private final static byte[][] AUTHORIZED_APDU_AID_40 = new byte[][] {
    106         { 0x00, 0x06, 0x00, 0x00 }, { (byte) 0x80, 0x06, 0x00, 0x00 },
    107         { (byte) 0xA0, 0x06, 0x00, 0x00 },
    108         { (byte) 0x94, 0x06, 0x00, 0x00 },
    109         { 0x00, 0x0A, 0x00, 0x00, 0x01, (byte) 0xAA },
    110         { (byte) 0x80, 0x0A, 0x00, 0x00, 0x01, (byte) 0xAA },
    111         { (byte) 0xA0, 0x0A, 0x00, 0x00, 0x01, (byte) 0xAA },
    112         { (byte) 0x94, 0x0A, 0x00, 0x00, 0x01, (byte) 0xAA },
    113         { 0x00, 0x08, 0x00, 0x00, 0x00 },
    114         { (byte) 0x80, 0x08, 0x00, 0x00, 0x00 },
    115         { (byte) 0xA0, 0x08, 0x00, 0x00, 0x00 },
    116         { (byte) 0x94, 0x08, 0x00, 0x00, 0x00 },
    117         { 0x00, (byte) 0xC0, 0x00, 0x00, 0x01, (byte) 0xAA, 0x00 },
    118         { (byte) 0x80, (byte) 0xC0, 0x00, 0x00, 0x01, (byte) 0xAA, 0x00 },
    119         { (byte) 0xA0, (byte) 0xC0, 0x00, 0x00, 0x01, (byte) 0xAA, 0x00 },
    120         { (byte) 0x94, (byte) 0xC0, 0x00, 0x00, 0x01, (byte) 0xAA, 0x00 }};
    121 
    122     /* Authorized APDU for AID_41 */
    123     private final static byte[][] AUTHORIZED_APDU_AID_41 = new byte[][] {
    124         { (byte) 0x94, 0x06, 0x00, 0x00 },
    125         { (byte) 0x94, 0x08, 0x00, 0x00, 0x00 },
    126         { (byte) 0x94, (byte) 0xC0, 0x00, 0x00, 0x01, (byte) 0xAA, 0x00 },
    127         { (byte) 0x94, 0x0A, 0x00, 0x00, 0x01, (byte) 0xAA } };
    128     /* Unauthorized APDU for AID_41 */
    129     private final static byte[][] UNAUTHORIZED_APDU_AID_41 = new byte[][] {
    130         { 0x00, 0x06, 0x00, 0x00 }, { (byte) 0x80, 0x06, 0x00, 0x00 },
    131         { (byte) 0xA0, 0x06, 0x00, 0x00 },
    132         { 0x00, 0x08, 0x00, 0x00, 0x00 },
    133         { (byte) 0x00, 0x0A, 0x00, 0x00, 0x01, (byte) 0xAA },
    134         { (byte) 0x80, 0x0A, 0x00, 0x00, 0x01, (byte) 0xAA },
    135         { (byte) 0xA0, 0x0A, 0x00, 0x00, 0x01, (byte) 0xAA },
    136         { (byte) 0x80, 0x08, 0x00, 0x00, 0x00 },
    137         { (byte) 0xA0, 0x08, 0x00, 0x00, 0x00 },
    138         { 0x00, (byte) 0xC0, 0x00, 0x00, 0x01, (byte) 0xAA, 0x00 },
    139         { (byte) 0x80, (byte) 0xC0, 0x00, 0x00, 0x01, (byte) 0xAA, 0x00 },
    140         { (byte) 0xA0, (byte) 0xC0, 0x00, 0x00, 0x01, (byte) 0xAA, 0x00 },
    141     };
    142 
    143     private final long SERVICE_CONNECTION_TIME_OUT = 3000;
    144     private SEService seService;
    145     private Object serviceMutex = new Object();
    146     private Timer connectionTimer;
    147     private ServiceConnectionTimerTask mTimerTask = new ServiceConnectionTimerTask();
    148     private boolean connected = false;
    149 
    150     private final OnConnectedListener mListener = new OnConnectedListener() {
    151         @Override
    152         public void onConnected() {
    153             synchronized (serviceMutex) {
    154                 connected = true;
    155                 serviceMutex.notify();
    156             }
    157         }
    158     };
    159 
    160     class SynchronousExecutor implements Executor {
    161         public void execute(Runnable r) {
    162             r.run();
    163         }
    164     }
    165 
    166     private boolean supportsHardware() {
    167         final PackageManager pm = InstrumentationRegistry.getContext().getPackageManager();
    168         boolean lowRamDevice = PropertyUtil.propertyEquals("ro.config.low_ram", "true");
    169         return !lowRamDevice || (lowRamDevice && pm.hasSystemFeature("android.hardware.type.watch"));
    170     }
    171 
    172     @Before
    173     public void setUp() throws Exception {
    174         assumeTrue(supportsHardware());
    175         seService = new SEService(InstrumentationRegistry.getContext(), new SynchronousExecutor(), mListener);
    176         connectionTimer = new Timer();
    177         connectionTimer.schedule(mTimerTask, SERVICE_CONNECTION_TIME_OUT);
    178     }
    179 
    180     @After
    181     public void tearDown() throws Exception {
    182         if (seService != null && seService.isConnected()) {
    183             seService.shutdown();
    184             connected = false;
    185         }
    186     }
    187 
    188     private void waitForConnection() throws TimeoutException {
    189         synchronized (serviceMutex) {
    190             if (!connected) {
    191                 try {
    192                     serviceMutex.wait();
    193                  } catch (InterruptedException e) {
    194                     e.printStackTrace();
    195                  }
    196             }
    197             if (!connected) {
    198                 throw new TimeoutException(
    199                     "Service could not be connected after "
    200                     + SERVICE_CONNECTION_TIME_OUT + " ms");
    201             }
    202             if (connectionTimer != null) {
    203                 connectionTimer.cancel();
    204             }
    205         }
    206     }
    207 
    208     @Test
    209     public void testAuthorizedAID() {
    210         for (byte[] aid : AUTHORIZED_AID) {
    211             testSelectableAid(aid);
    212         }
    213     }
    214 
    215     @Test
    216     public void testUnauthorizedAID() {
    217         for (byte[] aid : UNAUTHORIZED_AID) {
    218             testUnauthorisedAid(aid);
    219         }
    220     }
    221 
    222     @Test
    223     public void testAuthorizedAPDUAID40() {
    224         for (byte[] apdu : AUTHORIZED_APDU_AID_40) {
    225             testTransmitAPDU(AID_40, apdu);
    226         }
    227     }
    228 
    229     @Test
    230     public void testAuthorizedAPDUAID41() {
    231         for (byte[] apdu : AUTHORIZED_APDU_AID_41) {
    232             testTransmitAPDU(AID_41, apdu);
    233         }
    234     }
    235 
    236     @Test
    237     public void testUnauthorisedAPDUAID41() {
    238         for (byte[] apdu : UNAUTHORIZED_APDU_AID_41) {
    239             testUnauthorisedAPDU(AID_41, apdu);
    240         }
    241     }
    242 
    243     private void testSelectableAid(byte[] aid) {
    244         Session session = null;
    245         Channel channel = null;
    246         try {
    247             waitForConnection();
    248             Reader[] readers = seService.getReaders();
    249             for (Reader reader : readers) {
    250                 assertTrue(reader.isSecureElementPresent());
    251                 session = reader.openSession();
    252                 assertNotNull("Null Session", session);
    253                 channel = session.openLogicalChannel(aid, (byte)0x00);
    254                 assertNotNull("Null Channel", channel);
    255                 byte[] selectResponse = channel.getSelectResponse();
    256                 assertNotNull("Null Select Response", selectResponse);
    257                 assertEquals(selectResponse[selectResponse.length - 1] & 0xFF, 0x00);
    258                 assertEquals(selectResponse[selectResponse.length - 2] & 0xFF, 0x90);
    259                 assertTrue("Select Response is not complete", verifyBerTlvData(selectResponse));
    260             }
    261         } catch (Exception e) {
    262             fail("Unexpected Exception " + e);
    263         } finally{
    264             if (channel != null)
    265                 channel.close();
    266             if (session != null)
    267                 session.close();
    268         }
    269     }
    270 
    271     private void testUnauthorisedAid(byte[] aid) {
    272         Session session = null;
    273         Channel channel = null;
    274         try {
    275             waitForConnection();
    276             Reader[] readers = seService.getReaders();
    277 
    278             for (Reader reader : readers) {
    279                 assertTrue(reader.isSecureElementPresent());
    280                 session = reader.openSession();
    281                 assertNotNull("Null Session", session);
    282                 channel = session.openLogicalChannel(aid, (byte)0x00);
    283                 fail("SecurityException Expected ");
    284             }
    285         } catch(SecurityException ex){ }
    286         catch (Exception e) {
    287             fail("Unexpected Exception " + e);
    288         }
    289         if (channel != null)
    290             channel.close();
    291         if (session != null)
    292             session.close();
    293     }
    294 
    295     private void testTransmitAPDU(byte[] aid, byte[] apdu) {
    296         Session session = null;
    297         Channel channel = null;
    298         try {
    299             waitForConnection();
    300             Reader[] readers = seService.getReaders();
    301 
    302             for (Reader reader : readers) {
    303                 assertTrue(reader.isSecureElementPresent());
    304                 session = reader.openSession();
    305                 assertNotNull("Null Session", session);
    306                 channel = session.openLogicalChannel(aid, (byte)0x00);
    307                 assertNotNull("Null Channel", channel);
    308                 byte[] selectResponse = channel.getSelectResponse();
    309                 assertNotNull("Null Select Response", selectResponse);
    310                 assertEquals(selectResponse[selectResponse.length - 1] & 0xFF, 0x00);
    311                 assertEquals(selectResponse[selectResponse.length - 2] & 0xFF, 0x90);
    312                 assertTrue("Select Response is not complete", verifyBerTlvData(selectResponse));
    313                 byte[] apduResponse = channel.transmit(apdu);
    314                 assertNotNull("Null Channel", apduResponse);
    315             }
    316         } catch (Exception e) {
    317             fail("Unexpected Exception " + e);
    318         }
    319         if (channel != null)
    320             channel.close();
    321         if (session != null)
    322             session.close();
    323     }
    324 
    325     private void testUnauthorisedAPDU(byte[] aid, byte[] apdu) {
    326         Session session = null;
    327         Channel channel = null;
    328         boolean exceptionOnTransmit = false;
    329         try {
    330             waitForConnection();
    331             Reader[] readers = seService.getReaders();
    332 
    333             for (Reader reader : readers) {
    334                 assertTrue(reader.isSecureElementPresent());
    335                 session = reader.openSession();
    336                 assertNotNull("Null Session", session);
    337                 channel = session.openLogicalChannel(aid, (byte)0x00);
    338                 assertNotNull("Null Channel", channel);
    339                 byte[] selectResponse = channel.getSelectResponse();
    340                 assertNotNull("Null Select Response", selectResponse);
    341                 assertEquals(selectResponse[selectResponse.length - 1] & 0xFF, 0x00);
    342                 assertEquals(selectResponse[selectResponse.length - 2] & 0xFF, 0x90);
    343                 assertTrue("Select Response is not complete", verifyBerTlvData(selectResponse));
    344                 exceptionOnTransmit = true;
    345                 channel.transmit(apdu);
    346                 fail("Security Exception is expected");
    347             }
    348         } catch (SecurityException ex) {
    349           if (!exceptionOnTransmit) {
    350             fail("Unexpected SecurityException onSelect" + ex);
    351           }
    352         } catch (Exception e) {
    353           fail("Unexpected Exception " + e);
    354         } finally {
    355             if(channel != null)
    356                 channel.close();
    357             if (session != null)
    358                 session.close();
    359         }
    360     }
    361 
    362     /**
    363      * Verifies TLV data
    364      *
    365      * @param tlv
    366      * @return true if the data is tlv formatted, false otherwise
    367      */
    368     private static boolean verifyBerTlvData(byte[] tlv) {
    369         if (tlv == null || tlv.length == 0) {
    370             throw new RuntimeException("Invalid tlv, null");
    371         }
    372 
    373         int i = 0;
    374         byte[] key = new byte[2];
    375         key[0] = tlv[i];
    376         if ((key[0] & 0x1F) == 0x1F) {
    377             // extra byte for TAG field
    378             key[1] = tlv[i = i + 1];
    379         }
    380 
    381         int len = tlv[i = i + 1] & 0xFF;
    382         if (len > 127) {
    383             // more than 1 byte for length
    384             int bytesLength = len - 128;
    385             len = 0;
    386             for (int j = bytesLength - 1; j >= 0; j--) {
    387               len += (tlv[i = i + 1] & 0xFF) * Math.pow(10, j);
    388             }
    389         }
    390         return tlv.length == (i + len + 3);
    391     }
    392 
    393     class ServiceConnectionTimerTask extends TimerTask {
    394         @Override
    395         public void run() {
    396             synchronized (serviceMutex) {
    397                 serviceMutex.notifyAll();
    398             }
    399         }
    400     }
    401 }
    402