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 25set -e 26 27WORK_DIR="" 28DATA_DEV="" 29HASH_DEV="" 30DM_NAME="verity-test-$$" 31CLEANUP_DONE=0 32 33# Module parameters (detected at runtime) 34KEYRING_UNSEALED="" 35REQUIRE_SIGNATURES="" 36 37# Colors for output 38RED='\033[0;31m' 39GREEN='\033[0;32m' 40YELLOW='\033[1;33m' 41NC='\033[0m' # No Color 42 43log_info() { 44 echo -e "${GREEN}[INFO]${NC} $*" 45} 46 47log_warn() { 48 echo -e "${YELLOW}[WARN]${NC} $*" 49} 50 51log_error() { 52 echo -e "${RED}[ERROR]${NC} $*" >&2 53} 54 55log_pass() { 56 echo -e "${GREEN}[PASS]${NC} $*" 57} 58 59log_fail() { 60 echo -e "${RED}[FAIL]${NC} $*" >&2 61} 62 63log_skip() { 64 echo -e "${YELLOW}[SKIP]${NC} $*" 65} 66 67cleanup() { 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 94trap cleanup EXIT 95 96die() { 97 log_error "$*" 98 exit 1 99} 100 101find_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 115get_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 126check_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 151load_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 194unload_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 212generate_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] 224distinguished_name = req_distinguished_name 225x509_extensions = v3_ca 226prompt = no 227 228[req_distinguished_name] 229CN = dm-verity-test-key 230 231[v3_ca] 232basicConstraints = critical,CA:FALSE 233keyUsage = digitalSignature 234subjectKeyIdentifier = hash 235authorityKeyIdentifier = keyid 236EOF 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 255seal_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 267create_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 284create_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 301create_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 325activate_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 355deactivate_verity_device() { 356 if dmsetup info "$DM_NAME" &>/dev/null; then 357 dmsetup remove "$DM_NAME" 2>/dev/null || true 358 fi 359} 360 361show_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 374list_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 405generate_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] 422distinguished_name = req_distinguished_name 423x509_extensions = v3_ca 424prompt = no 425 426[req_distinguished_name] 427CN = dm-verity-test-$name 428 429[v3_ca] 430basicConstraints = critical,CA:FALSE 431keyUsage = digitalSignature 432subjectKeyIdentifier = hash 433authorityKeyIdentifier = keyid 434EOF 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 449upload_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# 473test_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# 495test_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 599sign_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# 641test_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# 715test_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# 745test_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 784main() { 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 873main "$@" 874