summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libkeyutils/Android.bp9
-rw-r--r--libkeyutils/mini_keyctl.cpp188
-rw-r--r--libkeyutils/mini_keyctl_utils.cpp212
-rw-r--r--libkeyutils/mini_keyctl_utils.h48
-rw-r--r--rootdir/init.rc5
5 files changed, 312 insertions, 150 deletions
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 <dirent.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <fstream>
-#include <iostream>
-#include <iterator>
-#include <sstream>
-#include <string>
-#include <vector>
-
-#include <android-base/file.h>
-#include <android-base/logging.h>
-#include <android-base/properties.h>
-#include <android-base/strings.h>
-#include <keyutils.h>
-
-static constexpr int kMaxCertSize = 4096;
+#include "mini_keyctl_utils.h"
-// 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, int (*)(DIR*)> 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<std::string> SplitBySpace(const std::string& s) {
- std::istringstream iss(s);
- return std::vector<std::string>{std::istream_iterator<std::string>{iss},
- std::istream_iterator<std::string>{}};
-}
-
-// 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<std::string> 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;
-}
+#include <unistd.h>
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 <action> [args,]\n");
+ fprintf(stderr, " mini-keyctl add <type> <desc> <data> <keyring>\n");
+ fprintf(stderr, " mini-keyctl padd <type> <desc> <keyring>\n");
+ fprintf(stderr, " mini-keyctl dadd <type> <desc_prefix> <cert_dir> <keyring>\n");
+ fprintf(stderr, " mini-keyctl unlink <key> <keyring>\n");
+ fprintf(stderr, " mini-keyctl restrict_keyring <keyring>\n");
_exit(exit_code);
}
-int main(int argc, char** argv) {
- if (argc < 5) Usage(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";
+int main(int argc, const char** argv) {
+ if (argc < 2) Usage(1);
+ const std::string action = argv[1];
+
+ 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<std::string> 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 <mini_keyctl_utils.h>
+
+#include <dirent.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <fstream>
+#include <iostream>
+#include <iterator>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android-base/strings.h>
+#include <keyutils.h>
+
+static constexpr int kMaxCertSize = 4096;
+
+std::vector<std::string> SplitBySpace(const std::string& s) {
+ std::istringstream iss(s);
+ return std::vector<std::string>{std::istream_iterator<std::string>{iss},
+ std::istream_iterator<std::string>{}};
+}
+
+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, int (*)(DIR*)> 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<std::string> 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<char> 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 <string>
+
+// 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