vold: Support Storage keys for FBE
To prevent keys from being compromised if an attacker acquires read access to kernel memory, some inline encryption hardware supports protecting the keys in hardware without software having access to or the ability to set the plaintext keys. Instead, software only sees "wrapped keys", which may differ on every boot. 'wrappedkey_v0' fileencryption flag is used to denote that the device supports inline encryption hardware that supports this feature. On such devices keymaster is used to generate keys with STORAGE_KEY tag and export a per-boot ephemerally wrapped storage key to install it in the kernel. The wrapped key framework in the linux kernel ensures the wrapped key is provided to the inline encryption hardware where it is unwrapped and the file contents key is derived to encrypt contents without revealing the plaintext key in the clear. Test: FBE validation with Fscrypt v2 + inline crypt + wrapped key changes kernel. Bug: 147733587 Change-Id: I1f0de61b56534ec1df9baef075acb74bacd00758
This commit is contained in:
parent
68b9fb10ae
commit
3dfb094cb2
9 changed files with 131 additions and 22 deletions
40
FsCrypt.cpp
40
FsCrypt.cpp
|
@ -208,6 +208,19 @@ static bool get_data_file_encryption_options(EncryptionOptions* options) {
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool install_storage_key(const std::string& mountpoint, const EncryptionOptions& options,
|
||||
const KeyBuffer& key, EncryptionPolicy* policy) {
|
||||
KeyBuffer ephemeral_wrapped_key;
|
||||
if (options.use_hw_wrapped_key) {
|
||||
if (!exportWrappedStorageKey(key, &ephemeral_wrapped_key)) {
|
||||
LOG(ERROR) << "Failed to get ephemeral wrapped key";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return installKey(mountpoint, options, options.use_hw_wrapped_key ? ephemeral_wrapped_key : key,
|
||||
policy);
|
||||
}
|
||||
|
||||
// Retrieve the options to use for encryption policies on adoptable storage.
|
||||
static bool get_volume_file_encryption_options(EncryptionOptions* options) {
|
||||
auto contents_mode =
|
||||
|
@ -231,7 +244,7 @@ static bool read_and_install_user_ce_key(userid_t user_id,
|
|||
KeyBuffer ce_key;
|
||||
if (!read_and_fixate_user_ce_key(user_id, auth, &ce_key)) return false;
|
||||
EncryptionPolicy ce_policy;
|
||||
if (!installKey(DATA_MNT_POINT, options, ce_key, &ce_policy)) return false;
|
||||
if (!install_storage_key(DATA_MNT_POINT, options, ce_key, &ce_policy)) return false;
|
||||
s_ce_policies[user_id] = ce_policy;
|
||||
LOG(DEBUG) << "Installed ce key for user " << user_id;
|
||||
return true;
|
||||
|
@ -261,8 +274,8 @@ static bool create_and_install_user_keys(userid_t user_id, bool create_ephemeral
|
|||
EncryptionOptions options;
|
||||
if (!get_data_file_encryption_options(&options)) return false;
|
||||
KeyBuffer de_key, ce_key;
|
||||
if (!android::vold::randomKey(&de_key)) return false;
|
||||
if (!android::vold::randomKey(&ce_key)) return false;
|
||||
if (!generateStorageKey(options, &de_key)) return false;
|
||||
if (!generateStorageKey(options, &ce_key)) return false;
|
||||
if (create_ephemeral) {
|
||||
// If the key should be created as ephemeral, don't store it.
|
||||
s_ephemeral_users.insert(user_id);
|
||||
|
@ -282,10 +295,10 @@ static bool create_and_install_user_keys(userid_t user_id, bool create_ephemeral
|
|||
return false;
|
||||
}
|
||||
EncryptionPolicy de_policy;
|
||||
if (!installKey(DATA_MNT_POINT, options, de_key, &de_policy)) return false;
|
||||
if (!install_storage_key(DATA_MNT_POINT, options, de_key, &de_policy)) return false;
|
||||
s_de_policies[user_id] = de_policy;
|
||||
EncryptionPolicy ce_policy;
|
||||
if (!installKey(DATA_MNT_POINT, options, ce_key, &ce_policy)) return false;
|
||||
if (!install_storage_key(DATA_MNT_POINT, options, ce_key, &ce_policy)) return false;
|
||||
s_ce_policies[user_id] = ce_policy;
|
||||
LOG(DEBUG) << "Created keys for user " << user_id;
|
||||
return true;
|
||||
|
@ -338,7 +351,7 @@ static bool load_all_de_keys() {
|
|||
KeyBuffer de_key;
|
||||
if (!android::vold::retrieveKey(key_path, kEmptyAuthentication, &de_key)) return false;
|
||||
EncryptionPolicy de_policy;
|
||||
if (!installKey(DATA_MNT_POINT, options, de_key, &de_policy)) return false;
|
||||
if (!install_storage_key(DATA_MNT_POINT, options, de_key, &de_policy)) return false;
|
||||
s_de_policies[user_id] = de_policy;
|
||||
LOG(DEBUG) << "Installed de key for user " << user_id;
|
||||
}
|
||||
|
@ -360,12 +373,11 @@ bool fscrypt_initialize_systemwide_keys() {
|
|||
|
||||
KeyBuffer device_key;
|
||||
if (!android::vold::retrieveKey(true, kEmptyAuthentication, device_key_path, device_key_temp,
|
||||
&device_key))
|
||||
options, &device_key))
|
||||
return false;
|
||||
|
||||
EncryptionPolicy device_policy;
|
||||
if (!android::vold::installKey(DATA_MNT_POINT, options, device_key, &device_policy))
|
||||
return false;
|
||||
if (!install_storage_key(DATA_MNT_POINT, options, device_key, &device_policy)) return false;
|
||||
|
||||
std::string options_string;
|
||||
if (!OptionsToString(device_policy.options, &options_string)) {
|
||||
|
@ -380,10 +392,9 @@ bool fscrypt_initialize_systemwide_keys() {
|
|||
LOG(INFO) << "Wrote system DE key reference to:" << ref_filename;
|
||||
|
||||
KeyBuffer per_boot_key;
|
||||
if (!android::vold::randomKey(&per_boot_key)) return false;
|
||||
if (!generateStorageKey(options, &per_boot_key)) return false;
|
||||
EncryptionPolicy per_boot_policy;
|
||||
if (!android::vold::installKey(DATA_MNT_POINT, options, per_boot_key, &per_boot_policy))
|
||||
return false;
|
||||
if (!install_storage_key(DATA_MNT_POINT, options, per_boot_key, &per_boot_policy)) return false;
|
||||
std::string per_boot_ref_filename = std::string("/data") + fscrypt_key_per_boot_ref;
|
||||
if (!android::vold::writeStringToFile(per_boot_policy.key_raw_ref, per_boot_ref_filename))
|
||||
return false;
|
||||
|
@ -590,8 +601,9 @@ static bool read_or_create_volkey(const std::string& misc_path, const std::strin
|
|||
EncryptionOptions options;
|
||||
if (!get_volume_file_encryption_options(&options)) return false;
|
||||
KeyBuffer key;
|
||||
if (!android::vold::retrieveKey(true, auth, key_path, key_path + "_tmp", &key)) return false;
|
||||
if (!android::vold::installKey(BuildDataPath(volume_uuid), options, key, policy)) return false;
|
||||
if (!android::vold::retrieveKey(true, auth, key_path, key_path + "_tmp", options, &key))
|
||||
return false;
|
||||
if (!install_storage_key(BuildDataPath(volume_uuid), options, key, policy)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -135,6 +135,30 @@ static bool generateKeymasterKey(Keymaster& keymaster, const KeyAuthentication&
|
|||
keymaster.generateKey(paramBuilder, key);
|
||||
}
|
||||
|
||||
bool generateWrappedStorageKey(KeyBuffer* key) {
|
||||
Keymaster keymaster;
|
||||
if (!keymaster) return false;
|
||||
std::string key_temp;
|
||||
auto paramBuilder = km::AuthorizationSetBuilder().AesEncryptionKey(AES_KEY_BYTES * 8);
|
||||
paramBuilder.Authorization(km::TAG_ROLLBACK_RESISTANCE);
|
||||
paramBuilder.Authorization(km::TAG_STORAGE_KEY);
|
||||
if (!keymaster.generateKey(paramBuilder, &key_temp)) return false;
|
||||
*key = KeyBuffer(key_temp.size());
|
||||
memcpy(reinterpret_cast<void*>(key->data()), key_temp.c_str(), key->size());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool exportWrappedStorageKey(const KeyBuffer& kmKey, KeyBuffer* key) {
|
||||
Keymaster keymaster;
|
||||
if (!keymaster) return false;
|
||||
std::string key_temp;
|
||||
|
||||
if (!keymaster.exportKey(kmKey, &key_temp)) return false;
|
||||
*key = KeyBuffer(key_temp.size());
|
||||
memcpy(reinterpret_cast<void*>(key->data()), key_temp.c_str(), key->size());
|
||||
return true;
|
||||
}
|
||||
|
||||
static std::pair<km::AuthorizationSet, km::HardwareAuthToken> beginParams(
|
||||
const KeyAuthentication& auth, const std::string& appId) {
|
||||
auto paramBuilder = km::AuthorizationSetBuilder()
|
||||
|
|
|
@ -68,6 +68,11 @@ bool retrieveKey(const std::string& dir, const KeyAuthentication& auth, KeyBuffe
|
|||
bool destroyKey(const std::string& dir);
|
||||
|
||||
bool runSecdiscardSingle(const std::string& file);
|
||||
|
||||
// Generate wrapped storage key using keymaster. Uses STORAGE_KEY tag in keymaster.
|
||||
bool generateWrappedStorageKey(KeyBuffer* key);
|
||||
// Export the per-boot boot wrapped storage key using keymaster.
|
||||
bool exportWrappedStorageKey(const KeyBuffer& kmKey, KeyBuffer* key);
|
||||
} // namespace vold
|
||||
} // namespace android
|
||||
|
||||
|
|
15
KeyUtil.cpp
15
KeyUtil.cpp
|
@ -29,6 +29,7 @@
|
|||
#include <android-base/logging.h>
|
||||
#include <keyutils.h>
|
||||
|
||||
#include <fscrypt_uapi.h>
|
||||
#include "KeyStorage.h"
|
||||
#include "Utils.h"
|
||||
|
||||
|
@ -45,6 +46,13 @@ bool randomKey(KeyBuffer* key) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool generateStorageKey(const EncryptionOptions& options, KeyBuffer* key) {
|
||||
if (options.use_hw_wrapped_key) {
|
||||
return generateWrappedStorageKey(key);
|
||||
}
|
||||
return randomKey(key);
|
||||
}
|
||||
|
||||
// Return true if the kernel supports the ioctls to add/remove fscrypt keys
|
||||
// directly to/from the filesystem.
|
||||
bool isFsKeyringSupported(void) {
|
||||
|
@ -222,6 +230,7 @@ bool installKey(const std::string& mountpoint, const EncryptionOptions& options,
|
|||
return false;
|
||||
}
|
||||
|
||||
if (options.use_hw_wrapped_key) arg->flags |= FSCRYPT_ADD_KEY_FLAG_WRAPPED;
|
||||
// Provide the raw key.
|
||||
arg->raw_size = key.size();
|
||||
memcpy(arg->raw, key.data(), key.size());
|
||||
|
@ -307,8 +316,8 @@ bool evictKey(const std::string& mountpoint, const EncryptionPolicy& policy) {
|
|||
}
|
||||
|
||||
bool retrieveKey(bool create_if_absent, const KeyAuthentication& key_authentication,
|
||||
const std::string& key_path, const std::string& tmp_path, KeyBuffer* key,
|
||||
bool keepOld) {
|
||||
const std::string& key_path, const std::string& tmp_path,
|
||||
const EncryptionOptions& options, KeyBuffer* key, bool keepOld) {
|
||||
if (pathExists(key_path)) {
|
||||
LOG(DEBUG) << "Key exists, using: " << key_path;
|
||||
if (!retrieveKey(key_path, key_authentication, key, keepOld)) return false;
|
||||
|
@ -318,7 +327,7 @@ bool retrieveKey(bool create_if_absent, const KeyAuthentication& key_authenticat
|
|||
return false;
|
||||
}
|
||||
LOG(INFO) << "Creating new key in " << key_path;
|
||||
if (!randomKey(key)) return false;
|
||||
if (!generateStorageKey(options, key)) return false;
|
||||
if (!storeKeyAtomically(key_path, tmp_path, key_authentication, *key)) return false;
|
||||
}
|
||||
return true;
|
||||
|
|
|
@ -32,6 +32,8 @@ using namespace android::fscrypt;
|
|||
|
||||
bool randomKey(KeyBuffer* key);
|
||||
|
||||
bool generateStorageKey(const EncryptionOptions& options, KeyBuffer* key);
|
||||
|
||||
bool isFsKeyringSupported(void);
|
||||
|
||||
// Install a file-based encryption key to the kernel, for use by encrypted files
|
||||
|
@ -57,8 +59,8 @@ bool installKey(const std::string& mountpoint, const EncryptionOptions& options,
|
|||
bool evictKey(const std::string& mountpoint, const EncryptionPolicy& policy);
|
||||
|
||||
bool retrieveKey(bool create_if_absent, const KeyAuthentication& key_authentication,
|
||||
const std::string& key_path, const std::string& tmp_path, KeyBuffer* key,
|
||||
bool keepOld = true);
|
||||
const std::string& key_path, const std::string& tmp_path,
|
||||
const EncryptionOptions& options, KeyBuffer* key, bool keepOld = true);
|
||||
|
||||
} // namespace vold
|
||||
} // namespace android
|
||||
|
|
|
@ -138,6 +138,27 @@ bool Keymaster::generateKey(const km::AuthorizationSet& inParams, std::string* k
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Keymaster::exportKey(const KeyBuffer& kmKey, std::string* key) {
|
||||
auto kmKeyBlob = km::support::blob2hidlVec(std::string(kmKey.data(), kmKey.size()));
|
||||
km::ErrorCode km_error;
|
||||
auto hidlCb = [&](km::ErrorCode ret, const hidl_vec<uint8_t>& exportedKeyBlob) {
|
||||
km_error = ret;
|
||||
if (km_error != km::ErrorCode::OK) return;
|
||||
if (key)
|
||||
key->assign(reinterpret_cast<const char*>(&exportedKeyBlob[0]), exportedKeyBlob.size());
|
||||
};
|
||||
auto error = mDevice->exportKey(km::KeyFormat::RAW, kmKeyBlob, {}, {}, hidlCb);
|
||||
if (!error.isOk()) {
|
||||
LOG(ERROR) << "export_key failed: " << error.description();
|
||||
return false;
|
||||
}
|
||||
if (km_error != km::ErrorCode::OK) {
|
||||
LOG(ERROR) << "export_key failed, code " << int32_t(km_error);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Keymaster::deleteKey(const std::string& key) {
|
||||
auto keyBlob = km::support::blob2hidlVec(key);
|
||||
auto error = mDevice->deleteKey(keyBlob);
|
||||
|
|
|
@ -114,6 +114,8 @@ class Keymaster {
|
|||
explicit operator bool() { return mDevice.get() != nullptr; }
|
||||
// Generate a key in the keymaster from the given params.
|
||||
bool generateKey(const km::AuthorizationSet& inParams, std::string* key);
|
||||
// Exports a keymaster key with STORAGE_KEY tag wrapped with a per-boot ephemeral key
|
||||
bool exportKey(const KeyBuffer& kmKey, std::string* key);
|
||||
// If the keymaster supports it, permanently delete a key.
|
||||
bool deleteKey(const std::string& key);
|
||||
// Replace stored key blob in response to KM_ERROR_KEY_REQUIRES_UPGRADE.
|
||||
|
|
|
@ -113,6 +113,23 @@ static void commit_key(const std::string& dir) {
|
|||
LOG(INFO) << "Old Key deleted: " << dir;
|
||||
}
|
||||
|
||||
static bool retrieveMetadataKey(bool create_if_absent, const std::string& key_path,
|
||||
const std::string& tmp_path, KeyBuffer* key, bool keepOld) {
|
||||
if (pathExists(key_path)) {
|
||||
LOG(DEBUG) << "Key exists, using: " << key_path;
|
||||
if (!retrieveKey(key_path, kEmptyAuthentication, key, keepOld)) return false;
|
||||
} else {
|
||||
if (!create_if_absent) {
|
||||
LOG(ERROR) << "No key found in " << key_path;
|
||||
return false;
|
||||
}
|
||||
LOG(INFO) << "Creating new key in " << key_path;
|
||||
if (!randomKey(key)) return false;
|
||||
if (!storeKeyAtomically(key_path, tmp_path, kEmptyAuthentication, *key)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool read_key(const FstabEntry& data_rec, bool create_if_absent, KeyBuffer* key) {
|
||||
if (data_rec.metadata_key_dir.empty()) {
|
||||
LOG(ERROR) << "Failed to get metadata_key_dir";
|
||||
|
@ -143,9 +160,7 @@ static bool read_key(const FstabEntry& data_rec, bool create_if_absent, KeyBuffe
|
|||
unlink(newKeyPath.c_str());
|
||||
}
|
||||
bool needs_cp = cp_needsCheckpoint();
|
||||
if (!android::vold::retrieveKey(create_if_absent, kEmptyAuthentication, dir, temp, key,
|
||||
needs_cp))
|
||||
return false;
|
||||
if (!retrieveMetadataKey(create_if_absent, dir, temp, key, needs_cp)) return false;
|
||||
if (needs_cp && pathExists(newKeyPath)) std::thread(commit_key, dir).detach();
|
||||
return true;
|
||||
}
|
||||
|
|
19
fscrypt_uapi.h
Normal file
19
fscrypt_uapi.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
#ifndef _UAPI_LINUX_FSCRYPT_VOLD_H
|
||||
#define _UAPI_LINUX_FSCRYPT_VOLD_H
|
||||
|
||||
#include <linux/fscrypt.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#define FSCRYPT_ADD_KEY_FLAG_WRAPPED 0x01
|
||||
|
||||
struct sys_fscrypt_add_key_arg {
|
||||
struct fscrypt_key_specifier key_spec;
|
||||
__u32 raw_size;
|
||||
__u32 __reserved[8];
|
||||
__u32 flags;
|
||||
__u8 raw[];
|
||||
};
|
||||
|
||||
#define fscrypt_add_key_arg sys_fscrypt_add_key_arg
|
||||
|
||||
#endif //_UAPI_LINUX_FSCRYPT_VOLD_H
|
Loading…
Reference in a new issue