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:
Barani Muthukumaran 2020-02-03 13:06:45 -08:00 committed by Paul Crowley
parent 68b9fb10ae
commit 3dfb094cb2
9 changed files with 131 additions and 22 deletions

View file

@ -208,6 +208,19 @@ static bool get_data_file_encryption_options(EncryptionOptions* options) {
return true; 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. // Retrieve the options to use for encryption policies on adoptable storage.
static bool get_volume_file_encryption_options(EncryptionOptions* options) { static bool get_volume_file_encryption_options(EncryptionOptions* options) {
auto contents_mode = auto contents_mode =
@ -231,7 +244,7 @@ static bool read_and_install_user_ce_key(userid_t user_id,
KeyBuffer ce_key; KeyBuffer ce_key;
if (!read_and_fixate_user_ce_key(user_id, auth, &ce_key)) return false; if (!read_and_fixate_user_ce_key(user_id, auth, &ce_key)) return false;
EncryptionPolicy ce_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; s_ce_policies[user_id] = ce_policy;
LOG(DEBUG) << "Installed ce key for user " << user_id; LOG(DEBUG) << "Installed ce key for user " << user_id;
return true; return true;
@ -261,8 +274,8 @@ static bool create_and_install_user_keys(userid_t user_id, bool create_ephemeral
EncryptionOptions options; EncryptionOptions options;
if (!get_data_file_encryption_options(&options)) return false; if (!get_data_file_encryption_options(&options)) return false;
KeyBuffer de_key, ce_key; KeyBuffer de_key, ce_key;
if (!android::vold::randomKey(&de_key)) return false; if (!generateStorageKey(options, &de_key)) return false;
if (!android::vold::randomKey(&ce_key)) return false; if (!generateStorageKey(options, &ce_key)) return false;
if (create_ephemeral) { if (create_ephemeral) {
// If the key should be created as ephemeral, don't store it. // If the key should be created as ephemeral, don't store it.
s_ephemeral_users.insert(user_id); 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; return false;
} }
EncryptionPolicy de_policy; 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; s_de_policies[user_id] = de_policy;
EncryptionPolicy ce_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; s_ce_policies[user_id] = ce_policy;
LOG(DEBUG) << "Created keys for user " << user_id; LOG(DEBUG) << "Created keys for user " << user_id;
return true; return true;
@ -338,7 +351,7 @@ static bool load_all_de_keys() {
KeyBuffer de_key; KeyBuffer de_key;
if (!android::vold::retrieveKey(key_path, kEmptyAuthentication, &de_key)) return false; if (!android::vold::retrieveKey(key_path, kEmptyAuthentication, &de_key)) return false;
EncryptionPolicy de_policy; 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; s_de_policies[user_id] = de_policy;
LOG(DEBUG) << "Installed de key for user " << user_id; LOG(DEBUG) << "Installed de key for user " << user_id;
} }
@ -360,12 +373,11 @@ bool fscrypt_initialize_systemwide_keys() {
KeyBuffer device_key; KeyBuffer device_key;
if (!android::vold::retrieveKey(true, kEmptyAuthentication, device_key_path, device_key_temp, if (!android::vold::retrieveKey(true, kEmptyAuthentication, device_key_path, device_key_temp,
&device_key)) options, &device_key))
return false; return false;
EncryptionPolicy device_policy; EncryptionPolicy device_policy;
if (!android::vold::installKey(DATA_MNT_POINT, options, device_key, &device_policy)) if (!install_storage_key(DATA_MNT_POINT, options, device_key, &device_policy)) return false;
return false;
std::string options_string; std::string options_string;
if (!OptionsToString(device_policy.options, &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; LOG(INFO) << "Wrote system DE key reference to:" << ref_filename;
KeyBuffer per_boot_key; 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; EncryptionPolicy per_boot_policy;
if (!android::vold::installKey(DATA_MNT_POINT, options, per_boot_key, &per_boot_policy)) if (!install_storage_key(DATA_MNT_POINT, options, per_boot_key, &per_boot_policy)) return false;
return false;
std::string per_boot_ref_filename = std::string("/data") + fscrypt_key_per_boot_ref; 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)) if (!android::vold::writeStringToFile(per_boot_policy.key_raw_ref, per_boot_ref_filename))
return false; return false;
@ -590,8 +601,9 @@ static bool read_or_create_volkey(const std::string& misc_path, const std::strin
EncryptionOptions options; EncryptionOptions options;
if (!get_volume_file_encryption_options(&options)) return false; if (!get_volume_file_encryption_options(&options)) return false;
KeyBuffer key; KeyBuffer key;
if (!android::vold::retrieveKey(true, auth, key_path, key_path + "_tmp", &key)) return false; if (!android::vold::retrieveKey(true, auth, key_path, key_path + "_tmp", options, &key))
if (!android::vold::installKey(BuildDataPath(volume_uuid), options, key, policy)) return false; return false;
if (!install_storage_key(BuildDataPath(volume_uuid), options, key, policy)) return false;
return true; return true;
} }

View file

@ -135,6 +135,30 @@ static bool generateKeymasterKey(Keymaster& keymaster, const KeyAuthentication&
keymaster.generateKey(paramBuilder, key); 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( static std::pair<km::AuthorizationSet, km::HardwareAuthToken> beginParams(
const KeyAuthentication& auth, const std::string& appId) { const KeyAuthentication& auth, const std::string& appId) {
auto paramBuilder = km::AuthorizationSetBuilder() auto paramBuilder = km::AuthorizationSetBuilder()

View file

@ -68,6 +68,11 @@ bool retrieveKey(const std::string& dir, const KeyAuthentication& auth, KeyBuffe
bool destroyKey(const std::string& dir); bool destroyKey(const std::string& dir);
bool runSecdiscardSingle(const std::string& file); 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 vold
} // namespace android } // namespace android

View file

@ -29,6 +29,7 @@
#include <android-base/logging.h> #include <android-base/logging.h>
#include <keyutils.h> #include <keyutils.h>
#include <fscrypt_uapi.h>
#include "KeyStorage.h" #include "KeyStorage.h"
#include "Utils.h" #include "Utils.h"
@ -45,6 +46,13 @@ bool randomKey(KeyBuffer* key) {
return true; 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 // Return true if the kernel supports the ioctls to add/remove fscrypt keys
// directly to/from the filesystem. // directly to/from the filesystem.
bool isFsKeyringSupported(void) { bool isFsKeyringSupported(void) {
@ -222,6 +230,7 @@ bool installKey(const std::string& mountpoint, const EncryptionOptions& options,
return false; return false;
} }
if (options.use_hw_wrapped_key) arg->flags |= FSCRYPT_ADD_KEY_FLAG_WRAPPED;
// Provide the raw key. // Provide the raw key.
arg->raw_size = key.size(); arg->raw_size = key.size();
memcpy(arg->raw, key.data(), 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, bool retrieveKey(bool create_if_absent, const KeyAuthentication& key_authentication,
const std::string& key_path, const std::string& tmp_path, KeyBuffer* key, const std::string& key_path, const std::string& tmp_path,
bool keepOld) { const EncryptionOptions& options, KeyBuffer* key, bool keepOld) {
if (pathExists(key_path)) { if (pathExists(key_path)) {
LOG(DEBUG) << "Key exists, using: " << key_path; LOG(DEBUG) << "Key exists, using: " << key_path;
if (!retrieveKey(key_path, key_authentication, key, keepOld)) return false; 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; return false;
} }
LOG(INFO) << "Creating new key in " << key_path; 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; if (!storeKeyAtomically(key_path, tmp_path, key_authentication, *key)) return false;
} }
return true; return true;

View file

@ -32,6 +32,8 @@ using namespace android::fscrypt;
bool randomKey(KeyBuffer* key); bool randomKey(KeyBuffer* key);
bool generateStorageKey(const EncryptionOptions& options, KeyBuffer* key);
bool isFsKeyringSupported(void); bool isFsKeyringSupported(void);
// Install a file-based encryption key to the kernel, for use by encrypted files // 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 evictKey(const std::string& mountpoint, const EncryptionPolicy& policy);
bool retrieveKey(bool create_if_absent, const KeyAuthentication& key_authentication, bool retrieveKey(bool create_if_absent, const KeyAuthentication& key_authentication,
const std::string& key_path, const std::string& tmp_path, KeyBuffer* key, const std::string& key_path, const std::string& tmp_path,
bool keepOld = true); const EncryptionOptions& options, KeyBuffer* key, bool keepOld = true);
} // namespace vold } // namespace vold
} // namespace android } // namespace android

View file

@ -138,6 +138,27 @@ bool Keymaster::generateKey(const km::AuthorizationSet& inParams, std::string* k
return true; 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) { bool Keymaster::deleteKey(const std::string& key) {
auto keyBlob = km::support::blob2hidlVec(key); auto keyBlob = km::support::blob2hidlVec(key);
auto error = mDevice->deleteKey(keyBlob); auto error = mDevice->deleteKey(keyBlob);

View file

@ -114,6 +114,8 @@ class Keymaster {
explicit operator bool() { return mDevice.get() != nullptr; } explicit operator bool() { return mDevice.get() != nullptr; }
// Generate a key in the keymaster from the given params. // Generate a key in the keymaster from the given params.
bool generateKey(const km::AuthorizationSet& inParams, std::string* key); 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. // If the keymaster supports it, permanently delete a key.
bool deleteKey(const std::string& key); bool deleteKey(const std::string& key);
// Replace stored key blob in response to KM_ERROR_KEY_REQUIRES_UPGRADE. // Replace stored key blob in response to KM_ERROR_KEY_REQUIRES_UPGRADE.

View file

@ -113,6 +113,23 @@ static void commit_key(const std::string& dir) {
LOG(INFO) << "Old Key deleted: " << 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) { static bool read_key(const FstabEntry& data_rec, bool create_if_absent, KeyBuffer* key) {
if (data_rec.metadata_key_dir.empty()) { if (data_rec.metadata_key_dir.empty()) {
LOG(ERROR) << "Failed to get metadata_key_dir"; 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()); unlink(newKeyPath.c_str());
} }
bool needs_cp = cp_needsCheckpoint(); bool needs_cp = cp_needsCheckpoint();
if (!android::vold::retrieveKey(create_if_absent, kEmptyAuthentication, dir, temp, key, if (!retrieveMetadataKey(create_if_absent, dir, temp, key, needs_cp)) return false;
needs_cp))
return false;
if (needs_cp && pathExists(newKeyPath)) std::thread(commit_key, dir).detach(); if (needs_cp && pathExists(newKeyPath)) std::thread(commit_key, dir).detach();
return true; return true;
} }

19
fscrypt_uapi.h Normal file
View 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