upload android base code part6

This commit is contained in:
August 2018-08-08 17:48:24 +08:00
parent 421e214c7d
commit 4e516ec6ed
35396 changed files with 9188716 additions and 0 deletions

View file

@ -0,0 +1,52 @@
// Copyright (C) 2015 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// libgatekeeper contains just the code necessary to communicate with a
// GoogleGateKeeper implementation, e.g. one running in TrustZone.
cc_library_shared {
name: "libgatekeeper",
vendor_available: true,
vndk: {
enabled: true,
},
srcs: [
"gatekeeper_messages.cpp",
"gatekeeper.cpp",
],
cflags: [
"-Wall",
"-Werror",
"-g",
],
header_libs: [
"libhardware_headers",
],
export_include_dirs: ["include"],
// TODO(krasin): reenable coverage flags, when the new Clang toolchain is released.
// Currently, if enabled, these flags will cause an internal error in Clang.
// Bug: 25119481
clang_cflags: ["-fno-sanitize-coverage=edge,indirect-calls,8bit-counters,trace-cmp"],
}
// libgatekeeper_static is an empty static library that exports
// all of the files in gatekeeper as includes.
cc_library_static {
name: "libgatekeeper_static",
export_include_dirs: [
".",
"include",
],
}

View file

@ -0,0 +1,42 @@
# Copyright (C) 2015 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# If you don't need to do a full clean build but would like to touch
# a file or delete some intermediate files, add a clean step to the end
# of the list. These steps will only be run once, if they haven't been
# run before.
#
# E.g.:
# $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
#
# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
# files that are missing or have been moved.
#
# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
# Use $(OUT_DIR) to refer to the "out" directory.
#
# If you need to re-do something that's already mentioned, just copy
# the command and add it to the bottom of the list. E.g., if a change
# that you made last week required touching a file and a change you
# made today requires touching the same file, just copy the old
# touch step and add it to the end of the list.
#
# ************************************************
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
# ************************************************
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/hw/gatekeeper.default.so)

View file

@ -0,0 +1,2 @@
jdanis@google.com
swillden@google.com

View file

@ -0,0 +1,321 @@
/*
* 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 <gatekeeper/UniquePtr.h>
#include <gatekeeper/gatekeeper.h>
#include <endian.h>
#define DAY_IN_MS (1000 * 60 * 60 * 24)
namespace gatekeeper {
void GateKeeper::Enroll(const EnrollRequest &request, EnrollResponse *response) {
if (response == NULL) return;
if (!request.provided_password.buffer.get()) {
response->error = ERROR_INVALID;
return;
}
secure_id_t user_id = 0;// todo: rename to policy
uint32_t uid = request.user_id;
if (request.password_handle.buffer.get() == NULL) {
// Password handle does not match what is stored, generate new SecureID
GetRandom(&user_id, sizeof(secure_id_t));
} else {
password_handle_t *pw_handle =
reinterpret_cast<password_handle_t *>(request.password_handle.buffer.get());
if (pw_handle->version > HANDLE_VERSION) {
response->error = ERROR_INVALID;
return;
}
user_id = pw_handle->user_id;
uint64_t timestamp = GetMillisecondsSinceBoot();
uint32_t timeout = 0;
bool throttle = (pw_handle->version >= HANDLE_VERSION_THROTTLE);
if (throttle) {
bool throttle_secure = pw_handle->flags & HANDLE_FLAG_THROTTLE_SECURE;
failure_record_t record;
if (!GetFailureRecord(uid, user_id, &record, throttle_secure)) {
response->error = ERROR_UNKNOWN;
return;
}
if (ThrottleRequest(uid, timestamp, &record, throttle_secure, response)) return;
if (!IncrementFailureRecord(uid, user_id, timestamp, &record, throttle_secure)) {
response->error = ERROR_UNKNOWN;
return;
}
timeout = ComputeRetryTimeout(&record);
}
if (!DoVerify(pw_handle, request.enrolled_password)) {
// incorrect old password
if (throttle && timeout > 0) {
response->SetRetryTimeout(timeout);
} else {
response->error = ERROR_INVALID;
}
return;
}
}
uint64_t flags = 0;
if (ClearFailureRecord(uid, user_id, true)) {
flags |= HANDLE_FLAG_THROTTLE_SECURE;
} else {
ClearFailureRecord(uid, user_id, false);
}
salt_t salt;
GetRandom(&salt, sizeof(salt));
SizedBuffer password_handle;
if (!CreatePasswordHandle(&password_handle,
salt, user_id, flags, HANDLE_VERSION, request.provided_password.buffer.get(),
request.provided_password.length)) {
response->error = ERROR_INVALID;
return;
}
response->SetEnrolledPasswordHandle(&password_handle);
}
void GateKeeper::Verify(const VerifyRequest &request, VerifyResponse *response) {
if (response == NULL) return;
if (!request.provided_password.buffer.get() || !request.password_handle.buffer.get()) {
response->error = ERROR_INVALID;
return;
}
password_handle_t *password_handle = reinterpret_cast<password_handle_t *>(
request.password_handle.buffer.get());
if (password_handle->version > HANDLE_VERSION) {
response->error = ERROR_INVALID;
return;
}
secure_id_t user_id = password_handle->user_id;
secure_id_t authenticator_id = 0;
uint32_t uid = request.user_id;
uint64_t timestamp = GetMillisecondsSinceBoot();
uint32_t timeout = 0;
bool throttle = (password_handle->version >= HANDLE_VERSION_THROTTLE);
bool throttle_secure = password_handle->flags & HANDLE_FLAG_THROTTLE_SECURE;
if (throttle) {
failure_record_t record;
if (!GetFailureRecord(uid, user_id, &record, throttle_secure)) {
response->error = ERROR_UNKNOWN;
return;
}
if (ThrottleRequest(uid, timestamp, &record, throttle_secure, response)) return;
if (!IncrementFailureRecord(uid, user_id, timestamp, &record, throttle_secure)) {
response->error = ERROR_UNKNOWN;
return;
}
timeout = ComputeRetryTimeout(&record);
} else {
response->request_reenroll = true;
}
if (DoVerify(password_handle, request.provided_password)) {
// Signature matches
UniquePtr<uint8_t> auth_token_buffer;
uint32_t auth_token_len;
MintAuthToken(&auth_token_buffer, &auth_token_len, timestamp,
user_id, authenticator_id, request.challenge);
SizedBuffer auth_token(auth_token_len);
memcpy(auth_token.buffer.get(), auth_token_buffer.get(), auth_token_len);
response->SetVerificationToken(&auth_token);
if (throttle) ClearFailureRecord(uid, user_id, throttle_secure);
} else {
// compute the new timeout given the incremented record
if (throttle && timeout > 0) {
response->SetRetryTimeout(timeout);
} else {
response->error = ERROR_INVALID;
}
}
}
bool GateKeeper::CreatePasswordHandle(SizedBuffer *password_handle_buffer, salt_t salt,
secure_id_t user_id, uint64_t flags, uint8_t handle_version, const uint8_t *password,
uint32_t password_length) {
password_handle_buffer->buffer.reset(new uint8_t[sizeof(password_handle_t)]);
password_handle_buffer->length = sizeof(password_handle_t);
password_handle_t *password_handle = reinterpret_cast<password_handle_t *>(
password_handle_buffer->buffer.get());
password_handle->version = handle_version;
password_handle->salt = salt;
password_handle->user_id = user_id;
password_handle->flags = flags;
password_handle->hardware_backed = IsHardwareBacked();
uint32_t metadata_length = sizeof(user_id) + sizeof(flags) + sizeof(HANDLE_VERSION);
const size_t to_sign_size = password_length + metadata_length;
UniquePtr<uint8_t> to_sign(new uint8_t[to_sign_size]);
if (to_sign.get() == nullptr) {
return false;
}
memcpy(to_sign.get(), password_handle, metadata_length);
memcpy(to_sign.get() + metadata_length, password, password_length);
const uint8_t *password_key = NULL;
uint32_t password_key_length = 0;
GetPasswordKey(&password_key, &password_key_length);
if (!password_key || password_key_length == 0) {
return false;
}
ComputePasswordSignature(password_handle->signature, sizeof(password_handle->signature),
password_key, password_key_length, to_sign.get(), to_sign_size, salt);
return true;
}
bool GateKeeper::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->flags, expected_handle->version,
password.buffer.get(), password.length)) {
return false;
}
password_handle_t *generated_handle =
reinterpret_cast<password_handle_t *>(provided_handle.buffer.get());
return memcmp_s(generated_handle->signature, expected_handle->signature,
sizeof(expected_handle->signature)) == 0;
}
void GateKeeper::MintAuthToken(UniquePtr<uint8_t> *auth_token, uint32_t *length,
uint64_t timestamp, secure_id_t user_id, secure_id_t authenticator_id,
uint64_t challenge) {
if (auth_token == NULL) return;
hw_auth_token_t *token = new hw_auth_token_t;
SizedBuffer serialized_auth_token;
token->version = HW_AUTH_TOKEN_VERSION;
token->challenge = challenge;
token->user_id = user_id;
token->authenticator_id = authenticator_id;
token->authenticator_type = htonl(HW_AUTH_PASSWORD);
token->timestamp = htobe64(timestamp);
const uint8_t *auth_token_key = NULL;
uint32_t key_len = 0;
if (GetAuthTokenKey(&auth_token_key, &key_len)) {
uint32_t hash_len = (uint32_t)((uint8_t *)&token->hmac - (uint8_t *)token);
ComputeSignature(token->hmac, sizeof(token->hmac), auth_token_key, key_len,
reinterpret_cast<uint8_t *>(token), hash_len);
delete[] auth_token_key;
} else {
memset(token->hmac, 0, sizeof(token->hmac));
}
if (length != NULL) *length = sizeof(*token);
auth_token->reset(reinterpret_cast<uint8_t *>(token));
}
/*
* Calculates the timeout in milliseconds as a function of the failure
* counter 'x' as follows:
*
* [0. 5) -> 0
* 5 -> 30
* [6, 10) -> 0
* [11, 30) -> 30
* [30, 140) -> 30 * (2^((x - 30)/10))
* [140, inf) -> 1 day
*
*/
uint32_t GateKeeper::ComputeRetryTimeout(const failure_record_t *record) {
static const int failure_timeout_ms = 30000;
if (record->failure_counter == 0) return 0;
if (record->failure_counter > 0 && record->failure_counter <= 10) {
if (record->failure_counter % 5 == 0) {
return failure_timeout_ms;
} else {
return 0;
}
} else if (record->failure_counter < 30) {
return failure_timeout_ms;
} else if (record->failure_counter < 140) {
return failure_timeout_ms << ((record->failure_counter - 30) / 10);
}
return DAY_IN_MS;
}
bool GateKeeper::ThrottleRequest(uint32_t uid, uint64_t timestamp,
failure_record_t *record, bool secure, GateKeeperMessage *response) {
uint64_t last_checked = record->last_checked_timestamp;
uint32_t timeout = ComputeRetryTimeout(record);
if (timeout > 0) {
// we have a pending timeout
if (timestamp < last_checked + timeout && timestamp > last_checked) {
// attempt before timeout expired, return remaining time
response->SetRetryTimeout(timeout - (timestamp - last_checked));
return true;
} else if (timestamp <= last_checked) {
// device was rebooted or timer reset, don't count as new failure but
// reset timeout
record->last_checked_timestamp = timestamp;
if (!WriteFailureRecord(uid, record, secure)) {
response->error = ERROR_UNKNOWN;
return true;
}
response->SetRetryTimeout(timeout);
return true;
}
}
return false;
}
bool GateKeeper::IncrementFailureRecord(uint32_t uid, secure_id_t user_id, uint64_t timestamp,
failure_record_t *record, bool secure) {
record->secure_user_id = user_id;
record->failure_counter++;
record->last_checked_timestamp = timestamp;
return WriteFailureRecord(uid, record, secure);
}
} // namespace gatekeeper

View file

@ -0,0 +1,365 @@
/*
* 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 <gatekeeper/gatekeeper_messages.h>
#include <string.h>
using namespace std;
namespace gatekeeper {
/**
* Methods for serializing/deserializing SizedBuffers
*/
struct __attribute__((__packed__)) serial_header_t {
uint32_t error;
uint32_t user_id;
};
static inline uint32_t serialized_buffer_size(const SizedBuffer &buf) {
return sizeof(buf.length) + buf.length;
}
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);
if (to_append->length != 0) {
memcpy(*buffer, to_append->buffer.get(), to_append->length);
*buffer += to_append->length;
}
}
static inline gatekeeper_error_t read_from_buffer(const uint8_t **buffer, const uint8_t *end,
SizedBuffer *target) {
if (*buffer + sizeof(target->length) > end) return ERROR_INVALID;
memcpy(&target->length, *buffer, sizeof(target->length));
*buffer += sizeof(target->length);
if (target->length != 0) {
const size_t buffer_size = end - *buffer;
if (buffer_size < target->length) return ERROR_INVALID;
target->buffer.reset(new uint8_t[target->length]);
memcpy(target->buffer.get(), *buffer, target->length);
*buffer += target->length;
}
return ERROR_NONE;
}
uint32_t GateKeeperMessage::GetSerializedSize() const {
if (error == ERROR_NONE) {
uint32_t size = sizeof(serial_header_t) + nonErrorSerializedSize();
return size;
} else {
uint32_t size = sizeof(serial_header_t);
if (error == ERROR_RETRY) {
size += sizeof(retry_timeout);
}
return size;
}
}
uint32_t GateKeeperMessage::Serialize(uint8_t *buffer, const uint8_t *end) const {
uint32_t bytes_written = 0;
if (buffer + GetSerializedSize() > end) {
return 0;
}
serial_header_t *header = reinterpret_cast<serial_header_t *>(buffer);
if (error != ERROR_NONE) {
if (buffer + sizeof(serial_header_t) > end) return 0;
header->error = error;
header->user_id = user_id;
bytes_written += sizeof(*header);
if (error == ERROR_RETRY) {
memcpy(buffer + sizeof(serial_header_t), &retry_timeout, sizeof(retry_timeout));
bytes_written += sizeof(retry_timeout);
}
} else {
if (buffer + sizeof(serial_header_t) + nonErrorSerializedSize() > end)
return 0;
header->error = error;
header->user_id = user_id;
nonErrorSerialize(buffer + sizeof(*header));
bytes_written += sizeof(*header) + nonErrorSerializedSize();
}
return bytes_written;
}
gatekeeper_error_t GateKeeperMessage::Deserialize(const uint8_t *payload, const uint8_t *end) {
if (payload + sizeof(uint32_t) > end) return ERROR_INVALID;
const serial_header_t *header = reinterpret_cast<const serial_header_t *>(payload);
if (header->error == ERROR_NONE) {
if (payload == end) return ERROR_INVALID;
user_id = header->user_id;
error = nonErrorDeserialize(payload + sizeof(*header), end);
} else {
error = static_cast<gatekeeper_error_t>(header->error);
user_id = header->user_id;
if (error == ERROR_RETRY) {
if (payload + sizeof(serial_header_t) < end) {
memcpy(&retry_timeout, payload + sizeof(serial_header_t), sizeof(retry_timeout));
} else {
retry_timeout = 0;
}
}
}
return error;
}
void GateKeeperMessage::SetRetryTimeout(uint32_t retry_timeout) {
this->retry_timeout = retry_timeout;
this->error = ERROR_RETRY;
}
VerifyRequest::VerifyRequest(uint32_t user_id, uint64_t challenge,
SizedBuffer *enrolled_password_handle, SizedBuffer *provided_password_payload) {
this->user_id = user_id;
this->challenge = challenge;
this->password_handle.buffer.reset(enrolled_password_handle->buffer.release());
this->password_handle.length = enrolled_password_handle->length;
this->provided_password.buffer.reset(provided_password_payload->buffer.release());
this->provided_password.length = provided_password_payload->length;
}
VerifyRequest::VerifyRequest() {
memset_s(&password_handle, 0, sizeof(password_handle));
memset_s(&provided_password, 0, sizeof(provided_password));
}
VerifyRequest::~VerifyRequest() {
if (password_handle.buffer.get()) {
password_handle.buffer.reset();
}
if (provided_password.buffer.get()) {
memset_s(provided_password.buffer.get(), 0, provided_password.length);
provided_password.buffer.reset();
}
}
uint32_t VerifyRequest::nonErrorSerializedSize() const {
return sizeof(challenge) + serialized_buffer_size(password_handle)
+ serialized_buffer_size(provided_password);
}
void VerifyRequest::nonErrorSerialize(uint8_t *buffer) const {
memcpy(buffer, &challenge, sizeof(challenge));
buffer += sizeof(challenge);
append_to_buffer(&buffer, &password_handle);
append_to_buffer(&buffer, &provided_password);
}
gatekeeper_error_t VerifyRequest::nonErrorDeserialize(const uint8_t *payload, const uint8_t *end) {
gatekeeper_error_t error = ERROR_NONE;
if (password_handle.buffer.get()) {
password_handle.buffer.reset();
}
if (provided_password.buffer.get()) {
memset_s(provided_password.buffer.get(), 0, provided_password.length);
provided_password.buffer.reset();
}
memcpy(&challenge, payload, sizeof(challenge));
payload += sizeof(challenge);
error = read_from_buffer(&payload, end, &password_handle);
if (error != ERROR_NONE) return error;
return read_from_buffer(&payload, end, &provided_password);
}
VerifyResponse::VerifyResponse(uint32_t user_id, SizedBuffer *auth_token) {
this->user_id = user_id;
this->auth_token.buffer.reset(auth_token->buffer.release());
this->auth_token.length = auth_token->length;
this->request_reenroll = false;
}
VerifyResponse::VerifyResponse() {
request_reenroll = false;
memset_s(&auth_token, 0, sizeof(auth_token));
};
VerifyResponse::~VerifyResponse() {
if (auth_token.length > 0) {
auth_token.buffer.reset();
}
}
void VerifyResponse::SetVerificationToken(SizedBuffer *auth_token) {
this->auth_token.buffer.reset(auth_token->buffer.release());
this->auth_token.length = auth_token->length;
}
uint32_t VerifyResponse::nonErrorSerializedSize() const {
return serialized_buffer_size(auth_token) + sizeof(request_reenroll);
}
void VerifyResponse::nonErrorSerialize(uint8_t *buffer) const {
append_to_buffer(&buffer, &auth_token);
memcpy(buffer, &request_reenroll, sizeof(request_reenroll));
}
gatekeeper_error_t VerifyResponse::nonErrorDeserialize(const uint8_t *payload, const uint8_t *end) {
if (auth_token.buffer.get()) {
auth_token.buffer.reset();
}
gatekeeper_error_t err = read_from_buffer(&payload, end, &auth_token);
if (err != ERROR_NONE) {
return err;
}
memcpy(&request_reenroll, payload, sizeof(request_reenroll));
return ERROR_NONE;
}
EnrollRequest::EnrollRequest(uint32_t user_id, SizedBuffer *password_handle,
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() {
if (provided_password.buffer.get()) {
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();
}
}
uint32_t EnrollRequest::nonErrorSerializedSize() const {
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);
}
gatekeeper_error_t EnrollRequest::nonErrorDeserialize(const uint8_t *payload, const uint8_t *end) {
gatekeeper_error_t ret;
if (provided_password.buffer.get()) {
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();
}
ret = read_from_buffer(&payload, end, &provided_password);
if (ret != ERROR_NONE) {
return ret;
}
ret = read_from_buffer(&payload, end, &enrolled_password);
if (ret != ERROR_NONE) {
return ret;
}
return read_from_buffer(&payload, end, &password_handle);
}
EnrollResponse::EnrollResponse(uint32_t user_id, SizedBuffer *enrolled_password_handle) {
this->user_id = user_id;
this->enrolled_password_handle.buffer.reset(enrolled_password_handle->buffer.release());
this->enrolled_password_handle.length = enrolled_password_handle->length;
}
EnrollResponse::EnrollResponse() {
memset_s(&enrolled_password_handle, 0, sizeof(enrolled_password_handle));
}
EnrollResponse::~EnrollResponse() {
if (enrolled_password_handle.buffer.get()) {
enrolled_password_handle.buffer.reset();
}
}
void EnrollResponse::SetEnrolledPasswordHandle(SizedBuffer *enrolled_password_handle) {
this->enrolled_password_handle.buffer.reset(enrolled_password_handle->buffer.release());
this->enrolled_password_handle.length = enrolled_password_handle->length;
}
uint32_t EnrollResponse::nonErrorSerializedSize() const {
return serialized_buffer_size(enrolled_password_handle);
}
void EnrollResponse::nonErrorSerialize(uint8_t *buffer) const {
append_to_buffer(&buffer, &enrolled_password_handle);
}
gatekeeper_error_t EnrollResponse::nonErrorDeserialize(const uint8_t *payload, const uint8_t *end) {
if (enrolled_password_handle.buffer.get()) {
enrolled_password_handle.buffer.reset();
}
return read_from_buffer(&payload, end, &enrolled_password_handle);
}
};

View file

@ -0,0 +1,137 @@
/*
* Copyright (C) 2010 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 GATEKEEPER_UNIQUE_PTR_H_included
#define GATEKEEPER_UNIQUE_PTR_H_included
#include <stdlib.h> // For NULL.
namespace gatekeeper {
// Default deleter for pointer types.
template <typename T>
struct DefaultDelete {
enum { type_must_be_complete = sizeof(T) };
DefaultDelete() {}
void operator()(T* p) const {
delete p;
}
};
// Default deleter for array types.
template <typename T>
struct DefaultDelete<T[]> {
enum { type_must_be_complete = sizeof(T) };
void operator()(T* p) const {
delete[] p;
}
};
// A smart pointer that deletes the given pointer on destruction.
// Equivalent to C++0x's std::unique_ptr (a combination of boost::scoped_ptr
// and boost::scoped_array).
// Named to be in keeping with Android style but also to avoid
// collision with any other implementation, until we can switch over
// to unique_ptr.
// Use thus:
// UniquePtr<C> c(new C);
template <typename T, typename D = DefaultDelete<T> >
class UniquePtr {
public:
// Construct a new UniquePtr, taking ownership of the given raw pointer.
explicit UniquePtr(T* ptr = NULL) : mPtr(ptr) {
}
~UniquePtr() {
reset();
}
// Accessors.
T& operator*() const { return *mPtr; }
T* operator->() const { return mPtr; }
T* get() const { return mPtr; }
// Returns the raw pointer and hands over ownership to the caller.
// The pointer will not be deleted by UniquePtr.
T* release() __attribute__((warn_unused_result)) {
T* result = mPtr;
mPtr = NULL;
return result;
}
// Takes ownership of the given raw pointer.
// If this smart pointer previously owned a different raw pointer, that
// raw pointer will be freed.
void reset(T* ptr = NULL) {
if (ptr != mPtr) {
D()(mPtr);
mPtr = ptr;
}
}
private:
// The raw pointer.
T* mPtr;
// Comparing unique pointers is probably a mistake, since they're unique.
template <typename T2> bool operator==(const UniquePtr<T2>& p) const;
template <typename T2> bool operator!=(const UniquePtr<T2>& p) const;
// Disallow copy and assignment.
UniquePtr(const UniquePtr&);
void operator=(const UniquePtr&);
};
// Partial specialization for array types. Like std::unique_ptr, this removes
// operator* and operator-> but adds operator[].
template <typename T, typename D>
class UniquePtr<T[], D> {
public:
explicit UniquePtr(T* ptr = NULL) : mPtr(ptr) {
}
~UniquePtr() {
reset();
}
T& operator[](size_t i) const {
return mPtr[i];
}
T* get() const { return mPtr; }
T* release() __attribute__((warn_unused_result)) {
T* result = mPtr;
mPtr = NULL;
return result;
}
void reset(T* ptr = NULL) {
if (ptr != mPtr) {
D()(mPtr);
mPtr = ptr;
}
}
private:
T* mPtr;
// Disallow copy and assignment.
UniquePtr(const UniquePtr&);
void operator=(const UniquePtr&);
};
} //namespace gatekeeper
#endif // GATEKEEPER_UNIQUE_PTR_H_included

View file

@ -0,0 +1,213 @@
/*
* 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 GATEKEEPER_H_
#define GATEKEEPER_H_
#include <stdint.h>
#include <gatekeeper/UniquePtr.h>
#include <hardware/hw_auth_token.h>
#include "gatekeeper_messages.h"
#include "password_handle.h"
namespace gatekeeper {
struct __attribute__((packed)) failure_record_t {
uint64_t secure_user_id;
uint64_t last_checked_timestamp;
uint32_t failure_counter;
};
/**
* Base class for gatekeeper implementations. Provides all functionality except
* the ability to create/access keys and compute signatures. These are left up
* to the platform-specific implementation.
*/
class GateKeeper {
public:
GateKeeper() {}
virtual ~GateKeeper() {}
void Enroll(const EnrollRequest &request, EnrollResponse *response);
void Verify(const VerifyRequest &request, VerifyResponse *response);
protected:
// The following methods are intended to be implemented by concrete subclasses
/**
* Retrieves the key used by GateKeeper::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.
*
* Writes the length in bytes of the returned key to length if it is not null.
*
* Ownership of the auth_token_key pointer is maintained by the implementor.
*
* Returns true if the key was successfully fetched.
*
*/
virtual bool GetAuthTokenKey(const uint8_t **auth_token_key, uint32_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 be cached.
*
* Ownership of the password_key pointer is maintained by the implementor.
*
*/
virtual void GetPasswordKey(const uint8_t **password_key, uint32_t *length) = 0;
/**
* Uses platform-specific routines to compute a signature on the provided password.
*
* This can be implemented as a simple pass-through to ComputeSignature, but is
* available in case handling for password signatures is different from general
* purpose signatures.
*
* Writes the signature_length size signature to the 'signature' pointer.
*/
virtual void ComputePasswordSignature(uint8_t *signature, uint32_t signature_length,
const uint8_t *key, uint32_t key_length, const uint8_t *password,
uint32_t password_length, salt_t salt) const = 0;
/**
* Retrieves a unique, cryptographically randomly generated buffer for use in password
* hashing, etc.
*
* Assings the random to the random UniquePtr, relinquishing ownership to the caller
*/
virtual void GetRandom(void *random, uint32_t requested_size) const = 0;
/**
* Uses platform-specific routines to compute a signature on the provided message.
*
* Writes the signature_length size signature to the 'signature' pointer.
*/
virtual void ComputeSignature(uint8_t *signature, uint32_t signature_length,
const uint8_t *key, uint32_t key_length, const uint8_t *message,
const uint32_t length) const = 0;
/**
* Get the time since boot in milliseconds.
*
* Should return 0 on error.
*/
virtual uint64_t GetMillisecondsSinceBoot() const = 0;
/**
* Returns the value of the current failure record for the user.
*
* The failure record should be written to hardware-backed secure storage, such as
* RPMB, if the target device supports it.
*
* If 'secure' is false, password is operating in a fallback mode. Implementations
* may store the failure record in memory or in non-secure storage if this value is false.
*
* Returns true on success, false if failure record cannot be retrieved.
*/
virtual bool GetFailureRecord(uint32_t uid, secure_id_t user_id, failure_record_t *record,
bool secure) = 0;
/**
* Initializes or reinitializes the failure record for the current user.
*
* Must be persisted in secure storage if the target device supports it.
*
* If 'secure' is false, password is operating in a fallback mode. Implementations
* may store the failure record in memory or in non-secure storage if this value is false.
*
* Returns true if the failure record was successfully persisted.
*/
virtual bool ClearFailureRecord(uint32_t uid, secure_id_t user_id, bool secure) = 0;
/*
* Writes the provided failure record to persistent storage.
*
* Must be persisted in secure storage if the target device supports it.
*
* If 'secure' is false, password is operating in a fallback mode. Implementations
* may store the failure record in memory or in non-secure storage if this value is false.
*
* Returns true if record was successfully written.
*/
virtual bool WriteFailureRecord(uint32_t uid, failure_record_t *record, bool secure) = 0;
/**
* Computes the amount of time to throttle the user due to the current failure_record
* counter. An implementation is provided by the generic GateKeeper, but may be
* overriden.
*/
virtual uint32_t ComputeRetryTimeout(const failure_record_t *record);
/**
* Returns whether the GateKeeper implementation is backed by hardware.
*/
virtual bool IsHardwareBacked() const = 0;
/**
* Verifies that handle matches password HMAC'ed with the password_key
*/
virtual bool DoVerify(const password_handle_t *expected_handle, const SizedBuffer &password);
private:
/**
* Generates a signed attestation of an authentication event and assings
* to auth_token UniquePtr.
* The format is consistent with that of hw_auth_token_t.
* Also returns the length in length if it is not null.
*/
void MintAuthToken(UniquePtr<uint8_t> *auth_token, uint32_t *length, uint64_t timestamp,
secure_id_t user_id, secure_id_t authenticator_id, uint64_t challenge);
/**
* 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, uint8_t handle_version,
const uint8_t *password, uint32_t password_length);
/**
* Increments the counter on the current failure record for the provided user id.
* Sets the last_checked_timestamp to timestamp. Writes the updated record
* to *record if not null.
*
* Returns true if failure record was successfully incremented.
*/
bool IncrementFailureRecord(uint32_t uid, secure_id_t user_id, uint64_t timestamp,
failure_record_t *record, bool secure);
/**
* Determines whether the request is within the current throttle window.
*
* If the system timer has been reset due to a reboot or otherwise, resets
* the throttle window with a base at the current time.
*
* Returns true if the request is in the throttle window.
*/
bool ThrottleRequest(uint32_t uid, uint64_t timestamp,
failure_record_t *record, bool secure, GateKeeperMessage *response);
};
}
#endif // GATEKEEPER_H_

View file

@ -0,0 +1,211 @@
/*
* 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 GATEKEEPER_MESSAGES_H_
#define GATEKEEPER_MESSAGES_H_
#include <stdint.h>
#include <gatekeeper/UniquePtr.h>
#include "gatekeeper_utils.h"
/**
* Message serialization objects for communicating with the hardware gatekeeper.
*/
namespace gatekeeper {
const uint32_t ENROLL = 0;
const uint32_t VERIFY = 1;
typedef enum {
ERROR_NONE = 0,
ERROR_INVALID = 1,
ERROR_RETRY = 2,
ERROR_UNKNOWN = 3,
} gatekeeper_error_t;
struct SizedBuffer {
SizedBuffer() {
length = 0;
}
/*
* Constructs a SizedBuffer of a provided
* length.
*/
explicit SizedBuffer(uint32_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.
*/
SizedBuffer(uint8_t buf[], uint32_t len) {
buffer.reset(buf);
length = len;
}
UniquePtr<uint8_t[]> buffer;
uint32_t length;
};
/*
* 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.
*/
struct GateKeeperMessage {
GateKeeperMessage() : error(ERROR_NONE) {}
explicit GateKeeperMessage(gatekeeper_error_t error) : error(error) {}
virtual ~GateKeeperMessage() {}
/**
* Returns serialized size in bytes of the current state of the
* object.
*/
uint32_t GetSerializedSize() const;
/**
* Converts the object into its serialized representation.
*
* Expects payload to be allocated with GetSerializedSize bytes.
*
* Returns the number of bytes written or 0 on error.
*/
uint32_t Serialize(uint8_t *payload, const uint8_t *end) const;
/**
* Inflates the object from its serial representation.
*/
gatekeeper_error_t Deserialize(const uint8_t *payload, const uint8_t *end);
/**
* Calls may fail due to throttling. If so, this sets a timeout in milliseconds
* for when the caller should attempt the call again. Additionally, sets the
* error to ERROR_RETRY.
*/
void SetRetryTimeout(uint32_t retry_timeout);
/**
* The following methods are intended to be implemented by subclasses.
* They are hooks to serialize the elements specific to each particular
* specialization.
*/
/**
* Returns the size of serializing only the elements specific to the
* current sublclass.
*/
virtual uint32_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 must be exactly
* that returned by nonErrorSerializedSize() in bytes.
*/
virtual void nonErrorSerialize(uint8_t *) const { }
/**
* Deserializes subclass specific data from payload without reading past end.
*/
virtual gatekeeper_error_t nonErrorDeserialize(const uint8_t *, const uint8_t *) {
return ERROR_NONE;
}
gatekeeper_error_t error;
uint32_t user_id;
uint32_t retry_timeout;
};
struct VerifyRequest : public GateKeeperMessage {
VerifyRequest(
uint32_t user_id,
uint64_t challenge,
SizedBuffer *enrolled_password_handle,
SizedBuffer *provided_password_payload);
VerifyRequest();
~VerifyRequest();
virtual uint32_t nonErrorSerializedSize() const;
virtual void nonErrorSerialize(uint8_t *buffer) const;
virtual gatekeeper_error_t nonErrorDeserialize(const uint8_t *payload, const uint8_t *end);
uint64_t challenge;
SizedBuffer password_handle;
SizedBuffer provided_password;
};
struct VerifyResponse : public GateKeeperMessage {
VerifyResponse(uint32_t user_id, SizedBuffer *auth_token);
VerifyResponse();
~VerifyResponse();
void SetVerificationToken(SizedBuffer *auth_token);
virtual uint32_t nonErrorSerializedSize() const;
virtual void nonErrorSerialize(uint8_t *buffer) const;
virtual gatekeeper_error_t nonErrorDeserialize(const uint8_t *payload, const uint8_t *end);
SizedBuffer auth_token;
bool request_reenroll;
};
struct EnrollRequest : public GateKeeperMessage {
EnrollRequest(uint32_t user_id, SizedBuffer *password_handle,
SizedBuffer *provided_password, SizedBuffer *enrolled_password);
EnrollRequest();
~EnrollRequest();
virtual uint32_t nonErrorSerializedSize() const;
virtual void nonErrorSerialize(uint8_t *buffer) const;
virtual gatekeeper_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;
};
struct EnrollResponse : public GateKeeperMessage {
public:
EnrollResponse(uint32_t user_id, SizedBuffer *enrolled_password_handle);
EnrollResponse();
~EnrollResponse();
void SetEnrolledPasswordHandle(SizedBuffer *enrolled_password_handle);
virtual uint32_t nonErrorSerializedSize() const;
virtual void nonErrorSerialize(uint8_t *buffer) const;
virtual gatekeeper_error_t nonErrorDeserialize(const uint8_t *payload, const uint8_t *end);
SizedBuffer enrolled_password_handle;
};
}
#endif // GATEKEEPER_MESSAGES_H_

View file

@ -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_GATEKEEPER_UTILS_H_
#define GOOGLE_GATEKEEPER_UTILS_H_
#include <string.h>
namespace gatekeeper {
/**
* 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 inline 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_GATEKEEPER_UTILS_H_

View file

@ -0,0 +1,47 @@
/*
* 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 GATEKEEPER_PASSWORD_HANDLE_H_
#define GATEKEEPER_PASSWORD_HANDLE_H_
#define HANDLE_FLAG_THROTTLE_SECURE 1
#define HANDLE_VERSION_THROTTLE 2
namespace gatekeeper {
typedef uint64_t secure_id_t;
typedef uint64_t salt_t;
/**
* structure for easy serialization
* and deserialization of password handles.
*/
static const uint8_t HANDLE_VERSION = 2;
struct __attribute__ ((__packed__)) password_handle_t {
// fields included in signature
uint8_t version;
secure_id_t user_id;
uint64_t flags;
// fields not included in signature
salt_t salt;
uint8_t signature[32];
bool hardware_backed;
};
}
#endif // GATEKEEPER_PASSWORD_HANDLE_H_

View file

@ -0,0 +1,15 @@
LOCAL_DIR := $(GET_LOCAL_DIR)
MODULE := $(LOCAL_DIR)
MODULE_SRCS := \
$(LOCAL_DIR)/gatekeeper_messages.cpp \
$(LOCAL_DIR)/gatekeeper.cpp
GLOBAL_INCLUDES += $(LOCAL_DIR)/include/
MODULE_DEPS := \
lib/libc \
lib/libc-trusty \
include make/module.mk

View file

@ -0,0 +1,29 @@
#
# Copyright (C) 2015 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := gatekeeper-unit-tests
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
LOCAL_CFLAGS += -g -Wall -Werror -std=gnu++11 -Wno-missing-field-initializers
LOCAL_SHARED_LIBRARIES := libgatekeeper libcrypto libhardware
LOCAL_STATIC_LIBRARIES := libscrypt_static
LOCAL_C_INCLUDES := external/scrypt/lib/crypto
LOCAL_SRC_FILES := \
gatekeeper_messages_test.cpp \
gatekeeper_device_test.cpp
include $(BUILD_NATIVE_TEST)

View file

@ -0,0 +1,251 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <endian.h>
#include <gtest/gtest.h>
#include <hardware/gatekeeper.h>
#include <gatekeeper/gatekeeper.h> // For password_handle_t
#include <unistd.h>
using ::testing::Test;
using ::gatekeeper::password_handle_t;
using ::gatekeeper::secure_id_t;
class GateKeeperDeviceTest : public virtual Test {
public:
GateKeeperDeviceTest() {}
virtual ~GateKeeperDeviceTest() {}
virtual void SetUp() {
gatekeeper_device_initialize(&device);
}
virtual void TearDown() {
gatekeeper_close(device);
}
static void gatekeeper_device_initialize(gatekeeper_device_t **dev) {
int ret;
const hw_module_t *mod;
ret = hw_get_module_by_class(GATEKEEPER_HARDWARE_MODULE_ID, NULL, &mod);
ASSERT_EQ(0, ret);
ret = gatekeeper_open(mod, dev);
ASSERT_EQ(0, ret);
}
gatekeeper_device_t *device;
};
TEST_F(GateKeeperDeviceTest, EnrollAndVerifyStress) {
uint32_t password_len = 50;
uint8_t password_payload[password_len];
uint8_t *password_handle;
uint32_t password_handle_length;
uint8_t *auth_token;
uint32_t auth_token_len;
int ret;
ret = device->enroll(device, 400, NULL, 0, NULL, 0, password_payload, password_len,
&password_handle, &password_handle_length);
ASSERT_EQ(0, ret);
for (int i = 0; i < 1000; i++) {
bool should_reenroll;
ret = device->verify(device, 400, 0, password_handle, password_handle_length,
password_payload, password_len, &auth_token, &auth_token_len, &should_reenroll);
ASSERT_EQ(0, ret);
}
}
TEST_F(GateKeeperDeviceTest, EnrollAndVerify) {
uint32_t password_len = 50;
uint8_t password_payload[password_len];
uint8_t *password_handle;
uint32_t password_handle_length;
uint8_t *auth_token;
uint32_t auth_token_len;
hw_auth_token_t *hat;
int ret;
ret = device->enroll(device, 400, NULL, 0, NULL, 0, password_payload, password_len,
&password_handle, &password_handle_length);
ASSERT_EQ(0, ret);
bool should_reenroll;
ret = device->verify(device, 400, 0, password_handle, password_handle_length,
password_payload, password_len, &auth_token, &auth_token_len, &should_reenroll);
ASSERT_EQ(0, should_reenroll);
ASSERT_EQ(0, ret);
hat = reinterpret_cast<hw_auth_token_t *>(auth_token);
ASSERT_EQ(HW_AUTH_TOKEN_VERSION, hat->version);
ASSERT_EQ(htonl(HW_AUTH_PASSWORD), hat->authenticator_type);
}
TEST_F(GateKeeperDeviceTest, EnrollAndVerifyTimeout) {
uint32_t password_len = 50;
uint8_t password_payload[password_len];
uint8_t *password_handle;
uint32_t password_handle_length;
uint8_t *auth_token = NULL;
uint32_t auth_token_len;
bool should_reenroll;
int ret;
ret = device->enroll(device, 400, NULL, 0, NULL, 0, password_payload, password_len,
&password_handle, &password_handle_length);
ASSERT_EQ(0, ret);
int payload_val = password_payload[0];
password_payload[0] = 4;
int timeout = 0;
for (int i = 0; i < 20; i++) {
bool should_reenroll;
ret = device->verify(device, 400, 0, password_handle, password_handle_length,
password_payload, password_len, &auth_token, &auth_token_len,
&should_reenroll);
ASSERT_NE(0, ret);
ASSERT_EQ(NULL, auth_token);
if (ret > 0) {
timeout = ret;
}
}
ASSERT_NE(0, timeout);
sleep((timeout + 999)/ 1000);
password_payload[0] = payload_val;
ret = device->verify(device, 400, 0, password_handle, password_handle_length,
password_payload, password_len, &auth_token, &auth_token_len,
&should_reenroll);
ASSERT_EQ(0, ret);
}
TEST_F(GateKeeperDeviceTest, EnrollAndVerifyBadPassword) {
uint32_t password_len = 50;
uint8_t password_payload[password_len];
uint8_t *password_handle;
uint32_t password_handle_length;
uint8_t *auth_token = NULL;
uint32_t auth_token_len;
int ret;
ret = device->enroll(device, 400, NULL, 0, NULL, 0, password_payload, password_len,
&password_handle, &password_handle_length);
ASSERT_EQ(0, ret);
password_payload[0] = 4;
bool should_reenroll;
ret = device->verify(device, 400, 0, password_handle, password_handle_length,
password_payload, password_len, &auth_token, &auth_token_len,
&should_reenroll);
ASSERT_NE(0, ret);
ASSERT_EQ(NULL, auth_token);
}
TEST_F(GateKeeperDeviceTest, MinFailedAttemptsBeforeLockout) {
uint32_t password_len = 50;
uint8_t password_payload[password_len];
uint8_t *password_handle;
uint32_t password_handle_length;
uint8_t *auth_token = NULL;
uint32_t auth_token_len;
int ret;
ret = device->enroll(device, 400, NULL, 0, NULL, 0, password_payload, password_len,
&password_handle, &password_handle_length);
ASSERT_EQ(0, ret);
password_payload[0] = 4;
// User should have at least 4 attempts before being locked out
static const int MIN_FAILED_ATTEMPTS = 4;
bool should_reenroll;
for (int i = 0; i < MIN_FAILED_ATTEMPTS; i++) {
ret = device->verify(device, 400, 0, password_handle, password_handle_length,
password_payload, password_len, &auth_token, &auth_token_len,
&should_reenroll);
// shoudln't be a timeout
ASSERT_LT(ret, 0);
}
}
TEST_F(GateKeeperDeviceTest, UntrustedReEnroll) {
uint32_t password_len = 50;
uint8_t password_payload[password_len];
uint8_t *password_handle;
uint32_t password_handle_length;
int ret;
ret = device->enroll(device, 400, NULL, 0, NULL, 0, password_payload, password_len,
&password_handle, &password_handle_length);
ASSERT_EQ(0, ret);
password_handle_t *handle = reinterpret_cast<password_handle_t *>(password_handle);
secure_id_t sid = handle->user_id;
ret = device->enroll(device, 400, NULL, 0, NULL, 0, password_payload, password_len,
&password_handle, &password_handle_length);
ASSERT_EQ(0, ret);
handle = reinterpret_cast<password_handle_t *>(password_handle);
secure_id_t sid_tmp = handle->user_id;
ASSERT_NE(sid, sid_tmp);
}
TEST_F(GateKeeperDeviceTest, TrustedReEnroll) {
uint32_t password_len = 50;
uint8_t password_payload[password_len];
uint8_t *password_handle;
uint32_t password_handle_length;
int ret;
ret = device->enroll(device, 400, NULL, 0, NULL, 0, password_payload, password_len,
&password_handle, &password_handle_length);
ASSERT_EQ(0, ret);
password_handle_t *handle = reinterpret_cast<password_handle_t *>(password_handle);
secure_id_t sid = handle->user_id;
ret = device->enroll(device, 400, password_handle, password_handle_length, password_payload,
password_len, password_payload, password_len, &password_handle, &password_handle_length);
ASSERT_EQ(0, ret);
handle = reinterpret_cast<password_handle_t *>(password_handle);
secure_id_t sid_tmp = handle->user_id;
ASSERT_EQ(sid, sid_tmp);
}

View file

@ -0,0 +1,312 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <gtest/gtest.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <gatekeeper/gatekeeper_messages.h>
using ::gatekeeper::SizedBuffer;
using ::testing::Test;
using ::gatekeeper::EnrollRequest;
using ::gatekeeper::EnrollResponse;
using ::gatekeeper::VerifyRequest;
using ::gatekeeper::VerifyResponse;
using std::cout;
using std::endl;
static const uint32_t USER_ID = 3857;
static SizedBuffer *make_buffer(uint32_t size) {
SizedBuffer *result = new SizedBuffer;
result->length = size;
uint8_t *buffer = new uint8_t[size];
srand(size);
for (uint32_t i = 0; i < size; i++) {
buffer[i] = rand();
}
result->buffer.reset(buffer);
return result;
}
TEST(RoundTripTest, EnrollRequestNullEnrolledNullHandle) {
const uint32_t password_size = 512;
SizedBuffer *provided_password = make_buffer(password_size);
const SizedBuffer *deserialized_password;
// create request, serialize, deserialize, and validate
EnrollRequest msg(USER_ID, NULL, provided_password, NULL);
SizedBuffer serialized_msg(msg.GetSerializedSize());
msg.Serialize(serialized_msg.buffer.get(), serialized_msg.buffer.get() + serialized_msg.length);
EnrollRequest deserialized_msg;
deserialized_msg.Deserialize(serialized_msg.buffer.get(), serialized_msg.buffer.get()
+ serialized_msg.length);
ASSERT_EQ(gatekeeper::gatekeeper_error_t::ERROR_NONE,
deserialized_msg.error);
deserialized_password = &deserialized_msg.provided_password;
ASSERT_EQ(USER_ID, deserialized_msg.user_id);
ASSERT_EQ((uint32_t) password_size, deserialized_password->length);
ASSERT_EQ(0, memcmp(msg.provided_password.buffer.get(), deserialized_password->buffer.get(), password_size));
ASSERT_EQ((uint32_t) 0, deserialized_msg.enrolled_password.length);
ASSERT_EQ(NULL, deserialized_msg.enrolled_password.buffer.get());
ASSERT_EQ((uint32_t) 0, deserialized_msg.password_handle.length);
ASSERT_EQ(NULL, deserialized_msg.password_handle.buffer.get());
delete provided_password;
}
TEST(RoundTripTest, EnrollRequestEmptyEnrolledEmptyHandle) {
const uint32_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 msg(USER_ID, &handle, provided_password, &enrolled);
SizedBuffer serialized_msg(msg.GetSerializedSize());
msg.Serialize(serialized_msg.buffer.get(), serialized_msg.buffer.get() + serialized_msg.length);
EnrollRequest deserialized_msg;
deserialized_msg.Deserialize(serialized_msg.buffer.get(), serialized_msg.buffer.get()
+ serialized_msg.length);
ASSERT_EQ(gatekeeper::gatekeeper_error_t::ERROR_NONE,
deserialized_msg.error);
deserialized_password = &deserialized_msg.provided_password;
ASSERT_EQ(USER_ID, deserialized_msg.user_id);
ASSERT_EQ((uint32_t) password_size, deserialized_password->length);
ASSERT_EQ(0, memcmp(msg.provided_password.buffer.get(), deserialized_password->buffer.get(), password_size));
ASSERT_EQ((uint32_t) 0, deserialized_msg.enrolled_password.length);
ASSERT_EQ(NULL, deserialized_msg.enrolled_password.buffer.get());
ASSERT_EQ((uint32_t) 0, deserialized_msg.password_handle.length);
ASSERT_EQ(NULL, deserialized_msg.password_handle.buffer.get());
delete provided_password;
}
TEST(RoundTripTest, EnrollRequestNonNullEnrolledOrHandle) {
const uint32_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 msg(USER_ID, password_handle, provided_password, enrolled_password);
SizedBuffer serialized_msg(msg.GetSerializedSize());
msg.Serialize(serialized_msg.buffer.get(), serialized_msg.buffer.get() + serialized_msg.length);
EnrollRequest deserialized_msg;
deserialized_msg.Deserialize(serialized_msg.buffer.get(), serialized_msg.buffer.get()
+ serialized_msg.length);
ASSERT_EQ(gatekeeper::gatekeeper_error_t::ERROR_NONE,
deserialized_msg.error);
deserialized_password = &deserialized_msg.provided_password;
deserialized_enrolled = &deserialized_msg.enrolled_password;
deserialized_handle = &deserialized_msg.password_handle;
ASSERT_EQ(USER_ID, deserialized_msg.user_id);
ASSERT_EQ((uint32_t) password_size, deserialized_password->length);
ASSERT_EQ(0, memcmp(msg.provided_password.buffer.get(), deserialized_password->buffer.get(), password_size));
ASSERT_EQ((uint32_t) password_size, deserialized_enrolled->length);
ASSERT_EQ(0, memcmp(msg.enrolled_password.buffer.get(), deserialized_enrolled->buffer.get(), password_size));
ASSERT_EQ((uint32_t) password_size, deserialized_handle->length);
ASSERT_EQ(0, memcmp(msg.password_handle.buffer.get(), deserialized_handle->buffer.get(), password_size));
delete provided_password;
delete enrolled_password;
delete password_handle;
}
TEST(RoundTripTest, EnrollResponse) {
const uint32_t password_size = 512;
SizedBuffer *enrolled_password = make_buffer(password_size);
const SizedBuffer *deserialized_password;
// create request, serialize, deserialize, and validate
EnrollResponse msg(USER_ID, enrolled_password);
SizedBuffer serialized_msg(msg.GetSerializedSize());
msg.Serialize(serialized_msg.buffer.get(), serialized_msg.buffer.get() + serialized_msg.length);
EnrollResponse deserialized_msg;
deserialized_msg.Deserialize(serialized_msg.buffer.get(), serialized_msg.buffer.get()
+ serialized_msg.length);
ASSERT_EQ(gatekeeper::gatekeeper_error_t::ERROR_NONE,
deserialized_msg.error);
deserialized_password = &deserialized_msg.enrolled_password_handle;
ASSERT_EQ(USER_ID, deserialized_msg.user_id);
ASSERT_EQ((uint32_t) password_size, deserialized_password->length);
ASSERT_EQ(0, memcmp(msg.enrolled_password_handle.buffer.get(),
deserialized_password->buffer.get(), password_size));
}
TEST(RoundTripTest, VerifyRequest) {
const uint32_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 msg(USER_ID, 1, password_handle, provided_password);
SizedBuffer serialized_msg(msg.GetSerializedSize());
msg.Serialize(serialized_msg.buffer.get(), serialized_msg.buffer.get() + serialized_msg.length);
VerifyRequest deserialized_msg;
deserialized_msg.Deserialize(serialized_msg.buffer.get(), serialized_msg.buffer.get()
+ serialized_msg.length);
ASSERT_EQ(gatekeeper::gatekeeper_error_t::ERROR_NONE,
deserialized_msg.error);
ASSERT_EQ(USER_ID, deserialized_msg.user_id);
ASSERT_EQ((uint64_t) 1, deserialized_msg.challenge);
deserialized_password = &deserialized_msg.password_handle;
ASSERT_EQ((uint32_t) password_size, deserialized_password->length);
ASSERT_EQ(0, memcmp(msg.provided_password.buffer.get(), deserialized_password->buffer.get(),
password_size));
deserialized_password = &deserialized_msg.password_handle;
ASSERT_EQ((uint32_t) password_size, deserialized_password->length);
ASSERT_EQ(0, memcmp(msg.password_handle.buffer.get(), deserialized_password->buffer.get(),
password_size));
}
TEST(RoundTripTest, VerifyResponse) {
const uint32_t password_size = 512;
SizedBuffer *auth_token = make_buffer(password_size);
const SizedBuffer *deserialized_password;
// create request, serialize, deserialize, and validate
VerifyResponse msg(USER_ID, auth_token);
SizedBuffer serialized_msg(msg.GetSerializedSize());
msg.Serialize(serialized_msg.buffer.get(), serialized_msg.buffer.get() + serialized_msg.length);
VerifyResponse deserialized_msg;
deserialized_msg.Deserialize(serialized_msg.buffer.get(), serialized_msg.buffer.get()
+ serialized_msg.length);
ASSERT_EQ(gatekeeper::gatekeeper_error_t::ERROR_NONE,
deserialized_msg.error);
ASSERT_EQ(USER_ID, deserialized_msg.user_id);
deserialized_password = &deserialized_msg.auth_token;
ASSERT_EQ((uint32_t) password_size, deserialized_password->length);
ASSERT_EQ(0, memcmp(msg.auth_token.buffer.get(), deserialized_password->buffer.get(),
password_size));
}
TEST(RoundTripTest, VerifyResponseError) {
VerifyResponse msg;
msg.error = gatekeeper::gatekeeper_error_t::ERROR_INVALID;
SizedBuffer serialized_msg(msg.GetSerializedSize());
msg.Serialize(serialized_msg.buffer.get(), serialized_msg.buffer.get() + serialized_msg.length);
VerifyResponse deserialized_msg;
deserialized_msg.Deserialize(serialized_msg.buffer.get(), serialized_msg.buffer.get() + serialized_msg.length);
ASSERT_EQ(gatekeeper::gatekeeper_error_t::ERROR_INVALID,
deserialized_msg.error);
}
TEST(RoundTripTest, VerifyRequestError) {
VerifyRequest msg;
msg.error = gatekeeper::gatekeeper_error_t::ERROR_INVALID;
SizedBuffer serialized_msg(msg.GetSerializedSize());
msg.Serialize(serialized_msg.buffer.get(), serialized_msg.buffer.get() + serialized_msg.length);
VerifyRequest deserialized_msg;
deserialized_msg.Deserialize(serialized_msg.buffer.get(), serialized_msg.buffer.get() + serialized_msg.length);
ASSERT_EQ(gatekeeper::gatekeeper_error_t::ERROR_INVALID,
deserialized_msg.error);
}
TEST(RoundTripTest, EnrollResponseError) {
EnrollResponse msg;
msg.error = gatekeeper::gatekeeper_error_t::ERROR_INVALID;
SizedBuffer serialized_msg(msg.GetSerializedSize());
msg.Serialize(serialized_msg.buffer.get(), serialized_msg.buffer.get() + serialized_msg.length);
EnrollResponse deserialized_msg;
deserialized_msg.Deserialize(serialized_msg.buffer.get(), serialized_msg.buffer.get() + serialized_msg.length);
ASSERT_EQ(gatekeeper::gatekeeper_error_t::ERROR_INVALID,
deserialized_msg.error);
}
TEST(RoundTripTest, EnrollRequestError) {
EnrollRequest msg;
msg.error = gatekeeper::gatekeeper_error_t::ERROR_INVALID;
SizedBuffer serialized_msg(msg.GetSerializedSize());
msg.Serialize(serialized_msg.buffer.get(), serialized_msg.buffer.get() + serialized_msg.length);
EnrollRequest deserialized_msg;
deserialized_msg.Deserialize(serialized_msg.buffer.get(), serialized_msg.buffer.get() + serialized_msg.length);
ASSERT_EQ(gatekeeper::gatekeeper_error_t::ERROR_INVALID,
deserialized_msg.error);
}
uint8_t msgbuf[] = {
220, 88, 183, 255, 71, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 173, 0, 0, 0, 228, 174, 98, 187, 191, 135, 253, 200, 51, 230, 114, 247, 151, 109,
237, 79, 87, 32, 94, 5, 204, 46, 154, 30, 91, 6, 103, 148, 254, 129, 65, 171, 228,
167, 224, 163, 9, 15, 206, 90, 58, 11, 205, 55, 211, 33, 87, 178, 149, 91, 28, 236,
218, 112, 231, 34, 82, 82, 134, 103, 137, 115, 27, 156, 102, 159, 220, 226, 89, 42, 25,
37, 9, 84, 239, 76, 161, 198, 72, 167, 163, 39, 91, 148, 191, 17, 191, 87, 169, 179,
136, 10, 194, 154, 4, 40, 107, 109, 61, 161, 20, 176, 247, 13, 214, 106, 229, 45, 17,
5, 60, 189, 64, 39, 166, 208, 14, 57, 25, 140, 148, 25, 177, 246, 189, 43, 181, 88,
204, 29, 126, 224, 100, 143, 93, 60, 57, 249, 55, 0, 87, 83, 227, 224, 166, 59, 214,
81, 144, 129, 58, 6, 57, 46, 254, 232, 41, 220, 209, 230, 167, 138, 158, 94, 180, 125,
247, 26, 162, 116, 238, 202, 187, 100, 65, 13, 180, 44, 245, 159, 83, 161, 176, 58, 72,
236, 109, 105, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 11, 0, 0, 0, 98, 0, 0, 0, 1, 0, 0, 32, 2, 0, 0, 0, 1, 0,
0, 32, 3, 0, 0, 0, 2, 0, 0, 16, 1, 0, 0, 0, 3, 0, 0, 48, 0,
1, 0, 0, 200, 0, 0, 80, 3, 0, 0, 0, 0, 0, 0, 0, 244, 1, 0, 112,
1, 246, 1, 0, 112, 1, 189, 2, 0, 96, 144, 178, 236, 250, 255, 255, 255, 255, 145,
1, 0, 96, 144, 226, 33, 60, 222, 2, 0, 0, 189, 2, 0, 96, 0, 0, 0, 0,
0, 0, 0, 0, 190, 2, 0, 16, 1, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 110, 0, 0, 0, 0, 0, 0, 0, 11, 0,
0, 0, 98, 0, 0, 0, 1, 0, 0, 32, 2, 0, 0, 0, 1, 0, 0, 32, 3,
0, 0, 0, 2, 0, 0, 16, 1, 0, 0, 0, 3, 0, 0, 48, 0, 1, 0, 0,
200, 0, 0, 80, 3, 0, 0, 0, 0, 0, 0, 0, 244, 1, 0, 112, 1, 246, 1,
0, 112, 1, 189, 2, 0, 96, 144, 178, 236, 250, 255, 255, 255, 255, 145, 1, 0, 96,
144, 226, 33, 60, 222, 2, 0, 0, 189, 2, 0, 96, 0, 0, 0, 0, 0, 0, 0,
0, 190, 2, 0, 16, 1, 0, 0, 0,
};
/*
* These tests don't have any assertions or expectations. They just try to parse garbage, to see if
* the result will be a crash. This is especially informative when run under Valgrind memcheck.
*/
template <typename Message> void parse_garbage() {
Message msg;
uint32_t array_length = sizeof(msgbuf) / sizeof(msgbuf[0]);
const uint8_t* end = msgbuf + array_length;
for (uint32_t i = 0; i < array_length; ++i) {
const uint8_t* begin = msgbuf + i;
const uint8_t* p = begin;
msg.Deserialize(p, end);
}
}
#define GARBAGE_TEST(Message) \
TEST(GarbageTest, Message) { parse_garbage<Message>(); }
GARBAGE_TEST(VerifyRequest);
GARBAGE_TEST(VerifyResponse);
GARBAGE_TEST(EnrollRequest);
GARBAGE_TEST(EnrollResponse);