From 3a1eb672c5ad80fa7023763ab36499d82744ef22 Mon Sep 17 00:00:00 2001 From: Janis Danisevskis Date: Fri, 29 Mar 2019 11:14:31 -0700 Subject: [PATCH] Gatekeeperd maintenance * Move gatekeeper aidl definition to system/core/gatekeeperd * Retire hand written IGateKeeperService and use generated instead * Adjust gatekeeperd to use the generated aidl stubs. * Annotated enroll parameters with @nullable to match the documentation and the way it was used. (The hand written code was tolerant to null parameters, but it was undefined behavior.) * Removed Software implementation from gatekeeperd. * Also removed the upgrade path. * Software implementation including test moved to hardware/interfaces/gatekeeper/1.0/software Change-Id: I72b734db6f67b79b29c2629764490d75d179908a Merged-In: I72b734db6f67b79b29c2629764490d75d179908a Test: Manually tested setting pin and login. --- gatekeeperd/Android.bp | 37 ++- gatekeeperd/GateKeeperResponse.cpp | 83 +++++ gatekeeperd/IGateKeeperService.cpp | 173 ---------- gatekeeperd/IGateKeeperService.h | 118 ------- gatekeeperd/SoftGateKeeper.h | 182 ---------- gatekeeperd/SoftGateKeeperDevice.cpp | 110 ------ gatekeeperd/SoftGateKeeperDevice.h | 76 ----- .../gatekeeper/GateKeeperResponse.aidl | 24 ++ .../gatekeeper/IGateKeeperService.aidl | 87 +++++ gatekeeperd/gatekeeperd.cpp | 314 ++++++++---------- .../include/gatekeeper/GateKeeperResponse.h | 85 +++++ gatekeeperd/tests/Android.bp | 34 -- gatekeeperd/tests/gatekeeper_test.cpp | 204 ------------ 13 files changed, 454 insertions(+), 1073 deletions(-) create mode 100644 gatekeeperd/GateKeeperResponse.cpp delete mode 100644 gatekeeperd/IGateKeeperService.cpp delete mode 100644 gatekeeperd/IGateKeeperService.h delete mode 100644 gatekeeperd/SoftGateKeeper.h delete mode 100644 gatekeeperd/SoftGateKeeperDevice.cpp delete mode 100644 gatekeeperd/SoftGateKeeperDevice.h create mode 100644 gatekeeperd/binder/android/service/gatekeeper/GateKeeperResponse.aidl create mode 100644 gatekeeperd/binder/android/service/gatekeeper/IGateKeeperService.aidl create mode 100644 gatekeeperd/include/gatekeeper/GateKeeperResponse.h delete mode 100644 gatekeeperd/tests/Android.bp delete mode 100644 gatekeeperd/tests/gatekeeper_test.cpp diff --git a/gatekeeperd/Android.bp b/gatekeeperd/Android.bp index 2b7db79c3..778e08c99 100644 --- a/gatekeeperd/Android.bp +++ b/gatekeeperd/Android.bp @@ -23,8 +23,6 @@ cc_binary { "-Wunused", ], srcs: [ - "SoftGateKeeperDevice.cpp", - "IGateKeeperService.cpp", "gatekeeperd.cpp", ], @@ -43,9 +41,44 @@ cc_binary { "libhidltransport", "libhwbinder", "android.hardware.gatekeeper@1.0", + "libgatekeeper_aidl", ], static_libs: ["libscrypt_static"], include_dirs: ["external/scrypt/lib/crypto"], init_rc: ["gatekeeperd.rc"], } + +filegroup { + name: "gatekeeper_aidl", + srcs: [ + "binder/android/service/gatekeeper/IGateKeeperService.aidl", + ], + path: "binder", +} + +cc_library_shared { + name: "libgatekeeper_aidl", + srcs: [ + ":gatekeeper_aidl", + "GateKeeperResponse.cpp", + ], + aidl: { + export_aidl_headers: true, + include_dirs: [ + "system/core/gatekeeperd/binder", + "frameworks/base/core/java/", + ], + }, + export_include_dirs: ["include"], + shared_libs: [ + "libbase", + "libbinder", + "libcutils", + "liblog", + "libutils", + ], + export_shared_lib_headers: [ + "libbinder", + ], +} diff --git a/gatekeeperd/GateKeeperResponse.cpp b/gatekeeperd/GateKeeperResponse.cpp new file mode 100644 index 000000000..ca0c98fe5 --- /dev/null +++ b/gatekeeperd/GateKeeperResponse.cpp @@ -0,0 +1,83 @@ +/* +** +** Copyright 2019, 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 + +#include + +#include + +namespace android { +namespace service { +namespace gatekeeper { + +status_t GateKeeperResponse::readFromParcel(const Parcel* in) { + if (in == nullptr) { + LOG(ERROR) << "readFromParcel got null in parameter"; + return BAD_VALUE; + } + timeout_ = 0; + should_reenroll_ = false; + payload_ = {}; + response_code_ = ResponseCode(in->readInt32()); + if (response_code_ == ResponseCode::OK) { + should_reenroll_ = in->readInt32(); + ssize_t length = in->readInt32(); + if (length > 0) { + length = in->readInt32(); + const uint8_t* buf = reinterpret_cast(in->readInplace(length)); + if (buf == nullptr) { + LOG(ERROR) << "readInplace returned null buffer for length " << length; + return BAD_VALUE; + } + payload_.resize(length); + std::copy(buf, buf + length, payload_.data()); + } + } else if (response_code_ == ResponseCode::RETRY) { + timeout_ = in->readInt32(); + } + return NO_ERROR; +} +status_t GateKeeperResponse::writeToParcel(Parcel* out) const { + if (out == nullptr) { + LOG(ERROR) << "writeToParcel got null out parameter"; + return BAD_VALUE; + } + out->writeInt32(int32_t(response_code_)); + if (response_code_ == ResponseCode::OK) { + out->writeInt32(should_reenroll_); + out->writeInt32(payload_.size()); + if (payload_.size() != 0) { + out->writeInt32(payload_.size()); + uint8_t* buf = reinterpret_cast(out->writeInplace(payload_.size())); + if (buf == nullptr) { + LOG(ERROR) << "writeInplace returned null buffer for length " << payload_.size(); + return BAD_VALUE; + } + std::copy(payload_.begin(), payload_.end(), buf); + } + } else if (response_code_ == ResponseCode::RETRY) { + out->writeInt32(timeout_); + } + return NO_ERROR; +} + +} // namespace gatekeeper +} // namespace service +} // namespace android diff --git a/gatekeeperd/IGateKeeperService.cpp b/gatekeeperd/IGateKeeperService.cpp deleted file mode 100644 index 43d57088d..000000000 --- a/gatekeeperd/IGateKeeperService.cpp +++ /dev/null @@ -1,173 +0,0 @@ -/* - * 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 - -#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(data.readInplace(currentPasswordHandleSize)); - if (!currentPasswordHandle) currentPasswordHandleSize = 0; - - ssize_t currentPasswordSize = data.readInt32(); - const uint8_t *currentPassword = - static_cast(data.readInplace(currentPasswordSize)); - if (!currentPassword) currentPasswordSize = 0; - - ssize_t desiredPasswordSize = data.readInt32(); - const uint8_t *desiredPassword = - static_cast(data.readInplace(desiredPasswordSize)); - if (!desiredPassword) desiredPasswordSize = 0; - - uint8_t *out = NULL; - uint32_t outSize = 0; - int ret = enroll(uid, currentPasswordHandle, currentPasswordHandleSize, - currentPassword, currentPasswordSize, desiredPassword, - desiredPasswordSize, &out, &outSize); - - reply->writeNoException(); - reply->writeInt32(1); - if (ret == 0 && outSize > 0 && out != NULL) { - reply->writeInt32(GATEKEEPER_RESPONSE_OK); - reply->writeInt32(0); - reply->writeInt32(outSize); - reply->writeInt32(outSize); - void *buf = reply->writeInplace(outSize); - memcpy(buf, out, outSize); - delete[] out; - } else if (ret > 0) { - reply->writeInt32(GATEKEEPER_RESPONSE_RETRY); - reply->writeInt32(ret); - } else { - reply->writeInt32(GATEKEEPER_RESPONSE_ERROR); - } - return OK; - } - case VERIFY: { - CHECK_INTERFACE(IGateKeeperService, data, reply); - uint32_t uid = data.readInt32(); - ssize_t currentPasswordHandleSize = data.readInt32(); - const uint8_t *currentPasswordHandle = - static_cast(data.readInplace(currentPasswordHandleSize)); - if (!currentPasswordHandle) currentPasswordHandleSize = 0; - - ssize_t currentPasswordSize = data.readInt32(); - const uint8_t *currentPassword = - static_cast(data.readInplace(currentPasswordSize)); - if (!currentPassword) currentPasswordSize = 0; - - bool request_reenroll = false; - int ret = verify(uid, (uint8_t *) currentPasswordHandle, - currentPasswordHandleSize, (uint8_t *) currentPassword, currentPasswordSize, - &request_reenroll); - - reply->writeNoException(); - reply->writeInt32(1); - if (ret == 0) { - reply->writeInt32(GATEKEEPER_RESPONSE_OK); - reply->writeInt32(request_reenroll ? 1 : 0); - reply->writeInt32(0); // no payload returned from this call - } else if (ret > 0) { - reply->writeInt32(GATEKEEPER_RESPONSE_RETRY); - reply->writeInt32(ret); - } else { - reply->writeInt32(GATEKEEPER_RESPONSE_ERROR); - } - return OK; - } - 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(data.readInplace(currentPasswordHandleSize)); - if (!currentPasswordHandle) currentPasswordHandleSize = 0; - - ssize_t currentPasswordSize = data.readInt32(); - const uint8_t *currentPassword = - static_cast(data.readInplace(currentPasswordSize)); - if (!currentPassword) currentPasswordSize = 0; - - - uint8_t *out = NULL; - uint32_t outSize = 0; - bool request_reenroll = false; - int ret = verifyChallenge(uid, challenge, (uint8_t *) currentPasswordHandle, - currentPasswordHandleSize, (uint8_t *) currentPassword, currentPasswordSize, - &out, &outSize, &request_reenroll); - reply->writeNoException(); - reply->writeInt32(1); - if (ret == 0 && outSize > 0 && out != NULL) { - reply->writeInt32(GATEKEEPER_RESPONSE_OK); - reply->writeInt32(request_reenroll ? 1 : 0); - reply->writeInt32(outSize); - reply->writeInt32(outSize); - void *buf = reply->writeInplace(outSize); - memcpy(buf, out, outSize); - delete[] out; - } else if (ret > 0) { - reply->writeInt32(GATEKEEPER_RESPONSE_RETRY); - reply->writeInt32(ret); - } else { - reply->writeInt32(GATEKEEPER_RESPONSE_ERROR); - } - return OK; - } - case GET_SECURE_USER_ID: { - CHECK_INTERFACE(IGateKeeperService, data, reply); - uint32_t uid = data.readInt32(); - uint64_t sid = getSecureUserId(uid); - reply->writeNoException(); - reply->writeInt64(sid); - return OK; - } - case CLEAR_SECURE_USER_ID: { - CHECK_INTERFACE(IGateKeeperService, data, reply); - uint32_t uid = data.readInt32(); - clearSecureUserId(uid); - reply->writeNoException(); - return OK; - } - case REPORT_DEVICE_SETUP_COMPLETE: { - CHECK_INTERFACE(IGateKeeperService, data, reply); - reportDeviceSetupComplete(); - reply->writeNoException(); - return OK; - } - default: - return BBinder::onTransact(code, data, reply, flags); - } -}; - - -}; // namespace android diff --git a/gatekeeperd/IGateKeeperService.h b/gatekeeperd/IGateKeeperService.h deleted file mode 100644 index 2816efc6a..000000000 --- a/gatekeeperd/IGateKeeperService.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - * 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 -#include - -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, - GET_SECURE_USER_ID = IBinder::FIRST_CALL_TRANSACTION + 3, - CLEAR_SECURE_USER_ID = IBinder::FIRST_CALL_TRANSACTION + 4, - REPORT_DEVICE_SETUP_COMPLETE = IBinder::FIRST_CALL_TRANSACTION + 5, - }; - - enum { - GATEKEEPER_RESPONSE_OK = 0, - GATEKEEPER_RESPONSE_RETRY = 1, - GATEKEEPER_RESPONSE_ERROR = -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. - * Returns: - * - 0 on success - * - A timestamp T > 0 if the call has failed due to throttling and should not - * be reattempted until T milliseconds have elapsed - * - -1 on failure - */ - virtual 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) = 0; - - /** - * Verifies a password previously enrolled with the GateKeeper. - * Returns: - * - 0 on success - * - A timestamp T > 0 if the call has failed due to throttling and should not - * be reattempted until T milliseconds have elapsed - * - -1 on failure - */ - virtual int 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, - bool *request_reenroll) = 0; - - /** - * Verifies a password previously enrolled with the GateKeeper. - * Returns: - * - 0 on success - * - A timestamp T > 0 if the call has failed due to throttling and should not - * be reattempted until T milliseconds have elapsed - * - -1 on failure - */ - virtual int 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, bool *request_reenroll) = 0; - /** - * Returns the secure user ID for the provided android user - */ - virtual uint64_t getSecureUserId(uint32_t uid) = 0; - - /** - * Clears the secure user ID associated with the user. - */ - virtual void clearSecureUserId(uint32_t uid) = 0; - - /** - * Notifies gatekeeper that device setup has been completed and any potentially still existing - * state from before a factory reset can be cleaned up (if it has not been already). - */ - virtual void reportDeviceSetupComplete() = 0; -}; - -// ---------------------------------------------------------------------------- - -class BnGateKeeperService: public BnInterface { -public: - virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, - uint32_t flags = 0); -}; - -} // namespace android - -#endif - diff --git a/gatekeeperd/SoftGateKeeper.h b/gatekeeperd/SoftGateKeeper.h deleted file mode 100644 index 2f4f4d7e6..000000000 --- a/gatekeeperd/SoftGateKeeper.h +++ /dev/null @@ -1,182 +0,0 @@ -/* - * 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. - * - */ - -#ifndef SOFT_GATEKEEPER_H_ -#define SOFT_GATEKEEPER_H_ - -extern "C" { -#include -#include - -#include -} - -#include -#include - -#include -#include -#include - -namespace gatekeeper { - -struct fast_hash_t { - uint64_t salt; - uint8_t digest[SHA256_DIGEST_LENGTH]; -}; - -class SoftGateKeeper : public GateKeeper { -public: - static const uint32_t SIGNATURE_LENGTH_BYTES = 32; - - // scrypt params - static const uint64_t N = 16384; - static const uint32_t r = 8; - static const uint32_t p = 1; - - static const int MAX_UINT_32_CHARS = 11; - - SoftGateKeeper() { - key_.reset(new uint8_t[SIGNATURE_LENGTH_BYTES]); - memset(key_.get(), 0, SIGNATURE_LENGTH_BYTES); - } - - virtual ~SoftGateKeeper() { - } - - virtual bool GetAuthTokenKey(const uint8_t **auth_token_key, - uint32_t *length) const { - if (auth_token_key == NULL || length == NULL) return false; - uint8_t *auth_token_key_copy = new uint8_t[SIGNATURE_LENGTH_BYTES]; - memcpy(auth_token_key_copy, key_.get(), SIGNATURE_LENGTH_BYTES); - - *auth_token_key = auth_token_key_copy; - *length = SIGNATURE_LENGTH_BYTES; - return true; - } - - virtual void GetPasswordKey(const uint8_t **password_key, uint32_t *length) { - if (password_key == NULL || length == NULL) return; - uint8_t *password_key_copy = new uint8_t[SIGNATURE_LENGTH_BYTES]; - memcpy(password_key_copy, key_.get(), SIGNATURE_LENGTH_BYTES); - - *password_key = password_key_copy; - *length = SIGNATURE_LENGTH_BYTES; - } - - virtual void ComputePasswordSignature(uint8_t *signature, uint32_t signature_length, - const uint8_t *, uint32_t, const uint8_t *password, - uint32_t password_length, salt_t salt) const { - if (signature == NULL) return; - crypto_scrypt(password, password_length, reinterpret_cast(&salt), - sizeof(salt), N, r, p, signature, signature_length); - } - - virtual void GetRandom(void *random, uint32_t requested_length) const { - if (random == NULL) return; - RAND_pseudo_bytes((uint8_t *) random, requested_length); - } - - virtual void ComputeSignature(uint8_t *signature, uint32_t signature_length, - const uint8_t *, uint32_t, const uint8_t *, const uint32_t) const { - if (signature == NULL) return; - memset(signature, 0, signature_length); - } - - virtual uint64_t GetMillisecondsSinceBoot() const { - struct timespec time; - int res = clock_gettime(CLOCK_BOOTTIME, &time); - if (res < 0) return 0; - return (time.tv_sec * 1000) + (time.tv_nsec / 1000 / 1000); - } - - virtual bool IsHardwareBacked() const { - return false; - } - - virtual bool GetFailureRecord(uint32_t uid, secure_id_t user_id, failure_record_t *record, - bool /* secure */) { - failure_record_t *stored = &failure_map_[uid]; - if (user_id != stored->secure_user_id) { - stored->secure_user_id = user_id; - stored->last_checked_timestamp = 0; - stored->failure_counter = 0; - } - memcpy(record, stored, sizeof(*record)); - return true; - } - - virtual bool ClearFailureRecord(uint32_t uid, secure_id_t user_id, bool /* secure */) { - failure_record_t *stored = &failure_map_[uid]; - stored->secure_user_id = user_id; - stored->last_checked_timestamp = 0; - stored->failure_counter = 0; - return true; - } - - virtual bool WriteFailureRecord(uint32_t uid, failure_record_t *record, bool /* secure */) { - failure_map_[uid] = *record; - return true; - } - - fast_hash_t ComputeFastHash(const SizedBuffer &password, uint64_t salt) { - fast_hash_t fast_hash; - size_t digest_size = password.length + sizeof(salt); - std::unique_ptr digest(new uint8_t[digest_size]); - memcpy(digest.get(), &salt, sizeof(salt)); - memcpy(digest.get() + sizeof(salt), password.buffer.get(), password.length); - - SHA256(digest.get(), digest_size, (uint8_t *) &fast_hash.digest); - - fast_hash.salt = salt; - return fast_hash; - } - - bool VerifyFast(const fast_hash_t &fast_hash, const SizedBuffer &password) { - fast_hash_t computed = ComputeFastHash(password, fast_hash.salt); - return memcmp(computed.digest, fast_hash.digest, SHA256_DIGEST_LENGTH) == 0; - } - - bool DoVerify(const password_handle_t *expected_handle, const SizedBuffer &password) { - uint64_t user_id = android::base::get_unaligned(&expected_handle->user_id); - FastHashMap::const_iterator it = fast_hash_map_.find(user_id); - if (it != fast_hash_map_.end() && VerifyFast(it->second, password)) { - return true; - } else { - if (GateKeeper::DoVerify(expected_handle, password)) { - uint64_t salt; - GetRandom(&salt, sizeof(salt)); - fast_hash_map_[user_id] = ComputeFastHash(password, salt); - return true; - } - } - - return false; - } - -private: - - typedef std::unordered_map FailureRecordMap; - typedef std::unordered_map FastHashMap; - - std::unique_ptr key_; - FailureRecordMap failure_map_; - FastHashMap fast_hash_map_; -}; -} - -#endif // SOFT_GATEKEEPER_H_ diff --git a/gatekeeperd/SoftGateKeeperDevice.cpp b/gatekeeperd/SoftGateKeeperDevice.cpp deleted file mode 100644 index f5e2ce631..000000000 --- a/gatekeeperd/SoftGateKeeperDevice.cpp +++ /dev/null @@ -1,110 +0,0 @@ -/* - * 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 "SoftGateKeeper.h" -#include "SoftGateKeeperDevice.h" - -namespace android { - -int SoftGateKeeperDevice::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 (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; - } - - 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; - - impl_->Enroll(request, &response); - - if (response.error == ERROR_RETRY) { - return response.retry_timeout; - } else if (response.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 SoftGateKeeperDevice::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 (enrolled_password_handle == NULL || - provided_password == NULL) { - return -EINVAL; - } - - 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; - - impl_->Verify(request, &response); - - if (response.error == ERROR_RETRY) { - return response.retry_timeout; - } else if (response.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; -} -} // namespace android diff --git a/gatekeeperd/SoftGateKeeperDevice.h b/gatekeeperd/SoftGateKeeperDevice.h deleted file mode 100644 index e3dc068fb..000000000 --- a/gatekeeperd/SoftGateKeeperDevice.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * 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. - */ - -#ifndef SOFT_GATEKEEPER_DEVICE_H_ -#define SOFT_GATEKEEPER_DEVICE_H_ - -#include "SoftGateKeeper.h" - -#include - -using namespace gatekeeper; - -namespace android { - -/** - * Software based GateKeeper implementation - */ -class SoftGateKeeperDevice { -public: - SoftGateKeeperDevice() { - impl_.reset(new SoftGateKeeper()); - } - - // Wrappers to translate the gatekeeper HAL API to the Kegyuard Messages API. - - /** - * 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_handle 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 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 - */ - 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: - std::unique_ptr impl_; -}; - -} // namespace gatekeeper - -#endif //SOFT_GATEKEEPER_DEVICE_H_ diff --git a/gatekeeperd/binder/android/service/gatekeeper/GateKeeperResponse.aidl b/gatekeeperd/binder/android/service/gatekeeper/GateKeeperResponse.aidl new file mode 100644 index 000000000..097bb548c --- /dev/null +++ b/gatekeeperd/binder/android/service/gatekeeper/GateKeeperResponse.aidl @@ -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. + */ + +package android.service.gatekeeper; + +/** + * Response object for a GateKeeper verification request. + * @hide + */ +parcelable GateKeeperResponse cpp_header "gatekeeper/GateKeeperResponse.h"; + diff --git a/gatekeeperd/binder/android/service/gatekeeper/IGateKeeperService.aidl b/gatekeeperd/binder/android/service/gatekeeper/IGateKeeperService.aidl new file mode 100644 index 000000000..57adaba07 --- /dev/null +++ b/gatekeeperd/binder/android/service/gatekeeper/IGateKeeperService.aidl @@ -0,0 +1,87 @@ +/* + * 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. + */ + +package android.service.gatekeeper; + +import android.service.gatekeeper.GateKeeperResponse; + +/** + * Interface for communication with GateKeeper, the + * secure password storage daemon. + * + * This must be kept manually in sync with system/core/gatekeeperd + * until AIDL can generate both C++ and Java bindings. + * + * @hide + */ +interface IGateKeeperService { + /** + * Enrolls a password, returning the handle to the enrollment to be stored locally. + * @param uid The Android user ID associated to this enrollment + * @param currentPasswordHandle The previously enrolled handle, or null if none + * @param currentPassword The previously enrolled plaintext password, or null if none. + * If provided, must verify against the currentPasswordHandle. + * @param desiredPassword The new desired password, for which a handle will be returned + * upon success. + * @return an EnrollResponse or null on failure + */ + GateKeeperResponse enroll(int uid, in @nullable byte[] currentPasswordHandle, + in @nullable byte[] currentPassword, in byte[] desiredPassword); + + /** + * Verifies an enrolled handle against a provided, plaintext blob. + * @param uid The Android user ID associated to this enrollment + * @param enrolledPasswordHandle The handle against which the provided password will be + * verified. + * @param The plaintext blob to verify against enrolledPassword. + * @return a VerifyResponse, or null on failure. + */ + GateKeeperResponse verify(int uid, in byte[] enrolledPasswordHandle, in byte[] providedPassword); + + /** + * Verifies an enrolled handle against a provided, plaintext blob. + * @param uid The Android user ID associated to this enrollment + * @param challenge a challenge to authenticate agaisnt the device credential. If successful + * authentication occurs, this value will be written to the returned + * authentication attestation. + * @param enrolledPasswordHandle The handle against which the provided password will be + * verified. + * @param The plaintext blob to verify against enrolledPassword. + * @return a VerifyResponse with an attestation, or null on failure. + */ + GateKeeperResponse verifyChallenge(int uid, long challenge, in byte[] enrolledPasswordHandle, + in byte[] providedPassword); + + /** + * Retrieves the secure identifier for the user with the provided Android ID, + * or 0 if none is found. + * @param uid the Android user id + */ + long getSecureUserId(int uid); + + /** + * Clears secure user id associated with the provided Android ID. + * Must be called when password is set to NONE. + * @param uid the Android user id. + */ + void clearSecureUserId(int uid); + + /** + * Notifies gatekeeper that device setup has been completed and any potentially still existing + * state from before a factory reset can be cleaned up (if it has not been already). + */ + void reportDeviceSetupComplete(); +} diff --git a/gatekeeperd/gatekeeperd.cpp b/gatekeeperd/gatekeeperd.cpp index 8700c3446..1d65b1ced 100644 --- a/gatekeeperd/gatekeeperd.cpp +++ b/gatekeeperd/gatekeeperd.cpp @@ -16,7 +16,8 @@ #define LOG_TAG "gatekeeperd" -#include "IGateKeeperService.h" +#include +#include #include #include @@ -41,8 +42,6 @@ #include #include -#include "SoftGateKeeperDevice.h" - #include #include @@ -52,6 +51,11 @@ using android::hardware::gatekeeper::V1_0::GatekeeperStatusCode; using android::hardware::gatekeeper::V1_0::GatekeeperResponse; using android::hardware::Return; +using ::android::binder::Status; +using ::android::service::gatekeeper::BnGateKeeperService; +using GKResponse = ::android::service::gatekeeper::GateKeeperResponse; +using GKResponseCode = ::android::service::gatekeeper::ResponseCode; + namespace android { static const String16 KEYGUARD_PERMISSION("android.permission.ACCESS_KEYGUARD_SECURE_STORAGE"); @@ -64,9 +68,8 @@ public: hw_device = IGatekeeper::getService(); is_running_gsi = android::base::GetBoolProperty(android::gsi::kGsiBootedProp, false); - if (hw_device == nullptr) { - ALOGW("falling back to software GateKeeper"); - soft_device.reset(new SoftGateKeeperDevice()); + if (!hw_device) { + LOG(ERROR) << "Could not find Gatekeeper device, which makes me very sad."; } } @@ -92,7 +95,7 @@ public: if (mark_cold_boot() && !is_running_gsi) { ALOGI("cold boot: clearing state"); - if (hw_device != nullptr) { + if (hw_device) { hw_device->deleteAllUsers([](const GatekeeperResponse &){}); } } @@ -154,16 +157,16 @@ public: return uid; } - virtual 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) { +#define GK_ERROR *gkResponse = GKResponse::error(), Status::ok() + + Status enroll(int32_t uid, const std::unique_ptr>& currentPasswordHandle, + const std::unique_ptr>& currentPassword, + const std::vector& desiredPassword, GKResponse* gkResponse) override { 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; + return GK_ERROR; } // Make sure to clear any state from before factory reset as soon as a credential is @@ -171,225 +174,189 @@ public: clear_state_if_needed(); // need a desired password to enroll - if (desired_password_length == 0) return -EINVAL; + if (desiredPassword.size() == 0) return GK_ERROR; - int ret; - if (hw_device != nullptr) { - const gatekeeper::password_handle_t *handle = - reinterpret_cast(current_password_handle); + if (!hw_device) { + LOG(ERROR) << "has no HAL to talk to"; + return GK_ERROR; + } - if (handle != NULL && handle->version != 0 && !handle->hardware_backed) { - // handle is being re-enrolled from a software version. HAL probably won't accept - // the handle as valid, so we nullify it and enroll from scratch - current_password_handle = NULL; - current_password_handle_length = 0; - current_password = NULL; - current_password_length = 0; + android::hardware::hidl_vec curPwdHandle; + android::hardware::hidl_vec curPwd; + + if (currentPasswordHandle && currentPassword) { + if (currentPasswordHandle->size() != sizeof(gatekeeper::password_handle_t)) { + LOG(INFO) << "Password handle has wrong length"; + return GK_ERROR; } + curPwdHandle.setToExternal(const_cast(currentPasswordHandle->data()), + currentPasswordHandle->size()); + curPwd.setToExternal(const_cast(currentPassword->data()), + currentPassword->size()); + } - android::hardware::hidl_vec curPwdHandle; - curPwdHandle.setToExternal(const_cast(current_password_handle), - current_password_handle_length); - android::hardware::hidl_vec curPwd; - curPwd.setToExternal(const_cast(current_password), - current_password_length); - android::hardware::hidl_vec newPwd; - newPwd.setToExternal(const_cast(desired_password), - desired_password_length); + android::hardware::hidl_vec newPwd; + newPwd.setToExternal(const_cast(desiredPassword.data()), desiredPassword.size()); - uint32_t hw_uid = adjust_uid(uid); - Return hwRes = hw_device->enroll(hw_uid, curPwdHandle, curPwd, newPwd, - [&ret, enrolled_password_handle, enrolled_password_handle_length] - (const GatekeeperResponse &rsp) { - ret = static_cast(rsp.code); // propagate errors - if (rsp.code >= GatekeeperStatusCode::STATUS_OK) { - if (enrolled_password_handle != nullptr && - enrolled_password_handle_length != nullptr) { - *enrolled_password_handle = new uint8_t[rsp.data.size()]; - *enrolled_password_handle_length = rsp.data.size(); - memcpy(*enrolled_password_handle, rsp.data.data(), - *enrolled_password_handle_length); + uint32_t hw_uid = adjust_uid(uid); + Return hwRes = hw_device->enroll( + hw_uid, curPwdHandle, curPwd, newPwd, [&gkResponse](const GatekeeperResponse& rsp) { + if (rsp.code >= GatekeeperStatusCode::STATUS_OK) { + *gkResponse = GKResponse::ok({rsp.data.begin(), rsp.data.end()}); + } else if (rsp.code == GatekeeperStatusCode::ERROR_RETRY_TIMEOUT && + rsp.timeout > 0) { + *gkResponse = GKResponse::retry(rsp.timeout); + } else { + *gkResponse = GKResponse::error(); } - ret = 0; // all success states are reported as 0 - } else if (rsp.code == GatekeeperStatusCode::ERROR_RETRY_TIMEOUT && rsp.timeout > 0) { - ret = rsp.timeout; - } - }); - if (!hwRes.isOk()) { - ALOGE("enroll transaction failed\n"); - ret = -1; + }); + if (!hwRes.isOk()) { + LOG(ERROR) << "enroll transaction failed"; + return GK_ERROR; + } + + if (gkResponse->response_code() == GKResponseCode::OK && !gkResponse->should_reenroll()) { + if (gkResponse->payload().size() != sizeof(gatekeeper::password_handle_t)) { + LOG(ERROR) << "HAL returned password handle of invalid length " + << gkResponse->payload().size(); + return GK_ERROR; } - } else { - ret = soft_device->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); - } - if (ret == GATEKEEPER_RESPONSE_OK && (*enrolled_password_handle == nullptr || - *enrolled_password_handle_length != sizeof(password_handle_t))) { - ret = GATEKEEPER_RESPONSE_ERROR; - ALOGE("HAL: password_handle=%p size_of_handle=%" PRIu32 "\n", - *enrolled_password_handle, *enrolled_password_handle_length); - } - - if (ret == GATEKEEPER_RESPONSE_OK) { - gatekeeper::password_handle_t *handle = - reinterpret_cast(*enrolled_password_handle); + const gatekeeper::password_handle_t* handle = + reinterpret_cast( + gkResponse->payload().data()); store_sid(uid, handle->user_id); - bool rr; + GKResponse verifyResponse; // immediately verify this password so we don't ask the user to enter it again // if they just created it. - verify(uid, *enrolled_password_handle, sizeof(password_handle_t), desired_password, - desired_password_length, &rr); + auto status = verify(uid, gkResponse->payload(), desiredPassword, &verifyResponse); + if (!status.isOk() || verifyResponse.response_code() != GKResponseCode::OK) { + LOG(ERROR) << "Failed to verify password after enrolling"; + } } - return ret; + return Status::ok(); } - virtual int 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, bool *request_reenroll) { - uint8_t *auth_token = nullptr; - uint32_t auth_token_length; - int ret = verifyChallenge(uid, 0, enrolled_password_handle, enrolled_password_handle_length, - provided_password, provided_password_length, - &auth_token, &auth_token_length, request_reenroll); - delete [] auth_token; - return ret; + Status verify(int32_t uid, const ::std::vector& enrolledPasswordHandle, + const ::std::vector& providedPassword, GKResponse* gkResponse) override { + return verifyChallenge(uid, 0 /* challenge */, enrolledPasswordHandle, providedPassword, + gkResponse); } - virtual int 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, bool *request_reenroll) { + Status verifyChallenge(int32_t uid, int64_t challenge, + const std::vector& enrolledPasswordHandle, + const std::vector& providedPassword, + GKResponse* gkResponse) override { 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; + return GK_ERROR; } // can't verify if we're missing either param - if ((enrolled_password_handle_length | provided_password_length) == 0) - return -EINVAL; + if (enrolledPasswordHandle.size() == 0 || providedPassword.size() == 0) return GK_ERROR; - int ret; - if (hw_device != nullptr) { - const gatekeeper::password_handle_t *handle = - reinterpret_cast(enrolled_password_handle); - // handle version 0 does not have hardware backed flag, and thus cannot be upgraded to - // a HAL if there was none before - if (handle->version == 0 || handle->hardware_backed) { - uint32_t hw_uid = adjust_uid(uid); - android::hardware::hidl_vec curPwdHandle; - curPwdHandle.setToExternal(const_cast(enrolled_password_handle), - enrolled_password_handle_length); - android::hardware::hidl_vec enteredPwd; - enteredPwd.setToExternal(const_cast(provided_password), - provided_password_length); - Return hwRes = hw_device->verify(hw_uid, challenge, curPwdHandle, enteredPwd, - [&ret, request_reenroll, auth_token, auth_token_length] - (const GatekeeperResponse &rsp) { - ret = static_cast(rsp.code); // propagate errors - if (auth_token != nullptr && auth_token_length != nullptr && - rsp.code >= GatekeeperStatusCode::STATUS_OK) { - *auth_token = new uint8_t[rsp.data.size()]; - *auth_token_length = rsp.data.size(); - memcpy(*auth_token, rsp.data.data(), *auth_token_length); - if (request_reenroll != nullptr) { - *request_reenroll = (rsp.code == GatekeeperStatusCode::STATUS_REENROLL); - } - ret = 0; // all success states are reported as 0 - } else if (rsp.code == GatekeeperStatusCode::ERROR_RETRY_TIMEOUT && - rsp.timeout > 0) { - ret = rsp.timeout; + if (!hw_device) return GK_ERROR; + + if (enrolledPasswordHandle.size() != sizeof(gatekeeper::password_handle_t)) { + LOG(INFO) << "Password handle has wrong length"; + return GK_ERROR; + } + const gatekeeper::password_handle_t* handle = + reinterpret_cast( + enrolledPasswordHandle.data()); + + uint32_t hw_uid = adjust_uid(uid); + android::hardware::hidl_vec curPwdHandle; + curPwdHandle.setToExternal(const_cast(enrolledPasswordHandle.data()), + enrolledPasswordHandle.size()); + android::hardware::hidl_vec enteredPwd; + enteredPwd.setToExternal(const_cast(providedPassword.data()), + providedPassword.size()); + + Return hwRes = hw_device->verify( + hw_uid, challenge, curPwdHandle, enteredPwd, + [&gkResponse](const GatekeeperResponse& rsp) { + if (rsp.code >= GatekeeperStatusCode::STATUS_OK) { + *gkResponse = GKResponse::ok( + {rsp.data.begin(), rsp.data.end()}, + rsp.code == GatekeeperStatusCode::STATUS_REENROLL /* reenroll */); + } else if (rsp.code == GatekeeperStatusCode::ERROR_RETRY_TIMEOUT) { + *gkResponse = GKResponse::retry(rsp.timeout); + } else { + *gkResponse = GKResponse::error(); } }); - if (!hwRes.isOk()) { - ALOGE("verify transaction failed\n"); - ret = -1; - } - } else { - // upgrade scenario, a HAL has been added to this device where there was none before - SoftGateKeeperDevice soft_dev; - ret = soft_dev.verify(uid, challenge, - enrolled_password_handle, enrolled_password_handle_length, - provided_password, provided_password_length, auth_token, auth_token_length, - request_reenroll); - if (ret == 0) { - // success! re-enroll with HAL - *request_reenroll = true; + if (!hwRes.isOk()) { + LOG(ERROR) << "verify transaction failed"; + return GK_ERROR; + } + + if (gkResponse->response_code() == GKResponseCode::OK) { + if (gkResponse->payload().size() != 0) { + sp sm = defaultServiceManager(); + sp binder = sm->getService(String16("android.security.keystore")); + sp service = + interface_cast(binder); + + if (service) { + int result = 0; + auto binder_result = service->addAuthToken(gkResponse->payload(), &result); + if (!binder_result.isOk() || + !keystore::KeyStoreServiceReturnCode(result).isOk()) { + LOG(ERROR) << "Failure sending auth token to KeyStore: " << result; + } + } else { + LOG(ERROR) << "Cannot deliver auth token. Unable to communicate with Keystore."; } } - } else { - ret = soft_device->verify(uid, challenge, - enrolled_password_handle, enrolled_password_handle_length, - provided_password, provided_password_length, auth_token, auth_token_length, - request_reenroll); + + maybe_store_sid(uid, handle->user_id); } - if (ret == 0 && *auth_token != NULL && *auth_token_length > 0) { - // TODO: cache service? - sp sm = defaultServiceManager(); - sp binder = sm->getService(String16("android.security.keystore")); - sp service = - interface_cast(binder); - if (service != NULL) { - std::vector auth_token_vector(*auth_token, - (*auth_token) + *auth_token_length); - int result = 0; - auto binder_result = service->addAuthToken(auth_token_vector, &result); - if (!binder_result.isOk() || !keystore::KeyStoreServiceReturnCode(result).isOk()) { - ALOGE("Failure sending auth token to KeyStore: %" PRId32, result); - } - } else { - ALOGE("Unable to communicate with KeyStore"); - } - } - - if (ret == 0) { - maybe_store_sid(uid, reinterpret_cast( - enrolled_password_handle)->user_id); - } - - return ret; + return Status::ok(); } - virtual uint64_t getSecureUserId(uint32_t uid) { return read_sid(uid); } + Status getSecureUserId(int32_t uid, int64_t* sid) override { + *sid = read_sid(uid); + return Status::ok(); + } - virtual void clearSecureUserId(uint32_t uid) { + Status clearSecureUserId(int32_t uid) override { 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)) { ALOGE("%s: permission denied for [%d:%d]", __func__, calling_pid, calling_uid); - return; + return Status::ok(); } clear_sid(uid); - if (hw_device != nullptr) { + if (hw_device) { uint32_t hw_uid = adjust_uid(uid); hw_device->deleteUser(hw_uid, [] (const GatekeeperResponse &){}); } + return Status::ok(); } - virtual void reportDeviceSetupComplete() { + Status reportDeviceSetupComplete() override { 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)) { ALOGE("%s: permission denied for [%d:%d]", __func__, calling_pid, calling_uid); - return; + return Status::ok(); } clear_state_if_needed(); + return Status::ok(); } - virtual status_t dump(int fd, const Vector &) { + status_t dump(int fd, const Vector&) override { IPCThreadState* ipc = IPCThreadState::self(); const int pid = ipc->getCallingPid(); const int uid = ipc->getCallingUid(); @@ -410,7 +377,6 @@ public: private: sp hw_device; - std::unique_ptr soft_device; bool clear_state_if_needed_done; bool is_running_gsi; diff --git a/gatekeeperd/include/gatekeeper/GateKeeperResponse.h b/gatekeeperd/include/gatekeeper/GateKeeperResponse.h new file mode 100644 index 000000000..99fff024d --- /dev/null +++ b/gatekeeperd/include/gatekeeper/GateKeeperResponse.h @@ -0,0 +1,85 @@ +/* +** +** Copyright 2019, 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 GATEKEEPERD_INCLUDE_GATEKEEPER_GATEKEEPERRESPONSE_H_ +#define GATEKEEPERD_INCLUDE_GATEKEEPER_GATEKEEPERRESPONSE_H_ + +#include + +namespace android { +namespace service { +namespace gatekeeper { + +enum class ResponseCode : int32_t { + ERROR = -1, + OK = 0, + RETRY = 1, +}; + +class GateKeeperResponse : public ::android::Parcelable { + GateKeeperResponse(ResponseCode response_code, int32_t timeout = 0, + std::vector payload = {}, bool should_reenroll = false) + : response_code_(response_code), + timeout_(timeout), + payload_(std::move(payload)), + should_reenroll_(should_reenroll) {} + + public: + GateKeeperResponse() = default; + GateKeeperResponse(GateKeeperResponse&&) = default; + GateKeeperResponse(const GateKeeperResponse&) = default; + GateKeeperResponse& operator=(GateKeeperResponse&&) = default; + + static GateKeeperResponse error() { return GateKeeperResponse(ResponseCode::ERROR); } + static GateKeeperResponse retry(int32_t timeout) { + return GateKeeperResponse(ResponseCode::RETRY, timeout); + } + static GateKeeperResponse ok(std::vector payload, bool reenroll = false) { + return GateKeeperResponse(ResponseCode::OK, 0, std::move(payload), reenroll); + } + + status_t readFromParcel(const Parcel* in) override; + status_t writeToParcel(Parcel* out) const override; + + const std::vector& payload() const { return payload_; } + + void payload(std::vector payload) { payload_ = payload; } + + ResponseCode response_code() const { return response_code_; } + + void response_code(ResponseCode response_code) { response_code_ = response_code; } + + bool should_reenroll() const { return should_reenroll_; } + + void should_reenroll(bool should_reenroll) { should_reenroll_ = should_reenroll; } + + int32_t timeout() const { return timeout_; } + + void timeout(int32_t timeout) { timeout_ = timeout; } + + private: + ResponseCode response_code_; + int32_t timeout_; + std::vector payload_; + bool should_reenroll_; +}; + +} // namespace gatekeeper +} // namespace service +} // namespace android + +#endif // GATEKEEPERD_INCLUDE_GATEKEEPER_GATEKEEPERRESPONSE_H_ diff --git a/gatekeeperd/tests/Android.bp b/gatekeeperd/tests/Android.bp deleted file mode 100644 index d4cf93b60..000000000 --- a/gatekeeperd/tests/Android.bp +++ /dev/null @@ -1,34 +0,0 @@ -// -// 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. -// - -cc_test { - name: "gatekeeperd-unit-tests", - - cflags: [ - "-g", - "-Wall", - "-Werror", - "-Wno-missing-field-initializers", - ], - shared_libs: [ - "libgatekeeper", - "libcrypto", - "libbase", - ], - static_libs: ["libscrypt_static"], - include_dirs: ["external/scrypt/lib/crypto"], - srcs: ["gatekeeper_test.cpp"], -} diff --git a/gatekeeperd/tests/gatekeeper_test.cpp b/gatekeeperd/tests/gatekeeper_test.cpp deleted file mode 100644 index 100375fb8..000000000 --- a/gatekeeperd/tests/gatekeeper_test.cpp +++ /dev/null @@ -1,204 +0,0 @@ -/* - * 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. - */ - -#include -#include - -#include -#include - -#include "../SoftGateKeeper.h" - -using ::gatekeeper::SizedBuffer; -using ::testing::Test; -using ::gatekeeper::EnrollRequest; -using ::gatekeeper::EnrollResponse; -using ::gatekeeper::VerifyRequest; -using ::gatekeeper::VerifyResponse; -using ::gatekeeper::SoftGateKeeper; -using ::gatekeeper::secure_id_t; - -static void do_enroll(SoftGateKeeper &gatekeeper, EnrollResponse *response) { - SizedBuffer password; - - password.buffer.reset(new uint8_t[16]); - password.length = 16; - memset(password.buffer.get(), 0, 16); - EnrollRequest request(0, NULL, &password, NULL); - - gatekeeper.Enroll(request, response); -} - -TEST(GateKeeperTest, EnrollSuccess) { - SoftGateKeeper gatekeeper; - EnrollResponse response; - do_enroll(gatekeeper, &response); - ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, response.error); -} - -TEST(GateKeeperTest, EnrollBogusData) { - SoftGateKeeper gatekeeper; - SizedBuffer password; - EnrollResponse response; - - EnrollRequest request(0, NULL, &password, NULL); - - gatekeeper.Enroll(request, &response); - - ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_INVALID, response.error); -} - -TEST(GateKeeperTest, VerifySuccess) { - SoftGateKeeper gatekeeper; - SizedBuffer provided_password; - EnrollResponse enroll_response; - - provided_password.buffer.reset(new uint8_t[16]); - provided_password.length = 16; - memset(provided_password.buffer.get(), 0, 16); - - do_enroll(gatekeeper, &enroll_response); - ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, enroll_response.error); - VerifyRequest request(0, 1, &enroll_response.enrolled_password_handle, - &provided_password); - VerifyResponse response; - - gatekeeper.Verify(request, &response); - - ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, response.error); - - hw_auth_token_t *auth_token = - reinterpret_cast(response.auth_token.buffer.get()); - - ASSERT_EQ((uint32_t) HW_AUTH_PASSWORD, ntohl(auth_token->authenticator_type)); - ASSERT_EQ((uint64_t) 1, auth_token->challenge); - ASSERT_NE(~((uint32_t) 0), auth_token->timestamp); - ASSERT_NE((uint64_t) 0, auth_token->user_id); - ASSERT_NE((uint64_t) 0, auth_token->authenticator_id); -} - -TEST(GateKeeperTest, TrustedReEnroll) { - SoftGateKeeper gatekeeper; - SizedBuffer provided_password; - EnrollResponse enroll_response; - SizedBuffer password_handle; - - // do_enroll enrolls an all 0 password - provided_password.buffer.reset(new uint8_t[16]); - provided_password.length = 16; - memset(provided_password.buffer.get(), 0, 16); - do_enroll(gatekeeper, &enroll_response); - ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, enroll_response.error); - - // keep a copy of the handle - password_handle.buffer.reset(new uint8_t[enroll_response.enrolled_password_handle.length]); - password_handle.length = enroll_response.enrolled_password_handle.length; - memcpy(password_handle.buffer.get(), enroll_response.enrolled_password_handle.buffer.get(), - password_handle.length); - - // verify first password - VerifyRequest request(0, 0, &enroll_response.enrolled_password_handle, - &provided_password); - VerifyResponse response; - gatekeeper.Verify(request, &response); - ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, response.error); - hw_auth_token_t *auth_token = - reinterpret_cast(response.auth_token.buffer.get()); - - secure_id_t secure_id = auth_token->user_id; - - // enroll new password - provided_password.buffer.reset(new uint8_t[16]); - provided_password.length = 16; - memset(provided_password.buffer.get(), 0, 16); - SizedBuffer password; - password.buffer.reset(new uint8_t[16]); - memset(password.buffer.get(), 1, 16); - password.length = 16; - EnrollRequest enroll_request(0, &password_handle, &password, &provided_password); - gatekeeper.Enroll(enroll_request, &enroll_response); - ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, enroll_response.error); - - // verify new password - password.buffer.reset(new uint8_t[16]); - memset(password.buffer.get(), 1, 16); - password.length = 16; - VerifyRequest new_request(0, 0, &enroll_response.enrolled_password_handle, - &password); - gatekeeper.Verify(new_request, &response); - ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, response.error); - ASSERT_EQ(secure_id, - reinterpret_cast(response.auth_token.buffer.get())->user_id); -} - - -TEST(GateKeeperTest, UntrustedReEnroll) { - SoftGateKeeper gatekeeper; - SizedBuffer provided_password; - EnrollResponse enroll_response; - - // do_enroll enrolls an all 0 password - provided_password.buffer.reset(new uint8_t[16]); - provided_password.length = 16; - memset(provided_password.buffer.get(), 0, 16); - do_enroll(gatekeeper, &enroll_response); - ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, enroll_response.error); - - // verify first password - VerifyRequest request(0, 0, &enroll_response.enrolled_password_handle, - &provided_password); - VerifyResponse response; - gatekeeper.Verify(request, &response); - ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, response.error); - hw_auth_token_t *auth_token = - reinterpret_cast(response.auth_token.buffer.get()); - - secure_id_t secure_id = auth_token->user_id; - - // enroll new password - SizedBuffer password; - password.buffer.reset(new uint8_t[16]); - memset(password.buffer.get(), 1, 16); - password.length = 16; - EnrollRequest enroll_request(0, NULL, &password, NULL); - gatekeeper.Enroll(enroll_request, &enroll_response); - ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, enroll_response.error); - - // verify new password - password.buffer.reset(new uint8_t[16]); - memset(password.buffer.get(), 1, 16); - password.length = 16; - VerifyRequest new_request(0, 0, &enroll_response.enrolled_password_handle, - &password); - gatekeeper.Verify(new_request, &response); - ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_NONE, response.error); - ASSERT_NE(secure_id, - reinterpret_cast(response.auth_token.buffer.get())->user_id); -} - - -TEST(GateKeeperTest, VerifyBogusData) { - SoftGateKeeper gatekeeper; - SizedBuffer provided_password; - SizedBuffer password_handle; - VerifyResponse response; - - VerifyRequest request(0, 0, &provided_password, &password_handle); - - gatekeeper.Verify(request, &response); - - ASSERT_EQ(::gatekeeper::gatekeeper_error_t::ERROR_INVALID, response.error); -}