Merge "C++ AIDL on-device GateKeeper / SharedSecret impl" into main

This commit is contained in:
Cody Schuffelen 2024-04-14 22:08:37 +00:00 committed by Gerrit Code Review
commit e23e450487
13 changed files with 737 additions and 9 deletions

View file

@ -0,0 +1,71 @@
package {
// See: http://go/android-license-faq
// A large-scale-change added 'default_applicable_licenses' to import
// all of the 'license_kinds' from "hardware_interfaces_license"
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["hardware_interfaces_license"],
}
cc_binary {
name: "android.hardware.gatekeeper-service.nonsecure",
cflags: [
"-fvisibility=hidden",
"-Wall",
"-Werror",
],
installable: false, // installed in APEX
relative_install_path: "hw",
shared_libs: [
"android.hardware.gatekeeper-V1-ndk",
"android.hardware.security.sharedsecret-V1-ndk",
"lib_android_keymaster_keymint_utils",
"libbase",
"libbinder_ndk",
"libcrypto",
"libcutils",
"libgatekeeper",
"libhardware",
"libkeymaster_portable",
"liblog",
"libutils",
],
srcs: [
"GateKeeper.cpp",
"SharedSecret.cpp",
"service.cpp",
],
static_libs: ["libscrypt_static"],
vendor: true,
}
prebuilt_etc {
name: "gatekeeper_nonsecure_vintf",
srcs: [
"android.hardware.gatekeeper-service.nonsecure.xml",
"android.hardware.security.sharedsecret-gatekeeper.xml",
],
sub_dir: "vintf",
installable: false,
}
prebuilt_etc {
name: "android.hardware.gatekeeper-service.nonsecure.rc",
src: "android.hardware.gatekeeper-service.nonsecure.rc",
installable: false,
}
apex {
name: "com.android.hardware.gatekeeper.nonsecure",
binaries: ["android.hardware.gatekeeper-service.nonsecure"],
certificate: ":com.google.cf.apex.certificate",
file_contexts: "file_contexts",
key: "com.google.cf.apex.key",
manifest: "manifest.json",
prebuilts: [
"gatekeeper_nonsecure_vintf",
"android.hardware.gatekeeper-service.nonsecure.rc",
],
updatable: false,
vendor: true,
}

View file

@ -0,0 +1,149 @@
/*
* Copyright (C) 2016 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.
*/
#define LOG_TAG "android.hardware.gatekeeper-service.nonsecure"
#include <endian.h>
#include <android-base/logging.h>
#include "GateKeeper.h"
using ::gatekeeper::EnrollRequest;
using ::gatekeeper::EnrollResponse;
using ::gatekeeper::ERROR_NONE;
using ::gatekeeper::ERROR_RETRY;
using ::gatekeeper::SizedBuffer;
using ::gatekeeper::VerifyRequest;
using ::gatekeeper::VerifyResponse;
namespace aidl::android::hardware::gatekeeper {
SizedBuffer vec2sized_buffer(const std::vector<uint8_t>& vec) {
if (vec.size() == 0 || vec.size() > std::numeric_limits<uint32_t>::max()) {
return {};
}
auto unused = new uint8_t[vec.size()];
std::copy(vec.begin(), vec.end(), unused);
return {unused, static_cast<uint32_t>(vec.size())};
}
void sizedBuffer2AidlHWToken(SizedBuffer& buffer,
android::hardware::security::keymint::HardwareAuthToken* aidlToken) {
const hw_auth_token_t* authToken =
reinterpret_cast<const hw_auth_token_t*>(buffer.Data<uint8_t>());
aidlToken->challenge = authToken->challenge;
aidlToken->userId = authToken->user_id;
aidlToken->authenticatorId = authToken->authenticator_id;
// these are in network order: translate to host
aidlToken->authenticatorType =
static_cast<android::hardware::security::keymint::HardwareAuthenticatorType>(
be32toh(authToken->authenticator_type));
aidlToken->timestamp.milliSeconds = be64toh(authToken->timestamp);
aidlToken->mac.insert(aidlToken->mac.begin(), std::begin(authToken->hmac),
std::end(authToken->hmac));
}
SoftGateKeeperDevice::SoftGateKeeperDevice(::gatekeeper::SoftGateKeeper& impl) : impl_(impl) {}
::ndk::ScopedAStatus SoftGateKeeperDevice::enroll(int32_t uid,
const std::vector<uint8_t>& currentPasswordHandle,
const std::vector<uint8_t>& currentPassword,
const std::vector<uint8_t>& desiredPassword,
GatekeeperEnrollResponse* rsp) {
if (desiredPassword.size() == 0) {
LOG(ERROR) << "Desired password size is 0";
return ndk::ScopedAStatus(AStatus_fromServiceSpecificError(ERROR_GENERAL_FAILURE));
}
if (currentPasswordHandle.size() > 0) {
if (currentPasswordHandle.size() != sizeof(::gatekeeper::password_handle_t)) {
LOG(ERROR) << "Password handle has wrong length";
return ndk::ScopedAStatus(AStatus_fromServiceSpecificError(ERROR_GENERAL_FAILURE));
}
}
EnrollRequest request(uid, vec2sized_buffer(currentPasswordHandle),
vec2sized_buffer(desiredPassword), vec2sized_buffer(currentPassword));
EnrollResponse response;
impl_.Enroll(request, &response);
if (response.error == ERROR_RETRY) {
LOG(ERROR) << "Enroll response has a retry error";
*rsp = {ERROR_RETRY_TIMEOUT, static_cast<int32_t>(response.retry_timeout), 0, {}};
return ndk::ScopedAStatus::ok();
} else if (response.error != ERROR_NONE) {
LOG(ERROR) << "Enroll response has an error: " << response.error;
return ndk::ScopedAStatus(AStatus_fromServiceSpecificError(ERROR_GENERAL_FAILURE));
} else {
const ::gatekeeper::password_handle_t* password_handle =
response.enrolled_password_handle.Data<::gatekeeper::password_handle_t>();
*rsp = {STATUS_OK,
0,
static_cast<int64_t>(password_handle->user_id),
{response.enrolled_password_handle.Data<uint8_t>(),
(response.enrolled_password_handle.Data<uint8_t>() +
response.enrolled_password_handle.size())}};
}
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus SoftGateKeeperDevice::verify(
int32_t uid, int64_t challenge, const std::vector<uint8_t>& enrolledPasswordHandle,
const std::vector<uint8_t>& providedPassword, GatekeeperVerifyResponse* rsp) {
if (enrolledPasswordHandle.size() == 0) {
LOG(ERROR) << "Enrolled password size is 0";
return ndk::ScopedAStatus(AStatus_fromServiceSpecificError(ERROR_GENERAL_FAILURE));
}
if (enrolledPasswordHandle.size() > 0) {
if (enrolledPasswordHandle.size() != sizeof(::gatekeeper::password_handle_t)) {
LOG(ERROR) << "Password handle has wrong length";
return ndk::ScopedAStatus(AStatus_fromServiceSpecificError(ERROR_GENERAL_FAILURE));
}
}
VerifyRequest request(uid, challenge, vec2sized_buffer(enrolledPasswordHandle),
vec2sized_buffer(providedPassword));
VerifyResponse response;
impl_.Verify(request, &response);
if (response.error == ERROR_RETRY) {
LOG(ERROR) << "Verify request response gave retry error";
*rsp = {ERROR_RETRY_TIMEOUT, static_cast<int32_t>(response.retry_timeout), {}};
return ndk::ScopedAStatus::ok();
} else if (response.error != ERROR_NONE) {
LOG(ERROR) << "Verify request response gave error: " << response.error;
return ndk::ScopedAStatus(AStatus_fromServiceSpecificError(ERROR_GENERAL_FAILURE));
} else {
// On Success, return GatekeeperVerifyResponse with Success Status, timeout{0} and
// valid HardwareAuthToken.
*rsp = {response.request_reenroll ? STATUS_REENROLL : STATUS_OK, 0, {}};
// Convert the hw_auth_token_t to HardwareAuthToken in the response.
sizedBuffer2AidlHWToken(response.auth_token, &rsp->hardwareAuthToken);
}
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus SoftGateKeeperDevice::deleteUser(int32_t /*uid*/) {
LOG(ERROR) << "deleteUser is unimplemented";
return ndk::ScopedAStatus(AStatus_fromServiceSpecificError(ERROR_NOT_IMPLEMENTED));
}
::ndk::ScopedAStatus SoftGateKeeperDevice::deleteAllUsers() {
LOG(ERROR) << "deleteAllUsers is unimplemented";
return ndk::ScopedAStatus(AStatus_fromServiceSpecificError(ERROR_NOT_IMPLEMENTED));
}
} // namespace aidl::android::hardware::gatekeeper

View file

@ -0,0 +1,66 @@
/*
* Copyright (C) 2014 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.
*/
#pragma once
#include <aidl/android/hardware/gatekeeper/BnGatekeeper.h>
#include <gatekeeper/gatekeeper_messages.h>
#include "SoftGateKeeper.h"
namespace aidl::android::hardware::gatekeeper {
class SoftGateKeeperDevice : public BnGatekeeper {
public:
SoftGateKeeperDevice(::gatekeeper::SoftGateKeeper&);
/**
* Enrolls password_payload, which should be derived from a user selected pin
* or password, with the authentication factor private key used only for
* enrolling authentication factor data.
*
* Returns: 0 on success or an error code less than 0 on error.
* On error, enrolled_password_handle will not be allocated.
*/
::ndk::ScopedAStatus enroll(int32_t uid, const std::vector<uint8_t>& currentPasswordHandle,
const std::vector<uint8_t>& currentPassword,
const std::vector<uint8_t>& desiredPassword,
GatekeeperEnrollResponse* _aidl_return) override;
/**
* Verifies provided_password matches enrolled_password_handle.
*
* Implementations of this module may retain the result of this call
* to attest to the recency of authentication.
*
* On success, writes the address of a verification token to auth_token,
* usable to attest password verification to other trusted services. Clients
* may pass NULL for this value.
*
* Returns: 0 on success or an error code less than 0 on error
* On error, verification token will not be allocated
*/
::ndk::ScopedAStatus verify(int32_t uid, int64_t challenge,
const std::vector<uint8_t>& enrolledPasswordHandle,
const std::vector<uint8_t>& providedPassword,
GatekeeperVerifyResponse* _aidl_return) override;
::ndk::ScopedAStatus deleteAllUsers() override;
::ndk::ScopedAStatus deleteUser(int32_t uid) override;
private:
::gatekeeper::SoftGateKeeper& impl_;
};
} // namespace aidl::android::hardware::gatekeeper

View file

@ -0,0 +1,131 @@
/*
* Copyright 2024, 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 "SharedSecret.h"
#include <algorithm>
#include <cstring>
#include <mutex>
#include <vector>
#include <openssl/rand.h>
#include <KeyMintUtils.h>
#include <aidl/android/hardware/security/sharedsecret/BnSharedSecret.h>
#include <aidl/android/hardware/security/sharedsecret/SharedSecretParameters.h>
#include <android-base/logging.h>
#include <keymaster/android_keymaster_messages.h>
#include <keymaster/android_keymaster_utils.h>
#include <keymaster/km_openssl/ckdf.h>
#include <keymaster/km_openssl/hmac.h>
namespace aidl::android::hardware::security::sharedsecret {
::ndk::ScopedAStatus SoftSharedSecret::getSharedSecretParameters(
SharedSecretParameters* out_params) {
std::lock_guard lock(mutex_);
if (seed_.empty()) {
seed_.resize(32, 0);
}
out_params->seed = seed_;
if (nonce_.empty()) {
nonce_.resize(32, 0);
RAND_bytes(nonce_.data(), 32);
}
out_params->nonce = nonce_;
LOG(INFO) << "Presented shared secret parameters with seed size " << out_params->seed.size()
<< " and nonce size " << out_params->nonce.size();
return ::ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus SoftSharedSecret::computeSharedSecret(
const std::vector<SharedSecretParameters>& params, std::vector<uint8_t>* sharing_check) {
std::lock_guard lock(mutex_);
LOG(INFO) << "Computing shared secret";
// Reimplemented based on SoftKeymasterEnforcement, which does not expose
// enough functionality to satisfy the GateKeeper interface
keymaster::KeymasterKeyBlob key_agreement_key;
if (key_agreement_key.Reset(32) == nullptr) {
LOG(ERROR) << "key agreement key memory allocation failed";
return keymint::km_utils::kmError2ScopedAStatus(KM_ERROR_MEMORY_ALLOCATION_FAILED);
}
// Matching:
// - kFakeAgreementKey in system/keymaster/km_openssl/soft_keymaster_enforcement.cpp
// - Keys::kak in hardware/interfaces/security/keymint/aidl/default/ta/soft.rs
std::memset(key_agreement_key.writable_data(), 0, 32);
keymaster::KeymasterBlob label((uint8_t*)KEY_AGREEMENT_LABEL, strlen(KEY_AGREEMENT_LABEL));
if (label.data == nullptr) {
LOG(ERROR) << "label memory allocation failed";
return keymint::km_utils::kmError2ScopedAStatus(KM_ERROR_MEMORY_ALLOCATION_FAILED);
}
static_assert(sizeof(keymaster_blob_t) == sizeof(keymaster::KeymasterBlob));
bool found_mine = false;
std::vector<keymaster::KeymasterBlob> context_blobs;
for (const auto& param : params) {
auto& seed_blob = context_blobs.emplace_back();
if (seed_blob.Reset(param.seed.size()) == nullptr) {
LOG(ERROR) << "seed memory allocation failed";
return keymint::km_utils::kmError2ScopedAStatus(KM_ERROR_MEMORY_ALLOCATION_FAILED);
}
std::copy(param.seed.begin(), param.seed.end(), seed_blob.writable_data());
auto& nonce_blob = context_blobs.emplace_back();
if (nonce_blob.Reset(param.nonce.size()) == nullptr) {
LOG(ERROR) << "Nonce memory allocation failed";
return keymint::km_utils::kmError2ScopedAStatus(KM_ERROR_MEMORY_ALLOCATION_FAILED);
}
std::copy(param.nonce.begin(), param.nonce.end(), nonce_blob.writable_data());
if (param.seed == seed_ && param.nonce == nonce_) {
found_mine = true;
}
}
if (!found_mine) {
LOG(ERROR) << "Did not receive my own shared secret parameter back";
return keymint::km_utils::kmError2ScopedAStatus(KM_ERROR_INVALID_ARGUMENT);
}
auto context_blobs_ptr = reinterpret_cast<keymaster_blob_t*>(context_blobs.data());
if (hmac_key_.Reset(32) == nullptr) {
LOG(ERROR) << "hmac key allocation failed";
return keymint::km_utils::kmError2ScopedAStatus(KM_ERROR_MEMORY_ALLOCATION_FAILED);
}
auto error = keymaster::ckdf(key_agreement_key, label, context_blobs_ptr, context_blobs.size(),
&hmac_key_);
if (error != KM_ERROR_OK) {
LOG(ERROR) << "CKDF failed";
return keymint::km_utils::kmError2ScopedAStatus(error);
}
keymaster::HmacSha256 hmac_impl;
if (!hmac_impl.Init(hmac_key_.key_material, hmac_key_.key_material_size)) {
LOG(ERROR) << "hmac initialization failed";
return ::ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
}
sharing_check->clear();
sharing_check->resize(32, 0);
if (!hmac_impl.Sign((const uint8_t*)KEY_CHECK_LABEL, strlen(KEY_CHECK_LABEL),
sharing_check->data(), sharing_check->size())) {
return ::ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
}
return ::ndk::ScopedAStatus::ok();
}
keymaster::KeymasterKeyBlob SoftSharedSecret::HmacKey() const {
std::lock_guard lock(mutex_);
return hmac_key_;
}
} // namespace aidl::android::hardware::security::sharedsecret

View file

@ -0,0 +1,43 @@
/*
* Copyright 2020, 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.
*/
#pragma once
#include <cstdint>
#include <mutex>
#include <aidl/android/hardware/security/sharedsecret/BnSharedSecret.h>
#include <aidl/android/hardware/security/sharedsecret/SharedSecretParameters.h>
#include <keymaster/km_openssl/soft_keymaster_enforcement.h>
namespace aidl::android::hardware::security::sharedsecret {
class SoftSharedSecret : public BnSharedSecret {
public:
::ndk::ScopedAStatus getSharedSecretParameters(SharedSecretParameters* params) override;
::ndk::ScopedAStatus computeSharedSecret(const std::vector<SharedSecretParameters>& params,
std::vector<uint8_t>* sharingCheck) override;
keymaster::KeymasterKeyBlob HmacKey() const;
private:
mutable std::mutex mutex_;
std::vector<std::uint8_t> seed_;
std::vector<std::uint8_t> nonce_;
keymaster::KeymasterKeyBlob hmac_key_;
};
} // namespace aidl::android::hardware::security::sharedsecret

View file

@ -0,0 +1,189 @@
/*
* Copyright 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#ifndef SOFT_GATEKEEPER_H_
#define SOFT_GATEKEEPER_H_
extern "C" {
#include <openssl/rand.h>
#include <openssl/sha.h>
#include <crypto_scrypt.h>
}
#include <memory>
#include <unordered_map>
#include <android-base/logging.h>
#include <android-base/memory.h>
#include <gatekeeper/gatekeeper.h>
#include <keymaster/km_openssl/hmac.h>
#include "SharedSecret.h"
namespace gatekeeper {
struct fast_hash_t {
uint64_t salt;
uint8_t digest[SHA256_DIGEST_LENGTH];
};
class SoftGateKeeper : public GateKeeper {
public:
static const uint32_t SIGNATURE_LENGTH_BYTES = 32;
// scrypt params
static const uint64_t N = 16384;
static const uint32_t r = 8;
static const uint32_t p = 1;
static const int MAX_UINT_32_CHARS = 11;
SoftGateKeeper(const ::aidl::android::hardware::security::sharedsecret::SoftSharedSecret&
shared_secret)
: shared_secret_(shared_secret) {
key_.reset(new uint8_t[SIGNATURE_LENGTH_BYTES]);
memset(key_.get(), 0, SIGNATURE_LENGTH_BYTES);
}
virtual ~SoftGateKeeper() {}
virtual bool GetAuthTokenKey(const uint8_t** auth_token_key, uint32_t* length) const {
if (auth_token_key == NULL || length == NULL) return false;
if (hmac_key_.key_material == nullptr) {
hmac_key_ = shared_secret_.HmacKey();
}
*auth_token_key = hmac_key_.key_material;
*length = hmac_key_.key_material_size;
return true;
}
virtual void GetPasswordKey(const uint8_t** password_key, uint32_t* length) {
if (password_key == NULL || length == NULL) return;
*password_key = key_.get();
*length = SIGNATURE_LENGTH_BYTES;
}
virtual void ComputePasswordSignature(uint8_t* signature, uint32_t signature_length,
const uint8_t*, uint32_t, const uint8_t* password,
uint32_t password_length, salt_t salt) const {
if (signature == NULL) return;
crypto_scrypt(password, password_length, reinterpret_cast<uint8_t*>(&salt), sizeof(salt), N,
r, p, signature, signature_length);
}
virtual void GetRandom(void* random, uint32_t requested_length) const {
if (random == NULL) return;
RAND_pseudo_bytes((uint8_t*)random, requested_length);
}
virtual void ComputeSignature(uint8_t* signature, uint32_t signature_length, const uint8_t* key,
uint32_t key_length, const uint8_t* message,
const uint32_t message_length) const {
if (signature == NULL) return;
keymaster::HmacSha256 hmac_calculator;
if (!hmac_calculator.Init(key, key_length)) {
LOG(ERROR) << "ComputeSignature: Failed to initialize hmac calculator";
return;
}
if (!hmac_calculator.Sign(message, message_length, signature, signature_length)) {
LOG(ERROR) << "ComputeSignature: failed to create hmac";
}
}
virtual uint64_t GetMillisecondsSinceBoot() const {
struct timespec time;
int res = clock_gettime(CLOCK_BOOTTIME, &time);
if (res < 0) return 0;
return (time.tv_sec * 1000) + (time.tv_nsec / 1000 / 1000);
}
virtual bool IsHardwareBacked() const { return false; }
virtual bool GetFailureRecord(uint32_t uid, secure_id_t user_id, failure_record_t* record,
bool /* secure */) {
failure_record_t* stored = &failure_map_[uid];
if (user_id != stored->secure_user_id) {
stored->secure_user_id = user_id;
stored->last_checked_timestamp = 0;
stored->failure_counter = 0;
}
memcpy(record, stored, sizeof(*record));
return true;
}
virtual bool ClearFailureRecord(uint32_t uid, secure_id_t user_id, bool /* secure */) {
failure_record_t* stored = &failure_map_[uid];
stored->secure_user_id = user_id;
stored->last_checked_timestamp = 0;
stored->failure_counter = 0;
return true;
}
virtual bool WriteFailureRecord(uint32_t uid, failure_record_t* record, bool /* secure */) {
failure_map_[uid] = *record;
return true;
}
fast_hash_t ComputeFastHash(const SizedBuffer& password, uint64_t salt) {
fast_hash_t fast_hash;
size_t digest_size = password.size() + sizeof(salt);
std::unique_ptr<uint8_t[]> digest(new uint8_t[digest_size]);
memcpy(digest.get(), &salt, sizeof(salt));
memcpy(digest.get() + sizeof(salt), password.Data<uint8_t>(), password.size());
SHA256(digest.get(), digest_size, (uint8_t*)&fast_hash.digest);
fast_hash.salt = salt;
return fast_hash;
}
bool VerifyFast(const fast_hash_t& fast_hash, const SizedBuffer& password) {
fast_hash_t computed = ComputeFastHash(password, fast_hash.salt);
return memcmp(computed.digest, fast_hash.digest, SHA256_DIGEST_LENGTH) == 0;
}
bool DoVerify(const password_handle_t* expected_handle, const SizedBuffer& password) {
uint64_t user_id = android::base::get_unaligned<secure_id_t>(&expected_handle->user_id);
FastHashMap::const_iterator it = fast_hash_map_.find(user_id);
if (it != fast_hash_map_.end() && VerifyFast(it->second, password)) {
return true;
} else {
if (GateKeeper::DoVerify(expected_handle, password)) {
uint64_t salt;
GetRandom(&salt, sizeof(salt));
fast_hash_map_[user_id] = ComputeFastHash(password, salt);
return true;
}
}
return false;
}
private:
typedef std::unordered_map<uint32_t, failure_record_t> FailureRecordMap;
typedef std::unordered_map<uint64_t, fast_hash_t> FastHashMap;
const ::aidl::android::hardware::security::sharedsecret::SoftSharedSecret& shared_secret_;
std::unique_ptr<uint8_t[]> key_;
FailureRecordMap failure_map_;
FastHashMap fast_hash_map_;
mutable ::keymaster::KeymasterKeyBlob hmac_key_;
};
} // namespace gatekeeper
#endif // SOFT_GATEKEEPER_H_

View file

@ -0,0 +1,4 @@
service vendor.gatekeeper_nonsecure /apex/com.android.hardware.gatekeeper/bin/hw/android.hardware.gatekeeper-service.nonsecure
class early_hal
user system
group system

View file

@ -0,0 +1,10 @@
<manifest version="1.0" type="device">
<hal format="aidl">
<name>android.hardware.gatekeeper</name>
<version>1</version>
<interface>
<name>IGatekeeper</name>
<instance>default</instance>
</interface>
</hal>
</manifest>

View file

@ -0,0 +1,6 @@
<manifest version="1.0" type="device">
<hal format="aidl">
<name>android.hardware.security.sharedsecret</name>
<fqname>ISharedSecret/gatekeeper</fqname>
</hal>
</manifest>

View file

@ -0,0 +1,3 @@
(/.*)? u:object_r:vendor_file:s0
/etc(/.*)? u:object_r:vendor_configs_file:s0
/bin/hw/android\.hardware\.gatekeeper-service\.nonsecure u:object_r:hal_gatekeeper_remote_exec:s0

View file

@ -0,0 +1,5 @@
{
"name": "com.android.hardware.gatekeeper",
"version": 1,
"vendorBootstrap": true
}

View file

@ -0,0 +1,47 @@
/*
* Copyright (C) 2016 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.
*/
#define LOG_TAG "android.hardware.gatekeeper-service.nonsecure"
#include <android-base/logging.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
#include <cutils/properties.h>
#include "GateKeeper.h"
#include "SharedSecret.h"
#include "SoftGateKeeper.h"
using aidl::android::hardware::gatekeeper::SoftGateKeeperDevice;
using aidl::android::hardware::security::sharedsecret::SoftSharedSecret;
int main(int, char** argv) {
::android::base::InitLogging(argv, ::android::base::KernelLogger);
ABinderProcess_setThreadPoolMaxThreadCount(0);
auto secret = ndk::SharedRefBase::make<SoftSharedSecret>();
std::string secret_instance = SoftSharedSecret::descriptor + std::string("/gatekeeper");
auto status = AServiceManager_addService(secret->asBinder().get(), secret_instance.c_str());
CHECK_EQ(status, STATUS_OK);
::gatekeeper::SoftGateKeeper implementation(*secret);
auto gatekeeper = ndk::SharedRefBase::make<SoftGateKeeperDevice>(implementation);
const std::string instance = SoftGateKeeperDevice::descriptor + std::string("/default");
status = AServiceManager_addService(gatekeeper->asBinder().get(), instance.c_str());
CHECK_EQ(status, STATUS_OK);
ABinderProcess_joinThreadPool();
return -1; // Should never get here.
}

View file

@ -16,25 +16,29 @@
//! Monotonic clock implementation. //! Monotonic clock implementation.
use kmr_common::crypto; use kmr_common::crypto;
use std::time::Instant;
/// Monotonic clock. /// Monotonic clock.
pub struct StdClock { pub struct StdClock;
start: Instant,
}
impl StdClock { impl StdClock {
/// Create new clock instance, holding time since construction. /// Create new clock instance, holding time since construction.
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {}
start: Instant::now(),
}
} }
} }
impl crypto::MonotonicClock for StdClock { impl crypto::MonotonicClock for StdClock {
fn now(&self) -> crypto::MillisecondsSinceEpoch { fn now(&self) -> crypto::MillisecondsSinceEpoch {
let duration = self.start.elapsed(); let mut time = libc::timespec { tv_sec: 0, tv_nsec: 0 };
crypto::MillisecondsSinceEpoch(duration.as_millis().try_into().unwrap()) // Use `CLOCK_BOOTTIME` for consistency with the times used by the Cuttlefish
// C++ implementation of Gatekeeper.
let rc =
// Safety: `time` is a valid structure.
unsafe { libc::clock_gettime(libc::CLOCK_BOOTTIME, &mut time as *mut libc::timespec) };
if rc < 0 {
log::warn!("failed to get time!");
return crypto::MillisecondsSinceEpoch(0);
}
crypto::MillisecondsSinceEpoch(((time.tv_sec * 1000) + (time.tv_nsec / 1000 / 1000)).into())
} }
} }