avb_storage: fix nonce update; enable clearing
Nonce updating was copying without the
incoming offset and was not using the VERSION_SIZE
constant. This changes fixes the storage as well as
adds a mechanism for resetting the nonce when not
in production mode (without a reinstall) and binds it into
the ese_boot_tool and the boot interface (making a
framework for factory rese without adding it explicitly).
Test: Used increasing nonces and made sure they were single use and only
newer ones worked by: set-carrier, set-production, unlock-last,
unlock-newer, unset-production, set-carrier, ...
Bug: none
Change-Id: I038229c1bb089b2d5f98faeed81714dfc1c32e36
diff --git a/apps/boot/boot.c b/apps/boot/boot.c
index fe381af..c6f8c72 100644
--- a/apps/boot/boot.c
+++ b/apps/boot/boot.c
@@ -36,6 +36,8 @@
const uint8_t kSetLockState[] = {0x80, 0x08, 0x00, 0x00, 0x00};
const uint8_t kSetProduction[] = {0x80, 0x0a};
const uint8_t kCarrierLockTest[] = {0x80, 0x0c, 0x00, 0x00};
+const uint8_t kFactoryReset[] = {0x80, 0x0e, 0x00, 0x00};
+const uint8_t kLockReset[] = {0x80, 0x0e, 0x01, 0x00};
EseAppResult check_apdu_status(uint8_t code[2]) {
if (code[0] == 0x90 && code[1] == 0x00) {
@@ -607,6 +609,46 @@
return ESE_APP_RESULT_OK;
}
+ESE_API EseAppResult ese_boot_reset_locks(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 = kLockReset[0] | session->channel_id;
+ tx[0].base = &chan;
+ tx[0].len = 1;
+ tx[1].base = (uint8_t *)&kLockReset[1];
+ tx[1].len = sizeof(kLockReset) - 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_reset_locks: comms failure.");
+ return ESE_APP_RESULT_ERROR_COMM_FAILED;
+ }
+ if (rx_len == 2) {
+ ALOGE("ese_boot_reset_locks: SE exception");
+ EseAppResult ret = check_apdu_status(&reply[0]);
+ return ret;
+ }
+ // Expect the full payload plus the aplet status and the completion code.
+ if (rx_len != 4) {
+ ALOGE("ese_boot_reset_locks: not enough data (%d)", rx_len);
+ return ese_make_app_result(reply[0], reply[1]);
+ }
+ if (reply[0] != 0x0 || reply[1] != 0x0) {
+ ALOGE("ese_boot_reset_locks: applet error code %x %x", reply[0], reply[1]);
+ return ese_make_app_result(reply[0], reply[1]);
+ }
+ return ESE_APP_RESULT_OK;
+}
+
ESE_API EseAppResult ese_boot_get_state(struct EseBootSession *session,
uint8_t *state, uint16_t maxSize) {
struct EseSgBuffer tx[4];
diff --git a/apps/boot/card/src/com/android/verifiedboot/storage/CarrierLock.java b/apps/boot/card/src/com/android/verifiedboot/storage/CarrierLock.java
index db0ac32..1a4c7f7 100644
--- a/apps/boot/card/src/com/android/verifiedboot/storage/CarrierLock.java
+++ b/apps/boot/card/src/com/android/verifiedboot/storage/CarrierLock.java
@@ -433,7 +433,7 @@
// was seen or if we're not production() to assure it doesn't get
// rolled forward.
if (resp == 0) {
- Util.arrayCopy(lockMeta, (short)1,
+ Util.arrayCopy(lockMeta, (short)(VERSION_SIZE + lockMetaOffset),
storage, (short)(1 + storageOffset),
(short)NONCE_SIZE);
}
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 d01680b..9c2bd46 100644
--- a/apps/boot/card/src/com/android/verifiedboot/storage/Storage.java
+++ b/apps/boot/card/src/com/android/verifiedboot/storage/Storage.java
@@ -79,6 +79,10 @@
private final static byte INS_SET_LOCK = (byte) 0x08;
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 RESET_FACTORY = (byte) 0x0;
+ private final static byte RESET_LOCKS = (byte) 0x1;
private final static short NO_METADATA = (short) 0;
private final static short NO_REQ_LOCKS = (short) 0;
@@ -465,9 +469,23 @@
if (numBytes != bytesRead) {
resp = 0x0100;
}
- resp = ((CarrierLock)locks[0]).testVector(buffer, cdataOffset, bytesRead);
+ 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);
+ }
+ if (globalState.production() == true) {
+ resp = 0x0100;
+ sendResponseCode(apdu, resp);
+ }
+ Util.arrayFillNonAtomic(lockStorage, (short) 0,
+ (short) lockStorage.length, (byte) 0x00);
+ 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 80aa3d9..cffd8ee 100644
--- a/apps/boot/ese_boot_tool.cpp
+++ b/apps/boot/ese_boot_tool.cpp
@@ -46,6 +46,7 @@
" boot <byte>\n"
" owner 0\n"
" owner <non-zero byte> <keyValue>\n"
+ " reset\n"
" verify-key test <blob>\n"
" verify-key auto\n"
"\n"
@@ -269,7 +270,9 @@
EseBootLockId lockId;
uint16_t lockMetaLen = 0;
uint8_t lockMeta[1024];
- if (args[2] == "carrier") {
+ if (args[1] == "reset") {
+ // No work.
+ } else if (args[2] == "carrier") {
lockId = kEseBootLockIdCarrier;
} else if (args[2] == "device") {
lockId = kEseBootLockIdDevice;
@@ -304,6 +307,16 @@
fprintf(stderr, "lock: failed to get '%s' (%.8x)\n", args[2].c_str(), res);
handle_error(session->ese, res);
return 2;
+ } else if (args[1] == "reset") {
+ res = ese_boot_reset_locks(session);
+ if (res == ESE_APP_RESULT_OK) {
+ printf("done.\n");
+ return 0;
+ } else {
+ fprintf(stderr, "lock: failed to reset (%.8x)\n", res);
+ handle_error(session->ese, res);
+ return 3;
+ }
} else if (args[1] == "set") {
if (args.size() < 4) {
fprintf(stderr, "lock set: not enough arguments supplied\n");
diff --git a/apps/boot/include/ese/app/boot.h b/apps/boot/include/ese/app/boot.h
index 72892bc..c0cbff8 100644
--- a/apps/boot/include/ese/app/boot.h
+++ b/apps/boot/include/ese/app/boot.h
@@ -186,10 +186,19 @@
/**
* Reads a uint64_t from |slot| into |value|.
*
- * @retuns ESE_APP_RESULT_OK on success.
+ * @returns ESE_APP_RESULT_OK on success.
*/
EseAppResult ese_boot_rollback_index_read(struct EseBootSession *session, uint8_t slot, uint64_t *value);
+
+/**
+ * Resets all lock state -- including internal metadata.
+ * This should only be called in factory or under test.
+ *
+ * @returns ESE_APP_RESULT_OK on success.
+ */
+EseAppResult ese_boot_reset_locks(struct EseBootSession *session);
+
#ifdef __cplusplus
} /* extern "C" */
#endif