Split fsverity_init in multiple phases.

Soon we'll have a need for multiple fs-verity keys in the keyring; we
need a central place to manage the keys, as well as restrict the
keyring. fsverity_init makes most sense for this.

Allow fsverity_init to be called in 3 different ways:
--load-verified-keys: loads preloaded keys from trusted partitions
--load-extra-key: loads an additional key passed in from stdin; the key
name is given as an argument.
--lock: locks the keyring, and prevents new keys from being loaded

Bug: 165630556
Test: boot, cat /proc/keys/
Change-Id: I758e49a5c4229edc531d01ac2e8873a22a1da73e
This commit is contained in:
Martijn Coenen 2020-11-30 10:06:06 +01:00
parent a0a2d5da84
commit 0aeee3d632

View file

@ -37,19 +37,36 @@ bool LoadKeyToKeyring(key_serial_t keyring_id, const char* desc, const char* dat
return true;
}
void LoadKeyFromStdin(key_serial_t keyring_id, const char* keyname) {
std::string content;
if (!android::base::ReadFdToString(STDIN_FILENO, &content)) {
LOG(ERROR) << "Failed to read key from stdin";
return;
}
if (!LoadKeyToKeyring(keyring_id, keyname, content.c_str(), content.size())) {
LOG(ERROR) << "Failed to load key from stdin";
}
}
void LoadKeyFromFile(key_serial_t keyring_id, const char* keyname, const std::string& path) {
std::string content;
if (!android::base::ReadFileToString(path, &content)) {
LOG(ERROR) << "Failed to read key from " << path;
return;
}
if (!LoadKeyToKeyring(keyring_id, keyname, content.c_str(), content.size())) {
LOG(ERROR) << "Failed to load key from " << path;
}
}
void LoadKeyFromDirectory(key_serial_t keyring_id, const char* keyname, const char* dir) {
if (!std::filesystem::exists(dir)) {
return;
}
for (const auto& entry : std::filesystem::directory_iterator(dir)) {
if (!android::base::EndsWithIgnoreCase(entry.path().c_str(), ".der")) continue;
std::string content;
if (!android::base::ReadFileToString(entry.path(), &content)) {
continue;
}
if (!LoadKeyToKeyring(keyring_id, keyname, content.c_str(), content.size())) {
LOG(ERROR) << "Failed to load key from " << entry.path();
}
LoadKeyFromFile(keyring_id, keyname, entry.path());
}
}
@ -60,25 +77,44 @@ void LoadKeyFromVerifiedPartitions(key_serial_t keyring_id) {
LoadKeyFromDirectory(keyring_id, "fsv_product", "/product/etc/security/fsverity");
}
int main(int /*argc*/, const char** /*argv*/) {
int main(int argc, const char** argv) {
if (argc < 2) {
LOG(ERROR) << "Not enough arguments";
return -1;
}
key_serial_t keyring_id = android::GetKeyringId(".fs-verity");
if (keyring_id < 0) {
LOG(ERROR) << "Failed to find .fs-verity keyring id";
return -1;
}
// Requires files backed by fs-verity to be verified with a key in .fs-verity
// keyring.
if (!android::base::WriteStringToFile("1", "/proc/sys/fs/verity/require_signatures")) {
PLOG(ERROR) << "Failed to enforce fs-verity signature";
}
const std::string_view command = argv[1];
LoadKeyFromVerifiedPartitions(keyring_id);
if (!android::base::GetBoolProperty("ro.debuggable", false)) {
if (keyctl_restrict_keyring(keyring_id, nullptr, nullptr) < 0) {
PLOG(ERROR) << "Cannot restrict .fs-verity keyring";
if (command == "--load-verified-keys") {
LoadKeyFromVerifiedPartitions(keyring_id);
} else if (command == "--load-extra-key") {
if (argc != 3) {
LOG(ERROR) << "--load-extra-key requires <key_name> argument.";
return -1;
}
LoadKeyFromStdin(keyring_id, argv[2]);
} else if (command == "--lock") {
// Requires files backed by fs-verity to be verified with a key in .fs-verity
// keyring.
if (!android::base::WriteStringToFile("1", "/proc/sys/fs/verity/require_signatures")) {
PLOG(ERROR) << "Failed to enforce fs-verity signature";
}
if (!android::base::GetBoolProperty("ro.debuggable", false)) {
if (keyctl_restrict_keyring(keyring_id, nullptr, nullptr) < 0) {
PLOG(ERROR) << "Cannot restrict .fs-verity keyring";
}
}
} else {
LOG(ERROR) << "Unknown argument(s).";
return -1;
}
return 0;
}