diff options
author | Andres Morales <anmorales@google.com> | 2015-05-27 01:42:48 +0000 |
---|---|---|
committer | Android Git Automerger <android-git-automerger@android.com> | 2015-05-27 01:42:48 +0000 |
commit | 7577933d39d1cd83e8677ef4dc8670d8c5391a20 (patch) | |
tree | 7906bc0f61c49d67240cf1ac3db2a9c655ced280 | |
parent | 256f5c65de28f51aabf7cefa1d0c5a1ef44e147b (diff) | |
parent | aedf605d883b4ebade9c810eb39cbf5125a58c7d (diff) | |
download | gatekeeper-7577933d39d1cd83e8677ef4dc8670d8c5391a20.tar.gz |
am aedf605d: move throttling to GateKeeper layer
* commit 'aedf605d883b4ebade9c810eb39cbf5125a58c7d':
move throttling to GateKeeper layer
-rw-r--r-- | gatekeeper.cpp | 145 | ||||
-rw-r--r-- | gatekeeper_messages.cpp | 42 | ||||
-rw-r--r-- | include/gatekeeper/gatekeeper.h | 64 | ||||
-rw-r--r-- | include/gatekeeper/gatekeeper_messages.h | 11 | ||||
-rw-r--r-- | include/gatekeeper/password_handle.h | 4 | ||||
-rw-r--r-- | include/gatekeeper/soft_gatekeeper.h | 97 | ||||
-rw-r--r-- | tests/Android.mk | 1 | ||||
-rw-r--r-- | tests/gatekeeper_device_test.cpp | 7 | ||||
-rw-r--r-- | tests/gatekeeper_test.cpp | 203 |
9 files changed, 249 insertions, 325 deletions
diff --git a/gatekeeper.cpp b/gatekeeper.cpp index 77e14e2..20794b2 100644 --- a/gatekeeper.cpp +++ b/gatekeeper.cpp @@ -28,7 +28,8 @@ void GateKeeper::Enroll(const EnrollRequest &request, EnrollResponse *response) return; } - secure_id_t user_id = 0; + secure_id_t user_id = 0;// todo: rename to policy + uint32_t uid = request.user_id; if (request.password_handle.buffer.get() == NULL) { // Password handle does not match what is stored, generate new SecureID @@ -36,15 +37,51 @@ void GateKeeper::Enroll(const EnrollRequest &request, EnrollResponse *response) } else { password_handle_t *pw_handle = reinterpret_cast<password_handle_t *>(request.password_handle.buffer.get()); - if (!DoVerify(pw_handle, request.enrolled_password)) { - // incorrect old password + + user_id = pw_handle->user_id; + + uint64_t timestamp = GetMillisecondsSinceBoot(); + + bool throttle = true; + if (pw_handle->version == 0) { + // handle version is pre-throttling + throttle = false; + } else if (pw_handle->version != HANDLE_VERSION) { response->error = ERROR_INVALID; return; } - user_id = pw_handle->user_id; + uint32_t timeout = 0; + if (throttle) { + failure_record_t record; + if (!GetFailureRecord(uid, user_id, &record)) { + response->error = ERROR_UNKNOWN; + return; + } + + if (ThrottleRequest(uid, user_id, timestamp, &record, response)) return; + + if (!IncrementFailureRecord(uid, user_id, timestamp, &record)) { + response->error = ERROR_UNKNOWN; + return; + } + + timeout = ComputeRetryTimeout(&record); + } + + if (!DoVerify(pw_handle, request.enrolled_password)) { + // incorrect old password + if (throttle && timeout > 0) { + response->SetRetryTimeout(timeout); + } else { + response->error = ERROR_INVALID; + } + return; + } } + ClearFailureRecord(uid, user_id); + salt_t salt; GetRandom(&salt, sizeof(salt)); @@ -53,8 +90,8 @@ void GateKeeper::Enroll(const EnrollRequest &request, EnrollResponse *response) SizedBuffer password_handle; - if(!CreatePasswordHandle(&password_handle, - salt, user_id, authenticator_id, request.provided_password.buffer.get(), + if (!CreatePasswordHandle(&password_handle, + salt, user_id, authenticator_id, HANDLE_VERSION, request.provided_password.buffer.get(), request.provided_password.length)) { response->error = ERROR_INVALID; return; @@ -74,40 +111,70 @@ void GateKeeper::Verify(const VerifyRequest &request, VerifyResponse *response) password_handle_t *password_handle = reinterpret_cast<password_handle_t *>( request.password_handle.buffer.get()); - // Sanity check - if (password_handle->version != HANDLE_VERSION) { + bool throttle = true; + if (password_handle->version == 0) { + // handle version is pre-throttling + throttle = false; + response->request_reenroll = true; + } else if (password_handle->version != HANDLE_VERSION) { response->error = ERROR_INVALID; return; } secure_id_t user_id = password_handle->user_id; secure_id_t authenticator_id = password_handle->authenticator_id; + uint32_t uid = request.user_id; uint64_t timestamp = GetMillisecondsSinceBoot(); + uint32_t timeout = 0; + if (throttle) { + failure_record_t record; + if (!GetFailureRecord(uid, user_id, &record)) { + response->error = ERROR_UNKNOWN; + return; + } + + if (ThrottleRequest(uid, user_id, timestamp, &record, response)) return; + + if (!IncrementFailureRecord(uid, user_id, timestamp, &record)) { + response->error = ERROR_UNKNOWN; + return; + } + + timeout = ComputeRetryTimeout(&record); + } + if (DoVerify(password_handle, request.provided_password)) { // Signature matches SizedBuffer auth_token; MintAuthToken(&auth_token.buffer, &auth_token.length, timestamp, user_id, authenticator_id, request.challenge); response->SetVerificationToken(&auth_token); + if (throttle) ClearFailureRecord(uid, user_id); } else { - response->error = ERROR_INVALID; + // compute the new timeout given the incremented record + if (throttle && timeout > 0) { + response->SetRetryTimeout(timeout); + } else { + response->error = ERROR_INVALID; + } } } bool GateKeeper::CreatePasswordHandle(SizedBuffer *password_handle_buffer, salt_t salt, - secure_id_t user_id, secure_id_t authenticator_id, const uint8_t *password, + secure_id_t user_id, secure_id_t authenticator_id, uint8_t handle_version, const uint8_t *password, uint32_t password_length) { password_handle_buffer->buffer.reset(new uint8_t[sizeof(password_handle_t)]); password_handle_buffer->length = sizeof(password_handle_t); password_handle_t *password_handle = reinterpret_cast<password_handle_t *>( password_handle_buffer->buffer.get()); - password_handle->version = HANDLE_VERSION; + password_handle->version = handle_version; password_handle->salt = salt; password_handle->user_id = user_id; password_handle->authenticator_id = authenticator_id; + password_handle->hardware_backed = IsHardwareBacked(); uint32_t metadata_length = sizeof(user_id) /* user id */ + sizeof(authenticator_id) /* auth id */ + sizeof(HANDLE_VERSION) /* version */; @@ -133,11 +200,15 @@ bool GateKeeper::DoVerify(const password_handle_t *expected_handle, const SizedB SizedBuffer provided_handle; if (!CreatePasswordHandle(&provided_handle, expected_handle->salt, expected_handle->user_id, - expected_handle->authenticator_id, password.buffer.get(), password.length)) { + expected_handle->authenticator_id, expected_handle->version, + password.buffer.get(), password.length)) { return false; } - return memcmp_s(provided_handle.buffer.get(), expected_handle, sizeof(*expected_handle)) == 0; + password_handle_t *generated_handle = + reinterpret_cast<password_handle_t *>(provided_handle.buffer.get()); + return memcmp_s(generated_handle->signature, expected_handle->signature, + sizeof(expected_handle->signature)) == 0; } void GateKeeper::MintAuthToken(UniquePtr<uint8_t> *auth_token, uint32_t *length, @@ -169,4 +240,52 @@ void GateKeeper::MintAuthToken(UniquePtr<uint8_t> *auth_token, uint32_t *length, auth_token->reset(reinterpret_cast<uint8_t *>(token)); } +uint32_t GateKeeper::ComputeRetryTimeout(const failure_record_t *record) { + if (record->failure_counter > 0 && record->failure_counter <= 10) { + if (record->failure_counter % 5 == 0) { + return 30000; + } + } else { + return 30000; + } + return 0; +} + +bool GateKeeper::ThrottleRequest(uint32_t uid, secure_id_t user_id, uint64_t timestamp, + failure_record_t *record, GateKeeperMessage *response) { + + uint64_t last_checked = record->last_checked_timestamp; + uint32_t timeout = ComputeRetryTimeout(record); + + if (timeout > 0) { + // we have a pending timeout + if (timestamp < last_checked + timeout && timestamp > last_checked) { + // attempt before timeout expired, return remaining time + response->SetRetryTimeout(timeout - (timestamp - last_checked)); + return true; + } else if (timestamp <= last_checked) { + // device was rebooted or timer reset, don't count as new failure but + // reset timeout + record->last_checked_timestamp = timestamp; + if (!WriteFailureRecord(uid, record)) { + response->error = ERROR_UNKNOWN; + return true; + } + response->SetRetryTimeout(timeout); + return true; + } + } + + return false; +} + +bool GateKeeper::IncrementFailureRecord(uint32_t uid, secure_id_t user_id, uint64_t timestamp, + failure_record_t *record) { + record->secure_user_id = user_id; + record->failure_counter++; + record->last_checked_timestamp = timestamp; + + return WriteFailureRecord(uid, record); } +} // namespace gatekeeper + diff --git a/gatekeeper_messages.cpp b/gatekeeper_messages.cpp index 4e5e833..c803666 100644 --- a/gatekeeper_messages.cpp +++ b/gatekeeper_messages.cpp @@ -65,9 +65,14 @@ static inline gatekeeper_error_t read_from_buffer(const uint8_t **buffer, const uint32_t GateKeeperMessage::GetSerializedSize() const { if (error == ERROR_NONE) { - return 2 * sizeof(uint32_t) + nonErrorSerializedSize(); + uint32_t size = sizeof(serial_header_t) + nonErrorSerializedSize(); + return size; } else { - return sizeof(uint32_t); + uint32_t size = sizeof(serial_header_t); + if (error == ERROR_RETRY) { + size += sizeof(retry_timeout); + } + return size; } } @@ -79,9 +84,14 @@ uint32_t GateKeeperMessage::Serialize(uint8_t *buffer, const uint8_t *end) const serial_header_t *header = reinterpret_cast<serial_header_t *>(buffer); if (error != ERROR_NONE) { - if (buffer + sizeof(error) > end) return 0; + if (buffer + sizeof(serial_header_t) > end) return 0; header->error = error; - bytes_written += sizeof(error); + header->user_id = user_id; + bytes_written += sizeof(*header); + if (error == ERROR_RETRY) { + memcpy(buffer + sizeof(serial_header_t), &retry_timeout, sizeof(retry_timeout)); + bytes_written += sizeof(retry_timeout); + } } else { if (buffer + sizeof(serial_header_t) + nonErrorSerializedSize() > end) return 0; @@ -103,11 +113,23 @@ gatekeeper_error_t GateKeeperMessage::Deserialize(const uint8_t *payload, const error = nonErrorDeserialize(payload + sizeof(*header), end); } else { error = static_cast<gatekeeper_error_t>(header->error); + user_id = header->user_id; + if (error == ERROR_RETRY) { + if (payload + sizeof(serial_header_t) < end) { + memcpy(&retry_timeout, payload + sizeof(serial_header_t), sizeof(retry_timeout)); + } else { + retry_timeout = 0; + } + } } return error; } +void GateKeeperMessage::SetRetryTimeout(uint32_t retry_timeout) { + this->retry_timeout = retry_timeout; + this->error = ERROR_RETRY; +} VerifyRequest::VerifyRequest(uint32_t user_id, uint64_t challenge, SizedBuffer *enrolled_password_handle, SizedBuffer *provided_password_payload) { @@ -173,6 +195,7 @@ VerifyResponse::VerifyResponse(uint32_t user_id, SizedBuffer *auth_token) { this->user_id = user_id; this->auth_token.buffer.reset(auth_token->buffer.release()); this->auth_token.length = auth_token->length; + this->request_reenroll = false; } VerifyResponse::VerifyResponse() { @@ -191,11 +214,12 @@ void VerifyResponse::SetVerificationToken(SizedBuffer *auth_token) { } uint32_t VerifyResponse::nonErrorSerializedSize() const { - return serialized_buffer_size(auth_token); + return serialized_buffer_size(auth_token) + sizeof(request_reenroll); } void VerifyResponse::nonErrorSerialize(uint8_t *buffer) const { append_to_buffer(&buffer, &auth_token); + memcpy(buffer, &request_reenroll, sizeof(request_reenroll)); } gatekeeper_error_t VerifyResponse::nonErrorDeserialize(const uint8_t *payload, const uint8_t *end) { @@ -203,7 +227,13 @@ gatekeeper_error_t VerifyResponse::nonErrorDeserialize(const uint8_t *payload, c auth_token.buffer.reset(); } - return read_from_buffer(&payload, end, &auth_token); + gatekeeper_error_t err = read_from_buffer(&payload, end, &auth_token); + if (err != ERROR_NONE) { + return err; + } + + memcpy(&request_reenroll, payload, sizeof(request_reenroll)); + return ERROR_NONE; } EnrollRequest::EnrollRequest(uint32_t user_id, SizedBuffer *password_handle, diff --git a/include/gatekeeper/gatekeeper.h b/include/gatekeeper/gatekeeper.h index 4a5edc0..33ffb9f 100644 --- a/include/gatekeeper/gatekeeper.h +++ b/include/gatekeeper/gatekeeper.h @@ -26,6 +26,12 @@ namespace gatekeeper { +struct __attribute__((packed)) failure_record_t { + uint64_t secure_user_id; + uint64_t last_checked_timestamp; + uint32_t failure_counter; +}; + /** * Base class for gatekeeper implementations. Provides all functionality except * the ability to create/access keys and compute signatures. These are left up @@ -108,6 +114,39 @@ protected: */ virtual uint64_t GetMillisecondsSinceBoot() const = 0; + /** + * Returns the value of the current failure record for the user. + * The failure record should be written to hardware-backed secure storage, such as + * RPMB. + * + * Returns true on success, false if failure record cannot be retrieved. + */ + virtual bool GetFailureRecord(uint32_t uid, secure_id_t user_id, failure_record_t *record) = 0; + + /** + * Clears the failure record for the current user. Returning the counter to 0, or deleting + * it entirely. + */ + virtual void ClearFailureRecord(uint32_t uid, secure_id_t user_id) = 0; + + /* + * Persists the provided failure record to secure, persistent storage. + * Returns true if record was successfully written. + */ + virtual bool WriteFailureRecord(uint32_t uid, failure_record_t *record) = 0; + + /** + * Computes the amount of time to throttle the user due to the current failure_record + * counter. An implementation is provided by the generic GateKeeper, but may be + * overriden. + */ + virtual uint32_t ComputeRetryTimeout(const failure_record_t *record); + + /** + * Returns whether the GateKeeper implementation is backed by hardware. + */ + virtual bool IsHardwareBacked() const = 0; + private: /** * Generates a signed attestation of an authentication event and assings @@ -127,8 +166,29 @@ private: * Populates password_handle with the data provided and computes HMAC. */ bool CreatePasswordHandle(SizedBuffer *password_handle, salt_t salt, - secure_id_t secure_id, secure_id_t authenticator_id, const uint8_t *password, - uint32_t password_length); + secure_id_t secure_id, secure_id_t authenticator_id, uint8_t handle_version, + const uint8_t *password, uint32_t password_length); + + /** + * Increments the counter on the current failure record for the provided user id. + * Sets the last_checked_timestamp to timestamp. Writes the updated record + * to *record if not null. + * + * Returns true if failure record was successfully incremented. + */ + bool IncrementFailureRecord(uint32_t uid, secure_id_t user_id, uint64_t timestamp, + failure_record_t *record); + + /** + * Determines whether the request is within the current throttle window. + * + * If the system timer has been reset due to a reboot or otherwise, resets + * the throttle window with a base at the current time. + * + * Returns true if the request is in the throttle window. + */ + bool ThrottleRequest(uint32_t uid, secure_id_t user_id, uint64_t timestamp, + failure_record_t *record, GateKeeperMessage *response); }; } diff --git a/include/gatekeeper/gatekeeper_messages.h b/include/gatekeeper/gatekeeper_messages.h index 0f89047..cea7e1c 100644 --- a/include/gatekeeper/gatekeeper_messages.h +++ b/include/gatekeeper/gatekeeper_messages.h @@ -32,6 +32,8 @@ const uint32_t VERIFY = 1; typedef enum { ERROR_NONE = 0, ERROR_INVALID = 1, + ERROR_RETRY = 2, + ERROR_UNKNOWN = 3, } gatekeeper_error_t; struct SizedBuffer { @@ -96,6 +98,13 @@ struct GateKeeperMessage { gatekeeper_error_t Deserialize(const uint8_t *payload, const uint8_t *end); /** + * Calls may fail due to throttling. If so, this sets a timeout in milliseconds + * for when the caller should attempt the call again. Additionally, sets the + * error to ERROR_RETRY. + */ + void SetRetryTimeout(uint32_t retry_timeout); + + /** * The following methods are intended to be implemented by subclasses. * They are hooks to serialize the elements specific to each particular * specialization. @@ -122,6 +131,7 @@ struct GateKeeperMessage { gatekeeper_error_t error; uint32_t user_id; + uint32_t retry_timeout; }; struct VerifyRequest : public GateKeeperMessage { @@ -154,6 +164,7 @@ struct VerifyResponse : public GateKeeperMessage { virtual gatekeeper_error_t nonErrorDeserialize(const uint8_t *payload, const uint8_t *end); SizedBuffer auth_token; + bool request_reenroll; }; struct EnrollRequest : public GateKeeperMessage { diff --git a/include/gatekeeper/password_handle.h b/include/gatekeeper/password_handle.h index 9bf4cb2..3725f7c 100644 --- a/include/gatekeeper/password_handle.h +++ b/include/gatekeeper/password_handle.h @@ -25,7 +25,7 @@ typedef uint64_t salt_t; * structure for easy serialization * and deserialization of password handles. */ -static const uint8_t HANDLE_VERSION = 0; +static const uint8_t HANDLE_VERSION = 1; struct __attribute__ ((__packed__)) password_handle_t { // fields included in signature uint8_t version; @@ -35,6 +35,8 @@ struct __attribute__ ((__packed__)) password_handle_t { // fields not included in signature salt_t salt; uint8_t signature[32]; + + bool hardware_backed; }; } diff --git a/include/gatekeeper/soft_gatekeeper.h b/include/gatekeeper/soft_gatekeeper.h deleted file mode 100644 index d4b4251..0000000 --- a/include/gatekeeper/soft_gatekeeper.h +++ /dev/null @@ -1,97 +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 <openssl/rand.h> -#include <crypto_scrypt.h> -} - -#include <UniquePtr.h> -#include <gatekeeper/gatekeeper.h> -#include <iostream> - -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<const uint8_t *>(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<const uint8_t *>(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<uint8_t *>(&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); - } -private: - UniquePtr<uint8_t> key_; -}; -} - -#endif // SOFT_GATEKEEPER_H_ - diff --git a/tests/Android.mk b/tests/Android.mk index f1238af..203a524 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -25,6 +25,5 @@ LOCAL_STATIC_LIBRARIES := libscrypt_static LOCAL_C_INCLUDES := external/scrypt/lib/crypto LOCAL_SRC_FILES := \ gatekeeper_messages_test.cpp \ - gatekeeper_test.cpp \ gatekeeper_device_test.cpp include $(BUILD_NATIVE_TEST) diff --git a/tests/gatekeeper_device_test.cpp b/tests/gatekeeper_device_test.cpp index 9f0d718..2c96941 100644 --- a/tests/gatekeeper_device_test.cpp +++ b/tests/gatekeeper_device_test.cpp @@ -63,8 +63,9 @@ TEST_F(GateKeeperDeviceTest, EnrollAndVerify) { ASSERT_EQ(0, ret); + bool should_reenroll; ret = device->verify(device, 0, 0, password_handle, password_handle_length, - password_payload, password_len, &auth_token, &auth_token_len); + password_payload, password_len, &auth_token, &auth_token_len, &should_reenroll); ASSERT_EQ(0, ret); } @@ -85,8 +86,10 @@ TEST_F(GateKeeperDeviceTest, EnrollAndVerifyBadPassword) { password_payload[0] = 4; + bool should_reenroll; ret = device->verify(device, 0, 0, password_handle, password_handle_length, - password_payload, password_len, &auth_token, &auth_token_len); + password_payload, password_len, &auth_token, &auth_token_len, + &should_reenroll); ASSERT_NE(0, ret); ASSERT_EQ(NULL, auth_token); diff --git a/tests/gatekeeper_test.cpp b/tests/gatekeeper_test.cpp deleted file mode 100644 index c5e7087..0000000 --- a/tests/gatekeeper_test.cpp +++ /dev/null @@ -1,203 +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 <gtest/gtest.h> -#include <UniquePtr.h> -#include <iostream> - -#include <gatekeeper/soft_gatekeeper.h> -#include <hardware/hw_auth_token.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<hw_auth_token_t *>(response.auth_token.buffer.get()); - - ASSERT_EQ((uint32_t) HW_AUTH_PASSWORD, 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<hw_auth_token_t *>(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<hw_auth_token_t *>(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<hw_auth_token_t *>(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<hw_auth_token_t *>(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); -} |