diff mbox series

[24/42] mkfs.ubifs: Get key descriptor from command line and master key from file

Message ID 20181018143718.26298-25-richard@nod.at
State Accepted
Delegated to: David Oberhollenzer
Headers show
Series mtd-utils: Add fscrypt support to mkfs.ubifs | expand

Commit Message

Richard Weinberger Oct. 18, 2018, 2:37 p.m. UTC
From: David Oberhollenzer <david.oberhollenzer@sigma-star.at>

Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
Signed-off-by: Richard Weinberger <richard@nod.at>
---
 ubifs-utils/mkfs.ubifs/mkfs.ubifs.c | 131 ++++++++++++++++++++++++----
 1 file changed, 113 insertions(+), 18 deletions(-)
diff mbox series

Patch

diff --git a/ubifs-utils/mkfs.ubifs/mkfs.ubifs.c b/ubifs-utils/mkfs.ubifs/mkfs.ubifs.c
index 5be390e93da9..70c306bdf94e 100644
--- a/ubifs-utils/mkfs.ubifs/mkfs.ubifs.c
+++ b/ubifs-utils/mkfs.ubifs/mkfs.ubifs.c
@@ -217,8 +217,7 @@  static struct inum_mapping **hash_table;
 /* Inode creation sequence number */
 static unsigned long long creat_sqnum;
 
-//TODO: add options for double hash and encryption
-static const char *optstring = "d:r:m:o:D:yh?vVe:c:g:f:Fp:k:x:X:j:R:l:j:UQqa";
+static const char *optstring = "d:r:m:o:D:yh?vVe:c:g:f:Fp:k:x:X:j:R:l:j:UQqaK:b:";
 
 static const struct option longopts[] = {
 	{"root",               1, NULL, 'r'},
@@ -244,6 +243,8 @@  static const struct option longopts[] = {
 	{"squash-uids" ,       0, NULL, 'U'},
 	{"set-inode-attr",     0, NULL, 'a'},
 	{"selinux",            1, NULL, 's'},
+	{"key",                1, NULL, 'K'},
+	{"key-descriptor",     1, NULL, 'b'},
 	{NULL, 0, NULL, 0}
 };
 
@@ -288,6 +289,8 @@  static const char *helptext =
 "                         added to the image. The attribute will contain the inode\n"
 "                         number the file has in the generated image.\n"
 "-s, --selinux=FILE       Selinux context file\n"
+"-K, --key=FILE           load an encryption key from a specified file.\n"
+"-b, --key-descriptor=HEX specify the key descriptor as a hex string.\n"
 "-h, --help               display this help text\n\n"
 "Note, SIZE is specified in bytes, but it may also be specified in Kilobytes,\n"
 "Megabytes, and Gigabytes if a KiB, MiB, or GiB suffix is used.\n\n"
@@ -582,11 +585,87 @@  static void print_fscrypt_master_key_descriptor(struct fscrypt_context *fctx)
 	normsg("");
 }
 
+static int xdigit(int x)
+{
+	if (isupper(x))
+		return x - 'A' + 0x0A;
+	if (islower(x))
+		return x - 'a' + 0x0A;
+	return x - '0';
+}
+
+static int parse_key_descriptor(const char *desc, __u8 *dst)
+{
+	int i, hi, lo;
+
+	for (i = 0; i < FS_KEY_DESCRIPTOR_SIZE; ++i) {
+		if (!desc[i * 2] || !desc[i * 2 + 1]) {
+			err_msg("key descriptor '%s' is too short", desc);
+			return -1;
+		}
+		if (!isxdigit(desc[i * 2]) || !isxdigit(desc[i * 2 + 1])) {
+			err_msg("invalid key descriptor '%s'", desc);
+			return -1;
+		}
+
+		hi = xdigit(desc[i * 2]);
+		lo = xdigit(desc[i * 2 + 1]);
+
+		dst[i] = (hi << 4) | lo;
+	}
+
+	if (desc[i * 2]) {
+		err_msg("key descriptor '%s' is too long", desc);
+		return -1;
+	}
+	return 0;
+}
+
+static int load_master_key(const char *key_file)
+{
+	int kf;
+	ssize_t keysize;
+
+	kf = open(key_file, O_RDONLY);
+	if (kf < 0) {
+		sys_errmsg("open '%s'", key_file);
+		return -1;
+	}
+
+	keysize = read(kf, fscrypt_masterkey, sizeof(fscrypt_masterkey));
+	if (keysize < 0) {
+		sys_errmsg("read '%s'", key_file);
+		goto fail;
+	}
+	if (keysize == 0) {
+		err_msg("loading key from '%s': file is empty", key_file);
+		goto fail;
+	}
+
+	close(kf);
+	return 0;
+fail:
+	close(kf);
+	return -1;
+}
+
 static struct fscrypt_context *init_fscrypt_context(unsigned int flags,
-						void *master_key_descriptor,
-						void *nonce)
+						const char *key_file,
+						const char *key_descriptor)
 {
-	struct fscrypt_context *new_fctx = xmalloc(sizeof(*new_fctx));
+	__u8 master_key_descriptor[FS_KEY_DESCRIPTOR_SIZE];
+	__u8 nonce[FS_KEY_DERIVATION_NONCE_SIZE];
+	struct fscrypt_context *new_fctx;
+
+	if (parse_key_descriptor(key_descriptor, master_key_descriptor))
+		return NULL;
+
+	if (load_master_key(key_file))
+		return NULL;
+
+	RAND_bytes((void *)nonce, FS_KEY_DERIVATION_NONCE_SIZE);
+
+	new_fctx = xmalloc(sizeof(*new_fctx));
 
 	new_fctx->format = FS_ENCRYPTION_CONTEXT_FORMAT_V1;
 	new_fctx->contents_encryption_mode = FS_ENCRYPTION_MODE_AES_128_CBC;
@@ -635,6 +714,7 @@  static int open_ubi(const char *node)
 static int get_options(int argc, char**argv)
 {
 	int opt, i;
+	const char *key_file = NULL, *key_desc = NULL;
 	const char *tbl_file = NULL;
 	struct stat st;
 	char *endp;
@@ -812,6 +892,18 @@  static int get_options(int argc, char**argv)
 				return sys_err_msg("bad file context %s\n",
 								   context);
 			break;
+		case 'K':
+			if (key_file) {
+				return err_msg("key file specified more than once");
+			}
+			key_file = optarg;
+			break;
+		case 'b':
+			if (key_desc) {
+				return err_msg("key descriptor specified more than once");
+			}
+			key_desc = optarg;
+			break;
 		}
 	}
 
@@ -830,6 +922,22 @@  static int get_options(int argc, char**argv)
 			c->max_leb_cnt = c->vi.rsvd_lebs;
 	}
 
+	if (key_file || key_desc) {
+		if (!key_file)
+			return err_msg("no key file specified");
+		if (!key_desc)
+			return err_msg("no key descriptor specified");
+
+		c->double_hash = 1;
+		c->encrypted = 1;
+
+		root_fctx = init_fscrypt_context(FS_POLICY_FLAGS_PAD_4,
+						key_file, key_desc);
+		if (!root_fctx)
+			return -1;
+		print_fscrypt_master_key_descriptor(root_fctx);
+	}
+
 	if (c->min_io_size == -1)
 		return err_msg("min. I/O unit was not specified "
 			       "(use -h for help)");
@@ -2786,8 +2894,6 @@  static int close_target(void)
  */
 static int init(void)
 {
-	__u8 master_key_descriptor[FS_KEY_DESCRIPTOR_SIZE];
-	__u8 nonce[FS_KEY_DERIVATION_NONCE_SIZE];
 	int err, i, main_lebs, big_lpt = 0, sz;
 
 	c->highest_inum = UBIFS_FIRST_INO;
@@ -2829,17 +2935,6 @@  static int init(void)
 	sz = sizeof(struct inum_mapping *) * HASH_TABLE_SIZE;
 	hash_table = xzalloc(sz);
 
-	if (c->encrypted) {
-		RAND_bytes((void *)master_key_descriptor,
-				FS_KEY_DESCRIPTOR_SIZE);
-		RAND_bytes((void *)nonce, FS_KEY_DERIVATION_NONCE_SIZE);
-
-		root_fctx = init_fscrypt_context(FS_POLICY_FLAGS_PAD_4,
-						master_key_descriptor, nonce);
-		print_fscrypt_master_key_descriptor(root_fctx);
-		c->double_hash = 1;
-	}
-
 	err = init_compression();
 	if (err)
 		return err;