Merge changes from topics "metadata_wrapped_key_aosp", "volume_metadata" am: 36fd1ebfae am: 6891eb7e2d am: c14f46d114

Change-Id: I89f51bfaeb61c235aeccbe8a5a5a447ab14c46cb
This commit is contained in:
Automerger Merge Worker 2020-02-19 22:19:26 +00:00
commit 7489ab6961
11 changed files with 256 additions and 66 deletions

View file

@ -145,6 +145,7 @@ cc_library_static {
"model/PublicVolume.cpp", "model/PublicVolume.cpp",
"model/StubVolume.cpp", "model/StubVolume.cpp",
"model/VolumeBase.cpp", "model/VolumeBase.cpp",
"model/VolumeEncryption.cpp",
], ],
product_variables: { product_variables: {
arc: { arc: {

View file

@ -65,7 +65,7 @@ using android::vold::BuildDataPath;
using android::vold::IsFilesystemSupported; using android::vold::IsFilesystemSupported;
using android::vold::kEmptyAuthentication; using android::vold::kEmptyAuthentication;
using android::vold::KeyBuffer; using android::vold::KeyBuffer;
using android::vold::makeGen; using android::vold::KeyGeneration;
using android::vold::retrieveKey; using android::vold::retrieveKey;
using android::vold::retrieveOrGenerateKey; using android::vold::retrieveOrGenerateKey;
using android::vold::SetQuotaInherit; using android::vold::SetQuotaInherit;
@ -97,6 +97,11 @@ std::map<userid_t, EncryptionPolicy> s_ce_policies;
} // namespace } // namespace
// Returns KeyGeneration suitable for key as described in EncryptionOptions
static KeyGeneration makeGen(const EncryptionOptions& options) {
return KeyGeneration{FSCRYPT_MAX_KEY_SIZE, true, options.use_hw_wrapped_key};
}
static bool fscrypt_is_emulated() { static bool fscrypt_is_emulated() {
return property_get_bool("persist.sys.emulate_fbe", false); return property_get_bool("persist.sys.emulate_fbe", false);
} }

View file

@ -36,14 +36,6 @@
namespace android { namespace android {
namespace vold { namespace vold {
const KeyGeneration makeGen(const EncryptionOptions& options) {
return KeyGeneration{FSCRYPT_MAX_KEY_SIZE, true, options.use_hw_wrapped_key};
}
const KeyGeneration makeGen(const CryptoType& crypto) {
return KeyGeneration{crypto.get_keysize(), true, false};
}
const KeyGeneration neverGen() { const KeyGeneration neverGen() {
return KeyGeneration{0, false, false}; return KeyGeneration{0, false, false};
} }

View file

@ -17,7 +17,6 @@
#ifndef ANDROID_VOLD_KEYUTIL_H #ifndef ANDROID_VOLD_KEYUTIL_H
#define ANDROID_VOLD_KEYUTIL_H #define ANDROID_VOLD_KEYUTIL_H
#include "CryptoType.h"
#include "KeyBuffer.h" #include "KeyBuffer.h"
#include "KeyStorage.h" #include "KeyStorage.h"
@ -41,12 +40,6 @@ struct KeyGeneration {
// Generate a key as specified in KeyGeneration // Generate a key as specified in KeyGeneration
bool generateStorageKey(const KeyGeneration& gen, KeyBuffer* key); bool generateStorageKey(const KeyGeneration& gen, KeyBuffer* key);
// Returns KeyGeneration suitable for key as described in EncryptionOptions
const KeyGeneration makeGen(const EncryptionOptions& options);
// Returns KeyGeneration suitable for key as described in CryptoType
const KeyGeneration makeGen(const CryptoType& crypto);
// Returns a key with allow_gen false so generateStorageKey returns false; // Returns a key with allow_gen false so generateStorageKey returns false;
// this is used to indicate to retrieveOrGenerateKey that a key should not // this is used to indicate to retrieveOrGenerateKey that a key should not
// be generated. // be generated.

View file

@ -30,6 +30,7 @@
#include <android-base/file.h> #include <android-base/file.h>
#include <android-base/logging.h> #include <android-base/logging.h>
#include <android-base/properties.h> #include <android-base/properties.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h> #include <android-base/unique_fd.h>
#include <cutils/fs.h> #include <cutils/fs.h>
#include <fs_mgr.h> #include <fs_mgr.h>
@ -54,11 +55,20 @@ using android::fs_mgr::GetEntryForMountPoint;
using android::vold::KeyBuffer; using android::vold::KeyBuffer;
using namespace android::dm; using namespace android::dm;
// Parsed from metadata options
struct CryptoOptions {
struct CryptoType cipher = invalid_crypto_type;
bool is_legacy = false;
bool set_dun = true; // Non-legacy driver always sets DUN
bool use_hw_wrapped_key = false;
};
static const std::string kDmNameUserdata = "userdata"; static const std::string kDmNameUserdata = "userdata";
static const char* kFn_keymaster_key_blob = "keymaster_key_blob"; static const char* kFn_keymaster_key_blob = "keymaster_key_blob";
static const char* kFn_keymaster_key_blob_upgraded = "keymaster_key_blob_upgraded"; static const char* kFn_keymaster_key_blob_upgraded = "keymaster_key_blob_upgraded";
// The first entry in this table is the default crypto type.
constexpr CryptoType supported_crypto_types[] = {aes_256_xts, adiantum}; constexpr CryptoType supported_crypto_types[] = {aes_256_xts, adiantum};
static_assert(validateSupportedCryptoTypes(64, supported_crypto_types, static_assert(validateSupportedCryptoTypes(64, supported_crypto_types,
@ -68,12 +78,14 @@ static_assert(validateSupportedCryptoTypes(64, supported_crypto_types,
constexpr CryptoType legacy_aes_256_xts = constexpr CryptoType legacy_aes_256_xts =
CryptoType().set_config_name("aes-256-xts").set_kernel_name("AES-256-XTS").set_keysize(64); CryptoType().set_config_name("aes-256-xts").set_kernel_name("AES-256-XTS").set_keysize(64);
constexpr CryptoType legacy_crypto_types[] = {legacy_aes_256_xts}; static_assert(isValidCryptoType(64, legacy_aes_256_xts),
static_assert(validateSupportedCryptoTypes(64, legacy_crypto_types,
array_length(legacy_crypto_types)),
"We have a CryptoType which was incompletely constructed."); "We have a CryptoType which was incompletely constructed.");
// Returns KeyGeneration suitable for key as described in CryptoOptions
const KeyGeneration makeGen(const CryptoOptions& options) {
return KeyGeneration{options.cipher.get_keysize(), true, options.use_hw_wrapped_key};
}
static bool mount_via_fs_mgr(const char* mount_point, const char* blk_device) { static bool mount_via_fs_mgr(const char* mount_point, const char* blk_device) {
// We're about to mount data not verified by verified boot. Tell Keymaster that early boot has // We're about to mount data not verified by verified boot. Tell Keymaster that early boot has
// ended. // ended.
@ -173,21 +185,38 @@ static bool get_number_of_sectors(const std::string& real_blkdev, uint64_t* nr_s
} }
static bool create_crypto_blk_dev(const std::string& dm_name, const std::string& blk_device, static bool create_crypto_blk_dev(const std::string& dm_name, const std::string& blk_device,
bool is_legacy, const std::string& cipher, bool set_dun, const KeyBuffer& key, const CryptoOptions& options,
const KeyBuffer& key, std::string* crypto_blkdev) { std::string* crypto_blkdev, uint64_t* nr_sec) {
uint64_t nr_sec; if (!get_number_of_sectors(blk_device, nr_sec)) return false;
if (!get_number_of_sectors(blk_device, &nr_sec)) return false; // TODO(paulcrowley): don't hardcode that DmTargetDefaultKey uses 4096-byte
// sectors
*nr_sec &= ~7;
KeyBuffer module_key;
if (options.use_hw_wrapped_key) {
if (!exportWrappedStorageKey(key, &module_key)) {
LOG(ERROR) << "Failed to get ephemeral wrapped key";
return false;
}
} else {
module_key = key;
}
KeyBuffer hex_key_buffer; KeyBuffer hex_key_buffer;
if (android::vold::StrToHex(key, hex_key_buffer) != android::OK) { if (android::vold::StrToHex(module_key, hex_key_buffer) != android::OK) {
LOG(ERROR) << "Failed to turn key to hex"; LOG(ERROR) << "Failed to turn key to hex";
return false; return false;
} }
std::string hex_key(hex_key_buffer.data(), hex_key_buffer.size()); std::string hex_key(hex_key_buffer.data(), hex_key_buffer.size());
auto target = std::make_unique<DmTargetDefaultKey>(0, *nr_sec, options.cipher.get_kernel_name(),
hex_key, blk_device, 0);
if (options.is_legacy) target->SetIsLegacy();
if (options.set_dun) target->SetSetDun();
if (options.use_hw_wrapped_key) target->SetWrappedKeyV0();
DmTable table; DmTable table;
table.Emplace<DmTargetDefaultKey>(0, nr_sec, cipher, hex_key, blk_device, 0, is_legacy, table.AddTarget(std::move(target));
set_dun);
auto& dm = DeviceMapper::Instance(); auto& dm = DeviceMapper::Instance();
for (int i = 0;; i++) { for (int i = 0;; i++) {
@ -209,25 +238,38 @@ static bool create_crypto_blk_dev(const std::string& dm_name, const std::string&
return true; return true;
} }
static const CryptoType& lookup_cipher_in_table(const CryptoType table[], int table_len, static const CryptoType& lookup_cipher(const std::string& cipher_name) {
const std::string& cipher_name) { if (cipher_name.empty()) return supported_crypto_types[0];
if (cipher_name.empty()) return table[0]; for (size_t i = 0; i < array_length(supported_crypto_types); i++) {
for (int i = 0; i < table_len; i++) { if (cipher_name == supported_crypto_types[i].get_config_name()) {
if (cipher_name == table[i].get_config_name()) { return supported_crypto_types[i];
return table[i];
} }
} }
return invalid_crypto_type; return invalid_crypto_type;
} }
static const CryptoType& lookup_cipher(const std::string& cipher_name, bool is_legacy) { static bool parse_options(const std::string& options_string, CryptoOptions* options) {
if (is_legacy) { auto parts = android::base::Split(options_string, ":");
return lookup_cipher_in_table(legacy_crypto_types, array_length(legacy_crypto_types), if (parts.size() < 1 || parts.size() > 2) {
cipher_name); LOG(ERROR) << "Invalid metadata encryption option: " << options_string;
} else { return false;
return lookup_cipher_in_table(supported_crypto_types, array_length(supported_crypto_types),
cipher_name);
} }
std::string cipher_name = parts[0];
options->cipher = lookup_cipher(cipher_name);
if (options->cipher.get_kernel_name() == nullptr) {
LOG(ERROR) << "No metadata cipher named " << cipher_name << " found";
return false;
}
if (parts.size() == 2) {
if (parts[1] == "wrappedkey_v0") {
options->use_hw_wrapped_key = true;
} else {
LOG(ERROR) << "Invalid metadata encryption flag: " << parts[1];
return false;
}
}
return true;
} }
bool fscrypt_mount_metadata_encrypted(const std::string& blk_device, const std::string& mount_point, bool fscrypt_mount_metadata_encrypted(const std::string& blk_device, const std::string& mount_point,
@ -253,33 +295,36 @@ bool fscrypt_mount_metadata_encrypted(const std::string& blk_device, const std::
bool is_legacy; bool is_legacy;
if (!DmTargetDefaultKey::IsLegacy(&is_legacy)) return false; if (!DmTargetDefaultKey::IsLegacy(&is_legacy)) return false;
// Non-legacy driver always sets DUN CryptoOptions options;
bool set_dun = !is_legacy || android::base::GetBoolProperty("ro.crypto.set_dun", false); if (is_legacy) {
if (!set_dun && data_rec->fs_mgr_flags.checkpoint_blk) { if (!data_rec->metadata_encryption.empty()) {
LOG(ERROR) << "Block checkpoints and metadata encryption require ro.crypto.set_dun option"; LOG(ERROR) << "metadata_encryption options cannot be set in legacy mode";
return false; return false;
} }
options.cipher = legacy_aes_256_xts;
auto cipher = lookup_cipher(data_rec->metadata_cipher, is_legacy); options.is_legacy = true;
if (cipher.get_kernel_name() == nullptr) { options.set_dun = android::base::GetBoolProperty("ro.crypto.set_dun", false);
LOG(ERROR) << "No metadata cipher named " << data_rec->metadata_cipher if (!options.set_dun && data_rec->fs_mgr_flags.checkpoint_blk) {
<< " found, is_legacy=" << is_legacy; LOG(ERROR)
<< "Block checkpoints and metadata encryption require ro.crypto.set_dun option";
return false; return false;
} }
} else {
if (!parse_options(data_rec->metadata_encryption, &options)) return false;
}
auto gen = needs_encrypt ? makeGen(cipher) : neverGen(); auto gen = needs_encrypt ? makeGen(options) : neverGen();
KeyBuffer key; KeyBuffer key;
if (!read_key(data_rec->metadata_key_dir, gen, &key)) return false; if (!read_key(data_rec->metadata_key_dir, gen, &key)) return false;
std::string crypto_blkdev; std::string crypto_blkdev;
if (!create_crypto_blk_dev(kDmNameUserdata, data_rec->blk_device, is_legacy, uint64_t nr_sec;
cipher.get_kernel_name(), set_dun, key, &crypto_blkdev)) if (!create_crypto_blk_dev(kDmNameUserdata, data_rec->blk_device, key, options, &crypto_blkdev,
&nr_sec))
return false; return false;
// FIXME handle the corrupt case // FIXME handle the corrupt case
if (needs_encrypt) { if (needs_encrypt) {
uint64_t nr_sec;
if (!get_number_of_sectors(data_rec->blk_device, &nr_sec)) return false;
LOG(INFO) << "Beginning inplace encryption, nr_sec: " << nr_sec; LOG(INFO) << "Beginning inplace encryption, nr_sec: " << nr_sec;
off64_t size_already_done = 0; off64_t size_already_done = 0;
auto rc = cryptfs_enable_inplace(crypto_blkdev.data(), blk_device.data(), nr_sec, auto rc = cryptfs_enable_inplace(crypto_blkdev.data(), blk_device.data(), nr_sec,
@ -300,5 +345,27 @@ bool fscrypt_mount_metadata_encrypted(const std::string& blk_device, const std::
return true; return true;
} }
static bool get_volume_options(CryptoOptions* options) {
return parse_options(android::base::GetProperty("ro.crypto.volume.metadata.encryption", ""),
options);
}
bool defaultkey_volume_keygen(KeyGeneration* gen) {
CryptoOptions options;
if (!get_volume_options(&options)) return false;
*gen = makeGen(options);
return true;
}
bool defaultkey_setup_ext_volume(const std::string& label, const std::string& blk_device,
const KeyBuffer& key, std::string* out_crypto_blkdev) {
LOG(DEBUG) << "defaultkey_setup_ext_volume: " << label << " " << blk_device;
CryptoOptions options;
if (!get_volume_options(&options)) return false;
uint64_t nr_sec;
return create_crypto_blk_dev(label, blk_device, key, options, out_crypto_blkdev, &nr_sec);
}
} // namespace vold } // namespace vold
} // namespace android } // namespace android

View file

@ -19,12 +19,21 @@
#include <string> #include <string>
#include "KeyBuffer.h"
#include "KeyUtil.h"
namespace android { namespace android {
namespace vold { namespace vold {
bool fscrypt_mount_metadata_encrypted(const std::string& block_device, bool fscrypt_mount_metadata_encrypted(const std::string& block_device,
const std::string& mount_point, bool needs_encrypt); const std::string& mount_point, bool needs_encrypt);
bool defaultkey_volume_keygen(KeyGeneration* gen);
bool defaultkey_setup_ext_volume(const std::string& label, const std::string& blk_device,
const android::vold::KeyBuffer& key,
std::string* out_crypto_blkdev);
} // namespace vold } // namespace vold
} // namespace android } // namespace android
#endif #endif

View file

@ -325,7 +325,7 @@ static const CryptoType& get_crypto_type() {
} }
const KeyGeneration cryptfs_get_keygen() { const KeyGeneration cryptfs_get_keygen() {
return makeGen(get_crypto_type()); return KeyGeneration{get_crypto_type().get_keysize(), true, false};
} }
/* Should we use keymaster? */ /* Should we use keymaster? */

View file

@ -16,11 +16,11 @@
#include "Disk.h" #include "Disk.h"
#include "FsCrypt.h" #include "FsCrypt.h"
#include "KeyUtil.h"
#include "PrivateVolume.h" #include "PrivateVolume.h"
#include "PublicVolume.h" #include "PublicVolume.h"
#include "Utils.h" #include "Utils.h"
#include "VolumeBase.h" #include "VolumeBase.h"
#include "VolumeEncryption.h"
#include "VolumeManager.h" #include "VolumeManager.h"
#include <android-base/file.h> #include <android-base/file.h>
@ -31,8 +31,6 @@
#include <android-base/strings.h> #include <android-base/strings.h>
#include <fscrypt/fscrypt.h> #include <fscrypt/fscrypt.h>
#include "cryptfs.h"
#include <fcntl.h> #include <fcntl.h>
#include <inttypes.h> #include <inttypes.h>
#include <stdio.h> #include <stdio.h>
@ -537,7 +535,7 @@ status_t Disk::partitionMixed(int8_t ratio) {
} }
KeyBuffer key; KeyBuffer key;
if (!generateStorageKey(cryptfs_get_keygen(), &key)) { if (!generate_volume_key(&key)) {
LOG(ERROR) << "Failed to generate key"; LOG(ERROR) << "Failed to generate key";
return -EIO; return -EIO;
} }

View file

@ -17,8 +17,8 @@
#include "PrivateVolume.h" #include "PrivateVolume.h"
#include "EmulatedVolume.h" #include "EmulatedVolume.h"
#include "Utils.h" #include "Utils.h"
#include "VolumeEncryption.h"
#include "VolumeManager.h" #include "VolumeManager.h"
#include "cryptfs.h"
#include "fs/Ext4.h" #include "fs/Ext4.h"
#include "fs/F2fs.h" #include "fs/F2fs.h"
@ -87,9 +87,8 @@ status_t PrivateVolume::doCreate() {
// TODO: figure out better SELinux labels for private volumes // TODO: figure out better SELinux labels for private volumes
int res = cryptfs_setup_ext_volume(getId().c_str(), mRawDevPath.c_str(), mKeyRaw, &mDmDevPath); if (!setup_ext_volume(getId(), mRawDevPath, mKeyRaw, &mDmDevPath)) {
if (res != 0) { LOG(ERROR) << getId() << " failed to setup metadata encryption";
PLOG(ERROR) << getId() << " failed to setup cryptfs";
return -EIO; return -EIO;
} }

View file

@ -0,0 +1,94 @@
/*
* Copyright (C) 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.
*/
#include "VolumeEncryption.h"
#include <string>
#include <android-base/logging.h>
#include <android-base/properties.h>
#include "KeyBuffer.h"
#include "KeyUtil.h"
#include "MetadataCrypt.h"
#include "cryptfs.h"
namespace android {
namespace vold {
enum class VolumeMethod { kFailed, kCrypt, kDefaultKey };
static VolumeMethod lookup_volume_method() {
constexpr uint64_t pre_gki_level = 29;
auto first_api_level =
android::base::GetUintProperty<uint64_t>("ro.product.first_api_level", 0);
auto method = android::base::GetProperty("ro.crypto.volume.metadata.method", "default");
if (method == "default") {
return first_api_level > pre_gki_level ? VolumeMethod::kDefaultKey : VolumeMethod::kCrypt;
} else if (method == "dm-default-key") {
return VolumeMethod::kDefaultKey;
} else if (method == "dm-crypt") {
if (first_api_level > pre_gki_level) {
LOG(ERROR) << "volume encryption method dm-crypt cannot be used, "
"ro.product.first_api_level = "
<< first_api_level;
return VolumeMethod::kFailed;
}
return VolumeMethod::kCrypt;
} else {
LOG(ERROR) << "Unknown volume encryption method: " << method;
return VolumeMethod::kFailed;
}
}
static VolumeMethod volume_method() {
static VolumeMethod method = lookup_volume_method();
return method;
}
bool generate_volume_key(android::vold::KeyBuffer* key) {
KeyGeneration gen;
switch (volume_method()) {
case VolumeMethod::kFailed:
LOG(ERROR) << "Volume encryption setup failed";
return false;
case VolumeMethod::kCrypt:
gen = cryptfs_get_keygen();
break;
case VolumeMethod::kDefaultKey:
if (!defaultkey_volume_keygen(&gen)) return false;
break;
}
if (!generateStorageKey(gen, key)) return false;
return true;
}
bool setup_ext_volume(const std::string& label, const std::string& blk_device,
const android::vold::KeyBuffer& key, std::string* out_crypto_blkdev) {
switch (volume_method()) {
case VolumeMethod::kFailed:
LOG(ERROR) << "Volume encryption setup failed";
return false;
case VolumeMethod::kCrypt:
return cryptfs_setup_ext_volume(label.c_str(), blk_device.c_str(), key,
out_crypto_blkdev) == 0;
case VolumeMethod::kDefaultKey:
return defaultkey_setup_ext_volume(label, blk_device, key, out_crypto_blkdev);
}
}
} // namespace vold
} // namespace android

32
model/VolumeEncryption.h Normal file
View file

@ -0,0 +1,32 @@
/*
* Copyright (C) 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 <string>
#include "KeyBuffer.h"
namespace android {
namespace vold {
bool generate_volume_key(android::vold::KeyBuffer* key);
bool setup_ext_volume(const std::string& label, const std::string& blk_device,
const android::vold::KeyBuffer& key, std::string* out_crypto_blkdev);
} // namespace vold
} // namespace android