Merge "apps/boot: Clean up applet"
am: b6354cdea7
Change-Id: I2fea1af8bdba6b48d1d04d0243553e546669bb83
diff --git a/apps/boot/boot.c b/apps/boot/boot.c
index 6911d1d..a8ac08b 100644
--- a/apps/boot/boot.c
+++ b/apps/boot/boot.c
@@ -38,6 +38,9 @@
const uint8_t kCarrierLockTest[] = {0x80, 0x0c, 0x00, 0x00};
const uint8_t kFactoryReset[] = {0x80, 0x0e, 0x00, 0x00};
const uint8_t kLockReset[] = {0x80, 0x0e, 0x01, 0x00};
+const uint8_t kLoadMetaClear[] = {0x80, 0x10, 0x00, 0x00};
+const uint8_t kLoadMetaAppend[] = {0x80, 0x10, 0x01, 0x00};
+static const uint16_t kMaxMetadataLoadSize = 1024;
EseAppResult check_apdu_status(uint8_t code[2]) {
if (code[0] == 0x90 && code[1] == 0x00) {
@@ -206,7 +209,7 @@
rx_len = ese_transceive_sg(session->ese, tx, 4, rx, 3);
if (rx_len < 2 || ese_error(session->ese)) {
- ALOGE("Failed to read lock state (%d).", lock);
+ ALOGE("ese_boot_lock_xget: failed to read lock state (%d)", lock);
return ESE_APP_RESULT_ERROR_COMM_FAILED;
}
if (rx_len == 2) {
@@ -217,7 +220,8 @@
// Expect the full payload plus the aplet status and the completion code.
*length = (uint16_t)(rx_len - 4);
if (rx_len == 4) {
- ALOGE("Received applet error code %x %x", lockData[0], lockData[1]);
+ ALOGE("ese_boot_lock_xget: received applet error code %x %x", lockData[0],
+ lockData[1]);
return ese_make_app_result(lockData[0], lockData[1]);
}
return ESE_APP_RESULT_OK;
@@ -250,21 +254,21 @@
rx_len = ese_transceive_sg(session->ese, tx, 3, rx, 1);
if (rx_len < 2 || ese_error(session->ese)) {
- ALOGE("Failed to read lock state (%d).", lock);
+ ALOGE("ese_boot_lock_get: failed to read lock state (%d).", lock);
return ESE_APP_RESULT_ERROR_COMM_FAILED;
}
EseAppResult ret = check_apdu_status(&reply[rx_len - 2]);
if (ret != ESE_APP_RESULT_OK) {
- ALOGE("Get lock state returned a SE OS error.");
+ ALOGE("ese_boot_lock_get: SE OS error.");
return ret;
}
if (rx_len < 5) {
- ALOGE("Get lock state did not receive enough data.");
+ ALOGE("ese_boot_lock_get: communication error");
return ESE_APP_RESULT_ERROR_COMM_FAILED;
}
// TODO: unify in the applet, then map them here.
if (reply[0] != 0x0 && reply[1] != 0x0) {
- ALOGE("INS_GET_LOCK: Applet error: %x %x", reply[0], reply[1]);
+ ALOGE("ese_boot_lock_get: Applet error: %x %x", reply[0], reply[1]);
return ese_make_app_result(reply[0], reply[1]);
}
if (lockVal) {
@@ -278,11 +282,96 @@
return ESE_APP_RESULT_FALSE;
}
+EseAppResult ese_boot_meta_clear(struct EseBootSession *session) {
+ struct EseSgBuffer tx[2];
+ struct EseSgBuffer rx[1];
+ int rx_len;
+ if (!session || !session->ese || !session->active) {
+ return ESE_APP_RESULT_ERROR_ARGUMENTS;
+ }
+
+ uint8_t chan = kLoadMetaClear[0] | session->channel_id;
+ tx[0].base = &chan;
+ tx[0].len = 1;
+ tx[1].base = (uint8_t *)&kLoadMetaClear[1];
+ tx[1].len = sizeof(kLoadMetaClear) - 1;
+
+ uint8_t reply[4]; // App reply or APDU error.
+ rx[0].base = &reply[0];
+ rx[0].len = sizeof(reply);
+
+ rx_len = ese_transceive_sg(session->ese, tx, 2, rx, 1);
+ if (rx_len < 2 || ese_error(session->ese)) {
+ ALOGE("ese_boot_meta_clear: communication failure");
+ return ESE_APP_RESULT_ERROR_COMM_FAILED;
+ }
+ // Expect the full payload plus the applet status and the completion code.
+ if (rx_len < 4) {
+ ALOGE("ese_boot_meta_clear: SE exception");
+ EseAppResult ret = check_apdu_status(&reply[rx_len - 2]);
+ return ret;
+ }
+ if (reply[0] != 0x0 || reply[1] != 0x0) {
+ ALOGE("ese_boot_meta_clear: received applet error code %.2x %.2x", reply[0],
+ reply[1]);
+ return ese_make_app_result(reply[0], reply[1]);
+ }
+ return ESE_APP_RESULT_OK;
+}
+
+EseAppResult ese_boot_meta_append(struct EseBootSession *session,
+ const uint8_t *data, uint16_t dataLen) {
+ struct EseSgBuffer tx[4];
+ struct EseSgBuffer rx[1];
+ int rx_len;
+ if (!session || !session->ese || !session->active) {
+ return ESE_APP_RESULT_ERROR_ARGUMENTS;
+ }
+ if (dataLen > kMaxMetadataLoadSize) {
+ ALOGE("ese_boot_meta_append: too much data provided");
+ return ESE_APP_RESULT_ERROR_ARGUMENTS;
+ }
+
+ uint8_t chan = kLoadMetaAppend[0] | session->channel_id;
+ tx[0].base = &chan;
+ tx[0].len = 1;
+ tx[1].base = (uint8_t *)&kLoadMetaAppend[1];
+ tx[1].len = sizeof(kLoadMetaAppend) - 1;
+
+ uint8_t apdu_len[] = {0x0, (dataLen >> 8), (dataLen & 0xff)};
+ tx[2].base = &apdu_len[0];
+ tx[2].len = sizeof(apdu_len);
+ tx[3].c_base = data;
+ tx[3].len = dataLen;
+
+ uint8_t reply[4]; // App reply or APDU error.
+ rx[0].base = &reply[0];
+ rx[0].len = sizeof(reply);
+
+ rx_len = ese_transceive_sg(session->ese, tx, 4, rx, 1);
+ if (rx_len < 2 || ese_error(session->ese)) {
+ ALOGE("ese_boot_meta_append: communication failure");
+ return ESE_APP_RESULT_ERROR_COMM_FAILED;
+ }
+ // Expect the full payload plus the applet status and the completion code.
+ if (rx_len < 4) {
+ ALOGE("ese_boot_meta_append: SE exception");
+ EseAppResult ret = check_apdu_status(&reply[rx_len - 2]);
+ return ret;
+ }
+ if (reply[0] != 0x0 || reply[1] != 0x0) {
+ ALOGE("ese_boot_meta_append: received applet error code %.2x %.2x",
+ reply[0], reply[1]);
+ return ese_make_app_result(reply[0], reply[1]);
+ }
+ return ESE_APP_RESULT_OK;
+}
+
ESE_API EseAppResult ese_boot_lock_xset(struct EseBootSession *session,
EseBootLockId lockId,
const uint8_t *lockData,
uint16_t dataLen) {
- struct EseSgBuffer tx[5];
+ struct EseSgBuffer tx[3];
struct EseSgBuffer rx[1];
int rx_len;
if (!session || !session->ese || !session->active) {
@@ -292,36 +381,50 @@
return ESE_APP_RESULT_ERROR_ARGUMENTS;
}
if (dataLen < 1 || dataLen > kEseBootOwnerKeyMax + 1) {
- ALOGE("set_lock_with_meta: too much data: %hu > %d", dataLen,
+ ALOGE("ese_boot_lock_xset: too much data: %hu > %d", dataLen,
kEseBootOwnerKeyMax + 1);
return ESE_APP_RESULT_ERROR_ARGUMENTS;
}
+ // Locks with metadata require a multi-step upload to meet the
+ // constraints of the transport.
+ EseAppResult res = ese_boot_meta_clear(session);
+ if (res != ESE_APP_RESULT_OK) {
+ ALOGE("ese_boot_lock_xset: unable to clear scratch metadata");
+ return res;
+ }
+ // The first byte is the lock value itself, so we skip it.
+ const uint8_t *cursor = &lockData[1];
+ uint16_t remaining = dataLen - 1;
+ while (remaining > 0) {
+ uint16_t chunk = (512 < remaining) ? 512 : remaining;
+ res = ese_boot_meta_append(session, cursor, chunk);
+ ALOGI("ese_boot_lock_xset: sending chunk %x", remaining);
+ if (res != ESE_APP_RESULT_OK) {
+ ALOGE("ese_boot_lock_xset: unable to upload metadata");
+ return res;
+ }
+ remaining -= chunk;
+ cursor += chunk;
+ }
+
uint8_t chan = kSetLockState[0] | session->channel_id;
tx[0].base = &chan;
tx[0].len = 1;
tx[1].base = (uint8_t *)&kSetLockState[1];
tx[1].len = 1;
- uint8_t p1p2[] = {lockId, lockData[0]};
- tx[2].base = &p1p2[0];
- tx[2].len = sizeof(p1p2);
- dataLen--;
-
- uint8_t apdu_len[] = {0x0, (dataLen >> 8), (dataLen & 0xff)};
- tx[3].base = &apdu_len[0];
- tx[3].len = sizeof(apdu_len);
-
- tx[4].c_base = &lockData[1];
- tx[4].len = dataLen;
+ uint8_t lockIdLockValueUseMeta[] = {lockId, lockData[0], 0x1, 0x1};
+ tx[2].base = &lockIdLockValueUseMeta[0];
+ tx[2].len = sizeof(lockIdLockValueUseMeta);
uint8_t reply[4]; // App reply or APDU error.
rx[0].base = &reply[0];
rx[0].len = sizeof(reply);
- rx_len = ese_transceive_sg(session->ese, tx, 5, rx, 1);
+ rx_len = ese_transceive_sg(session->ese, tx, 3, rx, 1);
if (rx_len < 2 || ese_error(session->ese)) {
- ALOGE("Failed to set lock state (%d).", lockId);
+ ALOGE("ese_boot_lock_xset: failed to set lock state (%d).", lockId);
return ESE_APP_RESULT_ERROR_COMM_FAILED;
}
if (rx_len == 2) {
@@ -329,13 +432,14 @@
EseAppResult ret = check_apdu_status(&reply[0]);
return ret;
}
- // Expect the full payload plus the aplet status and the completion code.
+ // Expect the full payload plus the applet status and the completion code.
if (rx_len != 4) {
- ALOGE("Get lock state did not receive enough data: %d", rx_len);
+ ALOGE("ese_boot_lock_xset: communication error");
return ESE_APP_RESULT_ERROR_COMM_FAILED;
}
if (reply[0] != 0x0 || reply[1] != 0x0) {
- ALOGE("Received applet error code %x %x", reply[0], reply[1]);
+ ALOGE("ese_boot_lock_xset: received applet error code %x %x", reply[0],
+ reply[1]);
return ese_make_app_result(reply[0], reply[1]);
}
return ESE_APP_RESULT_OK;
@@ -360,9 +464,9 @@
tx[1].base = (uint8_t *)&kSetLockState[1];
tx[1].len = 1;
- uint8_t p1p2[] = {lockId, lockValue};
- tx[2].base = &p1p2[0];
- tx[2].len = sizeof(p1p2);
+ uint8_t lockIdLockValueNoMeta[] = {lockId, lockValue, 0x1, 0x0};
+ tx[2].base = &lockIdLockValueNoMeta[0];
+ tx[2].len = sizeof(lockIdLockValueNoMeta);
uint8_t reply[4]; // App reply or APDU error.
rx[0].base = &reply[0];
@@ -375,7 +479,7 @@
}
// Expect the full payload plus the applet status and the completion code.
if (rx_len < 4) {
- ALOGE("ese_boot_lock_xset: SE exception");
+ ALOGE("ese_boot_lock_set: SE exception");
EseAppResult ret = check_apdu_status(&reply[rx_len - 2]);
return ret;
}
diff --git a/apps/boot/card/src/com/android/verifiedboot/storage/BasicLock.java b/apps/boot/card/src/com/android/verifiedboot/storage/BasicLock.java
index 5cde61b..b3a6aad 100644
--- a/apps/boot/card/src/com/android/verifiedboot/storage/BasicLock.java
+++ b/apps/boot/card/src/com/android/verifiedboot/storage/BasicLock.java
@@ -232,6 +232,25 @@
}
/**
+ * Ensures any requiredLocks are unlocked.
+ * @return true if allowed or false if not.
+ */
+ public boolean prerequisitesMet() {
+ if (requiredLocks.length != 0) {
+ byte[] temp = new byte[1];
+ short resp = 0;
+ for (short l = 0; l < requiredLocks.length; ++l) {
+ resp = requiredLocks[l].get(temp, (short) 0);
+ // On error or not cleared, fail.
+ if (resp != 0 || temp[0] != (byte) 0x0) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
* {@inheritDoc}
*
* Returns 0x0 on success.
@@ -249,6 +268,10 @@
return 0x0002;
}
}
+ // To relock, the lock must be unlocked, then relocked.
+ if (val != (byte)0 && storage[lockOffset()] != (byte)0) {
+ return 0x0005;
+ }
if (globalState.production() == true) {
// Enforce only when in production.
if (onlyInBootloader == true) {
@@ -264,16 +287,8 @@
}
}
}
- if (requiredLocks.length != 0) {
- byte[] temp = new byte[1];
- short resp = 0;
- for (short l = 0; l < requiredLocks.length; ++l) {
- resp = requiredLocks[l].get(temp, (short) 0);
- // On error or not cleared, fail.
- if (resp != 0 || temp[0] != (byte) 0x0) {
- return 0x0a00;
- }
- }
+ if (prerequisitesMet() == false) {
+ return 0x0a00;
}
try {
storage[storageOffset] = val;
@@ -298,20 +313,46 @@
}
// No overruns, please.
if (lockMetaLength > metadataLength()) {
- return 0x0002;
+ return 0x0002;
+ }
+ // To relock, the lock must be unlocked, then relocked.
+ // This ensures that a lock like LOCK_OWNER cannot have its key value
+ // changed without first having the permission to unlock and lock again.
+ if (lockValue != (byte)0 && storage[lockOffset()] != (byte)0) {
+ return 0x0005;
}
if (metadataLength() == 0) {
- return set(lockValue);
+ return set(lockValue);
+ }
+ // Before copying, ensure changing the lock state is currently permitted.
+ if (prerequisitesMet() == false) {
+ return 0x0a00;
}
try {
- JCSystem.beginTransaction();
- storage[lockOffset()] = lockValue;
- Util.arrayCopy(lockMeta, lockMetaOffset,
- storage, metadataOffset(),
- lockMetaLength);
- JCSystem.commitTransaction();
+ // When unlocking, do so before clearing the metadata.
+ if (lockValue == (byte) 0) {
+ JCSystem.beginTransaction();
+ storage[lockOffset()] = lockValue;
+ JCSystem.commitTransaction();
+ }
+ if (lockMetaLength == 0) {
+ // An empty lockMeta will clear the value.
+ Util.arrayFillNonAtomic(storage, metadataOffset(),
+ metadataLength(), (byte) 0x00);
+ } else {
+ Util.arrayCopyNonAtomic(lockMeta, lockMetaOffset,
+ storage, metadataOffset(),
+ lockMetaLength);
+ }
+ // When locking, do so after the copy as interrupting it will
+ // not impact its use in a locked state.
+ if (lockValue != (byte) 0) {
+ JCSystem.beginTransaction();
+ storage[lockOffset()] = lockValue;
+ JCSystem.commitTransaction();
+ }
} catch (CardRuntimeException e) {
- return 0x0003;
+ return 0x0004;
}
return 0;
}
diff --git a/apps/boot/card/src/com/android/verifiedboot/storage/GlobalStateImpl.java b/apps/boot/card/src/com/android/verifiedboot/storage/GlobalStateImpl.java
index 5ac00aa..dd3df38 100644
--- a/apps/boot/card/src/com/android/verifiedboot/storage/GlobalStateImpl.java
+++ b/apps/boot/card/src/com/android/verifiedboot/storage/GlobalStateImpl.java
@@ -34,6 +34,10 @@
// Used to track if a client needs to be renotified in case of a
// power down, etc.
final static byte CLIENT_STATE_CLEAR_PENDING = (byte)0x1;
+ // Scenario values
+ final static byte BOOTLOADER_UNDEFINED = (byte) 0xff;
+ final static byte BOOTLOADER_HIGH = (byte) 0x5a;
+ final static byte BOOTLOADER_LOW = (byte) 0xa5;
private Object[] clientApplets;
private byte[] clientAppletState;
@@ -224,11 +228,15 @@
@Override
public boolean inBootloader() {
try {
- if (SystemInfo.getExternalState(SystemInfo.SYSTEMINFO_SCENARIO_0)
- == (byte) 0x00) {
+ switch (SystemInfo.getExternalState(
+ SystemInfo.SYSTEMINFO_SCENARIO_0)) {
+ case BOOTLOADER_HIGH:
+ return true;
+ case BOOTLOADER_LOW:
+ case BOOTLOADER_UNDEFINED:
+ default:
return false;
}
- return true;
} catch (ISOException e) {
// If we can't read it, we fail closed unless we're in debug mode.
return false;
@@ -236,6 +244,17 @@
}
/**
+ * Returns the external signal that feeds inBootloader().
+ */
+ public byte inBootloaderRaw() {
+ try {
+ return SystemInfo.getExternalState(SystemInfo.SYSTEMINFO_SCENARIO_0);
+ } catch (ISOException e) {
+ return (byte) 0x0;
+ }
+ }
+
+ /**
* {@inheritDoc}
*
* @param val value assigned to the inProduction value.
diff --git a/apps/boot/card/src/com/android/verifiedboot/storage/Storage.java b/apps/boot/card/src/com/android/verifiedboot/storage/Storage.java
index 9c2bd46..a18c88b 100644
--- a/apps/boot/card/src/com/android/verifiedboot/storage/Storage.java
+++ b/apps/boot/card/src/com/android/verifiedboot/storage/Storage.java
@@ -66,6 +66,10 @@
*/
private byte[] lockStorage;
private LockInterface[] locks;
+ private byte[] reservedMetadata;
+ private byte[] metadata;
+ private short metadataLength;
+
// Indices into locks[].
private final static byte LOCK_CARRIER = (byte) 0x00;
private final static byte LOCK_DEVICE = (byte) 0x01;
@@ -80,14 +84,19 @@
private final static byte INS_SET_PRODUCTION = (byte) 0x0a;
private final static byte INS_CARRIER_LOCK_TEST = (byte) 0x0c;
private final static byte INS_RESET = (byte) 0x0e;
+ private final static byte INS_LOAD_META = (byte) 0x10;
private final static byte RESET_FACTORY = (byte) 0x0;
private final static byte RESET_LOCKS = (byte) 0x1;
+ private final static byte LOAD_META_CLEAR = (byte) 0x0;
+ private final static byte LOAD_META_APPEND = (byte) 0x1;
+
private final static short NO_METADATA = (short) 0;
private final static short NO_REQ_LOCKS = (short) 0;
// Plenty of space for an owner key and any serialization.
private final static short OWNER_LOCK_METADATA_SIZE = (short) 2048;
+ private final static short INCOMING_BYTES_MAX = (short) 1024;
/**
* Installs this applet.
@@ -123,6 +132,10 @@
versionStorage);
lockStorage = new byte[4096];
+ // Reserve metadata for scratch if there's no transient
+ reservedMetadata = new byte[OWNER_LOCK_METADATA_SIZE];
+ metadata = null;
+
// Initialize all supported locks here.
locks = new LockInterface[4];
// LOCK_CARRIER can be set only when not in production mode
@@ -198,7 +211,8 @@
* VERSION (byte)
* Length (short)
* [global_state.OwnerInterface data]
- * inBootloader (byte)
+ * inBootloaderRaw (byte)
+ * inBootloader (boolean byte)
* production (byte)
* [lock state]
* numLocks (byte)
@@ -220,7 +234,7 @@
short resp = 0;
byte i;
short expectedLength = apdu.setOutgoing();
- short length = (short)(2 + 1 + 2 + 1 + 1 + 1 + (2 * locks.length) +
+ short length = (short)(2 + 1 + 2 + 1 + 1 + 1 + 1 + (2 * locks.length) +
2 + lockStorage.length + 2);
if (expectedLength < length) {
// Error with length.
@@ -264,6 +278,14 @@
}
try {
+ working[0] = globalState.inBootloaderRaw();
+ apdu.sendBytesLong(working, (short) 0, (short) 1);
+ length--;
+ } catch (CardRuntimeException e) {
+ ISOException.throwIt(length);
+ }
+
+ try {
working[0] = (byte)0;
if (globalState.inBootloader() == true) {
working[0] = (byte)1;
@@ -371,6 +393,50 @@
}
/**
+ * Fills the incoming buffer from APDU streams.
+ *
+ * @param apdu payload from the client.
+ * @param incoming buffer to fill from apdu buffer.
+ * @param iOffset starting offset into incoming.
+ * @param total total bytes to read from APDU.
+ * @return offset/length into incoming.
+ */
+ private short fillIncomingBuffer(APDU apdu, byte[] incoming, short iOffset, short available) {
+ final byte buffer[] = apdu.getBuffer();
+ final short cdataOffset = apdu.getOffsetCdata();
+ short sum = 0;
+ while (available > 0) {
+ Util.arrayCopyNonAtomic(buffer, cdataOffset,
+ incoming, (short)(sum + iOffset), available);
+ sum += available;
+ try {
+ available = apdu.receiveBytes(cdataOffset);
+ if (sum > (short)(incoming.length - available)) {
+ available = (short)(incoming.length - sum);
+ }
+ } catch (CardRuntimeException e) {
+ available = 0;
+ }
+ }
+ return (short)(sum + iOffset);
+ }
+
+ public boolean select() {
+ metadataLength = (short) 0;
+ // Try to get the RAM needed.
+ if (metadata == null ||
+ metadata == reservedMetadata) {
+ try {
+ metadata = JCSystem.makeTransientByteArray(
+ OWNER_LOCK_METADATA_SIZE,
+ JCSystem.CLEAR_ON_DESELECT);
+ } catch (CardRuntimeException e) {
+ metadata = reservedMetadata;
+ }
+ }
+ return true;
+ }
+ /**
* Handles incoming APDU requests
*
* @param apdu payload from the client.
@@ -391,10 +457,17 @@
ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);
}
- short bytesRead = apdu.setIncomingAndReceive();
+ short availableBytes = apdu.setIncomingAndReceive();
short numBytes = apdu.getIncomingLength();
short cdataOffset = apdu.getOffsetCdata();
+ // Maximum possible transmission before triggering weirdness
+ // (really it is 6 * 254 - framing).
+ if (numBytes > INCOMING_BYTES_MAX) {
+ sendResponseCode(apdu, (short)0x0f00);
+ return;
+ }
+
byte p1 = (byte)(buffer[ISO7816.OFFSET_P1] & (byte)0xff);
byte p2 = (byte)(buffer[ISO7816.OFFSET_P2] & (byte)0xff);
short length = 0;
@@ -435,22 +508,24 @@
sendResponseCode(apdu, resp);
}
return;
- case INS_SET_LOCK: /* setlock(index, val) { data } */
+ case INS_SET_LOCK: /* setlock(index, val) { useMetadata(byte) } */
if (p1 >= (byte)locks.length) {
sendResponseCode(apdu, (short)0x0100);
+ return;
}
-
- if (bytesRead == (short) 0) {
+ // useMetadata argument byte is required.
+ if (numBytes != 1) {
+ sendResponseCode(apdu, (short)0x0200);
+ return;
+ }
+ if (buffer[cdataOffset] == (byte) 0) {
resp = locks[p1].set(p2);
- } else {
- // Note, there may be more bytes to read than fit in the first pass.
- // If so, we'll need to stage it in a transient buffer to pass in.
- resp = (short) 0x0101;
- if (bytesRead == numBytes) {
- resp = locks[p1].setWithMetadata(p2, buffer,
- cdataOffset,
- bytesRead);
- }
+ } else if (buffer[cdataOffset] == (byte) 1) {
+ resp = locks[p1].setWithMetadata(p2, metadata,
+ (short) 0,
+ metadataLength);
+ // "Consume" the metadata even if an error occurred.
+ metadataLength = (short)0;
}
sendResponseCode(apdu, resp);
return;
@@ -464,28 +539,68 @@
return;
/* carrierLockTest() { testVector } */
case INS_CARRIER_LOCK_TEST:
- // Note, there may be more bytes to read than fit in the first pass.
- // If so, we'll need to stage it in a transient buffer to pass in.
- if (numBytes != bytesRead) {
- resp = 0x0100;
+ try {
+ short copied = fillIncomingBuffer(apdu, metadata, (short)0,
+ availableBytes);
+ if (numBytes != copied) {
+ // Declared length did not match read bytes.
+ sendResponseCode(apdu, (short)0x0101);
+ return;
+ }
+ resp = ((CarrierLock)locks[LOCK_CARRIER]).testVector(metadata,
+ (short)0, copied);
+ sendResponseCode(apdu, resp);
+ return;
+ } catch (CardRuntimeException e) {
+ sendResponseCode(apdu, (short)0x0201);
+ return;
}
- resp = ((CarrierLock)locks[LOCK_CARRIER]).testVector(buffer, cdataOffset, bytesRead);
- sendResponseCode(apdu, resp);
- return;
/* reset(0x0=factory 0x1=locks) {} */
case INS_RESET:
if (p1 != RESET_LOCKS) {
/* Not implemented */
resp = 0x0001;
sendResponseCode(apdu, resp);
+ return;
}
if (globalState.production() == true) {
resp = 0x0100;
sendResponseCode(apdu, resp);
+ return;
}
Util.arrayFillNonAtomic(lockStorage, (short) 0,
(short) lockStorage.length, (byte) 0x00);
return;
+ /* load_meta(new|append) {} */
+ case INS_LOAD_META:
+ if (p1 == LOAD_META_CLEAR) {
+ metadataLength = (short) 0;
+ sendResponseCode(apdu, (short) 0x0000);
+ return;
+ }
+ if (p1 != LOAD_META_APPEND) {
+ sendResponseCode(apdu, (short) 0x0100);
+ return;
+ }
+ try {
+ // fillIncomingBuffer will only copy up to the length.
+ short copied = fillIncomingBuffer(apdu, metadata,
+ metadataLength,
+ availableBytes);
+ copied -= metadataLength; // just the new stuff
+ metadataLength += copied;
+ if (numBytes != copied) {
+ // Could not read all the bytes -- the data is
+ // copied though.
+ sendResponseCode(apdu, (short)0x0101);
+ return;
+ }
+ } catch (CardRuntimeException e) {
+ sendResponseCode(apdu, (short)0x0201);
+ return;
+ }
+ sendResponseCode(apdu, (short) 0x0000);
+ return;
default:
ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
}
diff --git a/apps/boot/ese_boot_tool.cpp b/apps/boot/ese_boot_tool.cpp
index cffd8ee..98d2ce3 100644
--- a/apps/boot/ese_boot_tool.cpp
+++ b/apps/boot/ese_boot_tool.cpp
@@ -269,7 +269,7 @@
EseAppResult res;
EseBootLockId lockId;
uint16_t lockMetaLen = 0;
- uint8_t lockMeta[1024];
+ uint8_t lockMeta[kEseBootOwnerKeyMax + 1];
if (args[1] == "reset") {
// No work.
} else if (args[2] == "carrier") {
@@ -450,6 +450,7 @@
if (res != ESE_APP_RESULT_OK) {
fprintf(stderr, "failed to initiate session (%.8x)\n", res);
handle_error(ese, res);
+ ese_close(&ese);
return 1;
}
std::vector<std::string> args;
diff --git a/apps/boot/include/ese/app/boot.h b/apps/boot/include/ese/app/boot.h
index c0cbff8..09659a3 100644
--- a/apps/boot/include/ese/app/boot.h
+++ b/apps/boot/include/ese/app/boot.h
@@ -64,7 +64,6 @@
*/
const uint16_t kEseBootOwnerKeyMax = 2048;
-
/* Keep in sync with card/src/com/android/verifiedboot/storage/Storage.java */
/**
* This enum reflects the types of Locks that are supported by
diff --git a/apps/build.xml b/apps/build.xml
index 6eb0a75..77626cc 100644
--- a/apps/build.xml
+++ b/apps/build.xml
@@ -144,7 +144,7 @@
<!-- Base version (Version + .1) for displacing a preinstalled package on early cards. -->
<cap aid="A0000004765049584C424F4F540000"
package="com.android.verifiedboot.storage"
- version="2.1"
+ version="3.1"
output="${out}/avb_storage_clobber.cap"
sources="boot/card/src/com/android/verifiedboot"
export="${build}/export/avb_storage">
@@ -164,9 +164,9 @@
<import exps="${build}/export/avb_storage"/>
</cap>
<!-- 14th byte is the version. Increment on each release. -->
- <cap aid="A0000004765049584C424F4F540200"
+ <cap aid="A0000004765049584C424F4F540300"
package="com.android.verifiedboot.storage"
- version="2.0"
+ version="3.0"
output="${out}/avb_storage.cap"
sources="boot/card/src/com/android/verifiedboot"
export="${build}/export/avb_storage">
@@ -182,7 +182,7 @@
16th byte is 01 for the applet.
-->
<applet class="com.android.verifiedboot.storage.Storage"
- aid="A0000004765049584C424F4F54020101"/>
+ aid="A0000004765049584C424F4F54030101"/>
<import exps="${build}/export/avb_storage"/>
</cap>
</javacard>