diff options
author | Andres Morales <anmorales@google.com> | 2015-04-03 16:40:15 -0700 |
---|---|---|
committer | Andres Morales <anmorales@google.com> | 2015-04-08 15:20:22 -0700 |
commit | 2d08dce0beedcfc63b2a837045d1be7d49157555 (patch) | |
tree | 0a74bf6cd5b25138d1fc63ae8c0df389912efb0f /gatekeeperd | |
parent | 56b8a6a59f6e86ba88ede9719e3445e8eb3187ae (diff) | |
download | core-2d08dce0beedcfc63b2a837045d1be7d49157555.tar.gz core-2d08dce0beedcfc63b2a837045d1be7d49157555.tar.bz2 core-2d08dce0beedcfc63b2a837045d1be7d49157555.zip |
GateKeeper proxy service
Until we have SELinux support for gating access
to individual TEE services, we will proxy TEE requests
to GateKeeper via this daemon.
Change-Id: Ifa316b75f75bff79bdae613a112c8c3c2e7189a8
Diffstat (limited to 'gatekeeperd')
-rw-r--r-- | gatekeeperd/Android.mk | 29 | ||||
-rw-r--r-- | gatekeeperd/IGateKeeperService.cpp | 93 | ||||
-rw-r--r-- | gatekeeperd/IGateKeeperService.h | 70 | ||||
-rw-r--r-- | gatekeeperd/gatekeeperd.cpp | 153 |
4 files changed, 345 insertions, 0 deletions
diff --git a/gatekeeperd/Android.mk b/gatekeeperd/Android.mk new file mode 100644 index 000000000..195367241 --- /dev/null +++ b/gatekeeperd/Android.mk @@ -0,0 +1,29 @@ +# +# 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. +# + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_CFLAGS := -Wall -Wextra -Werror -Wunused +LOCAL_SRC_FILES := IGateKeeperService.cpp gatekeeperd.cpp +LOCAL_MODULE := gatekeeperd +LOCAL_SHARED_LIBRARIES := \ + libbinder \ + liblog \ + libhardware \ + libutils \ + libkeystore_binder +include $(BUILD_EXECUTABLE) diff --git a/gatekeeperd/IGateKeeperService.cpp b/gatekeeperd/IGateKeeperService.cpp new file mode 100644 index 000000000..133df4cbd --- /dev/null +++ b/gatekeeperd/IGateKeeperService.cpp @@ -0,0 +1,93 @@ +/* + * Copyright 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 "GateKeeperService" +#include <utils/Log.h> + +#include "IGateKeeperService.h" + +namespace android { + +const android::String16 IGateKeeperService::descriptor("android.service.gatekeeper.IGateKeeperService"); +const android::String16& IGateKeeperService::getInterfaceDescriptor() const { + return IGateKeeperService::descriptor; +} + +status_t BnGateKeeperService::onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { + switch(code) { + case ENROLL: { + CHECK_INTERFACE(IGateKeeperService, data, reply); + uint32_t uid = data.readInt32(); + + ssize_t currentPasswordHandleSize = data.readInt32(); + const uint8_t *currentPasswordHandle = + static_cast<const uint8_t *>(data.readInplace(currentPasswordHandleSize)); + if (!currentPasswordHandle) currentPasswordHandleSize = 0; + + ssize_t currentPasswordSize = data.readInt32(); + const uint8_t *currentPassword = + static_cast<const uint8_t *>(data.readInplace(currentPasswordSize)); + if (!currentPassword) currentPasswordSize = 0; + + ssize_t desiredPasswordSize = data.readInt32(); + const uint8_t *desiredPassword = + static_cast<const uint8_t *>(data.readInplace(desiredPasswordSize)); + if (!desiredPassword) desiredPasswordSize = 0; + + uint8_t *out = NULL; + uint32_t outSize = 0; + status_t ret = enroll(uid, currentPasswordHandle, currentPasswordHandleSize, + currentPassword, currentPasswordSize, desiredPassword, + desiredPasswordSize, &out, &outSize); + + reply->writeNoException(); + if (ret == NO_ERROR && outSize > 0 && out != NULL) { + reply->writeInt32(outSize); + void *buf = reply->writeInplace(outSize); + memcpy(buf, out, outSize); + free(out); + } else { + reply->writeInt32(-1); + } + return NO_ERROR; + } + case VERIFY: { + CHECK_INTERFACE(IGateKeeperService, data, reply); + uint32_t uid = data.readInt32(); + ssize_t currentPasswordHandleSize = data.readInt32(); + const uint8_t *currentPasswordHandle = + static_cast<const uint8_t *>(data.readInplace(currentPasswordHandleSize)); + if (!currentPasswordHandle) currentPasswordHandleSize = 0; + + ssize_t currentPasswordSize = data.readInt32(); + const uint8_t *currentPassword = + static_cast<const uint8_t *>(data.readInplace(currentPasswordSize)); + if (!currentPassword) currentPasswordSize = 0; + + status_t ret = verify(uid, (uint8_t *) currentPasswordHandle, currentPasswordHandleSize, + (uint8_t *) currentPassword, currentPasswordSize); + reply->writeNoException(); + reply->writeInt32(ret == NO_ERROR ? 1 : 0); + return NO_ERROR; + } + default: + return BBinder::onTransact(code, data, reply, flags); + } +}; + + +}; // namespace android diff --git a/gatekeeperd/IGateKeeperService.h b/gatekeeperd/IGateKeeperService.h new file mode 100644 index 000000000..7d8572cec --- /dev/null +++ b/gatekeeperd/IGateKeeperService.h @@ -0,0 +1,70 @@ +/* + * 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. + */ + +#ifndef IGATEKEEPER_SERVICE_H_ +#define IGATEKEEPER_SERVICE_H_ + +#include <binder/IInterface.h> +#include <binder/Parcel.h> + +namespace android { + +/* + * This must be kept manually in sync with frameworks/base's IGateKeeperService.aidl + */ +class IGateKeeperService : public IInterface { +public: + enum { + ENROLL = IBinder::FIRST_CALL_TRANSACTION + 0, + VERIFY = IBinder::FIRST_CALL_TRANSACTION + 1, + }; + + // DECLARE_META_INTERFACE - C++ client interface not needed + static const android::String16 descriptor; + virtual const android::String16& getInterfaceDescriptor() const; + IGateKeeperService() {} + virtual ~IGateKeeperService() {} + + /** + * Enrolls a password with the GateKeeper. Returns 0 on success, negative on failure. + */ + virtual status_t 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) = 0; + + /** + * Verifies a password previously enrolled with the GateKeeper. + * Returns 0 on success, negative on failure. + */ + virtual status_t verify(uint32_t uid, + const uint8_t *enrolled_password_handle, uint32_t enrolled_password_handle_length, + const uint8_t *provided_password, uint32_t provided_password_length) = 0; +}; + +// ---------------------------------------------------------------------------- + +class BnGateKeeperService: public BnInterface<IGateKeeperService> { +public: + virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, + uint32_t flags = 0); +}; + +} // namespace android + +#endif + diff --git a/gatekeeperd/gatekeeperd.cpp b/gatekeeperd/gatekeeperd.cpp new file mode 100644 index 000000000..492214059 --- /dev/null +++ b/gatekeeperd/gatekeeperd.cpp @@ -0,0 +1,153 @@ +/* + * 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 "gatekeeperd" + +#include "IGateKeeperService.h" + +#include <cutils/log.h> +#include <utils/Log.h> + +#include <binder/IPCThreadState.h> +#include <binder/IServiceManager.h> +#include <binder/PermissionCache.h> +#include <utils/String16.h> + +#include <keystore/IKeystoreService.h> +#include <hardware/gatekeeper.h> + +namespace android { + +static const String16 KEYGUARD_PERMISSION("android.permission.ACCESS_KEYGUARD_SECURE_STORAGE"); +static const String16 DUMP_PERMISSION("android.permission.DUMP"); + +class GateKeeperProxy : public BnGateKeeperService { +public: + GateKeeperProxy() { + int ret = hw_get_module_by_class(GATEKEEPER_HARDWARE_MODULE_ID, NULL, &module); + if (ret < 0) + LOG_ALWAYS_FATAL_IF(ret < 0, "Unable to find GateKeeper HAL"); + ret = gatekeeper_open(module, &device); + if (ret < 0) + LOG_ALWAYS_FATAL_IF(ret < 0, "Unable to open GateKeeper HAL"); + } + + virtual ~GateKeeperProxy() { + gatekeeper_close(device); + } + + virtual status_t 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) { + IPCThreadState* ipc = IPCThreadState::self(); + const int calling_pid = ipc->getCallingPid(); + const int calling_uid = ipc->getCallingUid(); + if (!PermissionCache::checkPermission(KEYGUARD_PERMISSION, calling_pid, calling_uid)) { + return PERMISSION_DENIED; + } + + // need a desired password to enroll + if (desired_password_length == 0) return -EINVAL; + int ret = device->enroll(device, 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); + return ret >= 0 ? NO_ERROR : UNKNOWN_ERROR; + } + + virtual status_t verify(uint32_t uid, + const uint8_t *enrolled_password_handle, uint32_t enrolled_password_handle_length, + const uint8_t *provided_password, uint32_t provided_password_length) { + IPCThreadState* ipc = IPCThreadState::self(); + const int calling_pid = ipc->getCallingPid(); + const int calling_uid = ipc->getCallingUid(); + if (!PermissionCache::checkPermission(KEYGUARD_PERMISSION, calling_pid, calling_uid)) { + return PERMISSION_DENIED; + } + + // can't verify if we're missing either param + if ((enrolled_password_handle_length | provided_password_length) == 0) + return -EINVAL; + + uint8_t *auth_token; + uint32_t auth_token_length; + int ret = device->verify(device, uid, + enrolled_password_handle, enrolled_password_handle_length, + provided_password, provided_password_length, &auth_token, &auth_token_length); + + if (ret >= 0 && auth_token != NULL && auth_token_length > 0) { + // TODO: cache service? + sp<IServiceManager> sm = defaultServiceManager(); + sp<IBinder> binder = sm->getService(String16("android.security.keystore")); + sp<IKeystoreService> service = interface_cast<IKeystoreService>(binder); + if (service != NULL) { + if (service->addAuthToken(auth_token, auth_token_length) != NO_ERROR) { + ALOGE("Falure sending auth token to KeyStore"); + } + } else { + ALOGE("Unable to communicate with KeyStore"); + } + } + + return ret >= 0 ? NO_ERROR : UNKNOWN_ERROR; + } + + virtual status_t dump(int fd, const Vector<String16> &) { + IPCThreadState* ipc = IPCThreadState::self(); + const int pid = ipc->getCallingPid(); + const int uid = ipc->getCallingUid(); + if (!PermissionCache::checkPermission(DUMP_PERMISSION, pid, uid)) { + return PERMISSION_DENIED; + } + + if (device == NULL) { + const char *result = "Device not available"; + write(fd, result, strlen(result) + 1); + } else { + const char *result = "OK"; + write(fd, result, strlen(result) + 1); + } + + return NO_ERROR; + } + +private: + gatekeeper_device_t *device; + const hw_module_t *module; +}; +}// namespace android + +int main() { + ALOGI("Starting gatekeeperd..."); + android::sp<android::IServiceManager> sm = android::defaultServiceManager(); + android::sp<android::GateKeeperProxy> proxy = new android::GateKeeperProxy(); + android::status_t ret = sm->addService( + android::String16("android.service.gatekeeper.IGateKeeperService"), proxy); + if (ret != android::OK) { + ALOGE("Couldn't register binder service!"); + return -1; + } + + /* + * We're the only thread in existence, so we're just going to process + * Binder transaction as a single-threaded program. + */ + android::IPCThreadState::self()->joinThreadPool(); + return 0; +} |