| /* |
| * Copyright (C) 2017 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| * See the README.md in the parent (../../..) directory. |
| */ |
| |
| #ifndef ESE_APP_BOOT_H_ |
| #define ESE_APP_BOOT_H_ 1 |
| |
| #include "../../../../../libese/include/ese/ese.h" |
| #include "../../../../../libese/include/ese/log.h" |
| #include "../../../../../libese-sysdeps/include/ese/sysdeps.h" |
| |
| #include "../../../../include/ese/app/result.h" |
| |
| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| |
| /** |
| * EseBootSession carries the necessary start for interfacing |
| * with the methods below. |
| * |
| * Its usage follows a lifecycle like: |
| * |
| * EseAppResult res; |
| * EseBootSession session; |
| * ese_boot_session_init(&session); |
| * res = ese_boot_session_open(ese, &session); |
| * if (res != ESE_APP_RESULT_OK) { |
| * ... handle error (especially cooldown) ... |
| * } |
| * ... ese_boot_* ... |
| * ese_boot_session_close(&session); |
| * |
| */ |
| struct EseBootSession { |
| struct EseInterface *ese; |
| bool active; |
| uint8_t channel_id; |
| }; |
| |
| /** |
| * The Storage applet supports up to 8 64-bit storage slots for storing |
| * rollback protection indices. |
| */ |
| const uint8_t kEseBootRollbackSlotCount = 8; |
| /** |
| * When using the LOCK_OWNER, a key, or other relevant value, must be supplied. |
| * It may be at most OWNER_LOCK_METADATA_SIZE as defined in |
| * card/src/com/android/verifiedboot/storage/Storage.java. |
| */ |
| 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 |
| * the ese_boot_lock_* calls. |
| */ |
| typedef enum { |
| kEseBootLockIdCarrier = 0, |
| kEseBootLockIdDevice, |
| kEseBootLockIdBoot, |
| kEseBootLockIdOwner, |
| kEseBootLockIdMax = kEseBootLockIdOwner, |
| } EseBootLockId; |
| |
| |
| /** |
| * Initializes a pre-allocated |session| for use. |
| */ |
| void ese_boot_session_init(struct EseBootSession *session); |
| |
| /** |
| * Configures a communication session with the Storage applet using a logical |
| * channel on an already open |ese| object. |
| * |
| * @returns ESE_APP_RESULT_OK on success. |
| */ |
| EseAppResult ese_boot_session_open(struct EseInterface *ese, struct EseBootSession *session); |
| |
| /** |
| * Shuts down the logical channel with the Storage applet and invalidates |
| * the |session| internal state. |
| * |
| * @returns ESE_APP_RESULT_OK on success. |
| */ |
| EseAppResult ese_boot_session_close(struct EseBootSession *session); |
| |
| /** |
| * Retrieves the uint8_t value stored for the lock specified by |lockId|. |
| * On success, the value is stored in |lockVal|. If the byte is 0x0, then |
| * the lock is cleared (or unlocked). If it is any non-zero value, then it |
| * is locked. Any specific byte value may have additional meaning to the |
| * caller. |
| * |
| * @returns ESE_APP_RESULT_OK if |lockVal| contains a valid byte. |
| */ |
| EseAppResult ese_boot_lock_get(struct EseBootSession *session, EseBootLockId lockId, uint8_t *lockVal); |
| /** |
| * Retrieves extended lock data for the lock specified by |lockId|. |
| * |
| * |maxSize| specifies how many bytes may be written to |lockData|. |dataLen| |
| * will be updated to hold the length of the data received from the applet on |
| * success. |
| * |
| * The first byte of |lockData| will be the lock's value. The remaining bytes |
| * are the associated metadata. See the README.md for more details |
| * on each lock's behavior. |
| * |
| * @returns ESE_APP_RESULT_OK on success. |
| */ |
| EseAppResult ese_boot_lock_xget( |
| struct EseBootSession *session, EseBootLockId lockId, uint8_t *lockData, |
| uint16_t maxSize, uint16_t *dataLen); |
| |
| /** |
| * Sets the lock specified by |lockId| to |lockVal|. |
| * |
| * @returns ESE_APP_RESULT_OK on success. |
| */ |
| |
| EseAppResult ese_boot_lock_set(struct EseBootSession *session, EseBootLockId lockId, uint8_t lockVal); |
| /** |
| * Sets the lock and its metadata specified by |lockId| and |lockData|, |
| * respectively. |dataLen| indicates the length of |lockData|. |
| * |
| * The first byte of |lockData| will be treated as the new value for the lock. |
| * |
| * @returns ESE_APP_RESULT_OK on success. |
| */ |
| EseAppResult ese_boot_lock_xset(struct EseBootSession *session, EseBootLockId lockId, const uint8_t *lockData, uint16_t dataLen); |
| |
| /** |
| * Performs a test of the carrier unlock code by allowing the caller to specify |
| * a fake internal nonce value, fake internal device data, as well as an actual |
| * unlock token (made up of a nonce and signature). |
| * |
| * @returns ESE_APP_RESULT_OK on success. On failure, it is worthwhile to |
| * check the upper two bytes in the result code if the lower two bytes |
| * are ESE_APP_RESULT_ERROR_APPLET as it will provide an error |
| * specific to the code path. These applet codes are not (yet) |
| * considered API and should be relied on for debugging. |
| */ |
| EseAppResult ese_boot_carrier_lock_test(struct EseBootSession *session, const uint8_t *testdata, uint16_t len); |
| |
| /** |
| * Transitions the applet from "factory" mode to "production" mode. |
| * This can only be done if the bootloader gpio has not been cleared. |
| * |
| * When not in production mode, the applet will ignore the bootloader gpio |
| * and allow for all the locks to be provisioned. Once |mode| is set |
| * to true, LOCK_CARRIER can not be "lock"ed once cleared and any locks |
| * that depend on being in the bootloader (gpio not cleared) will respect |
| * that value. |
| */ |
| EseAppResult ese_boot_set_production(struct EseBootSession *session, bool production_mode); |
| |
| /** |
| * Debugging helper that emits the internal value of production, bootloader gpio, |
| * and lock initialization and storage. It is not insecure in the field, but |
| * it is not expected to be needed during normal operation. |
| */ |
| EseAppResult ese_boot_get_state(struct EseBootSession *session, uint8_t *state, uint16_t maxSize); |
| |
| /** |
| * Stores |value| in the specified |slot| in the applet. |
| * |
| * @returns ESE_APP_RESULT_OK on success |
| */ |
| EseAppResult ese_boot_rollback_index_write(struct EseBootSession *session, uint8_t slot, uint64_t value); |
| |
| /** |
| * Reads a uint64_t from |slot| into |value|. |
| * |
| * @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 |
| |
| #endif /* ESE_APP_BOOT_H_ */ |