diff options
Diffstat (limited to 'gatekeeperd')
-rw-r--r-- | gatekeeperd/Android.mk | 29 | ||||
-rw-r--r-- | gatekeeperd/IGateKeeperService.cpp | 124 | ||||
-rw-r--r-- | gatekeeperd/IGateKeeperService.h | 80 | ||||
-rw-r--r-- | gatekeeperd/gatekeeperd.cpp | 164 |
4 files changed, 397 insertions, 0 deletions
diff --git a/gatekeeperd/Android.mk b/gatekeeperd/Android.mk new file mode 100644 index 0000000..1953672 --- /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 0000000..b1e4811 --- /dev/null +++ b/gatekeeperd/IGateKeeperService.cpp @@ -0,0 +1,124 @@ +/* + * 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; + } + case VERIFY_CHALLENGE: { + CHECK_INTERFACE(IGateKeeperService, data, reply); + uint32_t uid = data.readInt32(); + uint64_t challenge = data.readInt64(); + 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; + + + uint8_t *out = NULL; + uint32_t outSize = 0; + status_t ret = verifyChallenge(uid, challenge, (uint8_t *) currentPasswordHandle, + currentPasswordHandleSize, (uint8_t *) currentPassword, currentPasswordSize, + &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; + } + 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 0000000..10b1b43 --- /dev/null +++ b/gatekeeperd/IGateKeeperService.h @@ -0,0 +1,80 @@ +/* + * 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, + VERIFY_CHALLENGE = IBinder::FIRST_CALL_TRANSACTION + 2, + }; + + // 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; + + /** + * Verifies a password previously enrolled with the GateKeeper. + * Returns 0 on success, negative on failure. + */ + virtual status_t verifyChallenge(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) = 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 0000000..d59e6fe --- /dev/null +++ b/gatekeeperd/gatekeeperd.cpp @@ -0,0 +1,164 @@ +/* + * 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 <keystore/keystore.h> // For error code +#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) { + uint8_t *auth_token; + uint32_t auth_token_length; + return verifyChallenge(uid, 0, enrolled_password_handle, enrolled_password_handle_length, + provided_password, provided_password_length, + &auth_token, &auth_token_length); + } + + virtual status_t verifyChallenge(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) { + 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; + + int ret = device->verify(device, uid, challenge, + 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) { + status_t ret = service->addAuthToken(*auth_token, *auth_token_length); + if (ret != ResponseCode::NO_ERROR) { + ALOGE("Falure sending auth token to KeyStore: %d", ret); + } + } 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; +} |