mirror of
https://github.com/libguestfs/libguestfs.git
synced 2026-03-21 22:53:37 +00:00
New APIs: Support for creating LUKS and managing keys.
This commit adds four APIs for creating new LUKS devices and key management. These are: luks_format Format a LUKS device with the default cipher. luks_format_cipher Format with a chosen cipher. luks_add_key Add another key to an existing device. luks_kill_slot Delete a key from an existing device. This enables all the significant functionality of the cryptsetup luks* commands. Note that you can obtain the UUID of a LUKS device already by using vfs-uuid. This also includes a regression test covering all the LUKS functions.
This commit is contained in:
2
TODO
2
TODO
@@ -365,7 +365,5 @@ groups. If it contains, eg., partitions, you cannot access them.
|
||||
We would like to add:
|
||||
|
||||
- An easier way to use this from guestfish.
|
||||
- Ability to create LUKS devices.
|
||||
- Ability to change LUKS keys on existing devices.
|
||||
- Direct access to the /dev/mapper device (eg. if it contains
|
||||
anything apart from VGs).
|
||||
|
||||
204
daemon/luks.c
204
daemon/luks.c
@@ -33,6 +33,49 @@ optgroup_luks_available (void)
|
||||
return prog_exists ("cryptsetup");
|
||||
}
|
||||
|
||||
/* Callers must also call remove_temp (tempfile). */
|
||||
static char *
|
||||
write_key_to_temp (const char *key)
|
||||
{
|
||||
char *tempfile = strdup ("/tmp/luksXXXXXX");
|
||||
if (!tempfile) {
|
||||
reply_with_perror ("strdup");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int fd = mkstemp (tempfile);
|
||||
if (fd == -1) {
|
||||
reply_with_perror ("mkstemp");
|
||||
goto error;
|
||||
}
|
||||
|
||||
size_t len = strlen (key);
|
||||
if (xwrite (fd, key, len) == -1) {
|
||||
reply_with_perror ("write");
|
||||
close (fd);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (close (fd) == -1) {
|
||||
reply_with_perror ("close");
|
||||
goto error;
|
||||
}
|
||||
|
||||
return tempfile;
|
||||
|
||||
error:
|
||||
unlink (tempfile);
|
||||
free (tempfile);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
remove_temp (char *tempfile)
|
||||
{
|
||||
unlink (tempfile);
|
||||
free (tempfile);
|
||||
}
|
||||
|
||||
static int
|
||||
luks_open (const char *device, const char *key, const char *mapname,
|
||||
int readonly)
|
||||
@@ -49,26 +92,9 @@ luks_open (const char *device, const char *key, const char *mapname,
|
||||
return -1;
|
||||
}
|
||||
|
||||
char tempfile[] = "/tmp/luksXXXXXX";
|
||||
int fd = mkstemp (tempfile);
|
||||
if (fd == -1) {
|
||||
reply_with_perror ("mkstemp");
|
||||
char *tempfile = write_key_to_temp (key);
|
||||
if (!tempfile)
|
||||
return -1;
|
||||
}
|
||||
|
||||
len = strlen (key);
|
||||
if (xwrite (fd, key, len) == -1) {
|
||||
reply_with_perror ("write");
|
||||
close (fd);
|
||||
unlink (tempfile);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (close (fd) == -1) {
|
||||
reply_with_perror ("close");
|
||||
unlink (tempfile);
|
||||
return -1;
|
||||
}
|
||||
|
||||
const char *argv[16];
|
||||
size_t i = 0;
|
||||
@@ -84,7 +110,7 @@ luks_open (const char *device, const char *key, const char *mapname,
|
||||
|
||||
char *err;
|
||||
int r = commandv (NULL, &err, (const char * const *) argv);
|
||||
unlink (tempfile);
|
||||
remove_temp (tempfile);
|
||||
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
@@ -136,3 +162,141 @@ do_luks_close (const char *device)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
luks_format (const char *device, const char *key, int keyslot,
|
||||
const char *cipher)
|
||||
{
|
||||
char *tempfile = write_key_to_temp (key);
|
||||
if (!tempfile)
|
||||
return -1;
|
||||
|
||||
const char *argv[16];
|
||||
char keyslot_s[16];
|
||||
size_t i = 0;
|
||||
|
||||
argv[i++] = "cryptsetup";
|
||||
argv[i++] = "-q";
|
||||
if (cipher) {
|
||||
argv[i++] = "--cipher";
|
||||
argv[i++] = cipher;
|
||||
}
|
||||
argv[i++] = "--key-slot";
|
||||
snprintf (keyslot_s, sizeof keyslot_s, "%d", keyslot);
|
||||
argv[i++] = keyslot_s;
|
||||
argv[i++] = "luksFormat";
|
||||
argv[i++] = device;
|
||||
argv[i++] = tempfile;
|
||||
argv[i++] = NULL;
|
||||
|
||||
char *err;
|
||||
int r = commandv (NULL, &err, (const char * const *) argv);
|
||||
remove_temp (tempfile);
|
||||
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
|
||||
udev_settle ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
do_luks_format (const char *device, const char *key, int keyslot)
|
||||
{
|
||||
return luks_format (device, key, keyslot, NULL);
|
||||
}
|
||||
|
||||
int
|
||||
do_luks_format_cipher (const char *device, const char *key, int keyslot,
|
||||
const char *cipher)
|
||||
{
|
||||
return luks_format (device, key, keyslot, cipher);
|
||||
}
|
||||
|
||||
int
|
||||
do_luks_add_key (const char *device, const char *key, const char *newkey,
|
||||
int keyslot)
|
||||
{
|
||||
char *keyfile = write_key_to_temp (key);
|
||||
if (!keyfile)
|
||||
return -1;
|
||||
|
||||
char *newkeyfile = write_key_to_temp (newkey);
|
||||
if (!newkeyfile) {
|
||||
remove_temp (keyfile);
|
||||
return -1;
|
||||
}
|
||||
|
||||
const char *argv[16];
|
||||
char keyslot_s[16];
|
||||
size_t i = 0;
|
||||
|
||||
argv[i++] = "cryptsetup";
|
||||
argv[i++] = "-q";
|
||||
argv[i++] = "-d";
|
||||
argv[i++] = keyfile;
|
||||
argv[i++] = "--key-slot";
|
||||
snprintf (keyslot_s, sizeof keyslot_s, "%d", keyslot);
|
||||
argv[i++] = keyslot_s;
|
||||
argv[i++] = "luksAddKey";
|
||||
argv[i++] = device;
|
||||
argv[i++] = newkeyfile;
|
||||
argv[i++] = NULL;
|
||||
|
||||
char *err;
|
||||
int r = commandv (NULL, &err, (const char * const *) argv);
|
||||
remove_temp (keyfile);
|
||||
remove_temp (newkeyfile);
|
||||
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
do_luks_kill_slot (const char *device, const char *key, int keyslot)
|
||||
{
|
||||
char *tempfile = write_key_to_temp (key);
|
||||
if (!tempfile)
|
||||
return -1;
|
||||
|
||||
const char *argv[16];
|
||||
char keyslot_s[16];
|
||||
size_t i = 0;
|
||||
|
||||
argv[i++] = "cryptsetup";
|
||||
argv[i++] = "-q";
|
||||
argv[i++] = "-d";
|
||||
argv[i++] = tempfile;
|
||||
argv[i++] = "luksKillSlot";
|
||||
argv[i++] = device;
|
||||
snprintf (keyslot_s, sizeof keyslot_s, "%d", keyslot);
|
||||
argv[i++] = keyslot_s;
|
||||
argv[i++] = NULL;
|
||||
|
||||
char *err;
|
||||
int r = commandv (NULL, &err, (const char * const *) argv);
|
||||
remove_temp (tempfile);
|
||||
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free (err);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ TESTS = \
|
||||
test-cancellation-download-librarycancels.sh \
|
||||
test-cancellation-upload-daemoncancels.sh \
|
||||
test-find0.sh \
|
||||
test-luks.sh \
|
||||
test-lvm-filtering.sh \
|
||||
test-lvm-mapping.pl \
|
||||
test-noexec-stack.pl \
|
||||
|
||||
88
regressions/test-luks.sh
Executable file
88
regressions/test-luks.sh
Executable file
@@ -0,0 +1,88 @@
|
||||
#!/bin/bash -
|
||||
# libguestfs
|
||||
# Copyright (C) 2010 Red Hat Inc.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
# Test LUKS device creation, opening, key slots.
|
||||
|
||||
set -e
|
||||
|
||||
rm -f test1.img
|
||||
|
||||
../fish/guestfish --keys-from-stdin <<EOF
|
||||
sparse test1.img 1G
|
||||
run
|
||||
part-disk /dev/sda mbr
|
||||
|
||||
# Create LUKS device with key "key0" in slot 0.
|
||||
luks-format /dev/sda1 0
|
||||
key0
|
||||
|
||||
# Open the device.
|
||||
luks-open /dev/sda1 lukstest
|
||||
key0
|
||||
|
||||
# Put some LVM structures on the encrypted device.
|
||||
pvcreate /dev/mapper/lukstest
|
||||
vgcreate VG /dev/mapper/lukstest
|
||||
lvcreate LV1 VG 64
|
||||
lvcreate LV2 VG 64
|
||||
vg-activate-all false
|
||||
|
||||
# Close the device.
|
||||
luks-close /dev/mapper/lukstest
|
||||
|
||||
# Add keys in other slots.
|
||||
luks-add-key /dev/sda1 1
|
||||
key0
|
||||
key1
|
||||
luks-add-key /dev/sda1 2
|
||||
key1
|
||||
key2
|
||||
luks-add-key /dev/sda1 3
|
||||
key2
|
||||
key3
|
||||
|
||||
# Check we can open the device with one of the new keys.
|
||||
luks-open /dev/sda1 lukstest
|
||||
key1
|
||||
luks-close /dev/mapper/lukstest
|
||||
luks-open /dev/sda1 lukstest
|
||||
key3
|
||||
luks-close /dev/mapper/lukstest
|
||||
|
||||
# Remove a key.
|
||||
luks-kill-slot /dev/sda1 1
|
||||
key0
|
||||
|
||||
# This is expected to fail.
|
||||
-luks-open /dev/sda1 lukstest
|
||||
key1
|
||||
|
||||
# Replace a key slot.
|
||||
luks-kill-slot /dev/sda1 3
|
||||
key2
|
||||
luks-add-key /dev/sda1 3
|
||||
key2
|
||||
newkey3
|
||||
|
||||
luks-open /dev/sda1 lukstest
|
||||
newkey3
|
||||
luks-close /dev/mapper/lukstest
|
||||
|
||||
EOF
|
||||
|
||||
rm -f test1.img
|
||||
@@ -1 +1 @@
|
||||
259
|
||||
263
|
||||
|
||||
@@ -4916,6 +4916,43 @@ C<device> parameter must be the name of the LUKS mapping
|
||||
device (ie. C</dev/mapper/mapname>) and I<not> the name
|
||||
of the underlying block device.");
|
||||
|
||||
("luks_format", (RErr, [Device "device"; Key "key"; Int "keyslot"]), 260, [Optional "luks"; DangerWillRobinson],
|
||||
[],
|
||||
"format a block device as a LUKS encrypted device",
|
||||
"\
|
||||
This command erases existing data on C<device> and formats
|
||||
the device as a LUKS encrypted device. C<key> is the
|
||||
initial key, which is added to key slot C<slot>. (LUKS
|
||||
supports 8 key slots, numbered 0-7).");
|
||||
|
||||
("luks_format_cipher", (RErr, [Device "device"; Key "key"; Int "keyslot"; String "cipher"]), 261, [Optional "luks"; DangerWillRobinson],
|
||||
[],
|
||||
"format a block device as a LUKS encrypted device",
|
||||
"\
|
||||
This command is the same as C<guestfs_luks_format> but
|
||||
it also allows you to set the C<cipher> used.");
|
||||
|
||||
("luks_add_key", (RErr, [Device "device"; Key "key"; Key "newkey"; Int "keyslot"]), 262, [Optional "luks"],
|
||||
[],
|
||||
"add a key on a LUKS encrypted device",
|
||||
"\
|
||||
This command adds a new key on LUKS device C<device>.
|
||||
C<key> is any existing key, and is used to access the device.
|
||||
C<newkey> is the new key to add. C<keyslot> is the key slot
|
||||
that will be replaced.
|
||||
|
||||
Note that if C<keyslot> already contains a key, then this
|
||||
command will fail. You have to use C<guestfs_luks_kill_slot>
|
||||
first to remove that key.");
|
||||
|
||||
("luks_kill_slot", (RErr, [Device "device"; Key "key"; Int "keyslot"]), 263, [Optional "luks"],
|
||||
[],
|
||||
"remove a key from a LUKS encrypted device",
|
||||
"\
|
||||
This command deletes the key in key slot C<keyslot> from the
|
||||
encrypted LUKS device C<device>. C<key> must be one of the
|
||||
I<other> keys.");
|
||||
|
||||
]
|
||||
|
||||
let all_functions = non_daemon_functions @ daemon_functions
|
||||
|
||||
Reference in New Issue
Block a user