From 5a43d61e66576733d6b6e3335cd3b35e8c984a0c Mon Sep 17 00:00:00 2001 From: Seth Moore Date: Tue, 19 Jan 2021 17:51:51 +0000 Subject: [PATCH] Add support for binding storage encryption to a seed With this change, vold exposes an API that may be used to bind key storage encryption keys to a given seed value. The seed value passed to vold must be consistent across reboots, or key storage keys will not be derived consistently. The seed is expected to be set very early in boot, prior to the use of any key storage encryption keys. This feature is intended to be used for embedded applications such as in autos, where the seed may be provided by some other component of the system. In such systems, there is a default user that is automatically signed in without a PIN or other credentials. By binding the file encryption to a platform-provided seed, the default user's data gains additional protection against removal of the Android embedded device from the integrated system. Bug: 157501579 Test: Set seed at startup via init.rc. Seed changes fail as expected. Change-Id: I9b048ec5e045b84c45883724ace2356d4ef6244d --- KeyStorage.cpp | 58 ++++++++++++++++++++++++++++++++++++ KeyStorage.h | 5 ++++ VoldNativeService.cpp | 8 +++++ VoldNativeService.h | 2 ++ binder/android/os/IVold.aidl | 2 ++ 5 files changed, 75 insertions(+) diff --git a/KeyStorage.cpp b/KeyStorage.cpp index 8147827..89844aa 100644 --- a/KeyStorage.cpp +++ b/KeyStorage.cpp @@ -22,6 +22,8 @@ #include "Utils.h" #include +#include +#include #include #include @@ -82,6 +84,31 @@ static const char* kFn_secdiscardable = "secdiscardable"; static const char* kFn_stretching = "stretching"; static const char* kFn_version = "version"; +namespace { + +// Storage binding info for ensuring key encryption keys include a +// platform-provided seed in their derivation. +struct StorageBindingInfo { + enum class State { + UNINITIALIZED, + IN_USE, // key storage keys are bound to seed + NOT_USED, // key storage keys are NOT bound to seed + }; + + // Binding seed mixed into all key storage keys. + std::vector seed; + + // State tracker for the key storage key binding. + State state = State::UNINITIALIZED; + + std::mutex guard; +}; + +// Never freed as the dtor is non-trivial. +StorageBindingInfo& storage_binding_info = *new StorageBindingInfo; + +} // namespace + static bool checkSize(const std::string& kind, size_t actual, size_t expected) { if (actual != expected) { LOG(ERROR) << "Wrong number of bytes in " << kind << ", expected " << expected << " got " @@ -456,6 +483,20 @@ static bool generateAppId(const KeyAuthentication& auth, const std::string& stre std::string stretched; if (!stretchSecret(stretching, auth.secret, salt, &stretched)) return false; *appId = secdiscardable_hash + stretched; + + const std::lock_guard scope_lock(storage_binding_info.guard); + switch (storage_binding_info.state) { + case StorageBindingInfo::State::UNINITIALIZED: + storage_binding_info.state = StorageBindingInfo::State::NOT_USED; + break; + case StorageBindingInfo::State::IN_USE: + appId->append(storage_binding_info.seed.begin(), storage_binding_info.seed.end()); + break; + case StorageBindingInfo::State::NOT_USED: + // noop + break; + } + return true; } @@ -715,5 +756,22 @@ bool destroyKey(const std::string& dir) { return success; } +bool setKeyStorageBindingSeed(const std::vector& seed) { + const std::lock_guard scope_lock(storage_binding_info.guard); + switch (storage_binding_info.state) { + case StorageBindingInfo::State::UNINITIALIZED: + storage_binding_info.state = StorageBindingInfo::State::IN_USE; + storage_binding_info.seed = seed; + return true; + case StorageBindingInfo::State::IN_USE: + LOG(ERROR) << "key storage binding seed already set"; + return false; + case StorageBindingInfo::State::NOT_USED: + LOG(ERROR) << "key storage already in use without binding"; + return false; + } + return false; +} + } // namespace vold } // namespace android diff --git a/KeyStorage.h b/KeyStorage.h index 1eb26ae..a69dbf7 100644 --- a/KeyStorage.h +++ b/KeyStorage.h @@ -19,7 +19,9 @@ #include "KeyBuffer.h" +#include #include +#include namespace android { namespace vold { @@ -72,6 +74,9 @@ bool runSecdiscardSingle(const std::string& file); bool generateWrappedStorageKey(KeyBuffer* key); // Export the per-boot boot wrapped storage key using keymaster. bool exportWrappedStorageKey(const KeyBuffer& kmKey, KeyBuffer* key); + +// Set a seed to be mixed into all key storage encryption keys. +bool setKeyStorageBindingSeed(const std::vector& seed); } // namespace vold } // namespace android diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp index 9f4f7b0..49bf4da 100644 --- a/VoldNativeService.cpp +++ b/VoldNativeService.cpp @@ -33,6 +33,7 @@ #include "Checkpoint.h" #include "FsCrypt.h" #include "IdleMaint.h" +#include "KeyStorage.h" #include "Keymaster.h" #include "MetadataCrypt.h" #include "MoveStorage.h" @@ -699,6 +700,13 @@ binder::Status VoldNativeService::encryptFstab(const std::string& blkDevice, fscrypt_mount_metadata_encrypted(blkDevice, mountPoint, true, shouldFormat, fsType)); } +binder::Status VoldNativeService::setStorageBindingSeed(const std::vector& seed) { + ENFORCE_SYSTEM_OR_ROOT; + ACQUIRE_CRYPT_LOCK; + + return translateBool(setKeyStorageBindingSeed(seed)); +} + binder::Status VoldNativeService::createUserKey(int32_t userId, int32_t userSerial, bool ephemeral) { ENFORCE_SYSTEM_OR_ROOT; diff --git a/VoldNativeService.h b/VoldNativeService.h index 47991c2..123f127 100644 --- a/VoldNativeService.h +++ b/VoldNativeService.h @@ -116,6 +116,8 @@ class VoldNativeService : public BinderService, public os::Bn binder::Status encryptFstab(const std::string& blkDevice, const std::string& mountPoint, bool shouldFormat, const std::string& fsType); + binder::Status setStorageBindingSeed(const std::vector& seed); + binder::Status createUserKey(int32_t userId, int32_t userSerial, bool ephemeral); binder::Status destroyUserKey(int32_t userId); diff --git a/binder/android/os/IVold.aidl b/binder/android/os/IVold.aidl index 19ce9ba..24a3b38 100644 --- a/binder/android/os/IVold.aidl +++ b/binder/android/os/IVold.aidl @@ -91,6 +91,8 @@ interface IVold { void mountFstab(@utf8InCpp String blkDevice, @utf8InCpp String mountPoint); void encryptFstab(@utf8InCpp String blkDevice, @utf8InCpp String mountPoint, boolean shouldFormat, @utf8InCpp String fsType); + void setStorageBindingSeed(in byte[] seed); + void createUserKey(int userId, int userSerial, boolean ephemeral); void destroyUserKey(int userId);