From 586a32fa67a078eddf552c8f50c3ec0d0ecc012a Mon Sep 17 00:00:00 2001 From: Alexey Polyudov Date: Mon, 29 Aug 2016 12:08:44 -0700 Subject: [PATCH] gatekeeper HIDL HAL definition Change-Id: I8224ba28abec42cfaea26b147acbcd1a27e09a9b Signed-off-by: Alexey Polyudov --- gatekeeper/1.0/Android.bp | 53 +++++++ gatekeeper/1.0/IGatekeeper.hal | 108 +++++++++++++ gatekeeper/1.0/default/Android.mk | 40 +++++ gatekeeper/1.0/default/Gatekeeper.cpp | 149 ++++++++++++++++++ gatekeeper/1.0/default/Gatekeeper.h | 57 +++++++ ...android.hardware.gatekeeper@1.0-service.rc | 4 + gatekeeper/1.0/default/service.cpp | 13 ++ gatekeeper/1.0/types.hal | 27 ++++ gatekeeper/Android.bp | 4 + 9 files changed, 455 insertions(+) create mode 100644 gatekeeper/1.0/Android.bp create mode 100644 gatekeeper/1.0/IGatekeeper.hal create mode 100644 gatekeeper/1.0/default/Android.mk create mode 100644 gatekeeper/1.0/default/Gatekeeper.cpp create mode 100644 gatekeeper/1.0/default/Gatekeeper.h create mode 100644 gatekeeper/1.0/default/android.hardware.gatekeeper@1.0-service.rc create mode 100644 gatekeeper/1.0/default/service.cpp create mode 100644 gatekeeper/1.0/types.hal create mode 100644 gatekeeper/Android.bp diff --git a/gatekeeper/1.0/Android.bp b/gatekeeper/1.0/Android.bp new file mode 100644 index 0000000000..76ee27623d --- /dev/null +++ b/gatekeeper/1.0/Android.bp @@ -0,0 +1,53 @@ +// This file is autogenerated by hidl-gen. Do not edit manually. + +genrule { + name: "android.hardware.gatekeeper@1.0_genc++", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces android.hardware.gatekeeper@1.0", + srcs: [ + "types.hal", + "IGatekeeper.hal", + ], + out: [ + "android/hardware/gatekeeper/1.0/types.cpp", + "android/hardware/gatekeeper/1.0/GatekeeperAll.cpp", + ], +} + +genrule { + name: "android.hardware.gatekeeper@1.0_genc++_headers", + tools: ["hidl-gen"], + cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces android.hardware.gatekeeper@1.0", + srcs: [ + "types.hal", + "IGatekeeper.hal", + ], + out: [ + "android/hardware/gatekeeper/1.0/types.h", + "android/hardware/gatekeeper/1.0/IGatekeeper.h", + "android/hardware/gatekeeper/1.0/IHwGatekeeper.h", + "android/hardware/gatekeeper/1.0/BnGatekeeper.h", + "android/hardware/gatekeeper/1.0/BpGatekeeper.h", + "android/hardware/gatekeeper/1.0/BsGatekeeper.h", + ], +} + +cc_library_shared { + name: "android.hardware.gatekeeper@1.0", + generated_sources: ["android.hardware.gatekeeper@1.0_genc++"], + generated_headers: ["android.hardware.gatekeeper@1.0_genc++_headers"], + export_generated_headers: ["android.hardware.gatekeeper@1.0_genc++_headers"], + shared_libs: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "libutils", + "libcutils", + ], + export_shared_lib_headers: [ + "libhidlbase", + "libhidltransport", + "libhwbinder", + "libutils", + ], +} diff --git a/gatekeeper/1.0/IGatekeeper.hal b/gatekeeper/1.0/IGatekeeper.hal new file mode 100644 index 0000000000..999a311011 --- /dev/null +++ b/gatekeeper/1.0/IGatekeeper.hal @@ -0,0 +1,108 @@ +package android.hardware.gatekeeper@1.0; + +interface IGatekeeper { + +/** + * Enrolls desiredPassword, which may be derived from a user selected pin + * or password, with the private key used only for enrolling authentication + * factor data. + * + * If there was already a password enrolled, current password handle must be + * passed in currentPasswordHandle, and current password must be passed in + * currentPassword. Valid currentPassword must verify() against + * currentPasswordHandle. + * + * @param uid The Android user identifier + * + * @param currentPasswordHandle The currently enrolled password handle the user + * wants to replace. May be empty only if there's no currently enrolled + * password. Otherwise must be non-empty. + * + * @param currentPassword The user's current password in plain text. + * it MUST verify against current_password_handle if the latter is not-empty + * + * @param desiredPassword The new password the user wishes to enroll in + * plaintext. + * + * @return response + * On success, data buffer must contain the new password handle referencing + * the password provided in desiredPassword. + * This buffer can be used on subsequent calls to enroll or + * verify. On error, this buffer must be empty. + * response.code must always contain operation completion status. + * This method may return ERROR_GENERAL_FAILURE or ERROR_RETRY_TIMEOUT on + * failure. It must return STATUS_OK on success. + * If ERROR_RETRY_TIMEOUT is returned, response.timeout must be non-zero. + */ +enroll(uint32_t uid, + vec currentPasswordHandle, + vec currentPassword, + vec desiredPassword) + generates (GatekeeperResponse response); + +/** + * Verifies that providedPassword matches enrolledPasswordHandle. + * + * Implementations of this module may retain the result of this call + * to attest to the recency of authentication. + * + * On success, returns verification token in response.data, which shall be + * usable to attest password verification to other trusted services. + * + * @param uid The Android user identifier + * + * @param challenge An optional challenge to authenticate against, or 0. + * Used when a separate authenticator requests password verification, + * or for transactional password authentication. + * + * @param enrolledPasswordHandle The currently enrolled password handle that + * user wishes to verify against. Must be non-empty. + * + * @param providedPassword The plaintext password to be verified against the + * enrolledPasswordHandle + * + * @return response + * On success, a non-empty data buffer containing the + * authentication token resulting from this verification is returned. + * On error, data buffer must be empty. + * response.code must always contain operation completion status. + * This method may return ERROR_GENERAL_FAILURE or ERROR_RETRY_TIMEOUT on + * failure. It must return STATUS_OK on success. + * If password re-enrollment is necessary, it must return STATUS_REENROLL. + * If ERROR_RETRY_TIMEOUT is returned, response.timeout must be non-zero. + */ +verify(uint32_t uid, uint64_t challenge, + vec enrolledPasswordHandle, + vec providedPassword) + generates (GatekeeperResponse response); + +/* + * Deletes the enrolledPasswordHandle associated with the uid. Once deleted + * the user cannot be verified anymore. + * This is an optional method. + * + * @param uid The Android user identifier + * + * @return response + * response.code must always contain operation completion status. + * This method may return ERROR_GENERAL_FAILURE or ERROR_RETRY_TIMEOUT on + * failure. It must return STATUS_OK on success. + * If not implemented, it must return ERROR_NOT_IMPLEMENTED. + * If ERROR_RETRY_TIMEOUT is returned, response.timeout must be non-zero. + */ +deleteUser(uint32_t uid) generates (GatekeeperResponse response); + +/* + * Deletes all the enrolled_password_handles for all uid's. Once called, + * no users must be enrolled on the device. + * This is an optional method. + * + * @return response + * response.code must always contain operation completion status. + * This method may return ERROR_GENERAL_FAILURE or ERROR_RETRY_TIMEOUT on + * failure. It must return STATUS_OK on success. + * If not implemented, it must return ERROR_NOT_IMPLEMENTED. + * If ERROR_RETRY_TIMEOUT is returned, response.timeout must be non-zero. + */ +deleteAllUsers() generates (GatekeeperResponse response); +}; diff --git a/gatekeeper/1.0/default/Android.mk b/gatekeeper/1.0/default/Android.mk new file mode 100644 index 0000000000..e3b7d10a0e --- /dev/null +++ b/gatekeeper/1.0/default/Android.mk @@ -0,0 +1,40 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE_RELATIVE_PATH := hw +LOCAL_MODULE := android.hardware.gatekeeper@1.0-impl + +LOCAL_SRC_FILES := \ + Gatekeeper.cpp \ + +LOCAL_SHARED_LIBRARIES := \ + android.hardware.gatekeeper@1.0 \ + libhardware \ + libhidlbase \ + libhidltransport \ + libhwbinder \ + libutils \ + liblog \ + +include $(BUILD_SHARED_LIBRARY) + +include $(CLEAR_VARS) + +LOCAL_MODULE_RELATIVE_PATH := hw +LOCAL_MODULE := android.hardware.gatekeeper@1.0-service +LOCAL_INIT_RC := android.hardware.gatekeeper@1.0-service.rc + +LOCAL_SRC_FILES := \ + service.cpp \ + +LOCAL_SHARED_LIBRARIES := \ + android.hardware.gatekeeper@1.0 \ + libhardware \ + libhidlbase \ + libhidltransport \ + libhwbinder \ + libutils \ + liblog \ + +include $(BUILD_EXECUTABLE) diff --git a/gatekeeper/1.0/default/Gatekeeper.cpp b/gatekeeper/1.0/default/Gatekeeper.cpp new file mode 100644 index 0000000000..8fcd8ca4a2 --- /dev/null +++ b/gatekeeper/1.0/default/Gatekeeper.cpp @@ -0,0 +1,149 @@ +#define LOG_TAG "android.hardware.gatekeeper@1.0-service" + +#include +#include + +#include "Gatekeeper.h" + +namespace android { +namespace hardware { +namespace gatekeeper { +namespace V1_0 { +namespace implementation { + +Gatekeeper::Gatekeeper() +{ + int ret = hw_get_module_by_class(GATEKEEPER_HARDWARE_MODULE_ID, NULL, &module); + device = NULL; + + if (!ret) { + ret = gatekeeper_open(module, &device); + } + if (ret < 0) { + LOG_ALWAYS_FATAL_IF(ret < 0, "Unable to open GateKeeper HAL"); + } +} + +Gatekeeper::~Gatekeeper() +{ + if (device != nullptr) { + int ret = gatekeeper_close(device); + if (ret < 0) { + ALOGE("Unable to close GateKeeper HAL"); + } + } + dlclose(module->dso); +} + +// Methods from ::android::hardware::gatekeeper::V1_0::IGatekeeper follow. +Return Gatekeeper::enroll(uint32_t uid, + const hidl_vec& currentPasswordHandle, + const hidl_vec& currentPassword, + const hidl_vec& desiredPassword, + enroll_cb cb) +{ + GatekeeperResponse rsp; + uint8_t *enrolled_password_handle = nullptr; + uint32_t enrolled_password_handle_length = 0; + + int ret = device->enroll(device, uid, + currentPasswordHandle.data(), currentPasswordHandle.size(), + currentPassword.data(), currentPassword.size(), + desiredPassword.data(), desiredPassword.size(), + &enrolled_password_handle, &enrolled_password_handle_length); + if (!ret) { + rsp.data.setToExternal(enrolled_password_handle, + enrolled_password_handle_length, + true); + rsp.code = GatekeeperStatusCode::STATUS_OK; + } else if (ret > 0) { + rsp.timeout = ret; + rsp.code = GatekeeperStatusCode::ERROR_RETRY_TIMEOUT; + } else { + rsp.code = GatekeeperStatusCode::ERROR_GENERAL_FAILURE; + } + cb(rsp); + return Void(); +} + +Return Gatekeeper::verify(uint32_t uid, + uint64_t challenge, + const hidl_vec& enrolledPasswordHandle, + const hidl_vec& providedPassword, + verify_cb cb) +{ + GatekeeperResponse rsp; + uint8_t *auth_token = nullptr; + uint32_t auth_token_length = 0; + bool request_reenroll = false; + + int ret = device->verify(device, uid, challenge, + enrolledPasswordHandle.data(), enrolledPasswordHandle.size(), + providedPassword.data(), providedPassword.size(), + &auth_token, &auth_token_length, + &request_reenroll); + if (!ret) { + rsp.data.setToExternal(auth_token, auth_token_length, true); + if (request_reenroll) { + rsp.code = GatekeeperStatusCode::STATUS_REENROLL; + } else { + rsp.code = GatekeeperStatusCode::STATUS_OK; + } + } else if (ret > 0) { + rsp.timeout = ret; + rsp.code = GatekeeperStatusCode::ERROR_RETRY_TIMEOUT; + } else { + rsp.code = GatekeeperStatusCode::ERROR_GENERAL_FAILURE; + } + cb(rsp); + return Void(); +} + +Return Gatekeeper::deleteUser(uint32_t uid, deleteUser_cb cb) { + GatekeeperResponse rsp; + + if (device->delete_user != nullptr) { + int ret = device->delete_user(device, uid); + if (!ret) { + rsp.code = GatekeeperStatusCode::STATUS_OK; + } else if (ret > 0) { + rsp.timeout = ret; + rsp.code = GatekeeperStatusCode::ERROR_RETRY_TIMEOUT; + } else { + rsp.code = GatekeeperStatusCode::ERROR_GENERAL_FAILURE; + } + } else { + rsp.code = GatekeeperStatusCode::ERROR_NOT_IMPLEMENTED; + } + cb(rsp); + return Void(); +} + +Return Gatekeeper::deleteAllUsers(deleteAllUsers_cb cb) { + GatekeeperResponse rsp; + if (device->delete_all_users != nullptr) { + int ret = device->delete_all_users(device); + if (!ret) { + rsp.code = GatekeeperStatusCode::STATUS_OK; + } else if (ret > 0) { + rsp.timeout = ret; + rsp.code = GatekeeperStatusCode::ERROR_RETRY_TIMEOUT; + } else { + rsp.code = GatekeeperStatusCode::ERROR_GENERAL_FAILURE; + } + } else { + rsp.code = GatekeeperStatusCode::ERROR_NOT_IMPLEMENTED; + } + cb(rsp); + return Void(); +} + +IGatekeeper* HIDL_FETCH_IGatekeeper(const char* /* name */) { + return new Gatekeeper(); +} + +} // namespace implementation +} // namespace V1_0 +} // namespace gatekeeper +} // namespace hardware +} // namespace android diff --git a/gatekeeper/1.0/default/Gatekeeper.h b/gatekeeper/1.0/default/Gatekeeper.h new file mode 100644 index 0000000000..a2188d4e8d --- /dev/null +++ b/gatekeeper/1.0/default/Gatekeeper.h @@ -0,0 +1,57 @@ +#ifndef HIDL_GENERATED_android_hardware_gatekeeper_V1_0_Gatekeeper_H_ +#define HIDL_GENERATED_android_hardware_gatekeeper_V1_0_Gatekeeper_H_ + +#include +#include + +#include + +#include +#include + +namespace android { +namespace hardware { +namespace gatekeeper { +namespace V1_0 { +namespace implementation { + +using ::android::hardware::gatekeeper::V1_0::GatekeeperResponse; +using ::android::hardware::gatekeeper::V1_0::IGatekeeper; +using ::android::hardware::Return; +using ::android::hardware::Void; +using ::android::hardware::hidl_vec; +using ::android::hardware::hidl_string; +using ::android::sp; + +class Gatekeeper : public IGatekeeper { +public: + Gatekeeper(); + ~Gatekeeper(); + + // Methods from ::android::hardware::gatekeeper::V1_0::IGatekeeper follow. + Return enroll(uint32_t uid, + const hidl_vec& currentPasswordHandle, + const hidl_vec& currentPassword, + const hidl_vec& desiredPassword, + enroll_cb _hidl_cb) override; + Return verify(uint32_t uid, + uint64_t challenge, + const hidl_vec& enrolledPasswordHandle, + const hidl_vec& providedPassword, + verify_cb _hidl_cb) override; + Return deleteUser(uint32_t uid, deleteUser_cb _hidl_cb) override; + Return deleteAllUsers(deleteAllUsers_cb _hidl_cb) override; +private: + gatekeeper_device_t *device; + const hw_module_t *module; +}; + +extern "C" IGatekeeper* HIDL_FETCH_IGatekeeper(const char* name); + +} // namespace implementation +} // namespace V1_0 +} // namespace gatekeeper +} // namespace hardware +} // namespace android + +#endif // HIDL_GENERATED_android_hardware_gatekeeper_V1_0_Gatekeeper_H_ diff --git a/gatekeeper/1.0/default/android.hardware.gatekeeper@1.0-service.rc b/gatekeeper/1.0/default/android.hardware.gatekeeper@1.0-service.rc new file mode 100644 index 0000000000..ac15e23815 --- /dev/null +++ b/gatekeeper/1.0/default/android.hardware.gatekeeper@1.0-service.rc @@ -0,0 +1,4 @@ +service gatekeeper-1-0 /system/bin/hw/android.hardware.gatekeeper@1.0-service + class hal + user system + group system diff --git a/gatekeeper/1.0/default/service.cpp b/gatekeeper/1.0/default/service.cpp new file mode 100644 index 0000000000..c3fc25c340 --- /dev/null +++ b/gatekeeper/1.0/default/service.cpp @@ -0,0 +1,13 @@ +#define LOG_TAG "android.hardware.gatekeeper@1.0-service" + +#include + +#include + +// Generated HIDL files +using android::hardware::gatekeeper::V1_0::IGatekeeper; +using android::hardware::defaultPassthroughServiceImplementation; + +int main() { + return defaultPassthroughServiceImplementation("gatekeeper"); +} diff --git a/gatekeeper/1.0/types.hal b/gatekeeper/1.0/types.hal new file mode 100644 index 0000000000..9ab11521bb --- /dev/null +++ b/gatekeeper/1.0/types.hal @@ -0,0 +1,27 @@ +package android.hardware.gatekeeper@1.0; + +/** + * Gatekeeper response codes; success >= 0; error < 0 + */ +enum GatekeeperStatusCode : int32_t { + STATUS_REENROLL = 1, // success, but upper layers should re-enroll + // the verified password due to a version change + STATUS_OK = 0, // operation is successful + ERROR_GENERAL_FAILURE = -1, // operation failed + ERROR_RETRY_TIMEOUT = -2, // operation should be retried after timeout + ERROR_NOT_IMPLEMENTED = -3, // operation is not implemented +}; + +/** + * Gatekeeper response to any/all requests has this structure as mandatory part + */ +struct GatekeeperResponse { + /* request completion status */ + GatekeeperStatusCode code; + /* retry timeout in ms, if code == ERROR_RETRY_TIMEOUT + * otherwise unused (0) + */ + uint32_t timeout; + /* optional crypto blob */ + vec data; +}; diff --git a/gatekeeper/Android.bp b/gatekeeper/Android.bp new file mode 100644 index 0000000000..bbb3e4bac0 --- /dev/null +++ b/gatekeeper/Android.bp @@ -0,0 +1,4 @@ +// This is an autogenerated file, do not edit. +subdirs = [ + "1.0", +]