From 865b1dc66ee059cde534e0ce20af2211128cee4f Mon Sep 17 00:00:00 2001 From: Ondrej Kozina Date: Fri, 12 Jan 2018 14:58:26 +0100 Subject: [PATCH] Add kernel key compat tests. This test can detect ugly dm-crypt kernel key bug present in kernels 4.10.0 through 4.15.0-rc8. --- tests/Makefile.am | 2 + tests/keyring-compat-test | 183 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 185 insertions(+) create mode 100755 tests/keyring-compat-test diff --git a/tests/Makefile.am b/tests/Makefile.am index 1f6d956f..11e0e180 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -11,6 +11,7 @@ TESTS = api-test \ luks1-compat-test \ device-test \ keyring-test \ + keyring-compat-test \ luks2-validation-test \ luks2-integrity-test @@ -55,6 +56,7 @@ EXTRA_DIST = compatimage.img.bz2 compatv10image.img.bz2 \ luks2-integrity-test \ device-test \ keyring-test \ + keyring-compat-test \ integrity-compat-test \ cryptsetup-valg-supps valg.sh valg-api.sh diff --git a/tests/keyring-compat-test b/tests/keyring-compat-test new file mode 100755 index 00000000..ee046660 --- /dev/null +++ b/tests/keyring-compat-test @@ -0,0 +1,183 @@ +#!/bin/bash + +CIPHER_XTS_PLAIN="aes-xts-plain64" +CIPHER_CBC_ESSIV="aes-cbc-essiv:sha256" +CIPHER_CBC_TCW="serpent-cbc-tcw" +# TODO: mode with LMK + +TEST_KEYRING_NAME="keyringtest_keyring" + +LOGON_KEY_16_OK="dmtst:lkey_16" +LOGON_KEY_32_OK="dmtst:lkey_32" +LOGON_KEY_64_OK="dmtst:lkey_64" + +HEXKEY_16="be21aa8c733229347bd4e681891e213d"; +HEXKEY_32="bb21158c733229347bd4e681891e213d94c685be6a5b84818afe7a78a6de7a1a"; +HEXKEY_64="34f95b96abff946b64f1339ff8653cc77c38697c93b797a496f3786e86eed7781850d5112bbae17d209b8310a8f3a034f1cd297667bc0cd1438fad28d87ef6a1" + +DEVSIZEMB=16 +DEVSECTORS=$((DEVSIZEMB*1024*1024/512)) +NAME=testcryptdev +CHKS_DMCRYPT=vk_in_dmcrypt.chk +CHKS_KEYRING=vk_in_keyring.chk + +function remove_mapping() +{ + [ -b /dev/mapper/$NAME ] && dmsetup remove $NAME + + # unlink whole test keyring + [ -n "$TEST_KEYRING" ] && keyctl unlink $TEST_KEYRING "@u" >/dev/null + + rmmod scsi_debug 2>/dev/null + + rm -f $CHKS_DMCRYPT $CHKS_KEYRING +} + +function skip() +{ + [ -n "$1" ] && echo "$1" + remove_mapping + exit 77 +} + +function fail() +{ + [ -n "$1" ] && echo "$1" + echo "FAILED at $(caller)" + remove_mapping + exit 2 +} + +# $1 hexbyte key +# $2 type +# $3 description +# $4 keyring +function load_key() +{ + local tmp="$1" + shift + echo -n "$tmp" | xxd -r -p | keyctl padd $@ >/dev/null +} + +function dm_crypt_keyring_support() +{ + VER_STR=$(dmsetup targets | grep crypt | cut -f2 -dv) + [ -z "$VER_STR" ] && fail "Failed to parse dm-crypt version." + + VER_MAJ=$(echo $VER_STR | cut -f 1 -d.) + VER_MIN=$(echo $VER_STR | cut -f 2 -d.) + + [ $VER_MAJ -gt 1 ] && return 0 + [ $VER_MAJ -lt 1 ] && return 1 + [ $VER_MIN -ge 15 ] +} + +function test_and_prepare_keyring() { + keyctl list "@s" > /dev/null || skip "Current session keyring is unreachable, test skipped" + TEST_KEYRING=$(keyctl newring $TEST_KEYRING_NAME "@u" 2> /dev/null) + test -n "$TEST_KEYRING" || skip "Failed to create keyring in user keyring" + keyctl search "@s" keyring "$TEST_KEYRING" > /dev/null 2>&1 || keyctl link "@u" "@s" > /dev/null 2>&1 + load_key "$HEXKEY_16" user test_key "$TEST_KEYRING" || skip "Kernel keyring service is useless on this system, test skipped." +} + +add_device() { + modprobe scsi_debug $@ + if [ $? -ne 0 ] ; then + echo "This kernel seems to not support proper scsi_debug module, test skipped." + exit 77 + fi + + sleep 2 + DEV=$(grep -l -e scsi_debug /sys/block/*/device/model | cut -f4 -d /) + + DEV="/dev/$DEV" + [ -b $DEV ] || fail "Cannot find $DEV." +} + +[ $(id -u) != 0 ] && skip "WARNING: You must be root to run this test, test skipped." +which dmsetup >/dev/null 2>&1 || skip "Cannot find dmsetup, test skipped" +which keyctl >/dev/null 2>&1 || skip "Cannot find keyctl, test skipped" +which xxd >/dev/null 2>&1 || skip "Cannot find xxd, test skipped" +which sha1sum > /dev/null 2>&1 || skip "Cannot find sha1sum, test skipped" +modprobe dm-crypt || fail "dm-crypt failed to load" +dm_crypt_keyring_support || skip "dm-crypt doesn't support kernel keyring, test skipped." + +test_and_prepare_keyring + +add_device dev_size_mb=$DEVSIZEMB + +dd if=/dev/urandom of=$DEV bs=1M count=$DEVSIZEMB oflag=direct > /dev/null 2>&1 || fail + +#test aes cipher with xts mode, plain IV +echo -n "Testing $CIPHER_XTS_PLAIN..." +dmsetup create $NAME --table "0 $DEVSECTORS crypt $CIPHER_XTS_PLAIN $HEXKEY_32 0 $DEV 0" || fail +sha1sum /dev/mapper/$NAME > $CHKS_DMCRYPT || fail +dmsetup remove $NAME || fail +load_key "$HEXKEY_32" logon $LOGON_KEY_32_OK "$TEST_KEYRING" || fail "Cannot load 32 byte logon key type" +dmsetup create $NAME --table "0 $DEVSECTORS crypt $CIPHER_XTS_PLAIN :32:logon:$LOGON_KEY_32_OK 0 $DEV 0" || fail +sha1sum /dev/mapper/$NAME > $CHKS_KEYRING || fail +dmsetup remove $NAME || fail +diff $CHKS_DMCRYPT $CHKS_KEYRING || fail "Plaintext checksums mismatch (corruption)" +# same test using message +dmsetup create $NAME --table "0 $DEVSECTORS crypt $CIPHER_XTS_PLAIN $HEXKEY_32 0 $DEV 0" || fail +sha1sum /dev/mapper/$NAME > $CHKS_DMCRYPT || fail +dmsetup remove $NAME || fail +dmsetup create $NAME --table "0 $DEVSECTORS crypt $CIPHER_XTS_PLAIN $HEXKEY_32 0 $DEV 0" || fail +dmsetup suspend $NAME || fail +dmsetup message $NAME 0 key wipe || fail +dmsetup message $NAME 0 "key set :32:logon:$LOGON_KEY_32_OK" || fail +dmsetup resume $NAME || fail +sha1sum /dev/mapper/$NAME > $CHKS_KEYRING || fail +dmsetup remove $NAME || fail +diff $CHKS_DMCRYPT $CHKS_KEYRING || fail "Plaintext checksums mismatch (corruption)" +echo "OK" + +#test aes cipher, xts mode, essiv IV +echo -n "Testing $CIPHER_CBC_ESSIV..." +dmsetup create $NAME --table "0 $DEVSECTORS crypt $CIPHER_CBC_ESSIV $HEXKEY_16 0 $DEV 0" || fail +sha1sum /dev/mapper/$NAME > $CHKS_DMCRYPT || fail +dmsetup remove $NAME || fail +load_key "$HEXKEY_16" logon $LOGON_KEY_16_OK "$TEST_KEYRING" || fail "Cannot load 16 byte logon key type" +dmsetup create $NAME --table "0 $DEVSECTORS crypt $CIPHER_CBC_ESSIV :16:logon:$LOGON_KEY_16_OK 0 $DEV 0" || fail +sha1sum /dev/mapper/$NAME > $CHKS_KEYRING || fail +dmsetup remove $NAME || fail +diff $CHKS_DMCRYPT $CHKS_KEYRING || fail "Plaintext checksums mismatch (corruption)" +# same test using message +dmsetup create $NAME --table "0 $DEVSECTORS crypt $CIPHER_CBC_ESSIV $HEXKEY_16 0 $DEV 0" || fail +sha1sum /dev/mapper/$NAME > $CHKS_DMCRYPT || fail +dmsetup remove $NAME || fail +dmsetup create $NAME --table "0 $DEVSECTORS crypt $CIPHER_CBC_ESSIV $HEXKEY_16 0 $DEV 0" || fail +dmsetup suspend $NAME || fail +dmsetup message $NAME 0 key wipe || fail +dmsetup message $NAME 0 "key set :16:logon:$LOGON_KEY_16_OK" || fail +dmsetup resume $NAME || fail +sha1sum /dev/mapper/$NAME > $CHKS_KEYRING || fail +dmsetup remove $NAME || fail +diff $CHKS_DMCRYPT $CHKS_KEYRING || fail "Plaintext checksums mismatch (corruption)" +echo "OK" + +#test serpent cipher, cbc mode, tcw IV +echo -n "Testing $CIPHER_CBC_TCW..." +dmsetup create $NAME --table "0 $DEVSECTORS crypt $CIPHER_CBC_TCW $HEXKEY_64 0 $DEV 0" || fail +sha1sum /dev/mapper/$NAME > $CHKS_DMCRYPT || fail +dmsetup remove $NAME || fail +load_key "$HEXKEY_64" logon $LOGON_KEY_64_OK "$TEST_KEYRING" || fail "Cannot load 16 byte logon key type" +dmsetup create $NAME --table "0 $DEVSECTORS crypt $CIPHER_CBC_TCW :64:logon:$LOGON_KEY_64_OK 0 $DEV 0" || fail +sha1sum /dev/mapper/$NAME > $CHKS_KEYRING || fail +dmsetup remove $NAME || fail +diff $CHKS_DMCRYPT $CHKS_KEYRING || fail "Plaintext checksum mismatch (corruption)" +# same test using message +dmsetup create $NAME --table "0 $DEVSECTORS crypt $CIPHER_CBC_TCW $HEXKEY_64 0 $DEV 0" || fail +sha1sum /dev/mapper/$NAME > $CHKS_DMCRYPT || fail +dmsetup remove $NAME || fail +dmsetup create $NAME --table "0 $DEVSECTORS crypt $CIPHER_CBC_TCW $HEXKEY_64 0 $DEV 0" || fail +dmsetup suspend $NAME || fail +dmsetup message $NAME 0 key wipe || fail +dmsetup message $NAME 0 "key set :64:logon:$LOGON_KEY_64_OK" || fail +dmsetup resume $NAME || fail +sha1sum /dev/mapper/$NAME > $CHKS_KEYRING || fail +dmsetup remove $NAME || fail +diff $CHKS_DMCRYPT $CHKS_KEYRING || fail "Plaintext checksums mismatch (corruption)" +echo "OK" + +remove_mapping