summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.mk8
-rw-r--r--include/keyguard/keyguard.h91
-rw-r--r--include/keyguard/keyguard_messages.h63
-rw-r--r--include/keyguard/keyguard_utils.h57
-rw-r--r--keyguard.cpp92
-rw-r--r--keyguard_messages.cpp63
-rw-r--r--tests/Android.mk6
-rw-r--r--tests/keyguard_messages_test.cpp16
-rw-r--r--tests/keyguard_test.cpp128
9 files changed, 482 insertions, 42 deletions
diff --git a/Android.mk b/Android.mk
index 8a28334..b82d90a 100644
--- a/Android.mk
+++ b/Android.mk
@@ -15,12 +15,14 @@
LOCAL_PATH := $(call my-dir)
###
-# libkeyguard_messages contains just the code necessary to communicate with a
+# libkeyguard contains just the code necessary to communicate with a
# GoogleKeyguard implementation, e.g. one running in TrustZone.
##
include $(CLEAR_VARS)
-LOCAL_MODULE:= libkeyguard_messages
-LOCAL_SRC_FILES:= keyguard_messages.cpp
+LOCAL_MODULE:= libkeyguard
+LOCAL_SRC_FILES := \
+ keyguard_messages.cpp \
+ google_keyguard.cpp
LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/include
LOCAL_CFLAGS = -Wall -Werror
diff --git a/include/keyguard/keyguard.h b/include/keyguard/keyguard.h
new file mode 100644
index 0000000..cae9d05
--- /dev/null
+++ b/include/keyguard/keyguard.h
@@ -0,0 +1,91 @@
+/*
+ * 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 GOOGLE_KEYGUARD_H_
+#define GOOGLE_KEYGUARD_H_
+
+#include <memory>
+#include <stdint.h>
+
+#include "keyguard_messages.h"
+
+namespace keyguard {
+
+/**
+ * Data format for an authentication record used to prove
+ * successful password verification. Consumed by KeyStore
+ * and keymaster to determine CryptoObject availability.
+ */
+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];
+};
+
+/**
+ * Base class for keyguard implementations. Provides all functionality except
+ * the ability to create/access keys and compute signatures. These are left up
+ * to the platform-specific implementation.
+ */
+class GoogleKeyguard {
+public:
+ GoogleKeyguard() {}
+ virtual ~GoogleKeyguard();
+
+ void Enroll(const EnrollRequest &request, EnrollResponse *response);
+ void Verify(const VerifyRequest &request, VerifyResponse *response);
+
+protected:
+ /**
+ * Generates a signed attestation of an authentication event.
+ * The format is consistent with that of AuthToken above.
+ */
+ std::unique_ptr<uint8_t> MintAuthToken(uint32_t user_id, size_t *length);
+
+ // The following methods are intended to be implemented by concrete subclasses
+
+ /**
+ * Retrieves the key used by GoogleKeyguard::MintAuthToken to sign the payload
+ * of the AuthToken. This is not cached as is may have changed due to an event such
+ * as a password change.
+ */
+ virtual std::unique_ptr<uint8_t[]> GetAuthTokenKey() const = 0;
+
+ /**
+ * Uses platform-specific routines to compute a signature on the provided message.
+ * Returns a pointer to the signature, as well as the length in signature_length if
+ * it is not NULL.
+ */
+ virtual std::unique_ptr<uint8_t> ComputeSignature(const uint8_t key[],
+ const uint8_t *message, const size_t length, size_t *signature_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.
+ */
+ std::unique_ptr<uint8_t[]> password_key_;
+};
+}
+
+#endif // GOOGLE_KEYGUARD_H_
diff --git a/include/keyguard/keyguard_messages.h b/include/keyguard/keyguard_messages.h
index 9907527..59c9f04 100644
--- a/include/keyguard/keyguard_messages.h
+++ b/include/keyguard/keyguard_messages.h
@@ -19,6 +19,10 @@
#include <memory>
#include <stdint.h>
+#include "google_keyguard_utils.h"
+/**
+ * Message serialization objects for communicating with the hardware keyguard.
+ */
namespace keyguard {
typedef enum {
@@ -31,36 +35,86 @@ typedef struct {
size_t length;
} SizedBuffer;
+/*
+ * Abstract base class of all message objects. Handles serialization of common
+ * elements like the error and user ID. Delegates specialized serialization
+ * to protected pure virtual functions implemented by subclasses.
+ */
class KeyguardMessage {
public:
KeyguardMessage() : error_(KG_ERROR_OK) {}
KeyguardMessage(keyguard_error_t error) : error_(error) {}
virtual ~KeyguardMessage() {}
+ /**
+ * Returns serialized size in bytes of the current state of the
+ * object.
+ */
size_t GetSerializedSize() const;
+ /**
+ * Converts the object into its serialized representation.
+ * The returned buffer's ownwership is tranferred to the caller.
+ * TODO: make this return a unique_ptr so that this is clear
+ */
uint8_t *Serialize() const;
+
+ /**
+ * Inflates the object from its serial representation.
+ */
keyguard_error_t Deserialize(const uint8_t *payload, const uint8_t *end);
+
keyguard_error_t GetError() const { return error_; }
+ void SetError(const keyguard_error_t error) { error_ = error; }
+ uint32_t GetUserId() const { return user_id_; }
protected:
+ /**
+ * The following methods are intended to be implemented by subclasses.
+ * They are hooks to serialize the elements specific to each particular
+ * specialization.
+ */
+
+ /**
+ * Returns the size of serializing only the elements specific to the
+ * current sublclass.
+ */
virtual size_t nonErrorSerializedSize() const { return 0; } ;
+ /**
+ * Takes a pointer to a buffer prepared by Serialize and writes
+ * the subclass specific data into it. The size of the buffer is exaclty
+ * that returned by nonErrorSerializedSize() in bytes.
+ */
virtual void nonErrorSerialize(uint8_t *buffer) const { }
+
+ /**
+ * Deserializes subclass specific data from payload without reading past end.
+ */
virtual keyguard_error_t nonErrorDeserialize(const uint8_t *payload, const uint8_t *end) {
return KG_ERROR_OK;
}
keyguard_error_t error_;
+ uint32_t user_id_;
};
class VerifyRequest : public KeyguardMessage {
public:
VerifyRequest(
+ uint32_t user_id,
SizedBuffer *enrolled_password_handle,
SizedBuffer *provided_password_payload);
VerifyRequest();
~VerifyRequest();
+ /**
+ * The currently enrolled password handle returned by Enroll.
+ */
const SizedBuffer *GetPasswordHandle() const { return &password_handle_; }
+
+ /**
+ * The password provided by the user to be verified against the password handle
+ * above.
+ */
const SizedBuffer *GetProvidedPassword() const { return &provided_password_; }
protected:
@@ -75,10 +129,11 @@ private:
class VerifyResponse : public KeyguardMessage {
public:
- VerifyResponse(SizedBuffer *verification_token);
+ VerifyResponse(uint32_t user_id, SizedBuffer *verification_token);
VerifyResponse();
~VerifyResponse();
+ void SetVerificationToken(SizedBuffer *verification_token);
const SizedBuffer *GetVerificationToken() const { return &verification_token_; }
protected:
@@ -92,10 +147,11 @@ private:
class EnrollRequest : public KeyguardMessage {
public:
- EnrollRequest(SizedBuffer *provided_password);
+ EnrollRequest(uint32_t user_id, SizedBuffer *provided_password);
EnrollRequest();
~EnrollRequest();
+
const SizedBuffer *GetProvidedPassword() const { return &provided_password_; }
protected:
@@ -108,10 +164,11 @@ private:
class EnrollResponse : public KeyguardMessage {
public:
- EnrollResponse(SizedBuffer *enrolled_password_handle);
+ EnrollResponse(uint32_t user_id, SizedBuffer *enrolled_password_handle);
EnrollResponse();
~EnrollResponse();
+ void SetEnrolledPasswordHandle(SizedBuffer *password_handle);
const SizedBuffer *GetEnrolledPasswordHandle() const { return &enrolled_password_handle_; }
protected:
diff --git a/include/keyguard/keyguard_utils.h b/include/keyguard/keyguard_utils.h
new file mode 100644
index 0000000..fd00248
--- /dev/null
+++ b/include/keyguard/keyguard_utils.h
@@ -0,0 +1,57 @@
+/*
+ * 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 GOOGLE_KEYGUARD_UTILS_H_
+#define GOOGLE_KEYGUARD_UTILS_H_
+
+#include <string.h>
+
+namespace keyguard {
+/**
+ * Variant of memset() that uses GCC-specific pragmas to disable optimizations, so effect is not
+ * optimized away. This is important because we often need to wipe blocks of sensitive data from
+ * memory. As an additional convenience, this implementation avoids writing to NULL pointers.
+ */
+#ifdef __clang__
+#define OPTNONE __attribute__((optnone))
+#else // not __clang__
+#define OPTNONE __attribute__((optimize("O0")))
+#endif // not __clang__
+inline OPTNONE void* memset_s(void* s, int c, size_t n) {
+ if (!s)
+ return s;
+ return memset(s, c, n);
+}
+#undef OPTNONE
+
+/**
+ * Return the number of elements in array \p a.
+ */
+template <typename T, size_t N> inline size_t array_length(const T (&)[N]) {
+ return N;
+}
+
+static int memcmp_s(const void* p1, const void* p2, size_t length) {
+ const uint8_t* s1 = static_cast<const uint8_t*>(p1);
+ const uint8_t* s2 = static_cast<const uint8_t*>(p2);
+ uint8_t result = 0;
+ while (length-- > 0)
+ result |= *s1++ ^ *s2++;
+ return result == 0 ? 0 : 1;
+}
+
+};
+#endif //GOOGLE_KEYGUARD_UTILS_H_
diff --git a/keyguard.cpp b/keyguard.cpp
new file mode 100644
index 0000000..95cfc73
--- /dev/null
+++ b/keyguard.cpp
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <sys/time.h>
+
+#include <keyguard/google_keyguard.h>
+
+namespace keyguard {
+
+GoogleKeyguard::~GoogleKeyguard() {
+ if (password_key_) {
+ memset_s(password_key_.get(), 0, sizeof(password_key_.get()) / sizeof(password_key_[0]));
+ }
+}
+
+void GoogleKeyguard::Enroll(const EnrollRequest &request, EnrollResponse *response) {
+ if (response == NULL) return;
+
+ SizedBuffer enrolled_password;
+ const SizedBuffer *provided_password = request.GetProvidedPassword();
+ if (provided_password == NULL || !provided_password->buffer) {
+ response->SetError(KG_ERROR_INVALID);
+ return;
+ }
+ enrolled_password.buffer = ComputeSignature(password_key_.get(),
+ provided_password->buffer.get(), provided_password->length, &enrolled_password.length);
+ response->SetEnrolledPasswordHandle(&enrolled_password);
+}
+
+void GoogleKeyguard::Verify(const VerifyRequest &request, VerifyResponse *response) {
+ if (response == NULL) return;
+
+ const SizedBuffer *enrolled_password = request.GetPasswordHandle();
+ const SizedBuffer *provided_password = request.GetProvidedPassword();
+
+
+ if (provided_password == NULL || !provided_password->buffer
+ || enrolled_password == NULL || !enrolled_password->buffer) {
+ response->SetError(KG_ERROR_INVALID);
+ return;
+ }
+
+ SizedBuffer signed_provided_password;
+ signed_provided_password.buffer = ComputeSignature(password_key_.get(),
+ provided_password->buffer.get(), provided_password->length,
+ &signed_provided_password.length);
+ if (memcmp_s(enrolled_password->buffer.get(), signed_provided_password.buffer.get(),
+ enrolled_password->length) == 0) {
+ // Signature matches
+ SizedBuffer auth_token;
+ auth_token.buffer = MintAuthToken(request.GetUserId(), &auth_token.length);
+ response->SetVerificationToken(&auth_token);
+ } else {
+ response->SetError(KG_ERROR_INVALID);
+ }
+}
+
+std::unique_ptr<uint8_t> GoogleKeyguard::MintAuthToken(uint32_t user_id, size_t *length) {
+ AuthToken *auth_token = new AuthToken;
+ SizedBuffer serialized_auth_token;
+
+ struct timeval time;
+ gettimeofday(&time, NULL);
+
+ auth_token->auth_token_size = sizeof(AuthToken) -
+ sizeof(auth_token->auth_token_tag) - sizeof(auth_token->auth_token_size);
+ auth_token->user_id = user_id;
+ auth_token->timestamp = static_cast<uint64_t>(time.tv_sec);
+
+ size_t hash_len = (size_t)((uint8_t *)&auth_token->hmac_tag - (uint8_t *)auth_token);
+ size_t signature_len;
+ std::unique_ptr<uint8_t> signature = ComputeSignature(GetAuthTokenKey().get(),
+ reinterpret_cast<uint8_t *>(auth_token), hash_len, &signature_len);
+
+ memcpy(&auth_token->hmac, signature.get(), sizeof(auth_token->hmac));
+ if (length != NULL) *length = sizeof(AuthToken);
+ std::unique_ptr<uint8_t> result(reinterpret_cast<uint8_t *>(auth_token));
+ return result;
+}
+}
diff --git a/keyguard_messages.cpp b/keyguard_messages.cpp
index 0c92e78..2b550c4 100644
--- a/keyguard_messages.cpp
+++ b/keyguard_messages.cpp
@@ -13,34 +13,20 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*
- *
- * TODO(anmorales): figure out a reasonable max buffer size
*/
#include <keyguard/keyguard_messages.h>
#include <string.h>
+
namespace keyguard {
/**
- * Variant of memset() that uses GCC-specific pragmas to disable optimizations, so effect is not
- * optimized away. This is important because we often need to wipe blocks of sensitive data from
- * memory. As an additional convenience, this implementation avoids writing to NULL pointers.
+ * Methods for serializing/deserializing SizedBuffers
*/
-#ifdef __clang__
-#define OPTNONE __attribute__((optnone))
-#else // not __clang__
-#define OPTNONE __attribute__((optimize("O0")))
-#endif // not __clang__
-inline OPTNONE void* memset_s(void* s, int c, size_t n) {
- if (!s)
- return s;
- return memset(s, c, n);
-}
-#undef OPTNONE
-
-static inline size_t buffer_size(const SizedBuffer &buf) {
+
+static inline size_t serialized_buffer_size(const SizedBuffer &buf) {
return sizeof(uint32_t) + buf.length;
}
@@ -66,9 +52,10 @@ static inline keyguard_error_t read_from_buffer(const uint8_t **buffer, const ui
return KG_ERROR_OK;
}
+
size_t KeyguardMessage::GetSerializedSize() const {
if (error_ == KG_ERROR_OK) {
- return sizeof(uint32_t) + nonErrorSerializedSize();
+ return 2 * sizeof(uint32_t) + nonErrorSerializedSize();
} else {
return sizeof(uint32_t);
}
@@ -80,10 +67,11 @@ uint8_t *KeyguardMessage::Serialize() const {
*error_buf = static_cast<uint32_t>(error_);
return reinterpret_cast<uint8_t *>(error_buf);
} else {
- uint8_t *buf = new uint8_t[sizeof(uint32_t) + nonErrorSerializedSize()];
+ uint8_t *buf = new uint8_t[2*sizeof(uint32_t) + nonErrorSerializedSize()];
uint32_t error_value = static_cast<uint32_t>(error_);
memcpy(buf, &error_value, sizeof(uint32_t));
- nonErrorSerialize(buf + sizeof(uint32_t));
+ memcpy(buf + sizeof(uint32_t), &user_id_, sizeof(user_id_));
+ nonErrorSerialize(buf + 2*sizeof(uint32_t));
return buf;
}
}
@@ -93,7 +81,10 @@ keyguard_error_t KeyguardMessage::Deserialize(const uint8_t *payload, const uint
if (payload + sizeof(uint32_t) > end) return KG_ERROR_INVALID;
memcpy(&error_value, payload, sizeof(uint32_t));
error_ = static_cast<keyguard_error_t>(error_value);
+ payload += sizeof(uint32_t);
if (error_ == KG_ERROR_OK) {
+ if (payload == end) return KG_ERROR_INVALID;
+ user_id_ = *((uint32_t *) payload);
error_ = nonErrorDeserialize(payload + sizeof(uint32_t), end);
}
@@ -101,8 +92,9 @@ keyguard_error_t KeyguardMessage::Deserialize(const uint8_t *payload, const uint
}
-VerifyRequest::VerifyRequest(SizedBuffer *enrolled_password_handle,
+VerifyRequest::VerifyRequest(uint32_t user_id, SizedBuffer *enrolled_password_handle,
SizedBuffer *provided_password_payload) {
+ user_id_ = user_id;
password_handle_.buffer = std::move(enrolled_password_handle->buffer);
password_handle_.length = enrolled_password_handle->length;
provided_password_.buffer = std::move(provided_password_payload->buffer);
@@ -126,7 +118,7 @@ VerifyRequest::~VerifyRequest() {
}
size_t VerifyRequest::nonErrorSerializedSize() const {
- return buffer_size(password_handle_) + buffer_size(provided_password_);
+ return serialized_buffer_size(password_handle_) + serialized_buffer_size(provided_password_);
}
void VerifyRequest::nonErrorSerialize(uint8_t *buffer) const {
@@ -153,7 +145,8 @@ keyguard_error_t VerifyRequest::nonErrorDeserialize(const uint8_t *payload, cons
}
-VerifyResponse::VerifyResponse(SizedBuffer *verification_token) {
+VerifyResponse::VerifyResponse(uint32_t user_id, SizedBuffer *verification_token) {
+ user_id_ = user_id;
verification_token_.buffer = std::move(verification_token->buffer);
verification_token_.length = verification_token->length;
}
@@ -168,8 +161,13 @@ VerifyResponse::~VerifyResponse() {
}
}
+void VerifyResponse::SetVerificationToken(SizedBuffer *verification_token) {
+ verification_token_.buffer = std::move(verification_token->buffer);
+ verification_token_.length = verification_token->length;
+}
+
size_t VerifyResponse::nonErrorSerializedSize() const {
- return buffer_size(verification_token_);
+ return serialized_buffer_size(verification_token_);
}
void VerifyResponse::nonErrorSerialize(uint8_t *buffer) const {
@@ -184,7 +182,8 @@ keyguard_error_t VerifyResponse::nonErrorDeserialize(const uint8_t *payload, con
return read_from_buffer(&payload, end, &verification_token_);
}
-EnrollRequest::EnrollRequest(SizedBuffer *provided_password) {
+EnrollRequest::EnrollRequest(uint32_t user_id, SizedBuffer *provided_password) {
+ user_id_ = user_id;
provided_password_.buffer = std::move(provided_password->buffer);
provided_password_.length = provided_password->length;
}
@@ -201,7 +200,7 @@ EnrollRequest::~EnrollRequest() {
}
size_t EnrollRequest::nonErrorSerializedSize() const {
- return buffer_size(provided_password_);
+ return serialized_buffer_size(provided_password_);
}
void EnrollRequest::nonErrorSerialize(uint8_t *buffer) const {
@@ -217,7 +216,8 @@ keyguard_error_t EnrollRequest::nonErrorDeserialize(const uint8_t *payload, cons
return read_from_buffer(&payload, end, &provided_password_);
}
-EnrollResponse::EnrollResponse(SizedBuffer *enrolled_password_handle) {
+EnrollResponse::EnrollResponse(uint32_t user_id, SizedBuffer *enrolled_password_handle) {
+ user_id_ = user_id;
enrolled_password_handle_.buffer = std::move(enrolled_password_handle->buffer);
enrolled_password_handle_.length = enrolled_password_handle->length;
}
@@ -232,8 +232,13 @@ EnrollResponse::~EnrollResponse() {
}
}
+void EnrollResponse::SetEnrolledPasswordHandle(SizedBuffer *enrolled_password_handle) {
+ enrolled_password_handle_.buffer = std::move(enrolled_password_handle->buffer);
+ enrolled_password_handle_.length = enrolled_password_handle->length;
+}
+
size_t EnrollResponse::nonErrorSerializedSize() const {
- return buffer_size(enrolled_password_handle_);
+ return serialized_buffer_size(enrolled_password_handle_);
}
void EnrollResponse::nonErrorSerialize(uint8_t *buffer) const {
diff --git a/tests/Android.mk b/tests/Android.mk
index 60fc50f..7b2f1f3 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -20,6 +20,8 @@ include $(CLEAR_VARS)
LOCAL_MODULE := keyguard-unit-tests
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
LOCAL_CFLAGS += -g -Wall -Werror -std=gnu++11 -Wno-missing-field-initializers
-LOCAL_SHARED_LIBRARIES += libkeyguard_messages
-LOCAL_SRC_FILES := keyguard_messages_test.cpp
+LOCAL_SHARED_LIBRARIES += libkeyguard
+LOCAL_SRC_FILES := \
+ keyguard_messages_test.cpp \
+ keyguard_test.cpp
include $(BUILD_NATIVE_TEST)
diff --git a/tests/keyguard_messages_test.cpp b/tests/keyguard_messages_test.cpp
index 77fbb99..dc579f7 100644
--- a/tests/keyguard_messages_test.cpp
+++ b/tests/keyguard_messages_test.cpp
@@ -30,6 +30,8 @@ using ::keyguard::VerifyResponse;
using std::cout;
using std::endl;
+static const uint32_t USER_ID = 3857;
+
static SizedBuffer *make_buffer(size_t size) {
SizedBuffer *result = new SizedBuffer;
result->length = size;
@@ -49,7 +51,7 @@ TEST(RoundTripTest, EnrollRequest) {
SizedBuffer *provided_password = make_buffer(password_size);
const SizedBuffer *deserialized_password;
// create request, serialize, deserialize, and validate
- EnrollRequest req(provided_password);
+ EnrollRequest req(USER_ID, provided_password);
uint8_t *serialized_req = req.Serialize();
EnrollRequest deserialized_req;
deserialized_req.Deserialize(serialized_req, serialized_req + req.GetSerializedSize());
@@ -59,6 +61,7 @@ TEST(RoundTripTest, EnrollRequest) {
deserialized_req.GetError());
deserialized_password = deserialized_req.GetProvidedPassword();
+ ASSERT_EQ(USER_ID, deserialized_req.GetUserId());
ASSERT_EQ((uint32_t) password_size, deserialized_password->length);
ASSERT_EQ(0, memcmp(req.GetProvidedPassword()->buffer.get(), deserialized_password->buffer.get(), password_size));
}
@@ -68,7 +71,7 @@ TEST(RoundTripTest, EnrollResponse) {
SizedBuffer *enrolled_password = make_buffer(password_size);
const SizedBuffer *deserialized_password;
// create request, serialize, deserialize, and validate
- EnrollResponse req(enrolled_password);
+ EnrollResponse req(USER_ID, enrolled_password);
uint8_t *serialized_req = req.Serialize();
EnrollResponse deserialized_req;
deserialized_req.Deserialize(serialized_req, serialized_req + req.GetSerializedSize());
@@ -78,17 +81,18 @@ TEST(RoundTripTest, EnrollResponse) {
deserialized_req.GetError());
deserialized_password = deserialized_req.GetEnrolledPasswordHandle();
+ ASSERT_EQ(USER_ID, deserialized_req.GetUserId());
ASSERT_EQ((uint32_t) password_size, deserialized_password->length);
ASSERT_EQ(0, memcmp(req.GetEnrolledPasswordHandle()->buffer.get(), deserialized_password->buffer.get(), password_size));
}
TEST(RoundTripTest, VerifyRequest) {
- const size_t password_size = 1;
+ const size_t password_size = 512;
SizedBuffer *provided_password = make_buffer(password_size),
*password_handle = make_buffer(password_size);
const SizedBuffer *deserialized_password;
// create request, serialize, deserialize, and validate
- VerifyRequest req(password_handle, provided_password);
+ VerifyRequest req(USER_ID, password_handle, provided_password);
uint8_t *serialized_req = req.Serialize();
VerifyRequest deserialized_req;
deserialized_req.Deserialize(serialized_req, serialized_req + req.GetSerializedSize());
@@ -96,6 +100,7 @@ TEST(RoundTripTest, VerifyRequest) {
ASSERT_EQ(keyguard::keyguard_error_t::KG_ERROR_OK,
deserialized_req.GetError());
+ ASSERT_EQ(USER_ID, deserialized_req.GetUserId());
deserialized_password = deserialized_req.GetProvidedPassword();
ASSERT_EQ((uint32_t) password_size, deserialized_password->length);
ASSERT_EQ(0, memcmp(req.GetProvidedPassword()->buffer.get(), deserialized_password->buffer.get(), password_size));
@@ -110,7 +115,7 @@ TEST(RoundTripTest, VerifyResponse) {
SizedBuffer *verification_token = make_buffer(password_size);
const SizedBuffer *deserialized_password;
// create request, serialize, deserialize, and validate
- VerifyResponse req(verification_token);
+ VerifyResponse req(USER_ID, verification_token);
uint8_t *serialized_req = req.Serialize();
VerifyResponse deserialized_req;
deserialized_req.Deserialize(serialized_req, serialized_req + req.GetSerializedSize());
@@ -119,6 +124,7 @@ TEST(RoundTripTest, VerifyResponse) {
ASSERT_EQ(keyguard::keyguard_error_t::KG_ERROR_OK,
deserialized_req.GetError());
+ ASSERT_EQ(USER_ID, deserialized_req.GetUserId());
deserialized_password = deserialized_req.GetVerificationToken();
ASSERT_EQ((uint32_t) password_size, deserialized_password->length);
ASSERT_EQ(0, memcmp(req.GetVerificationToken()->buffer.get(), deserialized_password->buffer.get(), password_size));
diff --git a/tests/keyguard_test.cpp b/tests/keyguard_test.cpp
new file mode 100644
index 0000000..8b733df
--- /dev/null
+++ b/tests/keyguard_test.cpp
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <keyguard/google_keyguard.h>
+
+using ::keyguard::SizedBuffer;
+using ::testing::Test;
+using ::keyguard::EnrollRequest;
+using ::keyguard::EnrollResponse;
+using ::keyguard::VerifyRequest;
+using ::keyguard::VerifyResponse;
+using ::keyguard::GoogleKeyguard;
+using ::keyguard::AuthToken;
+
+class FakeKeyguard : public GoogleKeyguard {
+public:
+ FakeKeyguard() {
+ password_key_ = std::unique_ptr<uint8_t[]>(new uint8_t[16] {
+ 2, 34, 23, 43, 52, 25, 234, 22, 65, 24, 90,
+ 48, 5, 52, 62, 12 });
+ }
+
+private:
+ std::unique_ptr<uint8_t[]> GetAuthTokenKey() const {
+ return std::unique_ptr<uint8_t[]>(new uint8_t[16] {
+ 2, 34, 23, 43, 52, 25, 234, 22, 65, 24, 90,
+ 48, 5, 52, 62, 12 });
+ }
+
+ std::unique_ptr<uint8_t> ComputeSignature(const uint8_t key[],
+ const uint8_t *message, const size_t length, size_t *signature_length) const {
+ const size_t signature_size = 16;
+ uint8_t *signature = new uint8_t[signature_size];
+ memset(signature, 0, signature_size);
+ size_t len = length >= signature_size ? signature_size : length;
+ memcpy(signature, message, len);
+ if (signature_length != NULL) *signature_length = len;
+ return std::unique_ptr<uint8_t>(signature);
+ }
+};
+
+TEST(KeyguardTest, EnrollSuccess) {
+ FakeKeyguard keyguard;
+ SizedBuffer password;
+ EnrollResponse response;
+
+ password.buffer = std::unique_ptr<uint8_t>(new uint8_t[16]);
+ password.length = 16;
+ memset(password.buffer.get(), 0, 16);
+ EnrollRequest request(0, &password);
+
+ keyguard.Enroll(request, &response);
+
+ ASSERT_EQ(::keyguard::keyguard_error_t::KG_ERROR_OK, response.GetError());
+ ASSERT_EQ((size_t) 16, response.GetEnrolledPasswordHandle()->length);
+}
+
+TEST(KeyguardTest, EnrollBogusData) {
+ FakeKeyguard keyguard;
+ SizedBuffer password;
+ EnrollResponse response;
+
+ EnrollRequest request(0, &password);
+
+ keyguard.Enroll(request, &response);
+
+ ASSERT_EQ(::keyguard::keyguard_error_t::KG_ERROR_INVALID, response.GetError());
+}
+
+TEST(KeyguardTest, VerifySuccess) {
+ FakeKeyguard keyguard;
+ SizedBuffer provided_password;
+ SizedBuffer password_handle;
+
+ provided_password.buffer = std::unique_ptr<uint8_t>(new uint8_t[16]);
+ provided_password.length = 16;
+ memset(provided_password.buffer.get(), 0, 16);
+
+ password_handle.buffer = std::unique_ptr<uint8_t>(new uint8_t[16]);
+ password_handle.length = 16;
+ memset(password_handle.buffer.get(), 0, 16);
+
+ VerifyRequest request(0, &password_handle, &provided_password);
+ VerifyResponse response;
+
+ keyguard.Verify(request, &response);
+
+ ASSERT_EQ(::keyguard::keyguard_error_t::KG_ERROR_OK, response.GetError());
+
+ AuthToken *auth_token =
+ reinterpret_cast<AuthToken *>(response.GetVerificationToken()->buffer.get());
+
+ 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);
+
+ ASSERT_EQ((uint32_t)0, auth_token->user_id);
+ ASSERT_EQ((uint32_t)0, auth_token->authenticator_id);
+}
+
+TEST(KeyguardTest, VerifyBogusData) {
+ FakeKeyguard keyguard;
+ SizedBuffer provided_password;
+ SizedBuffer password_handle;
+ VerifyResponse response;
+
+ VerifyRequest request(0, &provided_password, &password_handle);
+
+ keyguard.Verify(request, &response);
+
+ ASSERT_EQ(::keyguard::keyguard_error_t::KG_ERROR_INVALID, response.GetError());
+}