diff options
author | Andres Morales <anmorales@google.com> | 2015-03-12 13:30:15 -0700 |
---|---|---|
committer | Andres Morales <anmorales@google.com> | 2015-03-19 17:31:25 -0700 |
commit | edd3e3dc860ff3d99c0320a6ee7d66347b4dd1c3 (patch) | |
tree | b7fc1b8d21a0aad3e57c505c858aaaac5dc30f4f | |
parent | 99482129e592892ef40613195d2cbcd640e031cd (diff) | |
download | gatekeeper-edd3e3dc860ff3d99c0320a6ee7d66347b4dd1c3.tar.gz |
add SIDs and password storage support to Keyguard base
Change-Id: I2b1bb41a5e40e45e810f2bd299edb6b8765df9e6
-rw-r--r-- | Android.mk | 2 | ||||
-rw-r--r-- | include/keyguard/keyguard.h | 104 | ||||
-rw-r--r-- | include/keyguard/keyguard_messages.h | 34 | ||||
-rw-r--r-- | include/keyguard/soft_keyguard.h | 86 | ||||
-rw-r--r-- | keyguard.cpp | 234 | ||||
-rw-r--r-- | keyguard_messages.cpp | 107 | ||||
-rw-r--r-- | softkeyguard/module.cpp | 2 | ||||
-rw-r--r-- | softkeyguard/native_keyguard_file_io.h | 38 | ||||
-rw-r--r-- | softkeyguard/soft_keyguard_device.cpp | 71 | ||||
-rw-r--r-- | softkeyguard/soft_keyguard_device.h (renamed from include/keyguard/soft_keyguard_device.h) | 13 | ||||
-rw-r--r-- | tests/keyguard_device_test.cpp | 6 | ||||
-rw-r--r-- | tests/keyguard_messages_test.cpp | 77 | ||||
-rw-r--r-- | tests/keyguard_test.cpp | 179 |
13 files changed, 711 insertions, 242 deletions
@@ -25,7 +25,7 @@ LOCAL_SRC_FILES := \ keyguard.cpp LOCAL_C_INCLUDES := \ $(LOCAL_PATH)/include -LOCAL_CFLAGS = -Wall -Werror +LOCAL_CFLAGS = -Wall -Werror -g LOCAL_MODULE_TAGS := optional LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk diff --git a/include/keyguard/keyguard.h b/include/keyguard/keyguard.h index 7e06c3e..8141ce3 100644 --- a/include/keyguard/keyguard.h +++ b/include/keyguard/keyguard.h @@ -25,24 +25,28 @@ namespace keyguard { +typedef uint64_t secure_id_t; +typedef uint64_t salt_t; + /** * Data format for an authentication record used to prove * successful password verification. Consumed by KeyStore * and keymaster to determine CryptoObject availability. + * + * All fields are written in network order. */ +const uint8_t AUTH_TOKEN_VERSION = 0; struct __attribute__ ((__packed__)) AuthToken { - const uint8_t auth_token_tag = 0x01; - uint32_t auth_token_size; - const uint8_t user_id_tag = 0x02; - uint32_t user_id; - const uint8_t authenticator_id_tag = 0x03; - const uint32_t authenticator_id = 0; - const uint8_t timestamp_tag = 0x04; - uint64_t timestamp; - const uint8_t hmac_tag = 0x06; - uint8_t hmac[16]; + uint8_t auth_token_version = AUTH_TOKEN_VERSION; + secure_id_t root_secure_user_id; + secure_id_t auxiliary_secure_user_id; + uint32_t authenticator_id = 0; + uint32_t timestamp; + uint8_t hmac[32]; }; +struct password_handle_t; + /** * Base class for keyguard implementations. Provides all functionality except * the ability to create/access keys and compute signatures. These are left up @@ -51,7 +55,7 @@ struct __attribute__ ((__packed__)) AuthToken { class Keyguard { public: Keyguard() {} - virtual ~Keyguard(); + virtual ~Keyguard() {} void Enroll(const EnrollRequest &request, EnrollResponse *response); void Verify(const VerifyRequest &request, VerifyResponse *response); @@ -72,6 +76,16 @@ protected: */ virtual void GetAuthTokenKey(UniquePtr<uint8_t> *auth_token_key, size_t *length) const = 0; + /** + * The key used to sign and verify password data. + * + * MUST be different from the AuthTokenKey. + * + * GetPasswordKey is not const because unlike AuthTokenKey, + * this value can and should be cached in local memory. The + * + */ + virtual void GetPasswordKey(UniquePtr<uint8_t> *password_key, size_t *length) = 0; /** * Uses platform-specific routines to compute a signature on the provided password. @@ -80,41 +94,38 @@ protected: * available in case handling for password signatures is different from general * purpose signatures. * - * Assigns the signature to the signature UniquePtr, relinquishing ownership - * to the caller. - * Writes the length in bytes of the returned key to signature_length if it is not null. - * + * Writes the signature_length size signature to the 'signature' pointer. */ - virtual void ComputePasswordSignature(const uint8_t *key, size_t key_length, - const uint8_t *password, size_t password_length, const uint8_t *salt, - size_t salt_length, UniquePtr<uint8_t> *signature, size_t *signature_length) const = 0; + virtual void ComputePasswordSignature(uint8_t *signature, size_t signature_length, + const uint8_t *key, size_t key_length, const uint8_t *password, + size_t password_length, salt_t salt) const = 0; /** - * Retrieves a unique, cryptographically randomly generated salt for use in password - * hashing. + * Retrieves a unique, cryptographically randomly generated buffer for use in password + * hashing, etc. * - * Assings the salt to the salt UniquePtr, relinquishing ownership to the caller - * Writes the length in bytes of the salt to salt_length if it is not null. + * Assings the random to the random UniquePtr, relinquishing ownership to the caller */ - virtual void GetSalt(UniquePtr<uint8_t> *salt, size_t *salt_length) const = 0; + virtual void GetRandom(void *random, size_t requested_size) const = 0; /** * Uses platform-specific routines to compute a signature on the provided message. * - * Assigns the signature to the signature UniquePtr, relinquishing ownership - * to the caller. - * Writes the length in bytes of the returned key to signature_length if it is not null. + * Writes the signature_length size signature to the 'signature' pointer. */ - virtual void ComputeSignature(const uint8_t *key, size_t key_length, - const uint8_t *message, const size_t length, UniquePtr<uint8_t> *signature, - size_t *signature_length) const = 0; + virtual void ComputeSignature(uint8_t *signature, size_t signature_length, + const uint8_t *key, size_t key_length, const uint8_t *message, + const size_t length) const = 0; /** - * The key used to sign and verify password data. This is different from the AuthTokenKey. - * It can be cached in this member variable as Keyguard is its only consumer. It should at - * no point leave Keyguard for any reason. + * Write the password file to persistent storage. */ - SizedBuffer password_key_; + virtual void ReadPasswordFile(uint32_t uid, SizedBuffer *password_file) const = 0; + + /** + * Read the password file from persistent storage. + */ + virtual void WritePasswordFile(uint32_t uid, const SizedBuffer &password_file) const = 0; private: /** @@ -123,19 +134,28 @@ private: * The format is consistent with that of AuthToken above. * Also returns the length in length if it is not null. */ - void MintAuthToken(uint32_t user_id, UniquePtr<uint8_t> *auth_token, size_t *length); + void MintAuthToken(UniquePtr<uint8_t> *auth_token, size_t *length, uint32_t timestamp, + secure_id_t user_id, secure_id_t authenticator_id); - // Takes a salt/signature and their lengths and generates a pasword handle written - // into result. - void SerializeHandle(const uint8_t *salt, size_t salt_length, const uint8_t *signature, - size_t signataure_length, SizedBuffer &result); + /** + * Verifies that handle matches password HMAC'ed with the password_key + */ + bool DoVerify(const password_handle_t *expected_handle, const SizedBuffer &password); - // Takes a handle and generates pointers into the salt and password inside the handle and - // copies out the sizes of those buffers. Makes no allocations. - keyguard_error_t DeserializeHandle(const SizedBuffer *handle, uint8_t **salt, - size_t *salt_length, uint8_t **password, size_t *password_length); + /** + * Verifies that the provided handle matches byte-by-byte what was previously + * stored as a result of a call to 'Enroll' + */ + bool ValidatePasswordFile(uint32_t uid, const SizedBuffer &provided_handle); + /** + * 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, + size_t password_length); }; + } #endif // KEYGUARD_H_ diff --git a/include/keyguard/keyguard_messages.h b/include/keyguard/keyguard_messages.h index eb8a43c..87cb38a 100644 --- a/include/keyguard/keyguard_messages.h +++ b/include/keyguard/keyguard_messages.h @@ -37,6 +37,19 @@ struct SizedBuffer { } /* + * Constructs a SizedBuffer of a provided + * length. + */ + SizedBuffer(size_t length) { + if (length != 0) { + buffer.reset(new uint8_t[length]); + } else { + buffer.reset(); + } + this->length = length; + } + + /* * Constructs a SizedBuffer out of a pointer and a length * Takes ownership of the buf pointer, and deallocates it * when destructed. @@ -123,21 +136,22 @@ struct VerifyRequest : public KeyguardMessage { }; struct VerifyResponse : public KeyguardMessage { - VerifyResponse(uint32_t user_id, SizedBuffer *verification_token); + VerifyResponse(uint32_t user_id, SizedBuffer *auth_token); VerifyResponse(); ~VerifyResponse(); - void SetVerificationToken(SizedBuffer *verification_token); + void SetVerificationToken(SizedBuffer *auth_token); virtual size_t nonErrorSerializedSize() const; virtual void nonErrorSerialize(uint8_t *buffer) const; virtual keyguard_error_t nonErrorDeserialize(const uint8_t *payload, const uint8_t *end); - SizedBuffer verification_token; + SizedBuffer auth_token; }; struct EnrollRequest : public KeyguardMessage { - EnrollRequest(uint32_t user_id, SizedBuffer *provided_password); + EnrollRequest(uint32_t user_id, SizedBuffer *password_handle, + SizedBuffer *provided_password, SizedBuffer *enrolled_password); EnrollRequest(); ~EnrollRequest(); @@ -145,6 +159,18 @@ struct EnrollRequest : public KeyguardMessage { virtual void nonErrorSerialize(uint8_t *buffer) const; virtual keyguard_error_t nonErrorDeserialize(const uint8_t *payload, const uint8_t *end); + /** + * The password handle returned from the previous call to enroll or NULL + * if none + */ + SizedBuffer password_handle; + /** + * The currently enrolled password as entered by the user + */ + SizedBuffer enrolled_password; + /** + * The password desired by the user + */ SizedBuffer provided_password; }; diff --git a/include/keyguard/soft_keyguard.h b/include/keyguard/soft_keyguard.h index 52712af..56ba775 100644 --- a/include/keyguard/soft_keyguard.h +++ b/include/keyguard/soft_keyguard.h @@ -25,9 +25,20 @@ extern "C" { #include <UniquePtr.h> #include <keyguard/keyguard.h> +#include <iostream> namespace keyguard { +/** + * Convenience class for easily switching out a testing implementation + */ +class KeyguardFileIo { +public: + virtual ~KeyguardFileIo() {} + virtual void Write(const char *filename, const uint8_t *bytes, size_t length) = 0; + virtual size_t Read(const char *filename, UniquePtr<uint8_t> *bytes) const = 0; +}; + class SoftKeyguard : public Keyguard { public: static const size_t SALT_LENGTH = 8; @@ -38,46 +49,67 @@ public: static const uint32_t r = 8; static const uint32_t p = 1; - SoftKeyguard() { - password_key_.buffer.reset(); - password_key_.length = 0; + static const int MAX_UINT_32_CHARS = 11; + + SoftKeyguard(KeyguardFileIo *file_io) { + file_io_ = file_io; + } + + virtual ~SoftKeyguard() { + delete file_io_; } - virtual void GetAuthTokenKey(UniquePtr<uint8_t> *, + virtual void GetAuthTokenKey(UniquePtr<uint8_t> *auth_token_key, size_t *length) const { - // No auth token key for SW impl - if (length != NULL) *length = 0; + auth_token_key->reset(new uint8_t[SIGNATURE_LENGTH]); + memset(auth_token_key->get(), 0, SIGNATURE_LENGTH); + if (length != NULL) *length = SIGNATURE_LENGTH; } - virtual void ComputePasswordSignature(const uint8_t *, size_t, - const uint8_t *password, size_t password_length, const uint8_t *salt, size_t salt_length, - UniquePtr<uint8_t> *signature, size_t *signature_length) const { + virtual void GetPasswordKey(UniquePtr<uint8_t> *password_key, size_t *length) { + password_key->reset(new uint8_t[SIGNATURE_LENGTH]); + memset(password_key->get(), 0, SIGNATURE_LENGTH); + if (length != NULL) *length = SIGNATURE_LENGTH; + } + + virtual void ComputePasswordSignature(uint8_t *signature, size_t signature_length, + const uint8_t *, size_t, const uint8_t *password, + size_t password_length, salt_t salt) const { if (signature == NULL) return; - uint8_t *signature_bytes = new uint8_t[SIGNATURE_LENGTH]; - crypto_scrypt(password, password_length, salt, salt_length, N, r, p, - signature_bytes, SIGNATURE_LENGTH); - if (signature_length != NULL) *signature_length = SIGNATURE_LENGTH; - signature->reset(signature_bytes); + crypto_scrypt(password, password_length, reinterpret_cast<uint8_t *>(&salt), + sizeof(salt), N, r, p, signature, signature_length); } - virtual void GetSalt(UniquePtr<uint8_t> *salt, size_t *salt_length) const { - if (salt == NULL) return; - uint8_t *salt_bytes = new uint8_t[SALT_LENGTH]; - RAND_pseudo_bytes(salt_bytes, SALT_LENGTH); - if (salt_length != NULL) *salt_length = SALT_LENGTH; - salt->reset(salt_bytes); + virtual void GetRandom(void *random, size_t requested_length) const { + if (random == NULL) return; + RAND_pseudo_bytes((uint8_t *) random, requested_length); } - virtual void ComputeSignature(const uint8_t *, size_t, - const uint8_t *, const size_t, UniquePtr<uint8_t> *signature, - size_t *signature_length) const { + virtual void ComputeSignature(uint8_t *signature, size_t signature_length, + const uint8_t *, size_t, const uint8_t *, const size_t) const { if (signature == NULL) return; - if (signature_length != NULL) *signature_length = SIGNATURE_LENGTH; - uint8_t *result = new uint8_t[16]; - memset(result, 0, 16); - signature->reset(result); + memset(signature, 0, signature_length); + } + + virtual void ReadPasswordFile(uint32_t uid, SizedBuffer *password_file) const { + char buf[MAX_UINT_32_CHARS]; + sprintf(buf, "%u", uid); + UniquePtr<uint8_t> password_buffer; + size_t length = file_io_->Read(buf, &password_buffer); + password_file->buffer.reset(password_buffer.release()); + password_file->length = length; } + virtual void WritePasswordFile(uint32_t uid, const SizedBuffer &password_file) const { + char buf[MAX_UINT_32_CHARS]; + sprintf(buf, "%u", uid); + file_io_->Write(buf, password_file.buffer.get(), password_file.length); + } + +private: + KeyguardFileIo *file_io_; }; } + #endif // SOFT_KEYGUARD_H_ + diff --git a/keyguard.cpp b/keyguard.cpp index e435a3f..3e1f338 100644 --- a/keyguard.cpp +++ b/keyguard.cpp @@ -22,34 +22,74 @@ namespace keyguard { -Keyguard::~Keyguard() { - if (password_key_.buffer.get()) { - memset_s(password_key_.buffer.get(), 0, password_key_.length); - } -} +/** + * Internal only structure for easy serialization + * and deserialization of password handles. + */ +static const uint8_t HANDLE_VERSION = 0; +struct __attribute__ ((__packed__)) password_handle_t { + // fields included in signature + uint8_t version = HANDLE_VERSION; + secure_id_t user_id; + secure_id_t authenticator_id; + + // fields not included in signature + salt_t salt; + uint8_t signature[32]; +}; void Keyguard::Enroll(const EnrollRequest &request, EnrollResponse *response) { if (response == NULL) return; - SizedBuffer enrolled_password; if (!request.provided_password.buffer.get()) { response->error = KG_ERROR_INVALID; return; } - size_t salt_length; - UniquePtr<uint8_t> salt; - GetSalt(&salt, &salt_length); + secure_id_t user_id = 0; + uint8_t *current_password = NULL; + size_t current_password_size = 0; - size_t signature_length; - UniquePtr<uint8_t> signature; - ComputePasswordSignature(password_key_.buffer.get(), - password_key_.length, request.provided_password.buffer.get(), - request.provided_password.length, salt.get(), salt_length, &signature, - &signature_length); + if (request.password_handle.buffer.get() == NULL) { + // Password handle does not match what is stored, generate new SecureID + GetRandom(&user_id, sizeof(secure_id_t)); + } else { + if (!ValidatePasswordFile(request.user_id, request.password_handle)) { + response->error = KG_ERROR_INVALID; + return; + } else { + // Password handle matches password file + 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 + response->error = KG_ERROR_INVALID; + return; + } - SerializeHandle(salt.get(), salt_length, signature.get(), signature_length, enrolled_password); - response->SetEnrolledPasswordHandle(&enrolled_password); + user_id = pw_handle->user_id; + } + } + + salt_t salt; + GetRandom(&salt, sizeof(salt)); + + secure_id_t authenticator_id; + GetRandom(&authenticator_id, sizeof(authenticator_id)); + + + SizedBuffer password_handle; + if(!CreatePasswordHandle(&password_handle, + salt, user_id, authenticator_id, request.provided_password.buffer.get(), + request.provided_password.length)) { + response->error = KG_ERROR_INVALID; + return; + } + + + WritePasswordFile(request.user_id, password_handle); + + response->SetEnrolledPasswordHandle(&password_handle); } void Keyguard::Verify(const VerifyRequest &request, VerifyResponse *response) { @@ -60,104 +100,120 @@ void Keyguard::Verify(const VerifyRequest &request, VerifyResponse *response) { return; } - size_t salt_length, signature_length; - uint8_t *salt, *signature; - keyguard_error_t error = DeserializeHandle( - &request.password_handle, &salt, &salt_length, &signature, &signature_length); + secure_id_t user_id, authenticator_id; + password_handle_t *password_handle = reinterpret_cast<password_handle_t *>( + request.password_handle.buffer.get()); - if (error != KG_ERROR_OK) { - response->error = error; + // Sanity check + if (password_handle->version != HANDLE_VERSION) { + response->error = KG_ERROR_INVALID; return; } - size_t provided_password_signature_length; - UniquePtr<uint8_t> provided_password_signature; - ComputePasswordSignature(password_key_.buffer.get(), - password_key_.length, request.provided_password.buffer.get(), request.provided_password.length, - salt, salt_length, &provided_password_signature, &provided_password_signature_length); + if (!ValidatePasswordFile(request.user_id, request.password_handle)) { + // we don't allow access to keys if we can't validate the file. + // we must allow this case to support authentication before we decrypt + // /data, however. + user_id = 0; + authenticator_id = 0; + } else { + user_id = password_handle->user_id; + authenticator_id = password_handle->authenticator_id; + } + + struct timespec time; + uint64_t timestamp; + clock_gettime(CLOCK_MONOTONIC_RAW, &time); + timestamp = static_cast<uint32_t>(time.tv_sec); - if (provided_password_signature_length == signature_length && - memcmp_s(signature, provided_password_signature.get(), signature_length) == 0) { + if (DoVerify(password_handle, request.provided_password)) { // Signature matches SizedBuffer auth_token; - MintAuthToken(request.user_id, &auth_token.buffer, &auth_token.length); + MintAuthToken(&auth_token.buffer, &auth_token.length, timestamp, + user_id, authenticator_id); response->SetVerificationToken(&auth_token); } else { response->error = KG_ERROR_INVALID; } } -void Keyguard::MintAuthToken(uint32_t user_id, UniquePtr<uint8_t> *auth_token, size_t *length) { +bool Keyguard::CreatePasswordHandle(SizedBuffer *password_handle_buffer, salt_t salt, + secure_id_t user_id, secure_id_t authenticator_id, const uint8_t *password, + size_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->salt = salt; + password_handle->user_id = user_id; + password_handle->authenticator_id = authenticator_id; + + size_t metadata_length = sizeof(user_id) /* user id */ + + sizeof(authenticator_id) /* auth id */ + sizeof(uint8_t) /* version */; + uint8_t to_sign[password_length + metadata_length]; + memcpy(to_sign, &password_handle->version, metadata_length); + memcpy(to_sign + metadata_length, password, password_length); + + UniquePtr<uint8_t> password_key; + size_t password_key_length = 0; + GetPasswordKey(&password_key, &password_key_length); + + if (!password_key.get() || password_key_length == 0) { + return false; + } + + ComputePasswordSignature(password_handle->signature, sizeof(password_handle->signature), + password_key.get(), password_key_length, to_sign, sizeof(to_sign), salt); + return true; +} + +bool Keyguard::DoVerify(const password_handle_t *expected_handle, const SizedBuffer &password) { + if (!password.buffer.get()) return false; + + SizedBuffer provided_handle; + if (!CreatePasswordHandle(&provided_handle, expected_handle->salt, expected_handle->user_id, + expected_handle->authenticator_id, password.buffer.get(), password.length)) { + return false; + } + + return memcmp_s(provided_handle.buffer.get(), expected_handle, sizeof(*expected_handle)) == 0; +} + +bool Keyguard::ValidatePasswordFile(uint32_t uid, const SizedBuffer &provided_handle) { + SizedBuffer stored_handle; + ReadPasswordFile(uid, &stored_handle); + + if (!stored_handle.buffer.get() || stored_handle.length == 0) return false; + + // do we also verify the signature here? + return stored_handle.length == provided_handle.length && + memcmp_s(stored_handle.buffer.get(), provided_handle.buffer.get(), stored_handle.length) + == 0; +} + +void Keyguard::MintAuthToken(UniquePtr<uint8_t> *auth_token, size_t *length, + uint32_t timestamp, secure_id_t user_id, secure_id_t authenticator_id) { if (auth_token == NULL) return; AuthToken *token = new AuthToken; SizedBuffer serialized_auth_token; - struct timespec time; - clock_gettime(CLOCK_MONOTONIC_RAW, &time); - - token->auth_token_size = sizeof(AuthToken) - - sizeof(token->auth_token_tag) - sizeof(token->auth_token_size); - token->user_id = user_id; - token->timestamp = static_cast<uint64_t>(time.tv_sec); + token->root_secure_user_id = user_id; + token->auxiliary_secure_user_id = authenticator_id; + token->timestamp = timestamp; UniquePtr<uint8_t> auth_token_key; size_t key_len; GetAuthTokenKey(&auth_token_key, &key_len); - size_t hash_len = (size_t)((uint8_t *)&token->hmac_tag - (uint8_t *)token); - size_t signature_len; - UniquePtr<uint8_t> signature; - ComputeSignature(auth_token_key.get(), key_len, - reinterpret_cast<uint8_t *>(token), hash_len, &signature, &signature_len); - - memset(&token->hmac, 0, sizeof(token->hmac)); + size_t hash_len = (size_t)((uint8_t *)&token->hmac - (uint8_t *)token); + ComputeSignature(token->hmac, sizeof(token->hmac), auth_token_key.get(), key_len, + reinterpret_cast<uint8_t *>(token), hash_len); - memcpy(&token->hmac, signature.get(), signature_len > sizeof(token->hmac) - ? sizeof(token->hmac) : signature_len); if (length != NULL) *length = sizeof(AuthToken); auth_token->reset(reinterpret_cast<uint8_t *>(token)); } -void Keyguard::SerializeHandle(const uint8_t *salt, size_t salt_length, const uint8_t *signature, - size_t signature_length, SizedBuffer &result) { - const size_t buffer_len = 2 * sizeof(size_t) + salt_length + signature_length; - result.buffer.reset(new uint8_t[buffer_len]); - result.length = buffer_len; - uint8_t *buffer = result.buffer.get(); - memcpy(buffer, &salt_length, sizeof(salt_length)); - buffer += sizeof(salt_length); - memcpy(buffer, salt, salt_length); - buffer += salt_length; - memcpy(buffer, &signature_length, sizeof(signature_length)); - buffer += sizeof(signature_length); - memcpy(buffer, signature, signature_length); -} - -keyguard_error_t Keyguard::DeserializeHandle(const SizedBuffer *handle, uint8_t **salt, - size_t *salt_length, uint8_t **password, size_t *password_length) { - if (handle && handle->length > (2 * sizeof(size_t))) { - int read = 0; - uint8_t *buffer = handle->buffer.get(); - memcpy(salt_length, buffer, sizeof(*salt_length)); - read += sizeof(*salt_length); - if (read + *salt_length < handle->length) { - *salt = buffer + read; - read += *salt_length; - if (read + sizeof(*password_length) < handle->length) { - buffer += read; - memcpy(password_length, buffer, sizeof(*password_length)); - *password = buffer + sizeof(*password_length); - } else { - return KG_ERROR_INVALID; - } - } else { - return KG_ERROR_INVALID; - } - - return KG_ERROR_OK; - } - return KG_ERROR_INVALID; -} - } diff --git a/keyguard_messages.cpp b/keyguard_messages.cpp index d7b90a7..34c3c91 100644 --- a/keyguard_messages.cpp +++ b/keyguard_messages.cpp @@ -33,22 +33,26 @@ static inline size_t serialized_buffer_size(const SizedBuffer &buf) { static inline void append_to_buffer(uint8_t **buffer, const SizedBuffer *to_append) { memcpy(*buffer, &to_append->length, sizeof(to_append->length)); *buffer += sizeof(to_append->length); - memcpy(*buffer, to_append->buffer.get(), to_append->length); - *buffer += to_append->length; + if (to_append->length != 0) { + memcpy(*buffer, to_append->buffer.get(), to_append->length); + *buffer += to_append->length; + } } static inline keyguard_error_t read_from_buffer(const uint8_t **buffer, const uint8_t *end, SizedBuffer *target) { - if (*buffer + sizeof(target->length) >= end) return KG_ERROR_INVALID; + if (*buffer + sizeof(target->length) > end) return KG_ERROR_INVALID; memcpy(&target->length, *buffer, sizeof(target->length)); *buffer += sizeof(target->length); - const uint8_t *buffer_end = *buffer + target->length; - if (buffer_end > end || buffer_end <= *buffer) return KG_ERROR_INVALID; + if (target->length != 0) { + const uint8_t *buffer_end = *buffer + target->length; + if (buffer_end > end || buffer_end <= *buffer) return KG_ERROR_INVALID; - target->buffer.reset(new uint8_t[target->length]); - memcpy(target->buffer.get(), *buffer, target->length); - *buffer += target->length; + target->buffer.reset(new uint8_t[target->length]); + memcpy(target->buffer.get(), *buffer, target->length); + *buffer += target->length; + } return KG_ERROR_OK; } @@ -145,51 +149,70 @@ keyguard_error_t VerifyRequest::nonErrorDeserialize(const uint8_t *payload, cons } -VerifyResponse::VerifyResponse(uint32_t user_id, SizedBuffer *verification_token) { +VerifyResponse::VerifyResponse(uint32_t user_id, SizedBuffer *auth_token) { this->user_id = user_id; - this->verification_token.buffer.reset(verification_token->buffer.release()); - this->verification_token.length = verification_token->length; + this->auth_token.buffer.reset(auth_token->buffer.release()); + this->auth_token.length = auth_token->length; } VerifyResponse::VerifyResponse() { - memset_s(&verification_token, 0, sizeof(verification_token)); + memset_s(&auth_token, 0, sizeof(auth_token)); }; VerifyResponse::~VerifyResponse() { - if (verification_token.length > 0) { - verification_token.buffer.reset(); + if (auth_token.length > 0) { + auth_token.buffer.reset(); } } -void VerifyResponse::SetVerificationToken(SizedBuffer *verification_token) { - this->verification_token.buffer.reset(verification_token->buffer.release()); - this->verification_token.length = verification_token->length; +void VerifyResponse::SetVerificationToken(SizedBuffer *auth_token) { + this->auth_token.buffer.reset(auth_token->buffer.release()); + this->auth_token.length = auth_token->length; } size_t VerifyResponse::nonErrorSerializedSize() const { - return serialized_buffer_size(verification_token); + return serialized_buffer_size(auth_token); } void VerifyResponse::nonErrorSerialize(uint8_t *buffer) const { - append_to_buffer(&buffer, &verification_token); + append_to_buffer(&buffer, &auth_token); } keyguard_error_t VerifyResponse::nonErrorDeserialize(const uint8_t *payload, const uint8_t *end) { - if (verification_token.buffer.get()) { - verification_token.buffer.reset(); + if (auth_token.buffer.get()) { + auth_token.buffer.reset(); } - return read_from_buffer(&payload, end, &verification_token); + return read_from_buffer(&payload, end, &auth_token); } -EnrollRequest::EnrollRequest(uint32_t user_id, SizedBuffer *provided_password) { +EnrollRequest::EnrollRequest(uint32_t user_id, SizedBuffer *password_handle, + SizedBuffer *provided_password, SizedBuffer *enrolled_password) { this->user_id = user_id; this->provided_password.buffer.reset(provided_password->buffer.release()); this->provided_password.length = provided_password->length; + + if (enrolled_password == NULL) { + this->enrolled_password.buffer.reset(); + this->enrolled_password.length = 0; + } else { + this->enrolled_password.buffer.reset(enrolled_password->buffer.release()); + this->enrolled_password.length = enrolled_password->length; + } + + if (password_handle == NULL) { + this->password_handle.buffer.reset(); + this->password_handle.length = 0; + } else { + this->password_handle.buffer.reset(password_handle->buffer.release()); + this->password_handle.length = password_handle->length; + } } EnrollRequest::EnrollRequest() { memset_s(&provided_password, 0, sizeof(provided_password)); + memset_s(&enrolled_password, 0, sizeof(enrolled_password)); + memset_s(&password_handle, 0, sizeof(password_handle)); } EnrollRequest::~EnrollRequest() { @@ -197,23 +220,57 @@ EnrollRequest::~EnrollRequest() { memset_s(provided_password.buffer.get(), 0, provided_password.length); provided_password.buffer.reset(); } + + if (enrolled_password.buffer.get()) { + memset_s(enrolled_password.buffer.get(), 0, enrolled_password.length); + enrolled_password.buffer.reset(); + } + + if (password_handle.buffer.get()) { + memset_s(password_handle.buffer.get(), 0, password_handle.length); + password_handle.buffer.reset(); + } } size_t EnrollRequest::nonErrorSerializedSize() const { - return serialized_buffer_size(provided_password); + return serialized_buffer_size(provided_password) + serialized_buffer_size(enrolled_password) + + serialized_buffer_size(password_handle); } void EnrollRequest::nonErrorSerialize(uint8_t *buffer) const { append_to_buffer(&buffer, &provided_password); + append_to_buffer(&buffer, &enrolled_password); + append_to_buffer(&buffer, &password_handle); } keyguard_error_t EnrollRequest::nonErrorDeserialize(const uint8_t *payload, const uint8_t *end) { + keyguard_error_t ret; if (provided_password.buffer.get()) { memset_s(provided_password.buffer.get(), 0, provided_password.length); provided_password.buffer.reset(); } - return read_from_buffer(&payload, end, &provided_password); + if (enrolled_password.buffer.get()) { + memset_s(enrolled_password.buffer.get(), 0, enrolled_password.length); + enrolled_password.buffer.reset(); + } + + if (password_handle.buffer.get()) { + memset_s(password_handle.buffer.get(), 0, password_handle.length); + password_handle.buffer.reset(); + } + + ret = read_from_buffer(&payload, end, &provided_password); + if (ret != KG_ERROR_OK) { + return ret; + } + + ret = read_from_buffer(&payload, end, &enrolled_password); + if (ret != KG_ERROR_OK) { + return ret; + } + + return read_from_buffer(&payload, end, &password_handle); } EnrollResponse::EnrollResponse(uint32_t user_id, SizedBuffer *enrolled_password_handle) { diff --git a/softkeyguard/module.cpp b/softkeyguard/module.cpp index b41ee9d..07f1ec0 100644 --- a/softkeyguard/module.cpp +++ b/softkeyguard/module.cpp @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include<keyguard/soft_keyguard_device.h> +#include "soft_keyguard_device.h" extern struct keyguard_module soft_keyguard_device_module; diff --git a/softkeyguard/native_keyguard_file_io.h b/softkeyguard/native_keyguard_file_io.h new file mode 100644 index 0000000..61a75de --- /dev/null +++ b/softkeyguard/native_keyguard_file_io.h @@ -0,0 +1,38 @@ +/* + * 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 KEYGUARD_FILE_IO_ +#define KEYGUARD_FILE_IO_ + +#include <keyguard/soft_keyguard.h> + +namespace keyguard { + +class NativeKeyguardFileIo : public ::keyguard::KeyguardFileIo { +public: + virtual void Write(const char *filename, const uint8_t *bytes, size_t length) { + // TODO + } + + virtual size_t Read(const char *filename, UniquePtr<uint8_t> *bytes) const { + // TODO + return 0; + } +private: +}; +} + +#endif // KEYGUARD_FILE_IO_ diff --git a/softkeyguard/soft_keyguard_device.cpp b/softkeyguard/soft_keyguard_device.cpp index 6422531..8781b74 100644 --- a/softkeyguard/soft_keyguard_device.cpp +++ b/softkeyguard/soft_keyguard_device.cpp @@ -14,7 +14,8 @@ * limitations under the License. */ -#include <keyguard/soft_keyguard_device.h> +#include "soft_keyguard_device.h" +#include "native_keyguard_file_io.h" __attribute__((visibility("default"))) int softkeyguard_device_open(const hw_module_t *module, const char *name, hw_device_t **device) { @@ -53,7 +54,7 @@ struct keyguard_module soft_keyguard_device_module = { namespace keyguard { SoftKeyguardDevice::SoftKeyguardDevice(const hw_module_t *module) - : impl_(new SoftKeyguard()) { + : impl_(new SoftKeyguard(new NativeKeyguardFileIo())) { #if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) static_assert(std::is_standard_layout<SoftKeyguardDevice>::value, "SoftKeyguardDevice must be standard layout"); @@ -72,8 +73,8 @@ SoftKeyguardDevice::SoftKeyguardDevice(const hw_module_t *module) device_.common.module = const_cast<hw_module_t *>(module); device_.common.close = close_device; - device_.verify = verify; - device_.enroll = enroll; + device_.verify = Verify; + device_.enroll = Enroll; } hw_device_t *SoftKeyguardDevice::hw_device() { @@ -90,19 +91,42 @@ int SoftKeyguardDevice::close_device(hw_device_t* dev) { return 0; } -int SoftKeyguardDevice::enroll(const struct keyguard_device *dev, uint32_t uid, - const uint8_t *password_payload, size_t password_payload_length, - uint8_t **enrolled_password_handle, size_t *enrolled_password_handle_length) { +int SoftKeyguardDevice::Enroll(const struct keyguard_device *dev, uint32_t uid, + const uint8_t *current_password_handle, size_t current_password_handle_length, + const uint8_t *current_password, size_t current_password_length, + const uint8_t *desired_password, size_t desired_password_length, + uint8_t **enrolled_password_handle, size_t *enrolled_password_handle_length) { if (dev == NULL || - enrolled_password_handle == NULL || enrolled_password_handle_length == NULL) + enrolled_password_handle == NULL || enrolled_password_handle_length == NULL || + desired_password == NULL || desired_password_length == 0) return -EINVAL; - uint8_t *local_password_payload = new uint8_t[password_payload_length]; - memcpy(local_password_payload, password_payload, password_payload_length); + // 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); + } - SizedBuffer provided_password(local_password_payload, password_payload_length); - EnrollRequest request(uid, &provided_password); + EnrollRequest request(uid, ¤t_password_handle_buffer, &desired_password_buffer, + ¤t_password_buffer); EnrollResponse response; convert_device(dev)->impl_->Enroll(request, &response); @@ -115,25 +139,22 @@ int SoftKeyguardDevice::enroll(const struct keyguard_device *dev, uint32_t uid, return 0; } -int SoftKeyguardDevice::verify(const struct keyguard_device *dev, uint32_t uid, +int SoftKeyguardDevice::Verify(const struct keyguard_device *dev, uint32_t uid, const uint8_t *enrolled_password_handle, size_t enrolled_password_handle_length, const uint8_t *provided_password, size_t provided_password_length, - uint8_t **verification_token, size_t *verification_token_length) { + uint8_t **auth_token, size_t *auth_token_length) { if (dev == NULL || enrolled_password_handle == NULL || provided_password == NULL) { return -EINVAL; } - uint8_t *local_provided_password = new uint8_t[provided_password_length]; - uint8_t *local_enrolled_password = new uint8_t[enrolled_password_handle_length]; - memcpy(local_provided_password, provided_password, provided_password_length); - memcpy(local_enrolled_password, enrolled_password_handle, enrolled_password_handle_length); + 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); - SizedBuffer password_handle(local_enrolled_password, - enrolled_password_handle_length); - SizedBuffer provided(local_provided_password, provided_password_length); - VerifyRequest request(uid, &password_handle, &provided); + VerifyRequest request(uid, &password_handle_buffer, &provided_password_buffer); VerifyResponse response; convert_device(dev)->impl_->Verify(request, &response); @@ -141,9 +162,9 @@ int SoftKeyguardDevice::verify(const struct keyguard_device *dev, uint32_t uid, if (response.error != KG_ERROR_OK) return -EINVAL; - if (verification_token != NULL && verification_token_length != NULL) { - *verification_token = response.verification_token.buffer.release(); - *verification_token_length = response.verification_token.length; + if (auth_token != NULL && auth_token_length != NULL) { + *auth_token = response.auth_token.buffer.release(); + *auth_token_length = response.auth_token.length; } return 0; diff --git a/include/keyguard/soft_keyguard_device.h b/softkeyguard/soft_keyguard_device.h index 6da20de..23bc944 100644 --- a/include/keyguard/soft_keyguard_device.h +++ b/softkeyguard/soft_keyguard_device.h @@ -50,27 +50,28 @@ private: * Returns: 0 on success or an error code less than 0 on error. * On error, enrolled_password_handle will not be allocated. */ - static int enroll(const struct keyguard_device *dev, uint32_t uid, - const uint8_t *password_payload, size_t password_payload_length, + static int Enroll(const struct keyguard_device *dev, uint32_t uid, + const uint8_t *current_password_handle, size_t current_password_handle_length, + const uint8_t *current_password, size_t current_password_length, + const uint8_t *desired_password, size_t desired_password_length, uint8_t **enrolled_password_handle, size_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 verification_token, + * 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 */ - static int verify(const struct keyguard_device *dev, uint32_t uid, + static int Verify(const struct keyguard_device *dev, uint32_t uid, const uint8_t *enrolled_password_handle, size_t enrolled_password_handle_length, const uint8_t *provided_password, size_t provided_password_length, - uint8_t **verification_token, size_t *verification_token_length); + uint8_t **auth_token, size_t *auth_token_length); keyguard_device device_; UniquePtr<Keyguard> impl_; diff --git a/tests/keyguard_device_test.cpp b/tests/keyguard_device_test.cpp index 0bc7db9..b3f3b21 100644 --- a/tests/keyguard_device_test.cpp +++ b/tests/keyguard_device_test.cpp @@ -55,7 +55,7 @@ TEST_F(KeyguardDeviceTest, EnrollAndVerify) { size_t auth_token_len; int ret; - ret = device->enroll(device, 0, password_payload, password_len, + ret = device->enroll(device, 0, NULL, 0, NULL, 0, password_payload, password_len, &password_handle, &password_handle_length); ASSERT_EQ(0, ret); @@ -75,8 +75,8 @@ TEST_F(KeyguardDeviceTest, EnrollAndVerifyBadPassword) { size_t auth_token_len; int ret; - ret = device->enroll(device, 0, password_payload, password_len, - &password_handle, &password_handle_length); + ret = device->enroll(device, 0, NULL, 0, NULL, 0, password_payload, password_len, + &password_handle, &password_handle_length); ASSERT_EQ(0, ret); diff --git a/tests/keyguard_messages_test.cpp b/tests/keyguard_messages_test.cpp index 10f81bd..fd70c07 100644 --- a/tests/keyguard_messages_test.cpp +++ b/tests/keyguard_messages_test.cpp @@ -46,12 +46,12 @@ static SizedBuffer *make_buffer(size_t size) { return result; } -TEST(RoundTripTest, EnrollRequest) { +TEST(RoundTripTest, EnrollRequestNullEnrolledNullHandle) { const size_t password_size = 512; SizedBuffer *provided_password = make_buffer(password_size); const SizedBuffer *deserialized_password; // create request, serialize, deserialize, and validate - EnrollRequest req(USER_ID, provided_password); + EnrollRequest req(USER_ID, NULL, provided_password, NULL); uint8_t *serialized_req = req.Serialize(); EnrollRequest deserialized_req; deserialized_req.Deserialize(serialized_req, serialized_req + req.GetSerializedSize()); @@ -64,9 +64,74 @@ TEST(RoundTripTest, EnrollRequest) { ASSERT_EQ(USER_ID, deserialized_req.user_id); ASSERT_EQ((uint32_t) password_size, deserialized_password->length); ASSERT_EQ(0, memcmp(req.provided_password.buffer.get(), deserialized_password->buffer.get(), password_size)); + ASSERT_EQ((size_t) 0, deserialized_req.enrolled_password.length); + ASSERT_EQ(NULL, deserialized_req.enrolled_password.buffer.get()); + ASSERT_EQ((size_t) 0, deserialized_req.password_handle.length); + ASSERT_EQ(NULL, deserialized_req.password_handle.buffer.get()); delete provided_password; } +TEST(RoundTripTest, EnrollRequestEmptyEnrolledEmptyHandle) { + const size_t password_size = 512; + SizedBuffer *provided_password = make_buffer(password_size); + SizedBuffer enrolled; + SizedBuffer handle; + const SizedBuffer *deserialized_password; + // create request, serialize, deserialize, and validate + EnrollRequest req(USER_ID, &handle, provided_password, &enrolled); + uint8_t *serialized_req = req.Serialize(); + EnrollRequest deserialized_req; + deserialized_req.Deserialize(serialized_req, serialized_req + req.GetSerializedSize()); + delete[] serialized_req; + + ASSERT_EQ(keyguard::keyguard_error_t::KG_ERROR_OK, + deserialized_req.error); + + deserialized_password = &deserialized_req.provided_password; + ASSERT_EQ(USER_ID, deserialized_req.user_id); + ASSERT_EQ((uint32_t) password_size, deserialized_password->length); + ASSERT_EQ(0, memcmp(req.provided_password.buffer.get(), deserialized_password->buffer.get(), password_size)); + ASSERT_EQ((size_t) 0, deserialized_req.enrolled_password.length); + ASSERT_EQ(NULL, deserialized_req.enrolled_password.buffer.get()); + ASSERT_EQ((size_t) 0, deserialized_req.password_handle.length); + ASSERT_EQ(NULL, deserialized_req.password_handle.buffer.get()); + delete provided_password; +} + +TEST(RoundTripTest, EnrollRequestNonNullEnrolledOrHandle) { + const size_t password_size = 512; + SizedBuffer *provided_password = make_buffer(password_size); + SizedBuffer *enrolled_password = make_buffer(password_size); + SizedBuffer *password_handle = make_buffer(password_size); + const SizedBuffer *deserialized_password; + const SizedBuffer *deserialized_enrolled; + const SizedBuffer *deserialized_handle; + // create request, serialize, deserialize, and validate + EnrollRequest req(USER_ID, password_handle, provided_password, enrolled_password); + uint8_t *serialized_req = req.Serialize(); + EnrollRequest deserialized_req; + deserialized_req.Deserialize(serialized_req, serialized_req + req.GetSerializedSize()); + delete[] serialized_req; + + ASSERT_EQ(keyguard::keyguard_error_t::KG_ERROR_OK, + deserialized_req.error); + + deserialized_password = &deserialized_req.provided_password; + deserialized_enrolled = &deserialized_req.enrolled_password; + deserialized_handle = &deserialized_req.password_handle; + ASSERT_EQ(USER_ID, deserialized_req.user_id); + ASSERT_EQ((uint32_t) password_size, deserialized_password->length); + ASSERT_EQ(0, memcmp(req.provided_password.buffer.get(), deserialized_password->buffer.get(), password_size)); + ASSERT_EQ((uint32_t) password_size, deserialized_enrolled->length); + ASSERT_EQ(0, memcmp(req.enrolled_password.buffer.get(), deserialized_enrolled->buffer.get(), password_size)); + ASSERT_EQ((uint32_t) password_size, deserialized_handle->length); + ASSERT_EQ(0, memcmp(req.password_handle.buffer.get(), deserialized_handle->buffer.get(), password_size)); + delete provided_password; + delete enrolled_password; + delete password_handle; +} + + TEST(RoundTripTest, EnrollResponse) { const size_t password_size = 512; SizedBuffer *enrolled_password = make_buffer(password_size); @@ -116,10 +181,10 @@ TEST(RoundTripTest, VerifyRequest) { TEST(RoundTripTest, VerifyResponse) { const size_t password_size = 512; - SizedBuffer *verification_token = make_buffer(password_size); + SizedBuffer *auth_token = make_buffer(password_size); const SizedBuffer *deserialized_password; // create request, serialize, deserialize, and validate - VerifyResponse req(USER_ID, verification_token); + VerifyResponse req(USER_ID, auth_token); uint8_t *serialized_req = req.Serialize(); VerifyResponse deserialized_req; deserialized_req.Deserialize(serialized_req, serialized_req + req.GetSerializedSize()); @@ -129,9 +194,9 @@ TEST(RoundTripTest, VerifyResponse) { deserialized_req.error); ASSERT_EQ(USER_ID, deserialized_req.user_id); - deserialized_password = &deserialized_req.verification_token; + deserialized_password = &deserialized_req.auth_token; ASSERT_EQ((uint32_t) password_size, deserialized_password->length); - ASSERT_EQ(0, memcmp(req.verification_token.buffer.get(), deserialized_password->buffer.get(), + ASSERT_EQ(0, memcmp(req.auth_token.buffer.get(), deserialized_password->buffer.get(), password_size)); } diff --git a/tests/keyguard_test.cpp b/tests/keyguard_test.cpp index 4ee09ba..02a6c34 100644 --- a/tests/keyguard_test.cpp +++ b/tests/keyguard_test.cpp @@ -16,6 +16,7 @@ #include <gtest/gtest.h> #include <UniquePtr.h> +#include <iostream> #include <keyguard/soft_keyguard.h> @@ -27,6 +28,33 @@ using ::keyguard::VerifyRequest; using ::keyguard::VerifyResponse; using ::keyguard::SoftKeyguard; using ::keyguard::AuthToken; +using ::keyguard::secure_id_t; + +class TestKeyguardFileIo : public ::keyguard::KeyguardFileIo { +public: + TestKeyguardFileIo() { + bytes_.length = 0; + } + + virtual void Write(const char *filename, const uint8_t *bytes, size_t length) { + bytes_.buffer.reset(new uint8_t[length]); + memcpy(bytes_.buffer.get(), bytes, length); + bytes_.length = length; + } + + virtual size_t Read(const char *filename, UniquePtr<uint8_t> *bytes) const { + if (!bytes_.buffer.get() || bytes_.length == 0) { + bytes->reset(); + } else { + bytes->reset(new uint8_t[bytes_.length]); + memcpy(bytes->get(), bytes_.buffer.get(), bytes_.length); + } + + return bytes_.length; + } + + SizedBuffer bytes_; +}; static void do_enroll(SoftKeyguard &keyguard, EnrollResponse *response) { SizedBuffer password; @@ -34,24 +62,24 @@ static void do_enroll(SoftKeyguard &keyguard, EnrollResponse *response) { password.buffer.reset(new uint8_t[16]); password.length = 16; memset(password.buffer.get(), 0, 16); - EnrollRequest request(0, &password); + EnrollRequest request(0, NULL, &password, NULL); keyguard.Enroll(request, response); } TEST(KeyguardTest, EnrollSuccess) { - SoftKeyguard keyguard; + SoftKeyguard keyguard(new TestKeyguardFileIo()); EnrollResponse response; do_enroll(keyguard, &response); ASSERT_EQ(::keyguard::keyguard_error_t::KG_ERROR_OK, response.error); } TEST(KeyguardTest, EnrollBogusData) { - SoftKeyguard keyguard; + SoftKeyguard keyguard(new TestKeyguardFileIo()); SizedBuffer password; EnrollResponse response; - EnrollRequest request(0, &password); + EnrollRequest request(0, NULL, &password, NULL); keyguard.Enroll(request, &response); @@ -59,7 +87,7 @@ TEST(KeyguardTest, EnrollBogusData) { } TEST(KeyguardTest, VerifySuccess) { - SoftKeyguard keyguard; + SoftKeyguard keyguard(new TestKeyguardFileIo()); SizedBuffer provided_password; EnrollResponse enroll_response; @@ -78,19 +106,144 @@ TEST(KeyguardTest, VerifySuccess) { ASSERT_EQ(::keyguard::keyguard_error_t::KG_ERROR_OK, response.error); AuthToken *auth_token = - reinterpret_cast<AuthToken *>(response.verification_token.buffer.get()); + reinterpret_cast<AuthToken *>(response.auth_token.buffer.get()); + + ASSERT_EQ((uint32_t) 0, auth_token->authenticator_id); + ASSERT_NE(~((uint32_t) 0), auth_token->timestamp); + ASSERT_NE((uint64_t) 0, auth_token->root_secure_user_id); + ASSERT_NE((uint64_t) 0, auth_token->auxiliary_secure_user_id); +} + +TEST(KeyguardTest, VerifyBadPwFile) { + TestKeyguardFileIo *fw = new TestKeyguardFileIo(); + SoftKeyguard keyguard(fw); + 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(keyguard, &enroll_response); + ASSERT_EQ(::keyguard::keyguard_error_t::KG_ERROR_OK, enroll_response.error); + + VerifyRequest request(0, &enroll_response.enrolled_password_handle, + &provided_password); + VerifyResponse response; + fw->bytes_.buffer.reset(); + keyguard.Verify(request, &response); + ASSERT_EQ(::keyguard::keyguard_error_t::KG_ERROR_OK, response.error); + + AuthToken *auth_token = + reinterpret_cast<AuthToken *>(response.auth_token.buffer.get()); + + ASSERT_EQ((uint32_t) 0, auth_token->authenticator_id); + ASSERT_NE(~((uint32_t) 0), auth_token->timestamp); + ASSERT_EQ((uint64_t) 0, auth_token->root_secure_user_id); + ASSERT_EQ((uint64_t) 0, auth_token->auxiliary_secure_user_id); +} + +TEST(KeyguardTest, TrustedReEnroll) { + SoftKeyguard keyguard(new TestKeyguardFileIo()); + 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(keyguard, &enroll_response); + ASSERT_EQ(::keyguard::keyguard_error_t::KG_ERROR_OK, 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, &enroll_response.enrolled_password_handle, + &provided_password); + VerifyResponse response; + keyguard.Verify(request, &response); + ASSERT_EQ(::keyguard::keyguard_error_t::KG_ERROR_OK, response.error); + AuthToken *auth_token = + reinterpret_cast<AuthToken *>(response.auth_token.buffer.get()); + + secure_id_t secure_id = auth_token->root_secure_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); + keyguard.Enroll(enroll_request, &enroll_response); + ASSERT_EQ(::keyguard::keyguard_error_t::KG_ERROR_OK, 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, &enroll_response.enrolled_password_handle, + &password); + keyguard.Verify(new_request, &response); + ASSERT_EQ(::keyguard::keyguard_error_t::KG_ERROR_OK, response.error); + ASSERT_EQ(secure_id, + reinterpret_cast<AuthToken *>(response.auth_token.buffer.get())->root_secure_user_id); +} + + +TEST(KeyguardTest, UntrustedReEnroll) { + SoftKeyguard keyguard(new TestKeyguardFileIo()); + 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(keyguard, &enroll_response); + ASSERT_EQ(::keyguard::keyguard_error_t::KG_ERROR_OK, enroll_response.error); + + // verify first password + VerifyRequest request(0, &enroll_response.enrolled_password_handle, + &provided_password); + VerifyResponse response; + keyguard.Verify(request, &response); + ASSERT_EQ(::keyguard::keyguard_error_t::KG_ERROR_OK, response.error); + AuthToken *auth_token = + reinterpret_cast<AuthToken *>(response.auth_token.buffer.get()); + + secure_id_t secure_id = auth_token->root_secure_user_id; - ASSERT_EQ((uint8_t) 1, auth_token->auth_token_tag); - ASSERT_EQ((uint8_t) 2, auth_token->user_id_tag); - ASSERT_EQ((uint8_t) 3, auth_token->authenticator_id_tag); - ASSERT_EQ((uint8_t) 4, auth_token->timestamp_tag); + // 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); + keyguard.Enroll(enroll_request, &enroll_response); + ASSERT_EQ(::keyguard::keyguard_error_t::KG_ERROR_OK, enroll_response.error); - ASSERT_EQ((uint32_t)0, auth_token->user_id); - ASSERT_EQ((uint32_t)0, auth_token->authenticator_id); + // verify new password + password.buffer.reset(new uint8_t[16]); + memset(password.buffer.get(), 1, 16); + password.length = 16; + VerifyRequest new_request(0, &enroll_response.enrolled_password_handle, + &password); + keyguard.Verify(new_request, &response); + ASSERT_EQ(::keyguard::keyguard_error_t::KG_ERROR_OK, response.error); + ASSERT_NE(secure_id, + reinterpret_cast<AuthToken *>(response.auth_token.buffer.get())->root_secure_user_id); } + TEST(KeyguardTest, VerifyBogusData) { - SoftKeyguard keyguard; + SoftKeyguard keyguard(new TestKeyguardFileIo()); SizedBuffer provided_password; SizedBuffer password_handle; VerifyResponse response; |