summaryrefslogtreecommitdiffstats
path: root/tests/keyring-test
blob: 38abcfb9ca586b8eb23aa79b0d3adea5bbbd5460 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
#!/bin/bash

DEV_ZERO="dmtst-zero"
DEV_CRYPT="dmtst-crypt"

CIPHER="aes-xts-plain64"

TEST_KEYRING_NAME="keyringtest_keyring"

USER_KEY_32_OK="dmtst:ukey_32_ok"
USER_KEY_32_WRONG="dmtst:ukey_32_wrong_size"

LOGON_KEY_32_OK="dmtst:lkey_32_ok"
LOGON_KEY_32_WRONG="dmtst:lkey_32_wrong_size"

PAYLOAD_32="bb21158c733229347bd4e681891e213d"
PAYLOAD_31="bb21158c733229347bd4e681891e213"

HEXKEY_32="bb21158c733229347bd4e681891e213d94c685be6a5b84818afe7a78a6de7a1a";
HEXKEY_32_BAD="bb21158c733229347bd4e68189XXXX3d94c685be6a5b84818afe7a78a6de7a1a"
HEXKEY_31="bb21158c733229347bd4e681891e213d94c685be6a5b84818afe7a78a6de7a"

function remove_mapping()
{
	[ -b /dev/mapper/$DEV_CRYPT ] && dmsetup remove --retry $DEV_CRYPT
	[ -b /dev/mapper/$DEV_ZERO ] && dmsetup remove --retry $DEV_ZERO

	# unlink whole test keyring
	[ -n "$TEST_KEYRING" ] && keyctl unlink $TEST_KEYRING "@u" >/dev/null
}

function skip()
{
	[ -n "$1" ] && echo "$1"
	remove_mapping
	exit 77
}

function fail()
{
	[ -n "$1" ] && echo "$1"
	echo "FAILED backtrace:"
	while caller $frame; do ((frame++)); done
	remove_mapping
	exit 2
}

# $1 type
# $2 description
# $3 payload
# $4 keyring
function load_key()
{
	keyctl add $@ >/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 user test_key test_data "$TEST_KEYRING" || skip "Kernel keyring service is useless on this system, test skipped."
}

[ $(id -u) != 0 ] && skip "WARNING: You must be root to run this test, test skipped."
command -v dmsetup >/dev/null || skip "Cannot find dmsetup, test skipped"
command -v keyctl >/dev/null || skip "Cannot find keyctl, test skipped"
modprobe dm-crypt >/dev/null 2>&1 || fail "dm-crypt failed to load"
dm_crypt_keyring_support || skip "dm-crypt doesn't support kernel keyring, test skipped."

test_and_prepare_keyring

load_key logon $LOGON_KEY_32_OK $PAYLOAD_32 "$TEST_KEYRING" || fail "Cannot load 32 byte logon key type"
load_key user $USER_KEY_32_OK $PAYLOAD_32 "$TEST_KEYRING" || fail "Cannot load 32 byte user key type"
load_key logon $LOGON_KEY_32_WRONG $PAYLOAD_31 "$TEST_KEYRING" || fail "Cannot load 31 byte logon key type"
load_key user $USER_KEY_32_WRONG $PAYLOAD_31 "$TEST_KEYRING" || fail "Cannot load 31 byte user key type"

dmsetup create $DEV_ZERO --table "0 100 zero" || fail

echo "[1] Valid keyring keys"

# load logon type kernel key
KEY=":32:logon:$LOGON_KEY_32_OK"
dmsetup create $DEV_CRYPT --table "0 100 crypt $CIPHER $KEY 0 /dev/mapper/$DEV_ZERO 0" || fail
dmsetup table --showkeys $DEV_CRYPT | grep -q "crypt $CIPHER $KEY 0" || fail
dmsetup remove --retry $DEV_CRYPT || fail

# load user type kernel key
KEY=":32:user:$USER_KEY_32_OK"
dmsetup create $DEV_CRYPT --table "0 100 crypt $CIPHER $KEY 0 /dev/mapper/$DEV_ZERO 0" || fail
dmsetup table --showkeys $DEV_CRYPT | grep -q "crypt $CIPHER $KEY 0" || fail
dmsetup remove --retry $DEV_CRYPT || fail

# load logon type kernel key...
KEY=":32:logon:$LOGON_KEY_32_OK"
dmsetup create $DEV_CRYPT --table "0 100 crypt $CIPHER $KEY 0 /dev/mapper/$DEV_ZERO 0" || fail
dmsetup suspend $DEV_CRYPT || fail
dmsetup message $DEV_CRYPT 0 "key wipe" || fail
# ...replace the key with hexkey...
dmsetup message $DEV_CRYPT 0 "key set $HEXKEY_32" || fail
dmsetup table --showkeys $DEV_CRYPT | grep -q "crypt $CIPHER $HEXKEY_32 0" || fail
dmsetup resume $DEV_CRYPT || fail
dmsetup suspend $DEV_CRYPT || fail
# ...and replace it again with user type kernel key...
dmsetup message $DEV_CRYPT 0 "key set :32:user:$USER_KEY_32_OK" || fail
dmsetup table --showkeys $DEV_CRYPT | grep -q "crypt $CIPHER :32:user:$USER_KEY_32_OK 0" || fail
dmsetup message $DEV_CRYPT 0 "key set $HEXKEY_32" || fail
dmsetup table --showkeys $DEV_CRYPT | grep -q "crypt $CIPHER $HEXKEY_32 0" || fail
dmsetup resume $DEV_CRYPT || fail
dmsetup remove --retry $DEV_CRYPT || fail

dmsetup create $DEV_CRYPT --table "0 100 crypt $CIPHER $HEXKEY_32 0 /dev/mapper/$DEV_ZERO 0" || fail
dmsetup suspend $DEV_CRYPT || fail
dmsetup message $DEV_CRYPT 0 "key wipe" || fail
dmsetup message $DEV_CRYPT 0 "key set :32:user:$USER_KEY_32_OK" || fail
dmsetup resume $DEV_CRYPT || fail
dmsetup suspend $DEV_CRYPT || fail
dmsetup message $DEV_CRYPT 0 "key set :32:logon:$LOGON_KEY_32_OK" || fail
dmsetup resume $DEV_CRYPT || fail
dmsetup remove --retry $DEV_CRYPT || fail

echo "[2] message ioctl"
dmsetup create $DEV_CRYPT --table "0 100 crypt $CIPHER $HEXKEY_32 0 /dev/mapper/$DEV_ZERO 0" || fail
dmsetup suspend $DEV_CRYPT || fail
dmsetup message $DEV_CRYPT 0 "key set :32:logon:$LOGON_KEY_32_WRONG" 2> /dev/null && fail
# old key should be intact and valid
dmsetup table --showkeys $DEV_CRYPT | grep -q "crypt $CIPHER $HEXKEY_32 0" || fail
dmsetup resume $DEV_CRYPT || fail
dmsetup suspend $DEV_CRYPT || fail
# now the key gets destroyed by invalid input
dmsetup message $DEV_CRYPT 0 "key set $HEXKEY_32_BAD" 2> /dev/null && fail
dmsetup resume $DEV_CRYPT 2> /dev/null && fail
# hmm... see the output. don't like it
# dmsetup table --showkeys $DEV_CRYPT

dmsetup message $DEV_CRYPT 0 "key set :32:user:$USER_KEY_32_OK" || fail
dmsetup table --showkeys $DEV_CRYPT | grep -q "crypt $CIPHER :32:user:$USER_KEY_32_OK 0" || fail
dmsetup message $DEV_CRYPT 0 "key set :31:logon:$LOGON_KEY_32_OK" 2> /dev/null && fail
dmsetup message $DEV_CRYPT 0 "key set :" 2> /dev/null && fail
dmsetup message $DEV_CRYPT 0 "key set ::::" 2> /dev/null && fail
dmsetup message $DEV_CRYPT 0 "key set :0:logon:$LOGON_KEY_32_OK" 2> /dev/null && fail
dmsetup message $DEV_CRYPT 0 "key set :32" 2> /dev/null && fail
dmsetup message $DEV_CRYPT 0 "key set :32:" 2> /dev/null && fail
dmsetup message $DEV_CRYPT 0 "key set :32:logon" 2> /dev/null && fail
dmsetup message $DEV_CRYPT 0 "key set :32:logo" 2> /dev/null && fail
dmsetup message $DEV_CRYPT 0 "key set :32:logon:" 2> /dev/null && fail
dmsetup table --showkeys $DEV_CRYPT | grep -q "crypt $CIPHER :32:user:$USER_KEY_32_OK 0" || fail
dmsetup message $DEV_CRYPT 0 "key set :32:user:$USER_KEY_32_OK" || fail
dmsetup resume $DEV_CRYPT || fail
dmsetup remove --retry $DEV_CRYPT || fail

echo "[3] bOrked keys"
# declare the key having 32 bytes but load key which has in fact 31 bytes only
KEY=":32:logon:$LOGON_KEY_32_WRONG"
dmsetup create $DEV_CRYPT --table "0 100 crypt $CIPHER $KEY 0 /dev/mapper/$DEV_ZERO 0" 2> /dev/null && fail "dm-crypt accepted wrong key size"

# declare the key having 31 bytes (incompatible with cipher) and load key with 32 bytes in real
KEY=":31:logon:$LOGON_KEY_32_WRONG"
dmsetup create $DEV_CRYPT --table "0 100 crypt $CIPHER $KEY 0 /dev/mapper/$DEV_ZERO 0" 2> /dev/null && fail "dm-crypt accepted wrong key size"

# declare the key being user type but try to load logon one
KEY=":32:user:$LOGON_KEY_32"
dmsetup create $DEV_CRYPT --table "0 100 crypt $CIPHER $KEY 0 /dev/mapper/$DEV_ZERO 0" 2> /dev/null  && fail "dm-crypt accepted key description for invalid key type"

# now the other way
KEY=":32:logon:$USER_KEY_32"
dmsetup create $DEV_CRYPT --table "0 100 crypt $CIPHER $KEY 0 /dev/mapper/$DEV_ZERO 0" 2> /dev/null  && fail "dm-crypt accepted key description for invalid key type"

BORKED_KEYS=":\ 32:logon:$LOGON_KEY_32_OK
: 32:logon:$LOGON_KEY_32_OK
:+32:logon:$LOGON_KEY_32_OK
:-32:logon:$LOGON_KEY_32_OK
:32 :logon:$LOGON_KEY_32_OK
:32\ :logon:$LOGON_KEY_32_OK
:32_:logon:$LOGON_KEY_32_OK
:32+:logon:$LOGON_KEY_32_OK
:30+2:logon:$LOGON_KEY_32_OK
:32+0:logon:$LOGON_KEY_32_OK
:32: logon:$LOGON_KEY_32_OK
:32:\ logon:$LOGON_KEY_32_OK
:32:logonA:$LOGON_KEY_32_OK
:32:logo:$LOGON_KEY_32_OK
:32:llogon:$LOGON_KEY_32_OK
:32xlogon:$LOGON_KEY_32_OK
:32logon:$LOGON_KEY_32_OK
:32:logonx$LOGON_KEY_32_OK
:32:logon$LOGON_KEY_32_OK
: 32:user:$USER_KEY_32_OK
:\ 32:user:$USER_KEY_32_OK
:+32:user:$USER_KEY_32_OK
:-32:user:$USER_KEY_32_OK
:32 :user:$USER_KEY_32_OK
:32\ :user:$USER_KEY_32_OK
:32_:user:$USER_KEY_32_OK
:32+:user:$USER_KEY_32_OK
:30+2:user:$USER_KEY_32_OK
:32+0:user:$USER_KEY_32_OK
:32: user:$USER_KEY_32_OK
:32:\ user:$USER_KEY_32_OK
:32:userA:$USER_KEY_32_OK
:32:use:$USER_KEY_32_OK
:32:uuser:$USER_KEY_32_OK
:32xuser:$USER_KEY_32_OK
:32user:$USER_KEY_32_OK
:32:userx$USER_KEY_32_OK
:32:user$USER_KEY_32_OK
:32:userlogon:$USER_KEY_32_OK
:32:userlogon:$LOGON_KEY_32_OK
:32:logonuser:$USER_KEY_32_OK
:32:logonuser:$LOGON_KEY_32_OK
:32:logon:user:$USER_KEY_32_OK
:32:logon:user:$LOGON_KEY_32_OK
:32:user:logon:$USER_KEY_32_OK
:32:user:logon:$LOGON_KEY_32_OK"

# TODO: add tests with whitespace in key description (not possible with current libdevmapper)

IFS="
"

for key in $BORKED_KEYS; do
	dmsetup create $DEV_CRYPT --table "0 100 crypt $CIPHER $key 0 /dev/mapper/$DEV_ZERO 0" 2> /dev/null && fail "dm-crypt accepted seriously borked key string"
done

remove_mapping