From c029e9fb2ea8d2bf8d5bf3db9c3a2fc4ae8c5eaf Mon Sep 17 00:00:00 2001 From: Tellen Yu Date: Tue, 29 Aug 2017 11:38:44 +0000 Subject: hidl: add gatekeeper binderized [5/6] PD# NONE add binderized gatekeeper hal to system Change-Id: I2b707c2f16b3dffb1f86d7d04541a60320d5e55d --- diff --git a/Android.mk b/Android.mk new file mode 100644 index 0000000..ad5ca02 --- a/dev/null +++ b/Android.mk @@ -0,0 +1,46 @@ +# +# Copyright (C) 2015 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. +# + +# WARNING: Everything listed here will be built on ALL platforms, +# including x86, the emulator, and the SDK. Modules must be uniquely +# named (liblights.panda), and must build everywhere, or limit themselves +# to only building on ARM if they include assembly. Individual makefiles +# are responsible for having their own logic, for fine-grained control. + +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := gatekeeper.amlogic + +LOCAL_MODULE_RELATIVE_PATH := hw + +LOCAL_SRC_FILES := \ + module.cpp \ + trusty_gatekeeper_ipc.c \ + trusty_gatekeeper.cpp + +LOCAL_CLFAGS = -fvisibility=hidden -Wall -Werror + +LOCAL_SHARED_LIBRARIES := \ + libgatekeeper \ + liblog \ + libcutils \ + libtrusty + +LOCAL_MODULE_TAGS := optional + +include $(BUILD_SHARED_LIBRARY) diff --git a/gatekeeper_ipc.h b/gatekeeper_ipc.h new file mode 100644 index 0000000..b05dcd8 --- a/dev/null +++ b/gatekeeper_ipc.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2015 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. + */ + +#pragma once + +#define GATEKEEPER_PORT "com.android.trusty.gatekeeper" +#define GATEKEEPER_MAX_BUFFER_LENGTH 1024 + +enum gatekeeper_command { + GK_REQ_SHIFT = 1, + GK_RESP_BIT = 1, + + GK_ENROLL = (0 << GK_REQ_SHIFT), + GK_VERIFY = (1 << GK_REQ_SHIFT), +}; + +/** + * gatekeeper_message - Serial header for communicating with GK server + * @cmd: the command, one of ENROLL, VERIFY. Payload must be a serialized + * buffer of the corresponding request object. + * @payload: start of the serialized command specific payload + */ +struct gatekeeper_message { + uint32_t cmd; + uint8_t payload[0]; +}; + diff --git a/module.cpp b/module.cpp new file mode 100644 index 0000000..0ee3c2f --- a/dev/null +++ b/module.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2015 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. + */ + +#include + +#include +#include +#include + +#include "trusty_gatekeeper.h" + +using gatekeeper::TrustyGateKeeperDevice; + +static int trusty_gatekeeper_open(const hw_module_t *module, const char *name, + hw_device_t **device) { + + if (strcmp(name, HARDWARE_GATEKEEPER) != 0) { + return -EINVAL; + } + + TrustyGateKeeperDevice *gatekeeper = new TrustyGateKeeperDevice(module); + if (gatekeeper == NULL) return -ENOMEM; + *device = gatekeeper->hw_device(); + + return 0; +} + +static struct hw_module_methods_t gatekeeper_module_methods = { + .open = trusty_gatekeeper_open, +}; + +struct gatekeeper_module HAL_MODULE_INFO_SYM __attribute__((visibility("default"))) = { + .common = { + .tag = HARDWARE_MODULE_TAG, + .module_api_version = GATEKEEPER_MODULE_API_VERSION_0_1, + .hal_api_version = HARDWARE_HAL_API_VERSION, + .id = GATEKEEPER_HARDWARE_MODULE_ID, + .name = "Trusty GateKeeper HAL", + .author = "The Android Open Source Project", + .methods = &gatekeeper_module_methods, + .dso = 0, + .reserved = {} + }, +}; diff --git a/trusty_gatekeeper.cpp b/trusty_gatekeeper.cpp new file mode 100644 index 0000000..b3fbfa9 --- a/dev/null +++ b/trusty_gatekeeper.cpp @@ -0,0 +1,232 @@ +/* + * Copyright (C) 2015 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. + */ + +#define LOG_TAG "TrustyGateKeeper" + +#include +#include +#include + +#include + +#include + +#include "trusty_gatekeeper.h" +#include "trusty_gatekeeper_ipc.h" +#include "gatekeeper_ipc.h" + +namespace gatekeeper { + +const uint32_t SEND_BUF_SIZE = 8192; +const uint32_t RECV_BUF_SIZE = 8192; + +TrustyGateKeeperDevice::TrustyGateKeeperDevice(const hw_module_t *module) { +#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) + static_assert(std::is_standard_layout::value, + "TrustyGateKeeperDevice must be standard layout"); + static_assert(offsetof(TrustyGateKeeperDevice, device_) == 0, + "device_ must be the first member of TrustyGateKeeperDevice"); + static_assert(offsetof(TrustyGateKeeperDevice, device_.common) == 0, + "common must be the first member of gatekeeper_device"); +#else + assert(reinterpret_cast(this) == &device_); + assert(reinterpret_cast(this) == &(device_.common)); +#endif + + memset(&device_, 0, sizeof(device_)); + device_.common.tag = HARDWARE_DEVICE_TAG; + device_.common.version = 1; + device_.common.module = const_cast(module); + device_.common.close = close_device; + + device_.enroll = enroll; + device_.verify = verify; + device_.delete_user = nullptr; + device_.delete_all_users = nullptr; + + int rc = trusty_gatekeeper_connect(); + if (rc < 0) { + ALOGE("Error initializing trusty session: %d", rc); + } + + error_ = rc; + +} + +hw_device_t* TrustyGateKeeperDevice::hw_device() { + return &device_.common; +} + +int TrustyGateKeeperDevice::close_device(hw_device_t* dev) { + delete reinterpret_cast(dev); + return 0; +} + +TrustyGateKeeperDevice::~TrustyGateKeeperDevice() { + trusty_gatekeeper_disconnect(); +} + +int TrustyGateKeeperDevice::Enroll(uint32_t uid, const uint8_t *current_password_handle, + uint32_t current_password_handle_length, const uint8_t *current_password, + uint32_t current_password_length, const uint8_t *desired_password, + uint32_t desired_password_length, uint8_t **enrolled_password_handle, + uint32_t *enrolled_password_handle_length) { + + if (error_ != 0) { + return error_; + } + + SizedBuffer desired_password_buffer(desired_password_length); + memcpy(desired_password_buffer.buffer.get(), desired_password, desired_password_length); + + SizedBuffer current_password_handle_buffer(current_password_handle_length); + if (current_password_handle) { + memcpy(current_password_handle_buffer.buffer.get(), current_password_handle, + current_password_handle_length); + } + + SizedBuffer current_password_buffer(current_password_length); + if (current_password) { + memcpy(current_password_buffer.buffer.get(), current_password, current_password_length); + } + + EnrollRequest request(uid, ¤t_password_handle_buffer, &desired_password_buffer, + ¤t_password_buffer); + EnrollResponse response; + + gatekeeper_error_t error = Send(request, &response); + + if (error == ERROR_RETRY) { + return response.retry_timeout; + } else if (error != ERROR_NONE) { + return -EINVAL; + } + + *enrolled_password_handle = response.enrolled_password_handle.buffer.release(); + *enrolled_password_handle_length = response.enrolled_password_handle.length; + + + return 0; +} + +int TrustyGateKeeperDevice::Verify(uint32_t uid, uint64_t challenge, + const uint8_t *enrolled_password_handle, uint32_t enrolled_password_handle_length, + const uint8_t *provided_password, uint32_t provided_password_length, + uint8_t **auth_token, uint32_t *auth_token_length, bool *request_reenroll) { + if (error_ != 0) { + return error_; + } + + SizedBuffer password_handle_buffer(enrolled_password_handle_length); + memcpy(password_handle_buffer.buffer.get(), enrolled_password_handle, + enrolled_password_handle_length); + SizedBuffer provided_password_buffer(provided_password_length); + memcpy(provided_password_buffer.buffer.get(), provided_password, provided_password_length); + + VerifyRequest request(uid, challenge, &password_handle_buffer, &provided_password_buffer); + VerifyResponse response; + + gatekeeper_error_t error = Send(request, &response); + + if (error == ERROR_RETRY) { + return response.retry_timeout; + } else if (error != ERROR_NONE) { + return -EINVAL; + } + + if (auth_token != NULL && auth_token_length != NULL) { + *auth_token = response.auth_token.buffer.release(); + *auth_token_length = response.auth_token.length; + } + + if (request_reenroll != NULL) { + *request_reenroll = response.request_reenroll; + } + + return 0; +} + +gatekeeper_error_t TrustyGateKeeperDevice::Send(uint32_t command, const GateKeeperMessage& request, + GateKeeperMessage *response) { + uint32_t request_size = request.GetSerializedSize(); + if (request_size > SEND_BUF_SIZE) + return ERROR_INVALID; + uint8_t send_buf[SEND_BUF_SIZE]; + request.Serialize(send_buf, send_buf + request_size); + + // Send it + uint8_t recv_buf[RECV_BUF_SIZE]; + uint32_t response_size = RECV_BUF_SIZE; + int rc = trusty_gatekeeper_call(command, send_buf, request_size, recv_buf, &response_size); + if (rc < 0) { + ALOGE("error (%d) calling gatekeeper TA", rc); + return ERROR_INVALID; + } + + const gatekeeper_message *msg = reinterpret_cast(recv_buf); + const uint8_t *payload = msg->payload; + + return response->Deserialize(payload, payload + response_size); +} + +static inline TrustyGateKeeperDevice *convert_device(const gatekeeper_device *dev) { + return reinterpret_cast(const_cast(dev)); +} + +/* static */ +int TrustyGateKeeperDevice::enroll(const struct gatekeeper_device *dev, uint32_t uid, + const uint8_t *current_password_handle, uint32_t current_password_handle_length, + const uint8_t *current_password, uint32_t current_password_length, + const uint8_t *desired_password, uint32_t desired_password_length, + uint8_t **enrolled_password_handle, uint32_t *enrolled_password_handle_length) { + + if (dev == NULL || + enrolled_password_handle == NULL || enrolled_password_handle_length == NULL || + desired_password == NULL || desired_password_length == 0) + return -EINVAL; + + // Current password and current password handle go together + if (current_password_handle == NULL || current_password_handle_length == 0 || + current_password == NULL || current_password_length == 0) { + current_password_handle = NULL; + current_password_handle_length = 0; + current_password = NULL; + current_password_length = 0; + } + + return convert_device(dev)->Enroll(uid, current_password_handle, current_password_handle_length, + current_password, current_password_length, desired_password, desired_password_length, + enrolled_password_handle, enrolled_password_handle_length); + +} + +/* static */ +int TrustyGateKeeperDevice::verify(const struct gatekeeper_device *dev, uint32_t uid, + uint64_t challenge, const uint8_t *enrolled_password_handle, + uint32_t enrolled_password_handle_length, const uint8_t *provided_password, + uint32_t provided_password_length, uint8_t **auth_token, uint32_t *auth_token_length, + bool *request_reenroll) { + + if (dev == NULL || enrolled_password_handle == NULL || + provided_password == NULL) { + return -EINVAL; + } + + return convert_device(dev)->Verify(uid, challenge, enrolled_password_handle, + enrolled_password_handle_length, provided_password, provided_password_length, + auth_token, auth_token_length, request_reenroll); +} +}; diff --git a/trusty_gatekeeper.h b/trusty_gatekeeper.h new file mode 100644 index 0000000..2becc49 --- a/dev/null +++ b/trusty_gatekeeper.h @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2014 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. + */ + +#ifndef TRUSTY_GATEKEEPER_H +#define TRUSTY_GATEKEEPER_H + +#include +#include + +#include "gatekeeper_ipc.h" + +namespace gatekeeper { + +class TrustyGateKeeperDevice { + public: + + explicit TrustyGateKeeperDevice(const hw_module_t* module); + ~TrustyGateKeeperDevice(); + + hw_device_t* hw_device(); + + /** + * Enrolls password_payload, which should be derived from a user selected pin or password, + * with the authentication factor private key used only for enrolling authentication + * factor data. + * + * Returns: 0 on success or an error code less than 0 on error. + * On error, enrolled_password will not be allocated. + */ + int Enroll(uint32_t uid, const uint8_t *current_password_handle, + uint32_t current_password_handle_length, const uint8_t *current_password, + uint32_t current_password_length, const uint8_t *desired_password, + uint32_t desired_password_length, uint8_t **enrolled_password_handle, + uint32_t *enrolled_password_handle_length); + + /** + * Verifies provided_password matches expected_password after enrolling + * with the authentication factor private key. + * + * Implementations of this module may retain the result of this call + * to attest to the recency of authentication. + * + * On success, writes the address of a verification token to verification_token, + * + * Returns: 0 on success or an error code less than 0 on error + * On error, verification token will not be allocated + */ + int Verify(uint32_t uid, uint64_t challenge, const uint8_t *enrolled_password_handle, + uint32_t enrolled_password_handle_length, const uint8_t *provided_password, + uint32_t provided_password_length, uint8_t **auth_token, uint32_t *auth_token_length, + bool *request_reenroll); + + private: + + gatekeeper_error_t Send(uint32_t command, const GateKeeperMessage& request, + GateKeeperMessage* response); + + gatekeeper_error_t Send(const EnrollRequest& request, EnrollResponse *response) { + return Send(GK_ENROLL, request, response); + } + + gatekeeper_error_t Send(const VerifyRequest& request, VerifyResponse *response) { + return Send(GK_VERIFY, request, response); + } + + // Static methods interfacing the HAL API with the TrustyGateKeeper device + + /** + * Enrolls desired_password, which should be derived from a user selected pin or password, + * with the authentication factor private key used only for enrolling authentication + * factor data. + * + * If there was already a password enrolled, it should be provided in + * current_password_handle, along with the current password in current_password + * that should validate against current_password_handle. + * + * Returns: 0 on success or an error code less than 0 on error. + * On error, enrolled_password_handle will not be allocated. + */ + static int enroll(const struct gatekeeper_device *dev, uint32_t uid, + const uint8_t *current_password_handle, uint32_t current_password_handle_length, + const uint8_t *current_password, uint32_t current_password_length, + const uint8_t *desired_password, uint32_t desired_password_length, + uint8_t **enrolled_password_handle, uint32_t *enrolled_password_handle_length); + + /** + * Verifies provided_password matches enrolled_password_handle. + * + * Implementations of this module may retain the result of this call + * to attest to the recency of authentication. + * + * On success, writes the address of a verification token to auth_token, + * usable to attest password verification to other trusted services. Clients + * may pass NULL for this value. + * + * Returns: 0 on success or an error code less than 0 on error + * On error, verification token will not be allocated + */ + static int verify(const struct gatekeeper_device *dev, uint32_t uid, uint64_t challenge, + const uint8_t *enrolled_password_handle, uint32_t enrolled_password_handle_length, + const uint8_t *provided_password, uint32_t provided_password_length, + uint8_t **auth_token, uint32_t *auth_token_length, bool *request_reenroll); + + static int close_device(hw_device_t* dev); + + gatekeeper_device device_; + int error_; + +}; +} + +#endif + diff --git a/trusty_gatekeeper_ipc.c b/trusty_gatekeeper_ipc.c new file mode 100644 index 0000000..f67944b --- a/dev/null +++ b/trusty_gatekeeper_ipc.c @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2015 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. + */ + +#define LOG_TAG "TrustyGateKeeper" + +#include +#include +#include +#include +#include + +#include +#include + +#include "trusty_gatekeeper_ipc.h" +#include "gatekeeper_ipc.h" + +#define TRUSTY_DEVICE_NAME "/dev/trusty-ipc-dev0" + +static int handle_ = 0; + +int trusty_gatekeeper_connect() { + int rc = tipc_connect(TRUSTY_DEVICE_NAME, GATEKEEPER_PORT); + if (rc < 0) { + return rc; + } + + handle_ = rc; + return 0; +} + +int trusty_gatekeeper_call(uint32_t cmd, void *in, uint32_t in_size, uint8_t *out, + uint32_t *out_size) { + if (handle_ == 0) { + ALOGE("not connected\n"); + return -EINVAL; + } + + size_t msg_size = in_size + sizeof(struct gatekeeper_message); + struct gatekeeper_message *msg = malloc(msg_size); + msg->cmd = cmd; + memcpy(msg->payload, in, in_size); + + ssize_t rc = write(handle_, msg, msg_size); + free(msg); + + if (rc < 0) { + ALOGE("failed to send cmd (%d) to %s: %s\n", cmd, + GATEKEEPER_PORT, strerror(errno)); + return -errno; + } + + rc = read(handle_, out, *out_size); + if (rc < 0) { + ALOGE("failed to retrieve response for cmd (%d) to %s: %s\n", + cmd, GATEKEEPER_PORT, strerror(errno)); + return -errno; + } + + if ((size_t) rc < sizeof(struct gatekeeper_message)) { + ALOGE("invalid response size (%d)\n", (int) rc); + return -EINVAL; + } + + msg = (struct gatekeeper_message *) out; + + if ((cmd | GK_RESP_BIT) != msg->cmd) { + ALOGE("invalid command (%d)\n", msg->cmd); + return -EINVAL; + } + + *out_size = ((size_t) rc) - sizeof(struct gatekeeper_message); + return rc; +} + +void trusty_gatekeeper_disconnect() { + if (handle_ != 0) { + tipc_close(handle_); + } +} + diff --git a/trusty_gatekeeper_ipc.h b/trusty_gatekeeper_ipc.h new file mode 100644 index 0000000..f8de7f8 --- a/dev/null +++ b/trusty_gatekeeper_ipc.h @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2015 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. + */ + +__BEGIN_DECLS + +int trusty_gatekeeper_connect(); +int trusty_gatekeeper_call(uint32_t cmd, void *in, uint32_t in_size, uint8_t *out, + uint32_t *out_size); +void trusty_gatekeeper_disconnect(); + +__END_DECLS -- cgit