Skip to content

Commit 64ffd59

Browse files
committed
fscryptctl: add support for adding key by serial (ID)
Since Linux commit 93edd392ca ("fscrypt: support passing a keyring key to FS_IOC_ADD_ENCRYPTION_KEY"), it's possible to pass the key ID of a "fscrypt-provisioning" key that Linux should retrieve the raw key material from instead of passing it directly from userspace. This is useful to add fscrypt keys after unmounting and re-mounting. It would also prove useful should additional key types like trusted keys be allowed in future. Thus add a new --serial parameter to add_key to facilitate this. --serial was chosen over --id to avoid confusion with the KEY_IDENTIFIER used in the remove_key, key_status and set_policy documentation, which it is not interchangeable with. Signed-off-by: Ahmad Fatoum <[email protected]>
1 parent e863642 commit 64ffd59

File tree

3 files changed

+64
-10
lines changed

3 files changed

+64
-10
lines changed

README.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,12 +74,17 @@ tips](https://github.com/google/fscrypt#getting-encryption-not-enabled-on-an-ext
7474
For full usage details, see the manual page (`man fscryptctl`), or alternatively
7575
run `fscryptctl --help`.
7676

77-
The `add_key` command accepts the encryption key in binary on standard input.
77+
The `add_key` command, by default, accepts the encryption key in binary on
78+
standard input.
7879
It is critical that this be a real cryptographic key (and not a passphrase, for
7980
example), since `fscryptctl` doesn't do key stretching itself. Obviously, don't
8081
store the raw encryption key alongside the encrypted files. (If you need
8182
support for passphrases, use `fscrypt` instead of `fscryptctl`.)
8283

84+
Alternatively, `add_key --serial=$serial` will instruct the kernel to
85+
extract the kernel material from an existing key of type "fscrypt-provisioning"
86+
with the specified $serial (The ID returned and used by keyctl(1)).
87+
8388
After running the `add_key` command to add an encryption key to a filesystem,
8489
you can use the `set_policy` command to create an encrypted directory on that
8590
filesystem. The encryption key is specified by the 32-character hex "key

fscryptctl.1.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ feature, see the references at the end of this page.
4040

4141
# SUBCOMMANDS
4242

43-
## **fscryptctl add_key** *MOUNTPOINT*
43+
## **fscryptctl add_key** [*OPTION*..] *MOUNTPOINT*
4444

4545
Add an encryption key to the given mounted filesystem. This will "unlock" any
4646
files and directories that are protected by the given key on the given
@@ -54,7 +54,13 @@ If successful, **fscryptctl add_key** will print the key identifier of the newly
5454
added key; this will be a 32-character hex string which can be passed to other
5555
**fscryptctl** commands.
5656

57-
**fscryptctl add_key** does not accept any options.
57+
Options accepted by **fscryptctl add_key**:
58+
59+
**\-\-serial**=*SERIAL*
60+
: Don't read raw key material from standard input. Instead, instruct the
61+
kernel to extract key material from an existing key of type
62+
`fscrypt-provisioning` with specified SERIAL. SERIAL is the ID returned
63+
and used by keyctl(1).
5864

5965
## **fscryptctl remove_key** [*OPTION*...] *KEY_IDENTIFIER* *MOUNTPOINT*
6066

fscryptctl.c

Lines changed: 50 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include <errno.h>
2626
#include <fcntl.h>
2727
#include <getopt.h>
28+
#include <limits.h>
2829
#include <stdbool.h>
2930
#include <stdint.h>
3031
#include <stdio.h>
@@ -78,6 +79,7 @@ static const char *const mode_strings[] = {
7879
static const int padding_values[] = {4, 8, 16, 32};
7980

8081
enum {
82+
OPT_KEY_SERIAL,
8183
OPT_ALL_USERS,
8284
OPT_CONTENTS,
8385
OPT_DIRECT_KEY,
@@ -94,8 +96,8 @@ static void __attribute__((__noreturn__)) usage(FILE *out) {
9496
" fscryptctl <command> [arguments] [options]\n"
9597
"\nCommands:\n"
9698
" fscryptctl add_key <mountpoint>\n"
97-
" Read a key from stdin, add it to the specified mounted filesystem,\n"
98-
" and print its identifier.\n"
99+
" Add a key add to the specified mounted filesystem and print its\n"
100+
" identifier. Raw key is read from stdin by default.\n"
99101
" fscryptctl remove_key <key identifier> <mountpoint>\n"
100102
" Remove the key with the specified identifier from the specified\n"
101103
" mounted filesystem.\n"
@@ -112,6 +114,10 @@ static void __attribute__((__noreturn__)) usage(FILE *out) {
112114
" print this help screen\n"
113115
" -v, --version\n"
114116
" print the version of fscrypt\n"
117+
" add_key\n"
118+
" --serial=<serial>\n"
119+
" Instead of reading raw key material over stdin, use the\n"
120+
" payload of an existing \"fscrypt-provisioning\" key.\n"
115121
" remove_key\n"
116122
" --all-users\n"
117123
" force-remove all users' claims to the key (requires root)\n"
@@ -129,7 +135,10 @@ static void __attribute__((__noreturn__)) usage(FILE *out) {
129135
" --iv-ino-lblk-32\n"
130136
" optimize for eMMC inline crypto hardware (not recommended)\n"
131137
"\nNotes:\n"
132-
" Keys are identified by 32-character hex strings (key identifiers).\n"
138+
" fscrypt keys are identified by 32-character hex strings\n"
139+
" (key identifiers).\n"
140+
"\n"
141+
" Key serials are specified as decimal integers that fit into 31 bits.\n"
133142
"\n"
134143
" Raw keys are given on stdin in binary and usually must be 64 bytes.\n"
135144
"\n"
@@ -267,6 +276,16 @@ static bool hex_to_bytes(const char *hex, uint8_t *bytes, size_t num_bytes) {
267276
return true;
268277
}
269278

279+
// Converts a decimal string to a kernel key_serial_t
280+
static int32_t str_to_keyserial(const char *dec) {
281+
char *endp;
282+
unsigned long ret = strtoul(dec, &endp, 10);
283+
if (ret < 1 || ret > INT32_MAX || *endp) {
284+
return -1;
285+
}
286+
return ret;
287+
}
288+
270289
// Builds a 'struct fscrypt_key_specifier' for passing to the kernel, given a
271290
// key identifier hex string.
272291
static bool build_key_specifier(const char *identifier_hex,
@@ -372,7 +391,27 @@ static bool set_policy(const char *path,
372391
// -----------------------------------------------------------------------------
373392

374393
static int cmd_add_key(int argc, char *const argv[]) {
375-
handle_no_options(&argc, &argv);
394+
int32_t serial = 0;
395+
396+
static const struct option add_key_options[] = {
397+
{"serial", required_argument, NULL, OPT_KEY_SERIAL}, {NULL, 0, NULL, 0}};
398+
399+
int ch;
400+
while ((ch = getopt_long(argc, argv, "", add_key_options, NULL)) != -1) {
401+
switch (ch) {
402+
case OPT_KEY_SERIAL:
403+
serial = str_to_keyserial(optarg);
404+
if (serial < 0) {
405+
fputs("error: must specify valid key id\n", stderr);
406+
return EXIT_FAILURE;
407+
}
408+
break;
409+
default:
410+
usage(stderr);
411+
}
412+
}
413+
argc -= optind;
414+
argv += optind;
376415
if (argc != 1) {
377416
fputs("error: must specify a single mountpoint\n", stderr);
378417
return EXIT_FAILURE;
@@ -387,9 +426,13 @@ static int cmd_add_key(int argc, char *const argv[]) {
387426
}
388427

389428
int status = EXIT_FAILURE;
390-
arg->raw_size = read_key(arg->raw);
391-
if (arg->raw_size == 0) {
392-
goto cleanup;
429+
if (serial) {
430+
arg->key_id = serial;
431+
} else {
432+
arg->raw_size = read_key(arg->raw);
433+
if (arg->raw_size == 0) {
434+
goto cleanup;
435+
}
393436
}
394437
arg->key_spec.type = FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER;
395438

0 commit comments

Comments
 (0)