From b29b27ec7f47bde45ee65752cb218d6f7a0860d6 Mon Sep 17 00:00:00 2001 From: Xiaoyong Zhou Date: Fri, 8 Mar 2019 09:59:42 -0800 Subject: [PATCH] Change mini-keyctl command format. This CL change the mini-keyctl tool to make it compitable with libkeyctl tool to make it more useful. Bug: 112038861 Test: mini-keyctl padd asymmetric 'desc' .fs-verity < /path/to/cert.der Test: mini-keyctl unlink Test: mini-keyctl restrict_keyring Change-Id: I950f07c7718f173823ce5a5cd08e0d1a0e23a007 --- libkeyutils/Android.bp | 9 +- libkeyutils/mini_keyctl.cpp | 186 ++++++-------------------- libkeyutils/mini_keyctl_utils.cpp | 212 ++++++++++++++++++++++++++++++ libkeyutils/mini_keyctl_utils.h | 48 +++++++ rootdir/init.rc | 5 +- 5 files changed, 311 insertions(+), 149 deletions(-) create mode 100644 libkeyutils/mini_keyctl_utils.cpp create mode 100644 libkeyutils/mini_keyctl_utils.h diff --git a/libkeyutils/Android.bp b/libkeyutils/Android.bp index e81692648..dda491a08 100644 --- a/libkeyutils/Android.bp +++ b/libkeyutils/Android.bp @@ -19,13 +19,14 @@ cc_test { cc_binary { name: "mini-keyctl", - srcs: ["mini_keyctl.cpp"], - + srcs: [ + "mini_keyctl.cpp", + "mini_keyctl_utils.cpp" + ], shared_libs: [ "libbase", "libkeyutils", "liblog", ], - - cflags: ["-Werror", "-Wall", "-Wextra"], + cflags: ["-Werror", "-Wall", "-Wextra", "-fexceptions"], } diff --git a/libkeyutils/mini_keyctl.cpp b/libkeyutils/mini_keyctl.cpp index abc8f8245..4fe4c3c51 100644 --- a/libkeyutils/mini_keyctl.cpp +++ b/libkeyutils/mini_keyctl.cpp @@ -18,159 +18,57 @@ * A tool loads keys to keyring. */ -#include -#include -#include +#include "mini_keyctl_utils.h" + #include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -static constexpr int kMaxCertSize = 4096; - -// Add all the certs from directory path to keyring with keyring_id. Returns the number of keys -// added. -int AddKeys(const std::string& path, const key_serial_t keyring_id, const std::string& keyring_desc, - int start_index) { - std::unique_ptr dir(opendir(path.c_str()), closedir); - if (!dir) { - PLOG(WARNING) << "Failed to open directory " << path; - return 0; - } - int keys_added = 0; - struct dirent* dp; - while ((dp = readdir(dir.get())) != NULL) { - if (dp->d_type != DT_REG) { - continue; - } - std::string cert_path = path + "/" + dp->d_name; - std::string cert_buf; - if (!android::base::ReadFileToString(cert_path, &cert_buf, false /* follow_symlinks */)) { - LOG(ERROR) << "Failed to read " << cert_path; - continue; - } - - if (cert_buf.size() > kMaxCertSize) { - LOG(ERROR) << "Certficate size too large: " << cert_path; - continue; - } - - // Add key to keyring. - int key_desc_index = keys_added + start_index; - std::string key_desc = keyring_desc + "-key" + std::to_string(key_desc_index); - key_serial_t key = - add_key("asymmetric", key_desc.c_str(), &cert_buf[0], cert_buf.size(), keyring_id); - if (key < 0) { - PLOG(ERROR) << "Failed to add key to keyring: " << cert_path; - continue; - } - keys_added++; - } - return keys_added; -} - -std::vector SplitBySpace(const std::string& s) { - std::istringstream iss(s); - return std::vector{std::istream_iterator{iss}, - std::istream_iterator{}}; -} - -// Find the keyring id. Because request_key(2) syscall is not available or the key is -// kernel keyring, the id is looked up from /proc/keys. The keyring description may contain other -// information in the descritption section depending on the key type, only the first word in the -// keyring description is used for searching. -bool GetKeyringId(const std::string& keyring_desc, key_serial_t* keyring_id) { - if (!keyring_id) { - LOG(ERROR) << "keyring_id is null"; - return false; - } - - // Only keys allowed by SELinux rules will be shown here. - std::ifstream proc_keys_file("/proc/keys"); - if (!proc_keys_file.is_open()) { - PLOG(ERROR) << "Failed to open /proc/keys"; - return false; - } - - std::string line; - while (getline(proc_keys_file, line)) { - std::vector tokens = SplitBySpace(line); - if (tokens.size() < 9) { - continue; - } - std::string key_id = tokens[0]; - std::string key_type = tokens[7]; - // The key description may contain space. - std::string key_desc_prefix = tokens[8]; - // The prefix has a ":" at the end - std::string key_desc_pattern = keyring_desc + ":"; - if (key_type != "keyring" || key_desc_prefix != key_desc_pattern) { - continue; - } - *keyring_id = std::stoi(key_id, nullptr, 16); - return true; - } - return false; -} - static void Usage(int exit_code) { - fprintf(stderr, "usage: mini-keyctl -c PATHS -s DESCRIPTION\n"); - fprintf(stderr, "\n"); - fprintf(stderr, "-c, --cert_dirs the certificate locations, separated by comma\n"); - fprintf(stderr, "-k, --keyring the keyring description\n"); + fprintf(stderr, "usage: mini-keyctl [args,]\n"); + fprintf(stderr, " mini-keyctl add \n"); + fprintf(stderr, " mini-keyctl padd \n"); + fprintf(stderr, " mini-keyctl dadd \n"); + fprintf(stderr, " mini-keyctl unlink \n"); + fprintf(stderr, " mini-keyctl restrict_keyring \n"); _exit(exit_code); } -int main(int argc, char** argv) { - if (argc < 5) Usage(1); +int main(int argc, const char** argv) { + if (argc < 2) Usage(1); + const std::string action = argv[1]; - std::string arg_cert_dirs; - std::string arg_keyring_desc; - - for (int i = 1; i < argc; i++) { - std::string option = argv[i]; - if (option == "-c" || option == "--cert_dirs") { - if (i + 1 < argc) arg_cert_dirs = argv[++i]; - } else if (option == "-k" || option == "--keyring") { - if (i + 1 < argc) arg_keyring_desc = argv[++i]; - } - } - - if (arg_cert_dirs.empty() || arg_keyring_desc.empty()) { - LOG(ERROR) << "Missing cert_dirs or keyring desc"; + if (action == "add") { + if (argc != 6) Usage(1); + std::string type = argv[2]; + std::string desc = argv[3]; + std::string data = argv[4]; + std::string keyring = argv[5]; + return Add(type, desc, data, keyring); + } else if (action == "dadd") { + if (argc != 6) Usage(1); + std::string type = argv[2]; + // The key description contains desc_prefix and an index. + std::string desc_prefix = argv[3]; + std::string cert_dir = argv[4]; + std::string keyring = argv[5]; + return AddCertsFromDir(type, desc_prefix, cert_dir, keyring); + } else if (action == "padd") { + if (argc != 5) Usage(1); + std::string type = argv[2]; + std::string desc = argv[3]; + std::string keyring = argv[4]; + return Padd(type, desc, keyring); + } else if (action == "restrict_keyring") { + if (argc != 3) Usage(1); + std::string keyring = argv[2]; + return RestrictKeyring(keyring); + } else if (action == "unlink") { + if (argc != 4) Usage(1); + key_serial_t key = std::stoi(argv[2], nullptr, 16); + const std::string keyring = argv[3]; + return Unlink(key, keyring); + } else { Usage(1); } - // Get the keyring id - key_serial_t key_ring_id; - if (!GetKeyringId(arg_keyring_desc, &key_ring_id)) { - PLOG(ERROR) << "Can't find keyring with " << arg_keyring_desc; - return 1; - } - - std::vector cert_dirs = android::base::Split(arg_cert_dirs, ","); - int start_index = 0; - for (const auto& cert_dir : cert_dirs) { - int keys_added = AddKeys(cert_dir, key_ring_id, arg_keyring_desc, start_index); - start_index += keys_added; - } - - // Prevent new keys to be added. - if (!android::base::GetBoolProperty("ro.debuggable", false) && - keyctl_restrict_keyring(key_ring_id, nullptr, nullptr) < 0) { - PLOG(ERROR) << "Failed to restrict key ring " << arg_keyring_desc; - return 1; - } - return 0; } diff --git a/libkeyutils/mini_keyctl_utils.cpp b/libkeyutils/mini_keyctl_utils.cpp new file mode 100644 index 000000000..c4fc96cc6 --- /dev/null +++ b/libkeyutils/mini_keyctl_utils.cpp @@ -0,0 +1,212 @@ +/* + * Copyright (C) 2019 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 + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +static constexpr int kMaxCertSize = 4096; + +std::vector SplitBySpace(const std::string& s) { + std::istringstream iss(s); + return std::vector{std::istream_iterator{iss}, + std::istream_iterator{}}; +} + +int AddCertsFromDir(const std::string& type, const std::string& desc_prefix, + const std::string& cert_dir, const std::string& keyring) { + key_serial_t keyring_id; + if (!GetKeyringId(keyring, &keyring_id)) { + LOG(ERROR) << "Can not find keyring id"; + return 1; + } + + std::unique_ptr dir(opendir(cert_dir.c_str()), closedir); + if (!dir) { + PLOG(WARNING) << "Failed to open directory " << cert_dir; + return 1; + } + int keys_added = 0; + struct dirent* dp; + while ((dp = readdir(dir.get())) != NULL) { + if (dp->d_type != DT_REG) { + continue; + } + std::string cert_path = cert_dir + "/" + dp->d_name; + std::string cert_buf; + if (!android::base::ReadFileToString(cert_path, &cert_buf, false /* follow_symlinks */)) { + LOG(ERROR) << "Failed to read " << cert_path; + continue; + } + + if (cert_buf.size() > kMaxCertSize) { + LOG(ERROR) << "Certficate size too large: " << cert_path; + continue; + } + + // Add key to keyring. + int key_desc_index = keys_added; + std::string key_desc = desc_prefix + std::to_string(key_desc_index); + key_serial_t key = + add_key(type.c_str(), key_desc.c_str(), &cert_buf[0], cert_buf.size(), keyring_id); + if (key < 0) { + PLOG(ERROR) << "Failed to add key to keyring: " << cert_path; + continue; + } + LOG(INFO) << "Key " << cert_path << " added to " << keyring << " with key id 0x" << std::hex + << key; + keys_added++; + } + return 0; +} + +bool GetKeyringId(const std::string& keyring_desc, key_serial_t* keyring_id) { + if (!keyring_id) { + LOG(ERROR) << "keyring_id is null"; + return false; + } + + // If the keyring id is already a hex number, directly convert it to keyring id + try { + key_serial_t id = std::stoi(keyring_desc, nullptr, 16); + *keyring_id = id; + return true; + } catch (const std::exception& e) { + LOG(INFO) << "search /proc/keys for keyring id"; + } + + // Only keys allowed by SELinux rules will be shown here. + std::ifstream proc_keys_file("/proc/keys"); + if (!proc_keys_file.is_open()) { + PLOG(ERROR) << "Failed to open /proc/keys"; + return false; + } + + std::string line; + while (getline(proc_keys_file, line)) { + std::vector tokens = SplitBySpace(line); + if (tokens.size() < 9) { + continue; + } + std::string key_id = tokens[0]; + std::string key_type = tokens[7]; + // The key description may contain space. + std::string key_desc_prefix = tokens[8]; + // The prefix has a ":" at the end + std::string key_desc_pattern = keyring_desc + ":"; + if (key_type != "keyring" || key_desc_prefix != key_desc_pattern) { + continue; + } + *keyring_id = std::stoi(key_id, nullptr, 16); + return true; + } + return false; +} + +int Unlink(key_serial_t key, const std::string& keyring) { + key_serial_t keyring_id; + if (!GetKeyringId(keyring, &keyring_id)) { + LOG(ERROR) << "Can't find keyring " << keyring; + return 1; + } + + if (keyctl_unlink(key, keyring_id) < 0) { + PLOG(ERROR) << "Failed to unlink key 0x" << std::hex << key << " from keyring " << keyring_id; + return 1; + } + return 0; +} + +int Add(const std::string& type, const std::string& desc, const std::string& data, + const std::string& keyring) { + if (data.size() > kMaxCertSize) { + LOG(ERROR) << "Certificate too large"; + return 1; + } + + key_serial_t keyring_id; + if (!GetKeyringId(keyring, &keyring_id)) { + LOG(ERROR) << "Can not find keyring id"; + return 1; + } + + key_serial_t key = add_key(type.c_str(), desc.c_str(), data.c_str(), data.size(), keyring_id); + + if (key < 0) { + PLOG(ERROR) << "Failed to add key"; + return 1; + } + + LOG(INFO) << "Key " << desc << " added to " << keyring << " with key id: 0x" << std::hex << key; + return 0; +} + +int Padd(const std::string& type, const std::string& desc, const std::string& keyring) { + key_serial_t keyring_id; + if (!GetKeyringId(keyring, &keyring_id)) { + LOG(ERROR) << "Can not find keyring id"; + return 1; + } + + // read from stdin to get the certificates + std::istreambuf_iterator begin(std::cin), end; + std::string data(begin, end); + + if (data.size() > kMaxCertSize) { + LOG(ERROR) << "Certificate too large"; + return 1; + } + + key_serial_t key = add_key(type.c_str(), desc.c_str(), data.c_str(), data.size(), keyring_id); + + if (key < 0) { + PLOG(ERROR) << "Failed to add key"; + return 1; + } + + LOG(INFO) << "Key " << desc << " added to " << keyring << " with key id: 0x" << std::hex << key; + return 0; +} + +int RestrictKeyring(const std::string& keyring) { + key_serial_t keyring_id; + if (!GetKeyringId(keyring, &keyring_id)) { + LOG(ERROR) << "Cannot find keyring id"; + return 1; + } + + if (keyctl_restrict_keyring(keyring_id, nullptr, nullptr) < 0) { + PLOG(ERROR) << "Cannot restrict keyring " << keyring; + return 1; + } + return 0; +} diff --git a/libkeyutils/mini_keyctl_utils.h b/libkeyutils/mini_keyctl_utils.h new file mode 100644 index 000000000..3c6961170 --- /dev/null +++ b/libkeyutils/mini_keyctl_utils.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2019 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 "include/keyutils.h" + +#include + +// Add all files in a directory as certificates to a keyring. |keyring| could be the keyring +// description or keyring id in hex. +int AddCertsFromDir(const std::string& type, const std::string& desc_prefix, + const std::string& cert_dir, const std::string& keyring); + +// Add all the certs from directory path to keyring with keyring_id. Returns the number of keys +// added. Returns non-zero if any error happens. +int AddKeys(const std::string& path, const key_serial_t keyring_id, const std::string& type, + const std::string& desc, int start_index); + +// Add key to a keyring. Returns non-zero if error happens. +int Add(const std::string& type, const std::string& desc, const std::string& data, + const std::string& keyring); + +// Add key from stdin to a keyring. Returns non-zero if error happens. +int Padd(const std::string& type, const std::string& desc, const std::string& keyring); + +// Removes the link from a keyring to a key if exists. Return non-zero if error happens. +int Unlink(key_serial_t key, const std::string& keyring); + +// Apply key-linking to a keyring. Return non-zero if error happens. +int RestrictKeyring(const std::string& keyring); + +// Find the keyring id. Because request_key(2) syscall is not available or the key is +// kernel keyring, the id is looked up from /proc/keys. The keyring description may contain other +// information in the descritption section depending on the key type, only the first word in the +// keyring description is used for searching. +bool GetKeyringId(const std::string& keyring_desc, key_serial_t* keyring_id); diff --git a/rootdir/init.rc b/rootdir/init.rc index f2e7a7cf6..b769b9436 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -586,7 +586,10 @@ on post-fs-data restorecon --recursive --skip-ce /data # load fsverity keys - exec -- /system/bin/mini-keyctl -c /product/etc/security/cacerts_fsverity,/vendor/etc/security/cacerts_fsverity -k .fs-verity + exec -- /system/bin/mini-keyctl dadd asymmetric product_cert /product/etc/security/cacerts_fsverity .fs-verity + exec -- /system/bin/mini-keyctl dadd asymmetric vendor_cert /vendor/etc/security/cacerts_fsverity .fs-verity + # Prevent future key links to fsverity keyring + exec -- /system/bin/mini-keyctl restrict_keyring .fs-verity # Check any timezone data in /data is newer than the copy in the runtime module, delete if not. exec - system system -- /system/bin/tzdatacheck /apex/com.android.runtime/etc/tz /data/misc/zoneinfo