summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Lawrence <paullawrence@google.com>2015-03-16 15:35:55 -0700
committerJP Abgrall <jpa@google.com>2015-04-01 19:25:51 +0000
commit61980269c14ae78a9ca893a56df67cf475cdfafd (patch)
tree67b35eb8531604b94fec5cb50e7b96bbb911850c
parent17fb21d013743a93bab3cdfc899e952184cae58c (diff)
downloadextras-61980269c14ae78a9ca893a56df67cf475cdfafd.tar.gz
ext4_utils: Abstracting ext4 encryption property system
Change-Id: Iddca42328e9249eb09eb68e6d5339a02cfebecd0
-rw-r--r--ext4_utils/Android.mk3
-rw-r--r--ext4_utils/ext4_crypt.cpp46
-rw-r--r--ext4_utils/ext4_crypt_init_extensions.cpp94
-rw-r--r--ext4_utils/unencrypted_properties.cpp86
-rw-r--r--ext4_utils/unencrypted_properties.h70
5 files changed, 218 insertions, 81 deletions
diff --git a/ext4_utils/Android.mk b/ext4_utils/Android.mk
index 964f6668..76dd4534 100644
--- a/ext4_utils/Android.mk
+++ b/ext4_utils/Android.mk
@@ -54,7 +54,8 @@ include $(BUILD_HOST_EXECUTABLE)
libext4_utils_src_files += \
ext4_crypt.cpp \
- e4crypt_static.c
+ e4crypt_static.c \
+ unencrypted_properties.cpp
ifneq ($(HOST_OS),windows)
diff --git a/ext4_utils/ext4_crypt.cpp b/ext4_utils/ext4_crypt.cpp
index 70ad070d..bb573323 100644
--- a/ext4_utils/ext4_crypt.cpp
+++ b/ext4_utils/ext4_crypt.cpp
@@ -12,35 +12,29 @@
#include <cutils/klog.h>
#include <cutils/properties.h>
-// ext4enc::TODO remove this duplicated const
-static const std::string unencrypted_path = "/unencrypted";
+#include "unencrypted_properties.h"
-static std::map<std::string, std::string> s_password_store;
+namespace {
+ std::map<std::string, std::string> s_password_store;
+}
bool e4crypt_non_default_key(const char* dir)
{
int type = e4crypt_get_password_type(dir);
+
+ // ext4enc:TODO Use consts, not 1 here
return type != -1 && type != 1;
}
int e4crypt_get_password_type(const char* path)
{
- auto full_path = std::string() + path + unencrypted_path;
- if (!std::ifstream(full_path + "/key")) {
+ UnencryptedProperties props(path);
+ if (props.Get<std::string>(properties::key).empty()) {
KLOG_INFO(TAG, "No master key, so not ext4enc\n");
return -1;
}
- std::ifstream type(full_path + "/type");
- if (!type) {
- KLOG_INFO(TAG, "No password type so default\n");
- return 1; // Default
- }
-
- int value = 0;
- type >> value;
- KLOG_INFO(TAG, "Password type is %d\n", value);
- return value;
+ return props.Get<int>(properties::type, 1);
}
int e4crypt_change_password(const char* path, int crypt_type,
@@ -48,18 +42,17 @@ int e4crypt_change_password(const char* path, int crypt_type,
{
// ext4enc:TODO Encrypt master key with password securely. Store hash of
// master key for validation
- auto full_path = std::string() + path + unencrypted_path;
- std::ofstream(full_path + "/password") << password;
- std::ofstream(full_path + "/type") << crypt_type;
- return 0;
+ UnencryptedProperties props(path);
+ if ( props.Set(properties::password, password)
+ && props.Set(properties::type, crypt_type))
+ return 0;
+ return -1;
}
-int e4crypt_crypto_complete(const char* path)
+int e4crypt_crypto_complete(const char* path)
{
KLOG_INFO(TAG, "ext4 crypto complete called on %s\n", path);
-
- auto full_path = std::string() + path + unencrypted_path;
- if (!std::ifstream(full_path + "/key")) {
+ if (UnencryptedProperties(path).Get<std::string>(properties::key).empty()) {
KLOG_INFO(TAG, "No master key, so not ext4enc\n");
return -1;
}
@@ -69,14 +62,13 @@ int e4crypt_crypto_complete(const char* path)
int e4crypt_check_passwd(const char* path, const char* password)
{
- auto full_path = std::string() + path + unencrypted_path;
- if (!std::ifstream(full_path + "/key")) {
+ UnencryptedProperties props(path);
+ if (props.Get<std::string>(properties::key).empty()) {
KLOG_INFO(TAG, "No master key, so not ext4enc\n");
return -1;
}
- std::string actual_password;
- std::ifstream(full_path + "/password") >> actual_password;
+ auto actual_password = props.Get<std::string>(properties::password);
if (actual_password == password) {
s_password_store[path] = password;
diff --git a/ext4_utils/ext4_crypt_init_extensions.cpp b/ext4_utils/ext4_crypt_init_extensions.cpp
index 16d333e9..6d73fb2f 100644
--- a/ext4_utils/ext4_crypt_init_extensions.cpp
+++ b/ext4_utils/ext4_crypt_init_extensions.cpp
@@ -15,6 +15,8 @@
#include <cutils/properties.h>
#include <cutils/sockets.h>
+#include "unencrypted_properties.h"
+
// ext4enc:TODO Include structure from somewhere sensible
// MUST be in sync with ext4_crypto.c in kernel
#define EXT4_MAX_KEY_SIZE 76
@@ -24,7 +26,6 @@ struct ext4_encryption_key {
uint32_t size;
};
-static const std::string unencrypted_path = "/unencrypted";
static const std::string keyring = "@s";
static const std::string arbitrary_sequence_number = "42";
@@ -104,46 +105,40 @@ int e4crypt_create_device_key(const char* dir,
{
// Make sure folder exists. Use make_dir to set selinux permissions.
KLOG_INFO(TAG, "Creating test device key\n");
- std::string path = std::string() + dir + unencrypted_path;
- if (ensure_dir_exists(path.c_str())) {
+ UnencryptedProperties props(dir);
+ if (ensure_dir_exists(props.GetPath().c_str())) {
KLOG_ERROR(TAG, "Failed to create %s with error %s\n",
- path.c_str(), strerror(errno));
+ props.GetPath().c_str(), strerror(errno));
return -1;
}
- // Open key if it exists
- std::string key_path = path + "/key";
- std::ifstream key(key_path.c_str(), std::ifstream::binary);
-
- if (!key.good()) {
- // Create new key if it doesn't
- std::ofstream new_key(key_path.c_str(), std::ofstream::binary);
- if (!new_key) {
- KLOG_ERROR(TAG, "Failed to open %s\n", key_path.c_str());
- return -1;
- }
-
+ if (props.Get<std::string>(properties::key).empty()) {
+ // Create new key since it doesn't already exist
std::ifstream urandom("/dev/urandom", std::ifstream::binary);
if (!urandom) {
KLOG_ERROR(TAG, "Failed to open /dev/urandom\n");
return -1;
}
- char key_material[32];
- urandom.read(key_material, 32);
+ // ext4enc:TODO Don't hardcode 32
+ std::string key_material(32, '\0');
+ urandom.read(&key_material[0], key_material.length());
if (!urandom) {
KLOG_ERROR(TAG, "Failed to read random bytes\n");
return -1;
}
- new_key.write(key_material, 32);
- if (!new_key) {
+ if (!props.Set(properties::key, key_material)) {
KLOG_ERROR(TAG, "Failed to write key material");
return -1;
}
}
- remove((std::string(dir) + "/ref").c_str());
+ if (!props.Remove(properties::ref)) {
+ KLOG_ERROR(TAG, "Failed to remove key ref\n");
+ return -1;
+ }
+
return 0;
}
@@ -160,7 +155,8 @@ int e4crypt_install_keyring()
return -1;
}
- KLOG_INFO(TAG, "Keyring created wth id %d in process %d\n", device_keyring, getpid());
+ KLOG_INFO(TAG, "Keyring created wth id %d in process %d\n",
+ device_keyring, getpid());
// ext4enc:TODO set correct permissions
long result = keyctl_setperm(device_keyring, 0x3f3f3f3f);
@@ -174,23 +170,8 @@ int e4crypt_install_keyring()
int e4crypt_install_key(const char* dir)
{
- std::string path = std::string() + dir + unencrypted_path;
-
- // Open key if it exists
- std::string key_path = path + "/key";
- std::ifstream key(key_path.c_str(), std::ifstream::binary);
- if (!key.good()) {
- KLOG_ERROR(TAG, "Failed to open key %s\n", key_path.c_str());
- return -1;
- }
-
- char keyblob[256];
- key.read(keyblob, sizeof(keyblob));
- std::streamsize keyblob_size = key.gcount();
- if (keyblob_size <= 0) {
- KLOG_ERROR(TAG, "Failed to read key data\n");
- return -1;
- }
+ UnencryptedProperties props(dir);
+ auto key = props.Get<std::string>(properties::key);
// Get password to decrypt as needed
if (e4crypt_non_default_key(dir)) {
@@ -225,8 +206,14 @@ int e4crypt_install_key(const char* dir)
// Add key to keyring
ext4_encryption_key ext4_key = {0, {0}, 0};
- memcpy(ext4_key.raw, keyblob, keyblob_size);
- ext4_key.size = keyblob_size;
+ if (key.length() > sizeof(ext4_key.raw)) {
+ KLOG_ERROR(TAG, "Key too long\n");
+ return -1;
+ }
+
+ ext4_key.mode = 0;
+ memcpy(ext4_key.raw, &key[0], key.length());
+ ext4_key.size = key.length();
// ext4enc:TODO Use better reference not 1234567890
key_serial_t key_id = add_key("logon", "ext4-key:1234567890",
@@ -250,29 +237,30 @@ int e4crypt_install_key(const char* dir)
}
// Save reference to key so we can set policy later
- std::ofstream(path + "/ref") << "ext4-key:1234567890";
+ if (!props.Set(properties::ref, "ext4-key:1234567890")) {
+ KLOG_ERROR(TAG, "Cannot save key reference\n");
+ return -1;
+ }
+
return 0;
}
int e4crypt_set_directory_policy(const char* dir)
{
// Only set policy on first level /data directories
- // ext4enc:TODO don't hard code /data/
+ // To make this less restrictive, consider using a policy file.
+ // However this is overkill for as long as the policy is simply
+ // to apply a global policy to all /data folders created via makedir
if (!dir || strncmp(dir, "/data/", 6) || strchr(dir + 6, '/')) {
return 0;
}
- std::ifstream ref_file("/data/unencrypted/ref");
- if (!ref_file) {
- KLOG_ERROR(TAG, "Cannot open key reference file\n");
- return -1;
- }
-
- std::string ref;
- std::getline(ref_file, ref);
- std::string policy = std::string() + keyring + "." + ref;
+ UnencryptedProperties props("/data");
+ std::string ref = props.Get<std::string>(properties::ref);
+ std::string policy = keyring + "." + ref;
KLOG_INFO(TAG, "Setting policy %s\n", policy.c_str());
- if (do_policy_set(dir, policy.c_str())) {
+ int result = do_policy_set(dir, policy.c_str());
+ if (result) {
KLOG_ERROR(TAG, "Setting policy on %s failed!", dir);
return -1;
}
diff --git a/ext4_utils/unencrypted_properties.cpp b/ext4_utils/unencrypted_properties.cpp
new file mode 100644
index 00000000..bef7c57b
--- /dev/null
+++ b/ext4_utils/unencrypted_properties.cpp
@@ -0,0 +1,86 @@
+#include "unencrypted_properties.h"
+
+#include <sys/stat.h>
+
+namespace properties {
+ const char* key = "key";
+ const char* ref = "ref";
+ const char* type = "type";
+ const char* password = "password";
+}
+
+namespace
+{
+ const char* unencrypted_folder = "unencrypted";
+}
+
+UnencryptedProperties::UnencryptedProperties(const char* device)
+ : folder_(std::string() + device + "/" + unencrypted_folder)
+{
+}
+
+UnencryptedProperties::UnencryptedProperties()
+{
+}
+
+template<> std::string UnencryptedProperties::Get(const char* name,
+ std::string default_value)
+{
+ if (!OK()) return default_value;
+ std::ifstream i(folder_ + "/" + name, std::ios::binary);
+ if (!i) {
+ return default_value;
+ }
+
+ i.seekg(0, std::ios::end);
+ int length = i.tellg();
+ i.seekg(0, std::ios::beg);
+ if (length == -1) {
+ return default_value;
+ }
+
+ std::string s(length, 0);
+ i.read(&s[0], length);
+ if (!i) {
+ return default_value;
+ }
+
+ return s;
+}
+
+template<> bool UnencryptedProperties::Set(const char* name, std::string const& value)
+{
+ if (!OK()) return false;
+ std::ofstream o(folder_ + "/" + name, std::ios::binary);
+ o << value;
+ return !o.fail();
+}
+
+UnencryptedProperties UnencryptedProperties::GetChild(const char* name)
+{
+ UnencryptedProperties e4p;
+ if (!OK()) return e4p;
+
+ std::string directory(folder_ + "/" + name);
+ if (mkdir(directory.c_str(), 700) == -1 && errno != EEXIST) {
+ return e4p;
+ }
+
+ e4p.folder_ = directory;
+ return e4p;
+}
+
+bool UnencryptedProperties::Remove(const char* name)
+{
+ if (remove((folder_ + "/" + name).c_str())
+ && errno != ENOENT) {
+ return false;
+ }
+
+ return true;
+}
+
+bool UnencryptedProperties::OK() const
+{
+ return !folder_.empty();
+}
diff --git a/ext4_utils/unencrypted_properties.h b/ext4_utils/unencrypted_properties.h
new file mode 100644
index 00000000..80f41df4
--- /dev/null
+++ b/ext4_utils/unencrypted_properties.h
@@ -0,0 +1,70 @@
+#include <string>
+#include <fstream>
+
+// key names for properties we use
+namespace properties {
+ extern const char* key;
+ extern const char* ref;
+ extern const char* type;
+ extern const char* password;
+}
+
+/**
+ * Class to store data on the unencrypted folder of a device.
+ * Note that the folder must exist before this class is constructed.
+ * All names must be valid single level (no '/') file or directory names
+ * Data is organized hierarchically so we can get a child folder
+ */
+class UnencryptedProperties
+{
+public:
+ // Opens properties folder on named device.
+ // If folder does not exist, construction will succeed, but all
+ // getters will return default properties and setters will fail.
+ UnencryptedProperties(const char* device);
+
+ // Get named object. Return default if object does not exist or error.
+ template<typename t> t Get(const char* name, t default_value = t());
+
+ // Set named object. Return true if success, false otherwise
+ template<typename t> bool Set(const char* name, t const& value);
+
+ // Get child properties
+ UnencryptedProperties GetChild(const char* name);
+
+ // Remove named object
+ bool Remove(const char* name);
+
+ // Get path of folder
+ std::string const& GetPath() const {return folder_;}
+private:
+ UnencryptedProperties();
+ bool OK() const;
+ std::string folder_;
+};
+
+
+template<typename t> t UnencryptedProperties::Get(const char* name,
+ t default_value)
+{
+ if (!OK()) return default_value;
+ t value = default_value;
+ std::ifstream(folder_ + "/" + name) >> value;
+ return value;
+}
+
+template<typename t> bool UnencryptedProperties::Set(const char* name,
+ t const& value)
+{
+ if (!OK()) return false;
+ std::ofstream o(folder_ + "/" + name);
+ o << value;
+ return !o.fail();
+}
+
+// Specialized getters/setters for strings
+template<> std::string UnencryptedProperties::Get(const char* name,
+ std::string default_value);
+
+template<> bool UnencryptedProperties::Set(const char* name,
+ std::string const& value);