diff --git a/gatekeeper/aidl/software/Android.bp b/gatekeeper/aidl/software/Android.bp new file mode 100644 index 0000000000..d24446118e --- /dev/null +++ b/gatekeeper/aidl/software/Android.bp @@ -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, +} diff --git a/gatekeeper/aidl/software/GateKeeper.cpp b/gatekeeper/aidl/software/GateKeeper.cpp new file mode 100644 index 0000000000..1fc3682a80 --- /dev/null +++ b/gatekeeper/aidl/software/GateKeeper.cpp @@ -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 + +#include + +#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& vec) { + if (vec.size() == 0 || vec.size() > std::numeric_limits::max()) { + return {}; + } + auto unused = new uint8_t[vec.size()]; + std::copy(vec.begin(), vec.end(), unused); + return {unused, static_cast(vec.size())}; +} + +void sizedBuffer2AidlHWToken(SizedBuffer& buffer, + android::hardware::security::keymint::HardwareAuthToken* aidlToken) { + const hw_auth_token_t* authToken = + reinterpret_cast(buffer.Data()); + 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( + 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& currentPasswordHandle, + const std::vector& currentPassword, + const std::vector& 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(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(password_handle->user_id), + {response.enrolled_password_handle.Data(), + (response.enrolled_password_handle.Data() + + response.enrolled_password_handle.size())}}; + } + return ndk::ScopedAStatus::ok(); +} + +::ndk::ScopedAStatus SoftGateKeeperDevice::verify( + int32_t uid, int64_t challenge, const std::vector& enrolledPasswordHandle, + const std::vector& 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(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 diff --git a/gatekeeper/aidl/software/GateKeeper.h b/gatekeeper/aidl/software/GateKeeper.h new file mode 100644 index 0000000000..1327fad793 --- /dev/null +++ b/gatekeeper/aidl/software/GateKeeper.h @@ -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 +#include + +#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& currentPasswordHandle, + const std::vector& currentPassword, + const std::vector& 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& enrolledPasswordHandle, + const std::vector& 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 diff --git a/gatekeeper/aidl/software/SharedSecret.cpp b/gatekeeper/aidl/software/SharedSecret.cpp new file mode 100644 index 0000000000..f693700f77 --- /dev/null +++ b/gatekeeper/aidl/software/SharedSecret.cpp @@ -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 +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +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& params, std::vector* 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 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(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 diff --git a/gatekeeper/aidl/software/SharedSecret.h b/gatekeeper/aidl/software/SharedSecret.h new file mode 100644 index 0000000000..1b804e7e86 --- /dev/null +++ b/gatekeeper/aidl/software/SharedSecret.h @@ -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 +#include + +#include +#include +#include + +namespace aidl::android::hardware::security::sharedsecret { + +class SoftSharedSecret : public BnSharedSecret { + public: + ::ndk::ScopedAStatus getSharedSecretParameters(SharedSecretParameters* params) override; + ::ndk::ScopedAStatus computeSharedSecret(const std::vector& params, + std::vector* sharingCheck) override; + + keymaster::KeymasterKeyBlob HmacKey() const; + + private: + mutable std::mutex mutex_; + std::vector seed_; + std::vector nonce_; + keymaster::KeymasterKeyBlob hmac_key_; +}; + +} // namespace aidl::android::hardware::security::sharedsecret diff --git a/gatekeeper/aidl/software/SoftGateKeeper.h b/gatekeeper/aidl/software/SoftGateKeeper.h new file mode 100644 index 0000000000..305d997cb4 --- /dev/null +++ b/gatekeeper/aidl/software/SoftGateKeeper.h @@ -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 +#include + +#include +} + +#include +#include + +#include +#include +#include +#include + +#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(&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 digest(new uint8_t[digest_size]); + memcpy(digest.get(), &salt, sizeof(salt)); + memcpy(digest.get() + sizeof(salt), password.Data(), 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(&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 FailureRecordMap; + typedef std::unordered_map FastHashMap; + + const ::aidl::android::hardware::security::sharedsecret::SoftSharedSecret& shared_secret_; + std::unique_ptr key_; + FailureRecordMap failure_map_; + FastHashMap fast_hash_map_; + mutable ::keymaster::KeymasterKeyBlob hmac_key_; +}; +} // namespace gatekeeper + +#endif // SOFT_GATEKEEPER_H_ diff --git a/gatekeeper/aidl/software/android.hardware.gatekeeper-service.nonsecure.rc b/gatekeeper/aidl/software/android.hardware.gatekeeper-service.nonsecure.rc new file mode 100644 index 0000000000..d361730d0a --- /dev/null +++ b/gatekeeper/aidl/software/android.hardware.gatekeeper-service.nonsecure.rc @@ -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 diff --git a/gatekeeper/aidl/software/android.hardware.gatekeeper-service.nonsecure.xml b/gatekeeper/aidl/software/android.hardware.gatekeeper-service.nonsecure.xml new file mode 100644 index 0000000000..c35421ea27 --- /dev/null +++ b/gatekeeper/aidl/software/android.hardware.gatekeeper-service.nonsecure.xml @@ -0,0 +1,10 @@ + + + android.hardware.gatekeeper + 1 + + IGatekeeper + default + + + diff --git a/gatekeeper/aidl/software/android.hardware.security.sharedsecret-gatekeeper.xml b/gatekeeper/aidl/software/android.hardware.security.sharedsecret-gatekeeper.xml new file mode 100644 index 0000000000..5d94985004 --- /dev/null +++ b/gatekeeper/aidl/software/android.hardware.security.sharedsecret-gatekeeper.xml @@ -0,0 +1,6 @@ + + + android.hardware.security.sharedsecret + ISharedSecret/gatekeeper + + diff --git a/gatekeeper/aidl/software/file_contexts b/gatekeeper/aidl/software/file_contexts new file mode 100644 index 0000000000..23a62ea9df --- /dev/null +++ b/gatekeeper/aidl/software/file_contexts @@ -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 diff --git a/gatekeeper/aidl/software/manifest.json b/gatekeeper/aidl/software/manifest.json new file mode 100644 index 0000000000..d0def3666d --- /dev/null +++ b/gatekeeper/aidl/software/manifest.json @@ -0,0 +1,5 @@ +{ + "name": "com.android.hardware.gatekeeper", + "version": 1, + "vendorBootstrap": true +} diff --git a/gatekeeper/aidl/software/service.cpp b/gatekeeper/aidl/software/service.cpp new file mode 100644 index 0000000000..beef8c41dd --- /dev/null +++ b/gatekeeper/aidl/software/service.cpp @@ -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 +#include +#include +#include + +#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(); + 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(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. +} diff --git a/security/keymint/aidl/default/ta/clock.rs b/security/keymint/aidl/default/ta/clock.rs index ad8509abd3..03e04ec42f 100644 --- a/security/keymint/aidl/default/ta/clock.rs +++ b/security/keymint/aidl/default/ta/clock.rs @@ -16,25 +16,29 @@ //! Monotonic clock implementation. use kmr_common::crypto; -use std::time::Instant; /// Monotonic clock. -pub struct StdClock { - start: Instant, -} +pub struct StdClock; impl StdClock { /// Create new clock instance, holding time since construction. pub fn new() -> Self { - Self { - start: Instant::now(), - } + Self {} } } impl crypto::MonotonicClock for StdClock { fn now(&self) -> crypto::MillisecondsSinceEpoch { - let duration = self.start.elapsed(); - crypto::MillisecondsSinceEpoch(duration.as_millis().try_into().unwrap()) + let mut time = libc::timespec { tv_sec: 0, tv_nsec: 0 }; + // 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()) } }