Commit c9881f8c authored by Milan Broz's avatar Milan Broz

* Add crypt_get_type(), crypt_resize(), crypt_keyslot_max()

and crypt_get_active_device() to API.
* Rewrite all implementations in cryptsetup to new API.
* Fix luksRemoveKey to behave as documented (do not ask
for remaining keyslot passphrase).
* Add more regression tests for commands.

git-svn-id: https://cryptsetup.googlecode.com/svn/trunk@360 36d66b0a-2a48-0410-832c-cd162a569da5
parent 7b42e0b9
2010-11-01 Milan Broz <mbroz@redhat.com>
* No longer support luksDelKey, reload and --non-exclusive.
* Remove some obsolete info from man page.
* Add crypt_get_type(), crypt_resize(), crypt_keyslot_max()
and crypt_get_active_device() to API.
* Rewrite all implementations in cryptsetup to new API.
* Fix luksRemoveKey to behave as documented (do not ask
for remaining keyslot passphrase).
* Add more regression tests for commands.
2010-10-27 Milan Broz <mbroz@redhat.com>
* Rewrite cryptsetup luksFormat, luksOpen, luksAddKey to use new API
......
......@@ -144,6 +144,15 @@ int crypt_memory_lock(struct crypt_device *cd, int lock);
#define CRYPT_PLAIN "PLAIN" /* regular crypt device, no on-disk header */
#define CRYPT_LUKS1 "LUKS1" /* LUKS version 1 header on-disk */
/**
* Get device type
*
* @cd - crypt device handle
*
* Return string according to device type or NULL if not known.
*/
const char *crypt_get_type(struct crypt_device *cd);
struct crypt_params_plain {
const char *hash; /* password hash function */
uint64_t offset; /* offset in sectors */
......@@ -206,6 +215,19 @@ int crypt_load(struct crypt_device *cd,
const char *requested_type,
void *params);
/**
* Resize crypt device
*
* Returns 0 on success or negative errno value otherwise.
*
* @cd - crypt device handle
* @name - name of device to resize
* @new_size - new device size in sectors or 0 to use underlying device size
*/
int crypt_resize(struct crypt_device *cd,
const char *name,
uint64_t new_size);
/**
* Suspends crypt device.
*
......@@ -278,6 +300,16 @@ int crypt_keyslot_add_by_passphrase(struct crypt_device *cd,
const char *new_passphrase,
size_t new_passphrase_size);
/**
* Get number of keyslots supported for device type.
*
* Returns slot count or negative errno otherwise if device
* doesn't not support keyslots.
*
* @type - crypt device type
*/
int crypt_keyslot_max(const char *type);
/**
* Add key slot using provided key file path
*
......@@ -336,6 +368,32 @@ int crypt_keyslot_destroy(struct crypt_device *cd, int keyslot);
#define CRYPT_ACTIVATE_READONLY (1 << 0)
#define CRYPT_ACTIVATE_NO_UUID (1 << 1)
/**
* Active device runtime attributes
*/
struct crypt_active_device {
uint64_t offset; /* offset in sectors */
uint64_t iv_offset; /* IV initilisation sector */
uint64_t size; /* active device size */
uint32_t flags; /* activation flags */
};
/**
* Receives runtime attributes of active crypt device
*
* Returns 0 on success or negative errno value otherwise.
*
* @cd - crypt device handle
* @name - name of active device
* @cad - preallocated active device attributes to fill
*
* Note that this is old API function using global context.
* All error messages are reported also through log callback.
*/
int crypt_get_active_device(struct crypt_device *cd,
const char *name,
struct crypt_active_device *cad);
/**
* Activate device or check passphrase
*
......
......@@ -14,6 +14,7 @@ CRYPTSETUP_1.0 {
crypt_memory_lock;
crypt_format;
crypt_load;
crypt_resize;
crypt_suspend;
crypt_resume_by_passphrase;
crypt_resume_by_keyfile;
......@@ -38,9 +39,13 @@ CRYPTSETUP_1.0 {
crypt_get_volume_key_size;
crypt_get_device_name;
crypt_get_type;
crypt_get_active_device;
crypt_set_rng_type;
crypt_get_rng_type;
crypt_keyslot_max;
crypt_keyslot_status;
crypt_get_error;
crypt_get_dir;
......
......@@ -990,8 +990,11 @@ int crypt_init(struct crypt_device **cd, const char *device)
int crypt_init_by_name(struct crypt_device **cd, const char *name)
{
crypt_status_info ci;
char *device = NULL;
int r;
struct crypt_active_device cad;
char *device = NULL, *cipher_full = NULL, *device_uuid = NULL;
char cipher[MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN];
int key_size = 0, r;
log_dbg("Allocating crypt device context by device %s.", name);
......@@ -1004,8 +1007,9 @@ int crypt_init_by_name(struct crypt_device **cd, const char *name)
return -ENODEV;
}
r = dm_query_device(name, &device, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL);
r = dm_query_device(name, &device, &cad.size, &cad.iv_offset, &cad.offset,
&cipher_full, &key_size, NULL, NULL, NULL,
&device_uuid);
/* Underlying device disappeared but mapping still active */
if (r >= 0 && !device)
......@@ -1015,7 +1019,32 @@ int crypt_init_by_name(struct crypt_device **cd, const char *name)
if (r >= 0)
r = crypt_init(cd, device);
/* Try to initialise basic parameters from active device */
if (!r && *device_uuid) {
if (!strncmp(CRYPT_PLAIN, device_uuid, sizeof(CRYPT_PLAIN)-1)) {
(*cd)->type = strdup(CRYPT_PLAIN);
(*cd)->plain_uuid = strdup(device_uuid);
(*cd)->plain_hdr.hash = NULL; /* no way to get this */
(*cd)->plain_hdr.offset = cad.offset;
(*cd)->plain_hdr.skip = cad.iv_offset;
(*cd)->volume_key = crypt_alloc_volume_key(key_size, NULL);
if (!(*cd)->volume_key)
r = -ENOMEM;
r = crypt_parse_name_and_mode(cipher_full, cipher, cipher_mode);
if (!r) {
(*cd)->plain_cipher = strdup(cipher);
(*cd)->plain_cipher_mode = strdup(cipher_mode);
}
} else if (!strncmp(CRYPT_LUKS1, device_uuid, sizeof(CRYPT_LUKS1)-1)) {
if (device)
r = crypt_load(*cd, CRYPT_LUKS1, NULL);
}
}
free(device);
free(cipher_full);
free(device_uuid);
return r;
}
......@@ -1186,6 +1215,53 @@ int crypt_load(struct crypt_device *cd,
return r;
}
int crypt_resize(struct crypt_device *cd, const char *name, uint64_t new_size)
{
char *device = NULL, *cipher = NULL, *uuid = NULL, *key = NULL;
uint64_t size, skip, offset;
int key_size, read_only, r;
/* Device context type must be initialised */
if (!cd->type || !crypt_get_uuid(cd))
return -EINVAL;
r = dm_query_device(name, &device, &size, &skip, &offset,
&cipher, &key_size, &key, &read_only, NULL, &uuid);
if (r < 0) {
log_err(NULL, _("Device %s is not active.\n"), name);
goto out;
}
if (!uuid) {
r = -EINVAL;
goto out;
}
r = device_check_and_adjust(cd, device, &new_size, &offset, &read_only);
if (r)
goto out;
if (new_size == size) {
log_dbg("Device has already requested size %" PRIu64
" sectors.", size);
r = 0;
goto out;
}
log_dbg("Resizing device %s to %" PRIu64 " sectors.", name, new_size);
r = dm_create_device(name, device, cipher, cd->type,
crypt_get_uuid(cd), new_size, skip, offset,
key_size, key, read_only, 1);
out:
crypt_safe_free(key);
free(cipher);
free(device);
free(uuid);
return r;
}
int crypt_set_uuid(struct crypt_device *cd, const char *uuid)
{
if (!isLUKS(cd->type)) {
......@@ -2069,6 +2145,9 @@ const char *crypt_get_uuid(struct crypt_device *cd)
if (isLUKS(cd->type))
return cd->hdr.uuid;
if (isPLAIN(cd->type))
return cd->plain_uuid;
return NULL;
}
......@@ -2079,7 +2158,7 @@ const char *crypt_get_device_name(struct crypt_device *cd)
int crypt_get_volume_key_size(struct crypt_device *cd)
{
if (isPLAIN(cd->type))
if (isPLAIN(cd->type) && cd->volume_key)
return cd->volume_key->keylength;
if (isLUKS(cd->type))
......@@ -2108,3 +2187,32 @@ crypt_keyslot_info crypt_keyslot_status(struct crypt_device *cd, int keyslot)
return LUKS_keyslot_info(&cd->hdr, keyslot);
}
int crypt_keyslot_max(const char *type)
{
if (type && isLUKS(type))
return LUKS_NUMKEYS;
return -EINVAL;
}
const char *crypt_get_type(struct crypt_device *cd)
{
return cd->type;
}
int crypt_get_active_device(struct crypt_device *cd,
const char *name,
struct crypt_active_device *cad)
{
int r, readonly;
r = dm_query_device(name, NULL, &cad->size, &cad->iv_offset, &cad->offset,
NULL, NULL, NULL, &readonly, NULL, NULL);
if (r < 0)
return r;
cad->flags = readonly ? CRYPT_ACTIVATE_READONLY : 0;
return 0;
}
......@@ -22,11 +22,13 @@ int crypt_parse_name_and_mode(const char *s, char *cipher, char *cipher_mode)
{
if (sscanf(s, "%" MAX_CIPHER_LEN_STR "[^-]-%" MAX_CIPHER_LEN_STR "s",
cipher, cipher_mode) == 2) {
if (!strcmp(cipher_mode, "plain"))
strncpy(cipher_mode, "cbc-plain", 10);
return 0;
}
if (sscanf(s, "%" MAX_CIPHER_LEN_STR "[^-]", cipher) == 1) {
strncpy(cipher_mode, "cbc-plain", 9);
strncpy(cipher_mode, "cbc-plain", 10);
return 0;
}
......
......@@ -664,7 +664,7 @@ static int LUKS_open_key(const char *device,
if(r < 0) goto out;
r = LUKS_verify_volume_key(hdr, vk);
if (r >= 0)
if (!r)
log_verbose(ctx, _("Key slot %d unlocked.\n"), keyIndex);
out:
free(AfKey);
......@@ -684,8 +684,10 @@ int LUKS_open_key_with_hdr(const char *device,
*vk = crypt_alloc_volume_key(hdr->keyBytes, NULL);
if (keyIndex >= 0)
return LUKS_open_key(device, keyIndex, password, passwordLen, hdr, *vk, ctx);
if (keyIndex >= 0) {
r = LUKS_open_key(device, keyIndex, password, passwordLen, hdr, *vk, ctx);
return (r < 0) ? r : keyIndex;
}
for(i = 0; i < LUKS_NUMKEYS; i++) {
r = LUKS_open_key(device, i, password, passwordLen, hdr, *vk, ctx);
......
This diff is collapsed.
......@@ -8,6 +8,7 @@ DEV_NAME2=dummy2
ORIG_IMG=luks-test-orig
IMG=luks-test
KEY1=key1
KEY2=key2
LUKS_HEADER="S0-5 S6-7 S8-39 S40-71 S72-103 S104-107 S108-111 R112-131 R132-163 S164-167 S168-207 A0-591"
KEY_SLOT0="S208-211 S212-215 R216-247 A248-251 A251-255"
......@@ -25,7 +26,7 @@ function remove_mapping()
[ -b /dev/mapper/$DEV_NAME2 ] && dmsetup remove $DEV_NAME2
[ -b /dev/mapper/$DEV_NAME ] && dmsetup remove $DEV_NAME
losetup -d $LOOPDEV >/dev/null 2>&1
rm -f $ORIG_IMG $IMG $KEY1 >/dev/null 2>&1
rm -f $ORIG_IMG $IMG $KEY1 $KEY2 >/dev/null 2>&1
}
function fail()
......@@ -63,6 +64,10 @@ function prepare()
dd if=/dev/urandom of=$KEY1 count=1 bs=32 >/dev/null 2>&1
fi
if [ ! -e $KEY2 ]; then
dd if=/dev/urandom of=$KEY2 count=1 bs=16 >/dev/null 2>&1
fi
cp $IMG $ORIG_IMG
[ -n "$1" ] && echo "CASE: $1"
}
......@@ -192,5 +197,64 @@ $CRYPTSETUP -q luksFormat --master-key-file /dev/urandom -s 128 --uuid $TEST_UUI
$CRYPTSETUP luksOpen -d $KEY1 $LOOPDEV $DEV_NAME || fail
$CRYPTSETUP -q luksClose $DEV_NAME || fail
prepare "[17] AddKey passphrase and keyfile" wipe
# [0]key0 [1]key1 [2]$KEY1/1 [3]$KEY1 [4]$KEY2
$CRYPTSETUP -q luksFormat $LOOPDEV $KEY1 --key-slot 3 || fail
$CRYPTSETUP luksDump $LOOPDEV | grep -q "Key Slot 3: ENABLED" || fail
$CRYPTSETUP luksAddKey $LOOPDEV -d $KEY1 $KEY2 --key-slot 3 2>/dev/null && fail
# keyfile/keyfile
$CRYPTSETUP luksAddKey $LOOPDEV -d $KEY1 $KEY2 --key-slot 4 || fail
$CRYPTSETUP luksDump $LOOPDEV | grep -q "Key Slot 4: ENABLED" || fail
# passphrase/keyfile
echo "key0" | $CRYPTSETUP luksAddKey $LOOPDEV -d $KEY1 --key-slot 0 || fail
$CRYPTSETUP luksDump $LOOPDEV | grep -q "Key Slot 0: ENABLED" || fail
# passphrase/passphrase
echo -e "key0\nkey1\n" | $CRYPTSETUP luksAddKey $LOOPDEV --key-slot 1 || fail
$CRYPTSETUP luksDump $LOOPDEV | grep -q "Key Slot 1: ENABLED" || fail
# keyfile/passphrase
echo -e "key1\n" | $CRYPTSETUP luksAddKey $LOOPDEV $KEY1 --key-slot 2 --new-keyfile-size 1 || fail
$CRYPTSETUP luksDump $LOOPDEV | grep -q "Key Slot 2: ENABLED" || fail
prepare "[18] RemoveKey passphrase and keyfile" reuse
$CRYPTSETUP luksRemoveKey $LOOPDEV $KEY1 || fail
$CRYPTSETUP luksDump $LOOPDEV | grep -q "Key Slot 3: DISABLED" || fail
$CRYPTSETUP luksRemoveKey $LOOPDEV $KEY1 2>/dev/null && fail
$CRYPTSETUP luksRemoveKey $LOOPDEV $KEY2 --keyfile-size 1 2>/dev/null && fail
$CRYPTSETUP luksRemoveKey $LOOPDEV $KEY2 || fail
$CRYPTSETUP luksDump $LOOPDEV | grep -q "Key Slot 4: DISABLED" || fail
# kill slot using passphrase from 1
echo "key1" | $CRYPTSETUP luksKillSlot $LOOPDEV 2 || fail
$CRYPTSETUP luksDump $LOOPDEV | grep -q "Key Slot 2: DISABLED" || fail
# remove key0 / slot 0
echo "key0" | $CRYPTSETUP luksRemoveKey $LOOPDEV || fail
$CRYPTSETUP luksDump $LOOPDEV | grep -q "Key Slot 0: DISABLED" || fail
# last keyslot, in batch mode no passphrase needed...
$CRYPTSETUP luksKillSlot -q $LOOPDEV 1 || fail
$CRYPTSETUP luksDump $LOOPDEV | grep -q "Key Slot 1: DISABLED" || fail
prepare "[19] create & status & resize" wipe
echo "key0" | $CRYPTSETUP create $DEV_NAME $LOOPDEV --hash xxx 2>/dev/null && fail
echo "key0" | $CRYPTSETUP create $DEV_NAME $LOOPDEV --hash sha1 --cipher aes-cbc-essiv:sha256 --offset 3 --skip 4 --readonly || fail
$CRYPTSETUP -q status $DEV_NAME | grep "offset:" | grep -q "3 sectors" || fail
$CRYPTSETUP -q status $DEV_NAME | grep "skipped:" | grep -q "4 sectors" || fail
$CRYPTSETUP -q status $DEV_NAME | grep "mode:" | grep -q "readonly" || fail
$CRYPTSETUP -q resize $DEV_NAME --size 100 || fail
$CRYPTSETUP -q status $DEV_NAME | grep "size:" | grep -q "100 sectors" || fail
$CRYPTSETUP -q resize $DEV_NAME || fail
$CRYPTSETUP -q status $DEV_NAME | grep "size:" | grep -q "19997 sectors" || fail
$CRYPTSETUP -q remove $DEV_NAME || fail
echo "key0" | $CRYPTSETUP create $DEV_NAME $LOOPDEV || fail
$CRYPTSETUP -q remove $DEV_NAME || fail
echo "key0" | $CRYPTSETUP -q create $DEV_NAME $LOOPDEV || fail
$CRYPTSETUP -q remove $DEV_NAME || fail
# verify is ignored on non-tty input
echo "key0" | $CRYPTSETUP create $DEV_NAME $LOOPDEV --verify-passphrase || fail
$CRYPTSETUP -q remove $DEV_NAME || fail
$CRYPTSETUP create $DEV_NAME $LOOPDEV -d $KEY1 --key-size 255 2>/dev/null && fail
$CRYPTSETUP create $DEV_NAME $LOOPDEV -d $KEY1 || fail
$CRYPTSETUP create $DEV_NAME $LOOPDEV -d $KEY1 2>/dev/null && fail
$CRYPTSETUP create $DEV_NAME $LOOPDEV -d blah 2>/dev/null && fail
$CRYPTSETUP -q remove $DEV_NAME || fail
remove_mapping
exit 0
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment