diff --git a/gatekeeperd/Android.mk b/gatekeeperd/Android.mk index be3d6fc24..ce050aee7 100644 --- a/gatekeeperd/Android.mk +++ b/gatekeeperd/Android.mk @@ -25,9 +25,12 @@ LOCAL_SHARED_LIBRARIES := \ libgatekeeper \ liblog \ libhardware \ + libbase \ libutils \ libcrypto \ libkeystore_binder LOCAL_STATIC_LIBRARIES := libscrypt_static LOCAL_C_INCLUDES := external/scrypt/lib/crypto include $(BUILD_EXECUTABLE) + +include $(call first-makefiles-under,$(LOCAL_PATH)) diff --git a/gatekeeperd/IGateKeeperService.cpp b/gatekeeperd/IGateKeeperService.cpp index f5bbbf1f2..95fbfd10b 100644 --- a/gatekeeperd/IGateKeeperService.cpp +++ b/gatekeeperd/IGateKeeperService.cpp @@ -50,18 +50,25 @@ status_t BnGateKeeperService::onTransact( uint8_t *out = NULL; uint32_t outSize = 0; - status_t ret = enroll(uid, currentPasswordHandle, currentPasswordHandleSize, + int ret = enroll(uid, currentPasswordHandle, currentPasswordHandleSize, currentPassword, currentPasswordSize, desiredPassword, desiredPasswordSize, &out, &outSize); reply->writeNoException(); - if (ret == NO_ERROR && outSize > 0 && out != NULL) { + 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); - free(out); + delete[] out; + } else if (ret > 0) { + reply->writeInt32(GATEKEEPER_RESPONSE_RETRY); + reply->writeInt32(ret); } else { - reply->writeInt32(-1); + reply->writeInt32(GATEKEEPER_RESPONSE_ERROR); } return NO_ERROR; } @@ -78,10 +85,23 @@ status_t BnGateKeeperService::onTransact( static_cast(data.readInplace(currentPasswordSize)); if (!currentPassword) currentPasswordSize = 0; - status_t ret = verify(uid, (uint8_t *) currentPasswordHandle, - currentPasswordHandleSize, (uint8_t *) currentPassword, currentPasswordSize); + bool request_reenroll = false; + int ret = verify(uid, (uint8_t *) currentPasswordHandle, + currentPasswordHandleSize, (uint8_t *) currentPassword, currentPasswordSize, + &request_reenroll); + reply->writeNoException(); - reply->writeInt32(ret == NO_ERROR ? 1 : 0); + 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 NO_ERROR; } case VERIFY_CHALLENGE: { @@ -101,17 +121,25 @@ status_t BnGateKeeperService::onTransact( uint8_t *out = NULL; uint32_t outSize = 0; - status_t ret = verifyChallenge(uid, challenge, (uint8_t *) currentPasswordHandle, + bool request_reenroll = false; + int ret = verifyChallenge(uid, challenge, (uint8_t *) currentPasswordHandle, currentPasswordHandleSize, (uint8_t *) currentPassword, currentPasswordSize, - &out, &outSize); + &out, &outSize, &request_reenroll); reply->writeNoException(); - if (ret == NO_ERROR && outSize > 0 && out != NULL) { + 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); - free(out); + delete[] out; + } else if (ret > 0) { + reply->writeInt32(GATEKEEPER_RESPONSE_RETRY); + reply->writeInt32(ret); } else { - reply->writeInt32(-1); + reply->writeInt32(GATEKEEPER_RESPONSE_ERROR); } return NO_ERROR; } diff --git a/gatekeeperd/IGateKeeperService.h b/gatekeeperd/IGateKeeperService.h index a7773187e..f070486cd 100644 --- a/gatekeeperd/IGateKeeperService.h +++ b/gatekeeperd/IGateKeeperService.h @@ -35,6 +35,12 @@ public: CLEAR_SECURE_USER_ID = IBinder::FIRST_CALL_TRANSACTION + 4, }; + 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; @@ -43,8 +49,13 @@ public: /** * 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 status_t enroll(uint32_t 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, @@ -52,21 +63,29 @@ public: /** * Verifies a password previously enrolled 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 status_t verify(uint32_t uid, const uint8_t *enrolled_password_handle, + 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) = 0; + 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, 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 status_t verifyChallenge(uint32_t uid, uint64_t challenge, + 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) = 0; - + uint8_t **auth_token, uint32_t *auth_token_length, bool *request_reenroll) = 0; /** * Returns the secure user ID for the provided android user */ diff --git a/gatekeeperd/SoftGateKeeper.h b/gatekeeperd/SoftGateKeeper.h new file mode 100644 index 000000000..1ae45e633 --- /dev/null +++ b/gatekeeperd/SoftGateKeeper.h @@ -0,0 +1,127 @@ +/* + * 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 + +namespace gatekeeper { + + +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; + *auth_token_key = const_cast(key_.get()); + *length = SIGNATURE_LENGTH_BYTES; + return true; + } + + virtual void GetPasswordKey(const uint8_t **password_key, uint32_t *length) { + if (password_key == NULL || length == NULL) return; + *password_key = const_cast(key_.get()); + *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) { + 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 void ClearFailureRecord(uint32_t uid, secure_id_t user_id) { + failure_record_t *stored = &failure_map_[uid]; + stored->secure_user_id = user_id; + stored->last_checked_timestamp = 0; + stored->failure_counter = 0; + } + + virtual bool WriteFailureRecord(uint32_t uid, failure_record_t *record) { + failure_map_[uid] = *record; + return true; + } + +private: + UniquePtr key_; + std::unordered_map failure_map_; +}; +} + +#endif // SOFT_GATEKEEPER_H_ + diff --git a/gatekeeperd/SoftGateKeeperDevice.cpp b/gatekeeperd/SoftGateKeeperDevice.cpp index b96bf8d23..f5e2ce631 100644 --- a/gatekeeperd/SoftGateKeeperDevice.cpp +++ b/gatekeeperd/SoftGateKeeperDevice.cpp @@ -13,8 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include - +#include "SoftGateKeeper.h" #include "SoftGateKeeperDevice.h" namespace android { @@ -58,8 +57,11 @@ int SoftGateKeeperDevice::enroll(uint32_t uid, impl_->Enroll(request, &response); - if (response.error != ERROR_NONE) + 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; @@ -69,7 +71,8 @@ int SoftGateKeeperDevice::enroll(uint32_t uid, 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) { + 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) { @@ -87,14 +90,21 @@ int SoftGateKeeperDevice::verify(uint32_t uid, impl_->Verify(request, &response); - if (response.error != ERROR_NONE) - return -EINVAL; + 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 index c0b504737..51a85113b 100644 --- a/gatekeeperd/SoftGateKeeperDevice.h +++ b/gatekeeperd/SoftGateKeeperDevice.h @@ -17,7 +17,8 @@ #ifndef SOFT_GATEKEEPER_DEVICE_H_ #define SOFT_GATEKEEPER_DEVICE_H_ -#include +#include "SoftGateKeeper.h" + #include using namespace gatekeeper; @@ -65,7 +66,7 @@ public: 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); + uint8_t **auth_token, uint32_t *auth_token_length, bool *request_reenroll); private: UniquePtr impl_; }; diff --git a/gatekeeperd/gatekeeperd.cpp b/gatekeeperd/gatekeeperd.cpp index 72c7ba2c2..ad16fa5dd 100644 --- a/gatekeeperd/gatekeeperd.cpp +++ b/gatekeeperd/gatekeeperd.cpp @@ -102,7 +102,7 @@ public: } } - virtual status_t enroll(uint32_t 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, @@ -132,29 +132,29 @@ public: enrolled_password_handle, enrolled_password_handle_length); } - if (ret >= 0) { + if (ret == 0) { gatekeeper::password_handle_t *handle = reinterpret_cast(*enrolled_password_handle); store_sid(uid, handle->user_id); - return NO_ERROR; } - return UNKNOWN_ERROR; + + return ret; } - virtual status_t verify(uint32_t uid, + 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) { + const uint8_t *provided_password, uint32_t provided_password_length, bool *request_reenroll) { 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); + &auth_token, &auth_token_length, request_reenroll); } - virtual status_t verifyChallenge(uint32_t uid, uint64_t challenge, + 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) { + uint8_t **auth_token, uint32_t *auth_token_length, bool *request_reenroll) { IPCThreadState* ipc = IPCThreadState::self(); const int calling_pid = ipc->getCallingPid(); const int calling_uid = ipc->getCallingUid(); @@ -170,14 +170,16 @@ public: if (device) { ret = device->verify(device, uid, challenge, enrolled_password_handle, enrolled_password_handle_length, - provided_password, provided_password_length, auth_token, auth_token_length); + provided_password, provided_password_length, auth_token, auth_token_length, + request_reenroll); } else { ret = soft_device->verify(uid, challenge, enrolled_password_handle, enrolled_password_handle_length, - provided_password, provided_password_length, auth_token, auth_token_length); + provided_password, provided_password_length, auth_token, auth_token_length, + request_reenroll); } - if (ret >= 0 && *auth_token != NULL && *auth_token_length > 0) { + if (ret == 0 && *auth_token != NULL && *auth_token_length > 0) { // TODO: cache service? sp sm = defaultServiceManager(); sp binder = sm->getService(String16("android.security.keystore")); @@ -192,13 +194,12 @@ public: } } - if (ret >= 0) { + if (ret == 0) { maybe_store_sid(uid, reinterpret_cast( enrolled_password_handle)->user_id); - return NO_ERROR; } - return UNKNOWN_ERROR; + return ret; } virtual uint64_t getSecureUserId(uint32_t uid) { diff --git a/gatekeeperd/tests/Android.mk b/gatekeeperd/tests/Android.mk new file mode 100644 index 000000000..6fc4ac075 --- /dev/null +++ b/gatekeeperd/tests/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_MODULE := gatekeeperd-unit-tests +LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk +LOCAL_CFLAGS += -g -Wall -Werror -std=gnu++11 -Wno-missing-field-initializers +LOCAL_SHARED_LIBRARIES := libgatekeeper libcrypto +LOCAL_STATIC_LIBRARIES := libscrypt_static +LOCAL_C_INCLUDES := external/scrypt/lib/crypto +LOCAL_SRC_FILES := \ + gatekeeper_test.cpp +include $(BUILD_NATIVE_TEST) + diff --git a/gatekeeperd/tests/gatekeeper_test.cpp b/gatekeeperd/tests/gatekeeper_test.cpp new file mode 100644 index 000000000..15b2b6922 --- /dev/null +++ b/gatekeeperd/tests/gatekeeper_test.cpp @@ -0,0 +1,204 @@ +/* + * 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); +}