/*
* 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_ */