diff --git a/lib/libcryptsetup.h b/lib/libcryptsetup.h index f7d56a3f..52e11671 100644 --- a/lib/libcryptsetup.h +++ b/lib/libcryptsetup.h @@ -1469,6 +1469,17 @@ crypt_status_info crypt_status(struct crypt_device *cd, const char *name); */ int crypt_dump(struct crypt_device *cd); +/** + * Dump JSON-formatted information about LUKS2 device + * + * @param cd crypt device handle (only LUKS2 format supported) + * @param json buffer with JSON, if NULL use log callback for output + * @param flags dump flags (reserved) + * + * @return @e 0 on success or negative errno value otherwise. + */ +int crypt_dump_json(struct crypt_device *cd, const char **json, uint32_t flags); + /** * Get cipher used in device. * diff --git a/lib/libcryptsetup.sym b/lib/libcryptsetup.sym index 1f94b8d2..0a801d76 100644 --- a/lib/libcryptsetup.sym +++ b/lib/libcryptsetup.sym @@ -5,6 +5,7 @@ CRYPTSETUP_2.4 { crypt_header_is_detached; crypt_logf; crypt_activate_by_pin_token; + crypt_dump_json; }; CRYPTSETUP_2.0 { diff --git a/lib/luks2/luks2.h b/lib/luks2/luks2.h index ccd7b373..565f0f8c 100644 --- a/lib/luks2/luks2.h +++ b/lib/luks2/luks2.h @@ -158,6 +158,7 @@ int LUKS2_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr, int repair); int LUKS2_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr); int LUKS2_hdr_write_force(struct crypt_device *cd, struct luks2_hdr *hdr); int LUKS2_hdr_dump(struct crypt_device *cd, struct luks2_hdr *hdr); +int LUKS2_hdr_dump_json(struct crypt_device *cd, struct luks2_hdr *hdr, const char **json); int LUKS2_hdr_uuid(struct crypt_device *cd, struct luks2_hdr *hdr, diff --git a/lib/luks2/luks2_json_metadata.c b/lib/luks2/luks2_json_metadata.c index c9bd8f93..b57b5a80 100644 --- a/lib/luks2/luks2_json_metadata.c +++ b/lib/luks2/luks2_json_metadata.c @@ -1744,6 +1744,24 @@ int LUKS2_hdr_dump(struct crypt_device *cd, struct luks2_hdr *hdr) return 0; } +int LUKS2_hdr_dump_json(struct crypt_device *cd, struct luks2_hdr *hdr, const char **json) +{ + const char *json_buf; + + json_buf = json_object_to_json_string_ext(hdr->jobj, + JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_NOSLASHESCAPE); + + if (!json_buf) + return -EINVAL; + + if (json) + *json = json_buf; + else + crypt_log(cd, CRYPT_LOG_NORMAL, json_buf); + + return 0; +} + int LUKS2_get_data_size(struct luks2_hdr *hdr, uint64_t *size, bool *dynamic) { int sector_size; diff --git a/lib/setup.c b/lib/setup.c index 925eb466..313f12ba 100644 --- a/lib/setup.c +++ b/lib/setup.c @@ -4920,6 +4920,17 @@ int crypt_dump(struct crypt_device *cd) return -EINVAL; } +int crypt_dump_json(struct crypt_device *cd, const char **json, uint32_t flags) +{ + if (!cd || flags) + return -EINVAL; + if (isLUKS2(cd->type)) + return LUKS2_hdr_dump_json(cd, &cd->u.luks2.hdr, json); + + log_err(cd, _("Dump operation is not supported for this device type.")); + return -EINVAL; +} + /* internal only */ const char *crypt_get_cipher_spec(struct crypt_device *cd) { diff --git a/man/cryptsetup.8 b/man/cryptsetup.8 index 5481a13c..3b249643 100644 --- a/man/cryptsetup.8 +++ b/man/cryptsetup.8 @@ -502,7 +502,10 @@ To dump unbound key (LUKS2 format only), \-\-unbound parameter, specific \-\-key id and proper passphrase has to be supplied, either interactively or via \-\-key\-file. Optional \-\-master\-key\-file parameter enables unbound keyslot dump to a file. -\fB\fR can be [\-\-dump\-master\-key, \-\-key\-file, +To dump LUKS2 JSON metadata (without basic heade information like UUID) use +\-\-dump\-json\-metadata option. + +\fB\fR can be [\-\-dump\-master\-key, \-\-dump\-json\-metadata, \-\-key\-file, \-\-keyfile\-offset, \-\-keyfile\-size, \-\-header, \-\-disable\-locks, \-\-master\-key\-file, \-\-type, \-\-unbound, \-\-key-slot]. @@ -976,6 +979,10 @@ without having to know an existing one. For \fIopen\fR this allows one to open the LUKS device without giving a passphrase. .TP +.B "\-\-dump\-json\-metadata" +For \fIluksDump\fR (LUKS2 only) this option prints content +of LUKS2 header JSON metadata area. +.TP .B "\-\-dump\-master\-key" For \fIluksDump\fR this option includes the master key in the displayed information. Use with care, as the master key can be used to diff --git a/src/cryptsetup.c b/src/cryptsetup.c index cc03dc02..8012b387 100644 --- a/src/cryptsetup.c +++ b/src/cryptsetup.c @@ -2194,6 +2194,8 @@ static int action_luksDump(void) r = luksDump_with_volume_key(cd); else if (ARG_SET(OPT_UNBOUND_ID)) r = luksDump_with_unbound_key(cd); + else if (ARG_SET(OPT_DUMP_JSON_ID)) + r = crypt_dump_json(cd, NULL, 0); else r = crypt_dump(cd); out: diff --git a/src/cryptsetup_arg_list.h b/src/cryptsetup_arg_list.h index 46960892..c688048c 100644 --- a/src/cryptsetup_arg_list.h +++ b/src/cryptsetup_arg_list.h @@ -47,6 +47,8 @@ ARG(OPT_DISABLE_KEYRING, '\0', POPT_ARG_NONE, N_("Disable loading volume keys vi ARG(OPT_DISABLE_LOCKS, '\0', POPT_ARG_NONE, N_("Disable locking of on-disk metadata"), NULL, CRYPT_ARG_BOOL, {}, {}) +ARG(OPT_DUMP_JSON, '\0', POPT_ARG_NONE, N_("Dump info in JSON format (LUKS2 only)"), NULL, CRYPT_ARG_BOOL, {}, {}) + ARG(OPT_DUMP_MASTER_KEY, '\0', POPT_ARG_NONE, N_("Dump volume (master) key instead of keyslots info"), NULL, CRYPT_ARG_BOOL, {}, {}) ARG(OPT_ENCRYPT, '\0', POPT_ARG_NONE, N_("Encrypt LUKS2 device (in-place encryption)."), NULL, CRYPT_ARG_BOOL, {}, {}) diff --git a/src/utils_arg_names.h b/src/utils_arg_names.h index fc7c1ade..f3efa8c8 100644 --- a/src/utils_arg_names.h +++ b/src/utils_arg_names.h @@ -43,6 +43,7 @@ #define OPT_DECRYPT "decrypt" #define OPT_DISABLE_KEYRING "disable-keyring" #define OPT_DISABLE_LOCKS "disable-locks" +#define OPT_DUMP_JSON "dump-json-metadata" #define OPT_DUMP_MASTER_KEY "dump-master-key" #define OPT_ENCRYPT "encrypt" #define OPT_FEC_DEVICE "fec-device" diff --git a/tests/api-test-2.c b/tests/api-test-2.c index 02281a7e..8d6281cc 100644 --- a/tests/api-test-2.c +++ b/tests/api-test-2.c @@ -626,7 +626,7 @@ static void AddDeviceLuks2(void) }; char key[128], key2[128], key3[128]; - const char *passphrase = "blabla", *passphrase2 = "nsdkFI&Y#.sd"; + const char *tmp_buf, *passphrase = "blabla", *passphrase2 = "nsdkFI&Y#.sd"; const char *mk_hex = "bb21158c733229347bd4e681891e213d94c685be6a5b84818afe7a78a6de7a1a"; const char *mk_hex2 = "bb21158c733229347bd4e681891e213d94c685be6a5b84818afe7a78a6de7a1e"; size_t key_size = strlen(mk_hex) / 2; @@ -875,6 +875,14 @@ static void AddDeviceLuks2(void) OK_(!(global_lines != 0)); reset_log(); + FAIL_(crypt_dump_json(cd, NULL, 42), "flags be used later"); + OK_(crypt_dump_json(cd, NULL, 0)); + OK_(!(global_lines != 0)); + reset_log(); + OK_(crypt_dump_json(cd, &tmp_buf, 0)); + OK_(!tmp_buf); + OK_(!(strlen(tmp_buf) != 0)); + FAIL_(crypt_set_uuid(cd, "blah"), "wrong UUID format"); OK_(crypt_set_uuid(cd, DEVICE_TEST_UUID)); OK_(strcmp(DEVICE_TEST_UUID, crypt_get_uuid(cd))); diff --git a/tests/api-test.c b/tests/api-test.c index ef721aed..ea06916b 100644 --- a/tests/api-test.c +++ b/tests/api-test.c @@ -999,6 +999,7 @@ static void AddDeviceLuks(void) OK_(crypt_dump(cd)); OK_(!(global_lines != 0)); reset_log(); + FAIL_(crypt_dump_json(cd, NULL, 0), "LUKS1 not supported"); FAIL_(crypt_set_uuid(cd, "blah"), "wrong UUID format"); OK_(crypt_set_uuid(cd, DEVICE_TEST_UUID)); diff --git a/tests/compat-test2 b/tests/compat-test2 index 9862dc87..e33002e7 100755 --- a/tests/compat-test2 +++ b/tests/compat-test2 @@ -317,6 +317,8 @@ echo $PWD1 | $CRYPTSETUP -q $FAST_PBKDF_OPT -c aes-cbc-essiv:sha256 -s 128 luksF prepare "[4] format using hash sha512" wipe echo $PWD1 | $CRYPTSETUP $FAST_PBKDF_OPT -h sha512 -c aes-cbc-essiv:sha256 -s 128 luksFormat --type luks2 $LOOPDEV || fail $CRYPTSETUP -q luksDump $LOOPDEV | grep "0: pbkdf2" -A2 | grep "Hash:" | grep -qe sha512 || fail +# Check JSON dump for some mandatory section +$CRYPTSETUP -q luksDump $LOOPDEV --dump-json-metadata | grep -q '\"tokens\":' || fail prepare "[5] open" echo $PWD1 | $CRYPTSETUP luksOpen $LOOPDEV $DEV_NAME --test-passphrase || fail @@ -751,6 +753,7 @@ $CRYPTSETUP luksDump $LOOPDEV | grep -q "5: luks2" && fail prepare "[31] LUKS convert" wipe $CRYPTSETUP -q luksFormat $FAST_PBKDF_OPT --type luks1 $LOOPDEV $KEY5 --key-slot 5 || fail $CRYPTSETUP luksAddKey $FAST_PBKDF_OPT -S 1 -d $KEY5 $LOOPDEV $KEY1 || fail +$CRYPTSETUP -q luksDump $LOOPDEV --dump-json-metadata >/dev/null 2>&1 && fail $CRYPTSETUP -q convert --type luks1 $LOOPDEV >/dev/null 2>&1 && fail $CRYPTSETUP luksDump $LOOPDEV | grep -q "Key Slot 1: ENABLED" || fail $CRYPTSETUP luksDump $LOOPDEV | grep -q "Key Slot 5: ENABLED" || fail