summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndres Morales <anmorales@google.com>2015-03-12 13:30:15 -0700
committerAndres Morales <anmorales@google.com>2015-03-19 17:31:25 -0700
commitedd3e3dc860ff3d99c0320a6ee7d66347b4dd1c3 (patch)
treeb7fc1b8d21a0aad3e57c505c858aaaac5dc30f4f
parent99482129e592892ef40613195d2cbcd640e031cd (diff)
downloadgatekeeper-edd3e3dc860ff3d99c0320a6ee7d66347b4dd1c3.tar.gz
add SIDs and password storage support to Keyguard base
Change-Id: I2b1bb41a5e40e45e810f2bd299edb6b8765df9e6
-rw-r--r--Android.mk2
-rw-r--r--include/keyguard/keyguard.h104
-rw-r--r--include/keyguard/keyguard_messages.h34
-rw-r--r--include/keyguard/soft_keyguard.h86
-rw-r--r--keyguard.cpp234
-rw-r--r--keyguard_messages.cpp107
-rw-r--r--softkeyguard/module.cpp2
-rw-r--r--softkeyguard/native_keyguard_file_io.h38
-rw-r--r--softkeyguard/soft_keyguard_device.cpp71
-rw-r--r--softkeyguard/soft_keyguard_device.h (renamed from include/keyguard/soft_keyguard_device.h)13
-rw-r--r--tests/keyguard_device_test.cpp6
-rw-r--r--tests/keyguard_messages_test.cpp77
-rw-r--r--tests/keyguard_test.cpp179
13 files changed, 711 insertions, 242 deletions
diff --git a/Android.mk b/Android.mk
index 1c4916c..8a9bd86 100644
--- a/Android.mk
+++ b/Android.mk
@@ -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, &current_password_handle_buffer, &desired_password_buffer,
+ &current_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;