Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/testing/selftests/dm-verity/test-dm-verity-keyring.sh
121838 views
1
#!/bin/bash
2
# SPDX-License-Identifier: GPL-2.0
3
#
4
# Test script for dm-verity keyring functionality
5
#
6
# This script has two modes depending on kernel configuration:
7
#
8
# 1. keyring_unsealed=1 AND require_signatures=1:
9
# - Upload a test key to the .dm-verity keyring
10
# - Seal the keyring
11
# - Create a dm-verity device with a signed root hash
12
# - Verify signature verification works
13
#
14
# 2. keyring_unsealed=0 (default) OR require_signatures=0:
15
# - Verify the keyring is already sealed (if unsealed=0)
16
# - Verify keys cannot be added to a sealed keyring
17
# - Verify the keyring is inactive (not used for verification)
18
#
19
# Requirements:
20
# - Root privileges
21
# - openssl
22
# - veritysetup (cryptsetup)
23
# - keyctl (keyutils)
24
25
set -e
26
27
WORK_DIR=""
28
DATA_DEV=""
29
HASH_DEV=""
30
DM_NAME="verity-test-$$"
31
CLEANUP_DONE=0
32
33
# Module parameters (detected at runtime)
34
KEYRING_UNSEALED=""
35
REQUIRE_SIGNATURES=""
36
37
# Colors for output
38
RED='\033[0;31m'
39
GREEN='\033[0;32m'
40
YELLOW='\033[1;33m'
41
NC='\033[0m' # No Color
42
43
log_info() {
44
echo -e "${GREEN}[INFO]${NC} $*"
45
}
46
47
log_warn() {
48
echo -e "${YELLOW}[WARN]${NC} $*"
49
}
50
51
log_error() {
52
echo -e "${RED}[ERROR]${NC} $*" >&2
53
}
54
55
log_pass() {
56
echo -e "${GREEN}[PASS]${NC} $*"
57
}
58
59
log_fail() {
60
echo -e "${RED}[FAIL]${NC} $*" >&2
61
}
62
63
log_skip() {
64
echo -e "${YELLOW}[SKIP]${NC} $*"
65
}
66
67
cleanup() {
68
if [ "$CLEANUP_DONE" -eq 1 ]; then
69
return
70
fi
71
CLEANUP_DONE=1
72
73
log_info "Cleaning up..."
74
75
# Remove dm-verity device if it exists
76
if dmsetup info "$DM_NAME" &>/dev/null; then
77
dmsetup remove "$DM_NAME" 2>/dev/null || true
78
fi
79
80
# Detach loop devices
81
if [ -n "$DATA_DEV" ] && [[ "$DATA_DEV" == /dev/loop* ]]; then
82
losetup -d "$DATA_DEV" 2>/dev/null || true
83
fi
84
if [ -n "$HASH_DEV" ] && [[ "$HASH_DEV" == /dev/loop* ]]; then
85
losetup -d "$HASH_DEV" 2>/dev/null || true
86
fi
87
88
# Remove work directory
89
if [ -n "$WORK_DIR" ] && [ -d "$WORK_DIR" ]; then
90
rm -rf "$WORK_DIR"
91
fi
92
}
93
94
trap cleanup EXIT
95
96
die() {
97
log_error "$*"
98
exit 1
99
}
100
101
find_dm_verity_keyring() {
102
# The .dm-verity keyring is not linked to user-accessible keyrings,
103
# so we need to find it via /proc/keys
104
local serial_hex
105
serial_hex=$(awk '/\.dm-verity/ {print $1}' /proc/keys 2>/dev/null)
106
107
if [ -z "$serial_hex" ]; then
108
return 1
109
fi
110
111
# Convert hex to decimal for keyctl
112
echo $((16#$serial_hex))
113
}
114
115
get_module_param() {
116
local param="$1"
117
local path="/sys/module/dm_verity/parameters/$param"
118
119
if [ -f "$path" ]; then
120
cat "$path"
121
else
122
echo ""
123
fi
124
}
125
126
check_requirements() {
127
log_info "Checking requirements..."
128
129
# Check for root
130
if [ "$(id -u)" -ne 0 ]; then
131
die "This script must be run as root"
132
fi
133
134
# Check for required tools
135
for cmd in openssl veritysetup keyctl losetup dmsetup dd awk; do
136
if ! command -v "$cmd" &>/dev/null; then
137
die "Required command not found: $cmd"
138
fi
139
done
140
141
# Check for dm-verity module
142
if ! modprobe -n dm-verity &>/dev/null; then
143
die "dm-verity module not available"
144
fi
145
146
# Verify OpenSSL can create signatures
147
# OpenSSL cms -sign with -binary -outform DER creates detached signatures by default
148
log_info "Using OpenSSL for PKCS#7 signatures"
149
}
150
151
load_dm_verity_module() {
152
local keyring_unsealed="${1:-0}"
153
local require_signatures="${2:-0}"
154
155
log_info "Loading dm-verity module with keyring_unsealed=$keyring_unsealed require_signatures=$require_signatures"
156
157
# Unload if already loaded
158
if lsmod | grep -q '^dm_verity'; then
159
log_info "Unloading existing dm-verity module..."
160
modprobe -r dm-verity 2>/dev/null || \
161
die "Failed to unload dm-verity module (may be in use)"
162
sleep 1
163
fi
164
165
# Load with specified parameters
166
modprobe dm-verity keyring_unsealed="$keyring_unsealed" require_signatures="$require_signatures" || \
167
die "Failed to load dm-verity module"
168
169
# Wait for keyring to be created (poll with timeout)
170
local keyring_id=""
171
local timeout=50 # 5 seconds (50 * 0.1s)
172
while [ $timeout -gt 0 ]; do
173
keyring_id=$(find_dm_verity_keyring) && break
174
sleep 0.1
175
timeout=$((timeout - 1))
176
done
177
178
if [ -z "$keyring_id" ]; then
179
die "dm-verity keyring not found after module load (timeout)"
180
fi
181
182
log_info "Found .dm-verity keyring: $keyring_id"
183
echo "$keyring_id" > "$WORK_DIR/keyring_id"
184
185
# Read and display module parameters
186
KEYRING_UNSEALED=$(get_module_param "keyring_unsealed")
187
REQUIRE_SIGNATURES=$(get_module_param "require_signatures")
188
189
log_info "Module parameters:"
190
log_info " keyring_unsealed=$KEYRING_UNSEALED"
191
log_info " require_signatures=$REQUIRE_SIGNATURES"
192
}
193
194
unload_dm_verity_module() {
195
log_info "Unloading dm-verity module..."
196
197
# Clean up any dm-verity devices first
198
local dm_dev
199
while read -r dm_dev _; do
200
[ -n "$dm_dev" ] || continue
201
log_info "Removing dm-verity device: $dm_dev"
202
dmsetup remove "$dm_dev" 2>/dev/null || true
203
done < <(dmsetup ls --target verity 2>/dev/null)
204
205
if lsmod | grep -q '^dm_verity'; then
206
modprobe -r dm-verity 2>/dev/null || \
207
log_warn "Failed to unload dm-verity module"
208
sleep 1
209
fi
210
}
211
212
generate_keys() {
213
log_info "Generating signing key pair..."
214
215
# Generate private key (2048-bit for faster test execution)
216
openssl genrsa -out "$WORK_DIR/private.pem" 2048 2>/dev/null
217
218
# Create OpenSSL config for certificate extensions
219
# The kernel requires digitalSignature key usage for signature verification
220
# Both subjectKeyIdentifier and authorityKeyIdentifier are needed for
221
# the kernel to match keys in the keyring (especially for self-signed certs)
222
cat > "$WORK_DIR/openssl.cnf" << 'EOF'
223
[req]
224
distinguished_name = req_distinguished_name
225
x509_extensions = v3_ca
226
prompt = no
227
228
[req_distinguished_name]
229
CN = dm-verity-test-key
230
231
[v3_ca]
232
basicConstraints = critical,CA:FALSE
233
keyUsage = digitalSignature
234
subjectKeyIdentifier = hash
235
authorityKeyIdentifier = keyid
236
EOF
237
238
# Generate self-signed certificate with proper extensions
239
openssl req -new -x509 -key "$WORK_DIR/private.pem" \
240
-out "$WORK_DIR/cert.pem" -days 365 \
241
-config "$WORK_DIR/openssl.cnf" 2>/dev/null
242
243
# Convert certificate to DER format for kernel
244
openssl x509 -in "$WORK_DIR/cert.pem" -outform DER \
245
-out "$WORK_DIR/cert.der"
246
247
# Show certificate info for debugging
248
log_info "Certificate details:"
249
openssl x509 -in "$WORK_DIR/cert.pem" -noout -text 2>/dev/null | \
250
grep -E "Subject:|Issuer:|Key Usage|Extended" | head -10
251
252
log_info "Keys generated successfully"
253
}
254
255
seal_keyring() {
256
log_info "Sealing the .dm-verity keyring..."
257
258
local keyring_id
259
keyring_id=$(cat "$WORK_DIR/keyring_id")
260
261
keyctl restrict_keyring "$keyring_id" || \
262
die "Failed to seal keyring"
263
264
log_info "Keyring sealed successfully"
265
}
266
267
create_test_device() {
268
log_info "Creating test device images..."
269
270
# Create data image with random content (8MB is sufficient for testing)
271
dd if=/dev/urandom of="$WORK_DIR/data.img" bs=1M count=8 status=none
272
273
# Create hash image (will be populated by veritysetup)
274
dd if=/dev/zero of="$WORK_DIR/hash.img" bs=1M count=1 status=none
275
276
# Setup loop devices
277
DATA_DEV=$(losetup --find --show "$WORK_DIR/data.img")
278
HASH_DEV=$(losetup --find --show "$WORK_DIR/hash.img")
279
280
log_info "Data device: $DATA_DEV"
281
log_info "Hash device: $HASH_DEV"
282
}
283
284
create_verity_hash() {
285
log_info "Creating dm-verity hash tree..."
286
287
local root_hash output
288
output=$(veritysetup format "$DATA_DEV" "$HASH_DEV" 2>&1)
289
root_hash=$(echo "$output" | grep "Root hash:" | awk '{print $3}')
290
291
if [ -z "$root_hash" ]; then
292
log_error "veritysetup format output:"
293
echo "$output" | sed 's/^/ /'
294
die "Failed to get root hash from veritysetup format"
295
fi
296
297
echo "$root_hash" > "$WORK_DIR/root_hash"
298
log_info "Root hash: $root_hash"
299
}
300
301
create_detached_signature() {
302
local infile="$1"
303
local outfile="$2"
304
local cert="$3"
305
local key="$4"
306
307
# Use openssl smime (not cms) for PKCS#7 signatures compatible with kernel
308
# Flags from working veritysetup example:
309
# -nocerts: don't include certificate in signature
310
# -noattr: no signed attributes
311
# -binary: binary input mode
312
if openssl smime -sign -nocerts -noattr -binary \
313
-in "$infile" \
314
-inkey "$key" \
315
-signer "$cert" \
316
-outform der \
317
-out "$outfile" 2>/dev/null; then
318
return 0
319
fi
320
321
log_error "Failed to create signature"
322
return 1
323
}
324
325
activate_verity_device() {
326
local with_sig="$1"
327
local root_hash
328
root_hash=$(cat "$WORK_DIR/root_hash")
329
330
# Clear dmesg and capture any kernel messages during activation
331
dmesg -C 2>/dev/null || true
332
333
if [ "$with_sig" = "yes" ]; then
334
log_info "Activating dm-verity device with signature..."
335
veritysetup open "$DATA_DEV" "$DM_NAME" "$HASH_DEV" "$root_hash" \
336
--root-hash-signature="$WORK_DIR/root_hash.p7s" 2>&1
337
local ret=$?
338
else
339
log_info "Activating dm-verity device without signature..."
340
veritysetup open "$DATA_DEV" "$DM_NAME" "$HASH_DEV" "$root_hash" 2>&1
341
local ret=$?
342
fi
343
344
# Show relevant kernel messages
345
local kmsg
346
kmsg=$(dmesg 2>/dev/null | grep -i -E 'verity|pkcs|signature|asymmetric|key' | tail -10)
347
if [ -n "$kmsg" ]; then
348
log_info "Kernel messages:"
349
echo "$kmsg" | while read -r line; do echo " $line"; done
350
fi
351
352
return $ret
353
}
354
355
deactivate_verity_device() {
356
if dmsetup info "$DM_NAME" &>/dev/null; then
357
dmsetup remove "$DM_NAME" 2>/dev/null || true
358
fi
359
}
360
361
show_keyring_status() {
362
log_info "Keyring status:"
363
364
local keyring_id
365
keyring_id=$(find_dm_verity_keyring) || true
366
367
if [ -n "$keyring_id" ]; then
368
echo " Keyring ID: $keyring_id"
369
keyctl show "$keyring_id" 2>/dev/null || true
370
grep '\.dm-verity' /proc/keys 2>/dev/null || true
371
fi
372
}
373
374
list_keyring_keys() {
375
log_info "Keys in .dm-verity keyring:"
376
377
local keyring_id
378
keyring_id=$(cat "$WORK_DIR/keyring_id" 2>/dev/null) || \
379
keyring_id=$(find_dm_verity_keyring) || true
380
381
if [ -z "$keyring_id" ]; then
382
log_warn "Could not find keyring"
383
return
384
fi
385
386
# List all keys in the keyring
387
local keys
388
keys=$(keyctl list "$keyring_id" 2>/dev/null)
389
if [ -z "$keys" ] || [ "$keys" = "keyring is empty" ]; then
390
echo " (empty)"
391
else
392
echo "$keys" | while read -r line; do
393
echo " $line"
394
done
395
396
# Show detailed info for each key
397
log_info "Key details:"
398
keyctl list "$keyring_id" 2>/dev/null | awk '{print $1}' | grep -E '^[0-9]+$' | while read -r key_id; do
399
echo " Key $key_id:"
400
keyctl describe "$key_id" 2>/dev/null | sed 's/^/ /'
401
done
402
fi
403
}
404
405
generate_named_key() {
406
local name="$1"
407
local key_dir="$WORK_DIR/keys/$name"
408
409
mkdir -p "$key_dir"
410
411
# Log to stderr so it doesn't interfere with return value
412
echo "[INFO] Generating key pair: $name" >&2
413
414
# Generate private key
415
openssl genrsa -out "$key_dir/private.pem" 2048 2>/dev/null
416
417
# Create OpenSSL config for certificate extensions
418
# Both subjectKeyIdentifier and authorityKeyIdentifier are needed for
419
# the kernel to match keys in the keyring (especially for self-signed certs)
420
cat > "$key_dir/openssl.cnf" << EOF
421
[req]
422
distinguished_name = req_distinguished_name
423
x509_extensions = v3_ca
424
prompt = no
425
426
[req_distinguished_name]
427
CN = dm-verity-test-$name
428
429
[v3_ca]
430
basicConstraints = critical,CA:FALSE
431
keyUsage = digitalSignature
432
subjectKeyIdentifier = hash
433
authorityKeyIdentifier = keyid
434
EOF
435
436
# Generate self-signed certificate with proper extensions
437
openssl req -new -x509 -key "$key_dir/private.pem" \
438
-out "$key_dir/cert.pem" -days 365 \
439
-config "$key_dir/openssl.cnf" 2>/dev/null
440
441
# Convert certificate to DER format for kernel
442
openssl x509 -in "$key_dir/cert.pem" -outform DER \
443
-out "$key_dir/cert.der"
444
445
# Return the key directory path (only this goes to stdout)
446
echo "$key_dir"
447
}
448
449
upload_named_key() {
450
local name="$1"
451
local key_dir="$2"
452
453
local keyring_id
454
keyring_id=$(cat "$WORK_DIR/keyring_id")
455
456
log_info "Uploading key '$name' to keyring..."
457
458
local key_id
459
if key_id=$(keyctl padd asymmetric "$name" "$keyring_id" \
460
< "$key_dir/cert.der" 2>&1); then
461
log_info "Key '$name' uploaded with ID: $key_id"
462
echo "$key_id" > "$key_dir/key_id"
463
return 0
464
else
465
log_error "Failed to upload key '$name': $key_id"
466
return 1
467
fi
468
}
469
470
#
471
# Test: Verify sealed keyring rejects key additions
472
#
473
test_sealed_keyring_rejects_keys() {
474
log_info "TEST: Verify sealed keyring rejects key additions"
475
476
local keyring_id
477
keyring_id=$(cat "$WORK_DIR/keyring_id")
478
479
generate_keys
480
481
# Try to add a key - should fail
482
if keyctl padd asymmetric "dm-verity-test" "$keyring_id" \
483
< "$WORK_DIR/cert.der" 2>/dev/null; then
484
log_fail "Key addition should have been rejected on sealed keyring"
485
return 1
486
else
487
log_pass "Sealed keyring correctly rejected key addition"
488
return 0
489
fi
490
}
491
492
#
493
# Test: Multiple keys in keyring
494
#
495
test_multiple_keys() {
496
log_info "TEST: Multiple keys in keyring"
497
498
local key1_dir key2_dir key3_dir
499
500
# Generate three different keys
501
key1_dir=$(generate_named_key "vendor-a")
502
key2_dir=$(generate_named_key "vendor-b")
503
key3_dir=$(generate_named_key "vendor-c")
504
505
# Upload all three keys
506
upload_named_key "vendor-a" "$key1_dir" || return 1
507
upload_named_key "vendor-b" "$key2_dir" || return 1
508
upload_named_key "vendor-c" "$key3_dir" || return 1
509
510
log_info ""
511
log_info "Keys in keyring before sealing:"
512
list_keyring_keys
513
show_keyring_status
514
515
# Seal the keyring
516
log_info ""
517
seal_keyring
518
519
# List keys after sealing
520
log_info ""
521
log_info "Keys in keyring after sealing:"
522
list_keyring_keys
523
show_keyring_status
524
525
log_pass "Key upload and keyring sealing succeeded"
526
527
# Create test device
528
log_info ""
529
create_test_device
530
create_verity_hash
531
532
# Test 1: Sign with key1, should verify successfully
533
log_info ""
534
log_info "Sub-test: Verify with vendor-a key"
535
if ! sign_root_hash_with_key "$key1_dir"; then
536
log_fail "Failed to sign with vendor-a key"
537
return 1
538
fi
539
if activate_verity_device "yes"; then
540
log_pass "Verification with vendor-a key succeeded"
541
deactivate_verity_device
542
else
543
log_fail "Verification with vendor-a key should succeed"
544
return 1
545
fi
546
547
# Test 2: Sign with key2, should also verify successfully
548
log_info ""
549
log_info "Sub-test: Verify with vendor-b key"
550
if ! sign_root_hash_with_key "$key2_dir"; then
551
log_fail "Failed to sign with vendor-b key"
552
return 1
553
fi
554
if activate_verity_device "yes"; then
555
log_pass "Verification with vendor-b key succeeded"
556
deactivate_verity_device
557
else
558
log_fail "Verification with vendor-b key should succeed"
559
return 1
560
fi
561
562
# Test 3: Sign with key3, should also verify successfully
563
log_info ""
564
log_info "Sub-test: Verify with vendor-c key"
565
if ! sign_root_hash_with_key "$key3_dir"; then
566
log_fail "Failed to sign with vendor-c key"
567
return 1
568
fi
569
if activate_verity_device "yes"; then
570
log_pass "Verification with vendor-c key succeeded"
571
deactivate_verity_device
572
else
573
log_fail "Verification with vendor-c key should succeed"
574
return 1
575
fi
576
577
# Test 4: Generate a key NOT in the keyring, should fail
578
log_info ""
579
log_info "Sub-test: Verify with unknown key (should fail)"
580
local unknown_key_dir
581
unknown_key_dir=$(generate_named_key "unknown-vendor")
582
if ! sign_root_hash_with_key "$unknown_key_dir"; then
583
log_fail "Failed to sign with unknown-vendor key"
584
return 1
585
fi
586
if activate_verity_device "yes"; then
587
log_fail "Verification with unknown key should fail"
588
deactivate_verity_device
589
return 1
590
else
591
log_pass "Verification with unknown key correctly rejected"
592
fi
593
594
log_info ""
595
log_pass "Multiple keys test completed successfully"
596
return 0
597
}
598
599
sign_root_hash_with_key() {
600
local key_dir="$1"
601
602
local root_hash
603
root_hash=$(cat "$WORK_DIR/root_hash")
604
605
# Create the data to sign (hex string, not binary)
606
echo -n "$root_hash" > "$WORK_DIR/root_hash.txt"
607
608
# Debug: show exactly what we're signing
609
log_info "Root hash (hex): $root_hash"
610
log_info "Root hash hex string size: $(wc -c < "$WORK_DIR/root_hash.txt") bytes"
611
612
# Create detached PKCS#7 signature
613
if ! create_detached_signature "$WORK_DIR/root_hash.txt" "$WORK_DIR/root_hash.p7s" \
614
"$key_dir/cert.pem" "$key_dir/private.pem"; then
615
log_error "Failed to sign root hash with key from $key_dir"
616
return 1
617
fi
618
619
# Debug: show signing certificate info
620
log_info "Signed with certificate:"
621
openssl x509 -in "$key_dir/cert.pem" -noout -subject 2>/dev/null | sed 's/^/ /'
622
623
# Debug: verify signature locally
624
# -nointern: cert not in signature, use -certfile
625
# -noverify: skip certificate chain validation (self-signed)
626
if openssl smime -verify -binary -inform der -nointern -noverify \
627
-in "$WORK_DIR/root_hash.p7s" \
628
-content "$WORK_DIR/root_hash.txt" \
629
-certfile "$key_dir/cert.pem" \
630
-out /dev/null 2>/dev/null; then
631
log_info "Local signature verification: PASSED"
632
else
633
log_warn "Local signature verification: FAILED"
634
fi
635
return 0
636
}
637
638
#
639
# Test: Verify corrupted signatures are rejected
640
#
641
test_corrupted_signature() {
642
log_info "TEST: Verify corrupted signatures are rejected"
643
644
# This test requires a valid setup from test_multiple_keys or similar
645
# It modifies the signature file and verifies rejection
646
647
if [ ! -f "$WORK_DIR/root_hash.p7s" ]; then
648
log_warn "No signature file found, skipping corrupted signature test"
649
return 0
650
fi
651
652
# Save original signature
653
cp "$WORK_DIR/root_hash.p7s" "$WORK_DIR/root_hash.p7s.orig"
654
655
# Test 1: Truncated signature
656
log_info "Sub-test: Truncated signature (should fail)"
657
head -c 100 "$WORK_DIR/root_hash.p7s.orig" > "$WORK_DIR/root_hash.p7s"
658
if activate_verity_device "yes"; then
659
log_fail "Truncated signature should be rejected"
660
deactivate_verity_device
661
cp "$WORK_DIR/root_hash.p7s.orig" "$WORK_DIR/root_hash.p7s"
662
return 1
663
else
664
log_pass "Truncated signature correctly rejected"
665
fi
666
667
# Test 2: Corrupted signature (flip some bytes)
668
log_info "Sub-test: Corrupted signature bytes (should fail)"
669
cp "$WORK_DIR/root_hash.p7s.orig" "$WORK_DIR/root_hash.p7s"
670
# Corrupt bytes in the middle of the signature
671
local sig_size
672
sig_size=$(wc -c < "$WORK_DIR/root_hash.p7s")
673
local corrupt_offset=$((sig_size / 2))
674
printf '\xff\xff\xff\xff' | dd of="$WORK_DIR/root_hash.p7s" bs=1 seek=$corrupt_offset conv=notrunc 2>/dev/null
675
if activate_verity_device "yes"; then
676
log_fail "Corrupted signature should be rejected"
677
deactivate_verity_device
678
cp "$WORK_DIR/root_hash.p7s.orig" "$WORK_DIR/root_hash.p7s"
679
return 1
680
else
681
log_pass "Corrupted signature correctly rejected"
682
fi
683
684
# Test 3: Signature over wrong data (sign different content)
685
log_info "Sub-test: Signature over wrong data (should fail)"
686
# Create a different root hash (all zeros as hex string)
687
printf '%064d' 0 > "$WORK_DIR/wrong_hash.txt"
688
# Get the first key directory that was used
689
local key_dir="$WORK_DIR/keys/vendor-a"
690
if [ -d "$key_dir" ]; then
691
create_detached_signature "$WORK_DIR/wrong_hash.txt" "$WORK_DIR/root_hash.p7s" \
692
"$key_dir/cert.pem" "$key_dir/private.pem"
693
if activate_verity_device "yes"; then
694
log_fail "Signature over wrong data should be rejected"
695
deactivate_verity_device
696
cp "$WORK_DIR/root_hash.p7s.orig" "$WORK_DIR/root_hash.p7s"
697
return 1
698
else
699
log_pass "Signature over wrong data correctly rejected"
700
fi
701
else
702
log_warn "Key directory not found, skipping wrong data test"
703
fi
704
705
# Restore original signature
706
cp "$WORK_DIR/root_hash.p7s.orig" "$WORK_DIR/root_hash.p7s"
707
708
log_pass "Corrupted signature test completed successfully"
709
return 0
710
}
711
712
#
713
# Test: Verify keyring is sealed when keyring_unsealed=0
714
#
715
test_keyring_sealed_by_default() {
716
log_info "TEST: Verify keyring is sealed by default (keyring_unsealed=0)"
717
718
local keyring_id
719
keyring_id=$(cat "$WORK_DIR/keyring_id")
720
721
log_info "Current keyring state (should be empty and sealed):"
722
list_keyring_keys
723
show_keyring_status
724
725
generate_keys
726
727
# Try to add a key - should fail if keyring is sealed
728
log_info "Attempting to add key to sealed keyring..."
729
if keyctl padd asymmetric "dm-verity-test" "$keyring_id" \
730
< "$WORK_DIR/cert.der" 2>/dev/null; then
731
log_fail "Keyring should be sealed when keyring_unsealed=0"
732
list_keyring_keys
733
return 1
734
else
735
log_pass "Keyring is correctly sealed when keyring_unsealed=0"
736
log_info "Keyring state after failed add attempt:"
737
list_keyring_keys
738
return 0
739
fi
740
}
741
742
#
743
# Test: Verify dm-verity keyring is inactive when sealed empty
744
#
745
test_keyring_inactive_when_empty() {
746
log_info "TEST: Verify dm-verity keyring is inactive when sealed empty"
747
748
# When keyring_unsealed=0, the keyring is sealed immediately while empty
749
# This means it should NOT be used for verification (nr_leaves_on_tree=0)
750
751
log_info "Keyring state (should be empty and sealed):"
752
list_keyring_keys
753
show_keyring_status
754
755
create_test_device
756
create_verity_hash
757
758
# Without any keys in the dm-verity keyring, and with it sealed,
759
# verification should fall through to the secondary/platform keyrings
760
# and likely succeed (if require_signatures=0) or fail (if =1)
761
762
log_info "Sub-test: Device activation with sealed empty keyring"
763
if [ "$REQUIRE_SIGNATURES" = "Y" ] || [ "$REQUIRE_SIGNATURES" = "1" ]; then
764
if activate_verity_device "no"; then
765
log_fail "Device should NOT activate without signature when require_signatures=1"
766
deactivate_verity_device
767
return 1
768
else
769
log_pass "Device correctly rejected (require_signatures=1, no valid signature)"
770
fi
771
else
772
if activate_verity_device "no"; then
773
log_pass "Device activated (require_signatures=0, empty dm-verity keyring is inactive)"
774
deactivate_verity_device
775
else
776
log_fail "Device should activate when require_signatures=0"
777
return 1
778
fi
779
fi
780
781
return 0
782
}
783
784
main() {
785
local rc=0
786
787
log_info "=== dm-verity keyring test ==="
788
log_info ""
789
790
# Create work directory
791
WORK_DIR=$(mktemp -d -t dm-verity-test.XXXXXX)
792
log_info "Work directory: $WORK_DIR"
793
794
check_requirements
795
796
#
797
# Test 1: UNSEALED keyring mode (keyring_unsealed=1)
798
#
799
log_info ""
800
log_info "========================================"
801
log_info "=== TEST MODE: UNSEALED KEYRING ==="
802
log_info "========================================"
803
log_info ""
804
805
load_dm_verity_module 1 1 # keyring_unsealed=1, require_signatures=1
806
show_keyring_status
807
808
log_info ""
809
if ! test_multiple_keys; then
810
rc=1
811
fi
812
813
# After sealing, verify it rejects new keys
814
log_info ""
815
if ! test_sealed_keyring_rejects_keys; then
816
rc=1
817
fi
818
819
# Test corrupted signatures are rejected
820
log_info ""
821
if ! test_corrupted_signature; then
822
rc=1
823
fi
824
825
# Clean up devices before reloading module
826
deactivate_verity_device
827
if [ -n "$DATA_DEV" ] && [[ "$DATA_DEV" == /dev/loop* ]]; then
828
losetup -d "$DATA_DEV" 2>/dev/null || true
829
DATA_DEV=""
830
fi
831
if [ -n "$HASH_DEV" ] && [[ "$HASH_DEV" == /dev/loop* ]]; then
832
losetup -d "$HASH_DEV" 2>/dev/null || true
833
HASH_DEV=""
834
fi
835
836
#
837
# Test 2: SEALED keyring mode (keyring_unsealed=0, default)
838
#
839
log_info ""
840
log_info "========================================"
841
log_info "=== TEST MODE: SEALED KEYRING (default) ==="
842
log_info "========================================"
843
log_info ""
844
845
load_dm_verity_module 0 0 # keyring_unsealed=0, require_signatures=0
846
show_keyring_status
847
848
log_info ""
849
if ! test_keyring_sealed_by_default; then
850
rc=1
851
fi
852
853
log_info ""
854
if ! test_keyring_inactive_when_empty; then
855
rc=1
856
fi
857
858
#
859
# Summary
860
#
861
log_info ""
862
log_info "========================================"
863
if [ $rc -eq 0 ]; then
864
log_info "=== All tests PASSED ==="
865
else
866
log_error "=== Some tests FAILED ==="
867
fi
868
log_info "========================================"
869
870
return $rc
871
}
872
873
main "$@"
874
875