1 // 2 // Copyright (C) 2017 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 // Test on device with: 17 // echo -e '00A4040010A0000004765049584C424F4F54000101 9000\n8000000000 9000\n' | ese-replay nq-nci 18 // Install (after loading the two Shareable caps) with: 19 // ${JAVA_HOME}/bin/java -jar gp.jar -d --install avb_storage.cap 20 // 21 22 package com.android.verifiedboot.storage; 23 24 import javacard.framework.AID; 25 import javacard.framework.APDU; 26 import javacard.framework.Applet; 27 import javacard.framework.CardRuntimeException; 28 import javacard.framework.ISO7816; 29 import javacard.framework.ISOException; 30 import javacard.framework.JCSystem; 31 import javacard.framework.Shareable; 32 import javacard.framework.Util; 33 34 import javacard.security.KeyBuilder; 35 import javacard.security.MessageDigest; 36 import javacard.security.RSAPublicKey; 37 import javacard.security.Signature; 38 39 // Enables processing longer messages atomically. 40 import javacardx.apdu.ExtendedLength; 41 42 import com.android.verifiedboot.globalstate.callback.CallbackInterface; 43 import com.android.verifiedboot.globalstate.owner.OwnerInterface; 44 45 import com.android.verifiedboot.storage.GlobalStateImpl; 46 import com.android.verifiedboot.storage.BasicLock; 47 import com.android.verifiedboot.storage.CarrierLock; 48 import com.android.verifiedboot.storage.LockInterface; 49 import com.android.verifiedboot.storage.OsBackupInterface; 50 import com.android.verifiedboot.storage.VersionStorage; 51 52 import com.android.verifiedboot.storage.JcopBackupImpl; 53 54 public class Storage extends Applet implements ExtendedLength, Shareable { 55 final static byte VERSION = (byte) 0x01; 56 final static byte APPLET_CLA = (byte)0x80; 57 58 /* Note, globalState never needs to be backed up as any clients should re-register on every 59 * call -- not just on install(). 60 */ 61 private GlobalStateImpl globalState; 62 private VersionStorage versionStorage; 63 private OsBackupInterface osBackupImpl; 64 /* lockStorage can be backed up directly, as long as the locks themselves have been 65 * properly intiialized. 66 */ 67 private byte[] lockStorage; 68 private LockInterface[] locks; 69 private byte[] reservedMetadata; 70 private byte[] metadata; 71 private short metadataLength; 72 73 // Indices into locks[]. 74 private final static byte LOCK_CARRIER = (byte) 0x00; 75 private final static byte LOCK_DEVICE = (byte) 0x01; 76 private final static byte LOCK_BOOT = (byte) 0x02; 77 private final static byte LOCK_OWNER = (byte) 0x03; 78 79 private final static byte INS_GET_STATE = (byte) 0x00; 80 private final static byte INS_LOAD = (byte) 0x02; 81 private final static byte INS_STORE = (byte) 0x04; 82 private final static byte INS_GET_LOCK = (byte) 0x06; 83 private final static byte INS_SET_LOCK = (byte) 0x08; 84 private final static byte INS_SET_PRODUCTION = (byte) 0x0a; 85 private final static byte INS_CARRIER_LOCK_TEST = (byte) 0x0c; 86 private final static byte INS_RESET = (byte) 0x0e; 87 private final static byte INS_LOAD_META = (byte) 0x10; 88 89 private final static byte RESET_FACTORY = (byte) 0x0; 90 private final static byte RESET_LOCKS = (byte) 0x1; 91 92 private final static byte LOAD_META_CLEAR = (byte) 0x0; 93 private final static byte LOAD_META_APPEND = (byte) 0x1; 94 95 private final static short NO_METADATA = (short) 0; 96 private final static short NO_REQ_LOCKS = (short) 0; 97 // Plenty of space for an owner key and any serialization. 98 private final static short OWNER_LOCK_METADATA_SIZE = (short) 2048; 99 private final static short INCOMING_BYTES_MAX = (short) 1024; 100 101 /** 102 * Installs this applet. 103 * 104 * @param params the installation parameters 105 * @param offset the starting offset of the parameters 106 * @param length the length of the parameters 107 */ 108 public static void install(byte[] bArray, short bOffset, byte bLength) { 109 // GP-compliant-ish JavaCard applet registration 110 short aidOffset = bOffset; 111 short aidLength = bArray[aidOffset++]; 112 short privsOffset = (short)(aidOffset + aidLength); 113 short privLength = bArray[privsOffset++]; 114 // Grab the install parameters. 115 short paramsOffset = (short)(privsOffset + privLength); 116 short paramLength = bArray[paramsOffset++]; 117 118 Storage applet = new Storage(); 119 applet.register(bArray, aidOffset, (byte)aidLength); 120 if (paramLength == 0) { 121 // TODO(wad) Should we fail the install on failure? 122 applet.restore(bArray); 123 } 124 } 125 126 private Storage() { 127 globalState = new GlobalStateImpl(); 128 osBackupImpl = new JcopBackupImpl(); 129 130 versionStorage = new VersionStorage(globalState); 131 osBackupImpl.track(OsBackupInterface.TAG_VERSION_STORAGE, 132 versionStorage); 133 134 lockStorage = new byte[4096]; 135 // Reserve metadata for scratch if there's no transient 136 reservedMetadata = new byte[OWNER_LOCK_METADATA_SIZE]; 137 metadata = null; 138 139 // Initialize all supported locks here. 140 locks = new LockInterface[4]; 141 // LOCK_CARRIER can be set only when not in production mode 142 // but can be unlocked any time authenticated data is provided. 143 locks[LOCK_CARRIER] = new CarrierLock(); 144 osBackupImpl.track(OsBackupInterface.TAG_LOCK_CARRIER, 145 locks[LOCK_CARRIER]); 146 147 // LOCK_DEVICE can be toggled any time from anywhere. It 148 // expresses a HLOS management policy. 149 locks[LOCK_DEVICE] = new BasicLock(NO_METADATA, NO_REQ_LOCKS); 150 BasicLock lockRef = (BasicLock)locks[LOCK_DEVICE]; 151 lockRef.requireHLOS(true); 152 osBackupImpl.track(OsBackupInterface.TAG_LOCK_DEVICE, 153 lockRef); 154 155 // LOCK_BOOT can only be toggled if both the carrier and device 156 // locks are clear and then, only in the bootloader/fastboot. 157 locks[LOCK_BOOT] = new BasicLock(NO_METADATA, (short) 2); 158 lockRef = (BasicLock)locks[LOCK_BOOT]; 159 lockRef.addRequiredLock(locks[LOCK_CARRIER]); 160 lockRef.addRequiredLock(locks[LOCK_DEVICE]); 161 lockRef.requireBootloader(true); 162 osBackupImpl.track(OsBackupInterface.TAG_LOCK_BOOT, 163 lockRef); 164 165 // LOCK_OWNER can be toggled at any time if the BOOT_LOCK is unlocked. 166 // It modifies the behavior of LOCK_BOOT by providing an alternative 167 // "owner" boot key. 168 locks[LOCK_OWNER] = new BasicLock(OWNER_LOCK_METADATA_SIZE, (short) 1); 169 lockRef = (BasicLock)locks[LOCK_OWNER]; 170 lockRef.addRequiredLock(locks[LOCK_BOOT]); 171 lockRef.requireMetadata(true); 172 osBackupImpl.track(OsBackupInterface.TAG_LOCK_OWNER, 173 lockRef); 174 175 short offset = (short) 0; 176 byte lockNum = (byte) 0; 177 for ( ; lockNum < (byte) locks.length; ++lockNum) { 178 if (locks[lockNum].getStorageNeeded() > 179 (short)(lockStorage.length - offset)) { 180 ISOException.throwIt((short) 0xfeed); 181 } 182 locks[lockNum].initialize(globalState, lockStorage, offset); 183 offset += locks[lockNum].getStorageNeeded(); 184 } 185 186 } 187 188 /** 189 * Returns the globalState or OsBackupInterface object. 190 * 191 * @param clientAid AID of the caller. 192 * @param arg Object request indicator 193 */ 194 @Override 195 public Shareable getShareableInterfaceObject(AID clientAid, byte arg) { 196 if (clientAid != null) { // TODO: check AID. 197 switch (arg) { 198 case (byte) 0: 199 return globalState; 200 default: 201 return osBackupImpl.getShareableInterfaceObject(clientAid, arg); 202 } 203 } 204 return globalState; 205 } 206 207 /** 208 * Emits the state of this Applet to the wire. 209 * 210 * Format: 211 * VERSION (byte) 212 * Length (short) 213 * [global_state.OwnerInterface data] 214 * inBootloaderRaw (byte) 215 * inBootloader (boolean byte) 216 * production (byte) 217 * [lock state] 218 * numLocks (byte) 219 * locks[0].initialized (short) 220 * ... 221 * locks[numLocks - 1].initialized (short) 222 * [lockStorage] 223 * lockStorageLength (short) 224 * lockStorage (lockStorageLength=4096) 225 * 226 * TODO(wad) It'd be nice to TLV these values... 227 * 228 * @return 0x00 if the response has been sent. 229 */ 230 private short sendStorageState(APDU apdu) { 231 final byte buffer[] = apdu.getBuffer(); 232 byte[] working = new byte[2]; 233 short value = 0; 234 short resp = 0; 235 byte i; 236 short expectedLength = apdu.setOutgoing(); 237 short length = (short)(2 + 1 + 2 + 1 + 1 + 1 + 1 + (2 * locks.length) + 238 2 + lockStorage.length + 2); 239 if (expectedLength < length) { 240 // Error with length. 241 buffer[0] = (byte) 0x01; 242 buffer[1] = (byte) 0x00; 243 buffer[2] = (byte)(length >> 8); 244 buffer[3] = (byte)(length & 0xff); 245 apdu.setOutgoingLength((short) 4); 246 apdu.sendBytes((short) 0, (short) 4); 247 return 0x0; 248 } 249 try { 250 apdu.setOutgoingLength(length); 251 } catch (CardRuntimeException e) { 252 return 0x0101; 253 } 254 255 // Send the usual prefix status indicating we made it this far. 256 try { 257 Util.setShort(working, (short) 0, (short) 0x0); 258 apdu.sendBytesLong(working, (short) 0, (short) 2); 259 length -= 2; 260 } catch (CardRuntimeException e) { 261 return 0x0001; 262 } 263 264 try { 265 working[0] = VERSION; 266 apdu.sendBytesLong(working, (short) 0, (short) 1); 267 length--; 268 } catch (CardRuntimeException e) { 269 return 0x0001; 270 } 271 272 try { 273 Util.setShort(working, (short) 0, length); 274 apdu.sendBytesLong(working, (short) 0, (short) 2); 275 length -= 2; 276 } catch (CardRuntimeException e) { 277 ISOException.throwIt(length); 278 } 279 280 try { 281 working[0] = globalState.inBootloaderRaw(); 282 apdu.sendBytesLong(working, (short) 0, (short) 1); 283 length--; 284 } catch (CardRuntimeException e) { 285 ISOException.throwIt(length); 286 } 287 288 try { 289 working[0] = (byte)0; 290 if (globalState.inBootloader() == true) { 291 working[0] = (byte)1; 292 } 293 apdu.sendBytesLong(working, (short) 0, (short) 1); 294 length--; 295 } catch (CardRuntimeException e) { 296 ISOException.throwIt(length); 297 } 298 299 try { 300 working[0] = (byte)0; 301 if (globalState.production() == true) { 302 working[0] = (byte)1; 303 } 304 apdu.sendBytesLong(working, (short) 0, (short) 1); 305 length--; 306 } catch (CardRuntimeException e) { 307 ISOException.throwIt(length); 308 } 309 try { 310 working[0] = (byte)locks.length; 311 apdu.sendBytesLong(working, (short) 0, (short) 1); 312 length--; 313 } catch (CardRuntimeException e) { 314 ISOException.throwIt(length); 315 } 316 317 try { 318 for (i = 0; i < (byte)locks.length; ++i) { 319 Util.setShort(working, (short) 0, locks[i].initialized()); 320 apdu.sendBytesLong(working, (short) 0, (short) 2); 321 length -= 2; 322 } 323 } catch (CardRuntimeException e) { 324 ISOException.throwIt(length); 325 } 326 327 try { 328 Util.setShort(working, (short) 0, (short)lockStorage.length); 329 apdu.sendBytesLong(working, (short) 0, (short) 2); 330 length -= 2; 331 } catch (CardRuntimeException e) { 332 ISOException.throwIt(length); 333 } 334 335 try { 336 apdu.sendBytesLong(lockStorage, (short) 0, (short) lockStorage.length); 337 length -= (short) lockStorage.length; 338 } catch (CardRuntimeException e) { 339 ISOException.throwIt(length); 340 } 341 if (length != 0) { 342 ISOException.throwIt(length); 343 } 344 return 0; 345 } 346 347 private void sendResponseCode(APDU apdu, short resp) { 348 final byte buffer[] = apdu.getBuffer(); 349 buffer[0] = (byte)(resp >> 8); 350 buffer[1] = (byte)(resp & 0xff); 351 apdu.setOutgoingAndSend((short)0, (short)2); 352 } 353 354 /** 355 * Returns 0x0 if no data needs to be sent. 356 */ 357 private short sendLockData(APDU apdu, byte p1, byte p2) { 358 final byte buffer[] = apdu.getBuffer(); 359 short resp = 0; 360 if (p1 >= (byte)locks.length) { 361 return 0x0001; 362 } 363 if (locks[p1].initialized() != 0) { 364 return locks[p1].initialized(); 365 } 366 367 if (p2 == (byte) 0x00) { 368 resp = locks[p1].get(buffer, (short) 2); 369 Util.setShort(buffer, (short) 0, resp); 370 apdu.setOutgoingAndSend((short) 0, (short) 3); 371 return 0; 372 } 373 short length = (short)(3 + locks[p1].metadataLength()); 374 try { 375 byte[] resp_val = new byte[1]; 376 apdu.setOutgoing(); 377 apdu.setOutgoingLength(length); 378 379 // Send a successful response code. 380 resp_val[0] = (byte) 0x00; 381 apdu.sendBytesLong(resp_val, (short) 0, (short) 1); 382 apdu.sendBytesLong(resp_val, (short) 0, (short) 1); 383 // Then the lock byte. 384 apdu.sendBytesLong(lockStorage, locks[p1].lockOffset(), (short) 1); 385 // Then any exported metadata. Note that the metadataOffset may 386 // exclude some data which is considered private to the lock. 387 apdu.sendBytesLong(lockStorage, locks[p1].metadataOffset(), 388 locks[p1].metadataLength()); 389 return 0; 390 } catch (CardRuntimeException e) { 391 return 0x0002; 392 } 393 } 394 395 /** 396 * Fills the incoming buffer from APDU streams. 397 * 398 * @param apdu payload from the client. 399 * @param incoming buffer to fill from apdu buffer. 400 * @param iOffset starting offset into incoming. 401 * @param total total bytes to read from APDU. 402 * @return offset/length into incoming. 403 */ 404 private short fillIncomingBuffer(APDU apdu, byte[] incoming, short iOffset, short available) { 405 final byte buffer[] = apdu.getBuffer(); 406 final short cdataOffset = apdu.getOffsetCdata(); 407 short sum = 0; 408 while (available > 0) { 409 Util.arrayCopyNonAtomic(buffer, cdataOffset, 410 incoming, (short)(sum + iOffset), available); 411 sum += available; 412 try { 413 available = apdu.receiveBytes(cdataOffset); 414 if (sum > (short)(incoming.length - available)) { 415 available = (short)(incoming.length - sum); 416 } 417 } catch (CardRuntimeException e) { 418 available = 0; 419 } 420 } 421 return (short)(sum + iOffset); 422 } 423 424 public boolean select() { 425 metadataLength = (short) 0; 426 // Try to get the RAM needed. 427 if (metadata == null || 428 metadata == reservedMetadata) { 429 try { 430 metadata = JCSystem.makeTransientByteArray( 431 OWNER_LOCK_METADATA_SIZE, 432 JCSystem.CLEAR_ON_DESELECT); 433 } catch (CardRuntimeException e) { 434 metadata = reservedMetadata; 435 } 436 } 437 return true; 438 } 439 /** 440 * Handles incoming APDU requests 441 * 442 * @param apdu payload from the client. 443 */ 444 public void process(APDU apdu) { 445 final byte buffer[] = apdu.getBuffer(); 446 final byte cla = buffer[ISO7816.OFFSET_CLA]; 447 final byte ins = buffer[ISO7816.OFFSET_INS]; 448 // Handle standard commands 449 if (apdu.isISOInterindustryCLA()) { 450 switch (ins) { 451 case ISO7816.INS_SELECT: 452 // Do nothing, successfully 453 return; 454 default: 455 ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED); 456 } 457 ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED); 458 } 459 460 short availableBytes = apdu.setIncomingAndReceive(); 461 short numBytes = apdu.getIncomingLength(); 462 short cdataOffset = apdu.getOffsetCdata(); 463 464 // Maximum possible transmission before triggering weirdness 465 // (really it is 6 * 254 - framing). 466 if (numBytes > INCOMING_BYTES_MAX) { 467 sendResponseCode(apdu, (short)0x0f00); 468 return; 469 } 470 471 byte p1 = (byte)(buffer[ISO7816.OFFSET_P1] & (byte)0xff); 472 byte p2 = (byte)(buffer[ISO7816.OFFSET_P2] & (byte)0xff); 473 short length = 0; 474 short expectedLength = 0; 475 short resp = 0; 476 boolean enable = false; 477 if (p1 != 0) { 478 enable = true; 479 } 480 481 switch (buffer[ISO7816.OFFSET_INS]) { 482 case INS_GET_STATE: /* getStorageState(0x0, 0x0) */ 483 resp = sendStorageState(apdu); 484 if (resp != 0) { 485 sendResponseCode(apdu, resp); 486 } 487 return; 488 case INS_LOAD: /* getSlot(id) */ 489 resp = versionStorage.getSlot(p1, buffer, (short) 2); 490 buffer[0] = (byte)(resp >> 8); 491 buffer[1] = (byte)(resp & 0xff); 492 length = 2; 493 if (resp == 0) { 494 length += (short) VersionStorage.SLOT_BYTES; 495 } 496 // Always send the two bytes of status as they are more 497 // useful than the APDU error. 498 apdu.setOutgoingAndSend((short)0, length); 499 return; 500 case INS_STORE: /* setSlot(id) {uint64_t} */ 501 resp = versionStorage.setSlot(p1, buffer, cdataOffset); 502 Util.setShort(buffer, (short) 0, resp); 503 apdu.setOutgoingAndSend((short) 0, (short) 2); 504 return; 505 case INS_GET_LOCK: /* getLock(lockId, sendMetadata) */ 506 resp = sendLockData(apdu, p1, p2); 507 if (resp != 0) { 508 sendResponseCode(apdu, resp); 509 } 510 return; 511 case INS_SET_LOCK: /* setlock(index, val) { useMetadata(byte) } */ 512 if (p1 >= (byte)locks.length) { 513 sendResponseCode(apdu, (short)0x0100); 514 return; 515 } 516 // useMetadata argument byte is required. 517 if (numBytes != 1) { 518 sendResponseCode(apdu, (short)0x0200); 519 return; 520 } 521 if (buffer[cdataOffset] == (byte) 0) { 522 resp = locks[p1].set(p2); 523 } else if (buffer[cdataOffset] == (byte) 1) { 524 resp = locks[p1].setWithMetadata(p2, metadata, 525 (short) 0, 526 metadataLength); 527 // "Consume" the metadata even if an error occurred. 528 metadataLength = (short)0; 529 } 530 sendResponseCode(apdu, resp); 531 return; 532 case INS_SET_PRODUCTION: /* setProduction(p1) */ 533 if (globalState.setProduction(enable) == true) { 534 resp = 0x0000; 535 } else { 536 resp = 0x0001; 537 } 538 sendResponseCode(apdu, resp); 539 return; 540 /* carrierLockTest() { testVector } */ 541 case INS_CARRIER_LOCK_TEST: 542 try { 543 short copied = fillIncomingBuffer(apdu, metadata, (short)0, 544 availableBytes); 545 if (numBytes != copied) { 546 // Declared length did not match read bytes. 547 sendResponseCode(apdu, (short)0x0101); 548 return; 549 } 550 resp = ((CarrierLock)locks[LOCK_CARRIER]).testVector(metadata, 551 (short)0, copied); 552 sendResponseCode(apdu, resp); 553 return; 554 } catch (CardRuntimeException e) { 555 sendResponseCode(apdu, (short)0x0201); 556 return; 557 } 558 /* reset(0x0=factory 0x1=locks) {} */ 559 case INS_RESET: 560 if (p1 != RESET_LOCKS) { 561 /* Not implemented */ 562 resp = 0x0001; 563 sendResponseCode(apdu, resp); 564 return; 565 } 566 if (globalState.production() == true) { 567 resp = 0x0100; 568 sendResponseCode(apdu, resp); 569 return; 570 } 571 Util.arrayFillNonAtomic(lockStorage, (short) 0, 572 (short) lockStorage.length, (byte) 0x00); 573 return; 574 /* load_meta(new|append) {} */ 575 case INS_LOAD_META: 576 if (p1 == LOAD_META_CLEAR) { 577 metadataLength = (short) 0; 578 sendResponseCode(apdu, (short) 0x0000); 579 return; 580 } 581 if (p1 != LOAD_META_APPEND) { 582 sendResponseCode(apdu, (short) 0x0100); 583 return; 584 } 585 try { 586 // fillIncomingBuffer will only copy up to the length. 587 short copied = fillIncomingBuffer(apdu, metadata, 588 metadataLength, 589 availableBytes); 590 copied -= metadataLength; // just the new stuff 591 metadataLength += copied; 592 if (numBytes != copied) { 593 // Could not read all the bytes -- the data is 594 // copied though. 595 sendResponseCode(apdu, (short)0x0101); 596 return; 597 } 598 } catch (CardRuntimeException e) { 599 sendResponseCode(apdu, (short)0x0201); 600 return; 601 } 602 sendResponseCode(apdu, (short) 0x0000); 603 return; 604 default: 605 ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED); 606 } 607 } 608 609 /** 610 * Restores data across upgrades 611 * 612 * @param buffer bytes 613 * @return true on success and false on failure. 614 */ 615 private boolean restore(byte[] buffer) { 616 return osBackupImpl.restore(buffer, (short) 0); 617 } 618 } 619