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