From 2332446b29d7214d1b0857b87bba238e3bebf857 Mon Sep 17 00:00:00 2001 From: Ramakrishna Gali Date: Fri, 13 Sep 2024 19:48:10 +0000 Subject: [PATCH] Added Coconut-SVSM support to invoke AMD-ES/AMD-SEV for setting up the host, launching the guest (directly setting up snpguest in the guest VM), and performing attestation & measurement verification (using igvmmeasure vs snpguest) --- tools/snp.sh | 187 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 165 insertions(+), 22 deletions(-) diff --git a/tools/snp.sh b/tools/snp.sh index 95fa637..14fd465 100755 --- a/tools/snp.sh +++ b/tools/snp.sh @@ -94,6 +94,8 @@ GENERATED_INITRD_BIN="${SETUP_WORKING_DIR}/initrd.img" AMDSEV_URL="https://github.com/ryansavino/AMDSEV.git" AMDSEV_DEFAULT_BRANCH="snp-latest-fixes" AMDSEV_NON_UPM_BRANCH="snp-non-upm" +AMDSEV_SVSM_URL="https://github.com/ramagali24/AMDSEV-SVSM.git" +AMDSEV_SVSM_BRANCH="svsm-latest" SNPGUEST_URL="https://github.com/virtee/snpguest.git" SNPGUEST_BRANCH="tags/v0.7.1" NASM_SOURCE_TAR_URL="https://www.nasm.us/pub/nasm/releasebuilds/2.16.01/nasm-2.16.01.tar.gz" @@ -116,6 +118,7 @@ usage() { >&2 echo " stop-guests Stop all SNP guests started by this script" >&2 echo " where OPTIONS are:" >&2 echo " -n|--non-upm Build AMDSEV non UPM kernel (sev-snp-devel)" + >&2 echo " -s|--svsm Build coconut-svsm components, launch guest and verity attestaion & measurement" >&2 echo " -i|--image Path to existing image file" >&2 echo " -h|--help Usage information" @@ -522,12 +525,22 @@ save_binary_paths() { local guest_kernel=$(echo $(realpath "${SETUP_WORKING_DIR}/AMDSEV/linux/guest/vmlinuz-${guest_kernel_version}")) # Save binary paths in source file -cat > "${SETUP_WORKING_DIR}/source-bins" < "${SETUP_WORKING_DIR}/source-bins" < "${SETUP_WORKING_DIR}/source-bins" < "${LAUNCH_WORKING_DIR}/source-bins" < "${LAUNCH_WORKING_DIR}/source-bins" </dev/null } -build_and_install_amdsev() { +build_and_install_amdsev() { + local amdsev_branch="${1:-${AMDSEV_DEFAULT_BRANCH}}" - + + if [ "$SVSM" = true ]; then + local amdsev_branch="${1:-${AMDSEV_DEFAULT_BRANCH}}" + + else + AMDSEV_URL=${AMDSEV_SVSM_URL} + amdsev_branch="svsm-latest" + # Create directory + + fi + # Create directory mkdir -p "${SETUP_WORKING_DIR}" @@ -664,10 +696,12 @@ build_and_install_amdsev() { git remote set-url current "${AMDSEV_URL}" git fetch current "${amdsev_branch}" git checkout "current/${amdsev_branch}" - + + if [ "$SVSM" = true ]; then # Based on latest AMDSEV documentation # Delete the ovmf/ directory prior to the build step for ovmf re-initialization [ ! -d "ovmf" ] || rm -rf "ovmf" + fi # Build and copy files ./build.sh --package @@ -786,7 +820,12 @@ setup_and_launch_guest() { #add_qemu_cmdline_opts "-machine pc-q35-7.1" # snp object and kernel-hashes on - add_qemu_cmdline_opts "-object sev-snp-guest,id=sev0,cbitpos=51,reduced-phys-bits=1,kernel-hashes=on" + if [ "$SVSM" = true ]; then + add_qemu_cmdline_opts "-object sev-snp-guest,id=sev0,cbitpos=51,reduced-phys-bits=1,kernel-hashes=on" + else + add_qemu_cmdline_opts "-object memory-backend-memfd,size=2G,id=mem0,share=true,prealloc=false,reserve=off" + add_qemu_cmdline_opts "-object sev-snp-guest,id=sev0,cbitpos=51,reduced-phys-bits=1,init-flags=5,igvm-file="$IGVM_FILE"" + fi # ovmf, initrd, kernel and append options add_qemu_cmdline_opts "-bios ${OVMF_BIN}" @@ -1081,22 +1120,28 @@ attest_guest() { ssh_guest_command "sudo insmod /lib/modules/*/kernel/drivers/virt/coco/sev-guest/sev-guest.ko >/dev/null 2>&1 || true" # Request and display the snp attestation report with random data - ssh_guest_command "sudo ./snpguest report attestation-report.bin request-data.txt --random" - ssh_guest_command "./snpguest display report attestation-report.bin" + if [ "$SVSM" = true ]; then + ssh_guest_command "sudo ./snpguest report attestation-report.bin request-data.txt --random" + else + ssh_guest_command "sudo ./$Home/snpguest/target/release/snpguest report attestation-report.bin request-data.txt --random --vmpl 3" + fi + ssh_guest_command "./$Home/snpguest/target/release/snpguest display report attestation-report.bin" # Retrieve ark, ask, vcek (saved in ./certs) - ssh_guest_command "./snpguest fetch ca pem ${cpu_code_name} . --endorser vcek" - ssh_guest_command "./snpguest fetch vcek pem ${cpu_code_name} . attestation-report.bin" + ssh_guest_command "./$Home/snpguest/target/release/snpguest fetch ca pem ${cpu_code_name} ." + ssh_guest_command "./$Home/snpguest/target/release/snpguest fetch vcek pem ${cpu_code_name} . attestation-report.bin" # Verifies that ARK, ASK and VCEK are all properly signed - ssh_guest_command "./snpguest verify certs ." + ssh_guest_command "./$Home/snpguest/target/release/snpguest verify certs ." # Verifies the attestation-report trusted compute base matches vcek - ssh_guest_command "./snpguest verify attestation . attestation-report.bin" - - # Use sev-snp-measure utility to calculate the expected measurement - local expected_measurement=$(generate_snp_expected_measurement) - echo -e "\nExpected Measurement (sev-snp-measure): ${expected_measurement}" + ssh_guest_command "./$Home/snpguest/target/release/snpguest verify attestation . attestation-report.bin" + + if [ "$SVSM" = true ]; then + + # Use sev-snp-measure utility to calculate the expected measurement + local expected_measurement=$(generate_snp_expected_measurement) + echo -e "\nExpected Measurement (sev-snp-measure): ${expected_measurement}" # Parse the measurement out of the snp report local snpguest_report_measurement=$(ssh_guest_command \ @@ -1107,16 +1152,102 @@ attest_guest() { # Remove any special characters and print the value snpguest_report_measurement=$(echo ${snpguest_report_measurement} | sed $'s/[^[:print:]\t]//g') + echo -e "Measurement from SNP Attestation Report: ${snpguest_report_measurement}\n" + + # Compare the expected measurement to the guest report measurement + [[ "${expected_measurement}" == "${snpguest_report_measurement}" ]] \ + && echo -e "The expected measurement matches the snp guest report measurement!" \ + || { >&2 echo -e "FAIL: measurements do not match"; return 1; } +else + Verify_measurement +fi +} +setup_svsm_guest_attestation() { + + ssh_guest_command " + + # Update and install necessary packages + echo 'Updating package list...' + sudo apt-get update + + echo 'Installing necessary packages...' + sudo apt-get install -y git build-essential libtss2-dev tpm2-tools + + echo 'Installing Rust...' + source ""${HOME}"/.cargo/env" 2>/dev/null || true + + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs -sSf | sh -s -- -y + source ""${HOME}"/.cargo/env" 2>/dev/null + " + + # Check if 'snpguest' directory exists and remove it if it does + ssh_guest_command " + if [ -d \"snpguest\" ]; then + echo 'Directory snpguest exists. Removing it...' + rm -rf snpguest + else + echo 'Directory snpguest does not exist.' + fi +" + + # Clone the repository and build the project + ssh_guest_command "git clone https://github.com/virtee/snpguest.git" + ssh_guest_command "cd snpguest && source \$HOME/.cargo/env && cargo build --release" +} + +Verify_measurement(){ + + # Define the working directory and the output file + OUTPUT_FILE="$SETUP_WORKING_DIR/make_output.txt" + # Define the firmware file path + FW_FILE="$SETUP_WORKING_DIR/AMDSEV/ovmf/Build/OvmfX64/DEBUG_GCC5/FV/OVMF.fd" + + cd "$SETUP_WORKING_DIR"/AMDSEV/svsm + + # Run the make command and save the output to a file + FW_FILE="$FW_FILE" make &> "$OUTPUT_FILE" + + # Initialize the variable for Launch Digest + launch_digest="" + + # Read the output file line by line to find the Launch Digest + while IFS= read -r line; do + if [[ "$line" == *"Launch Digest:"* ]]; then + launch_digest=$(echo "$line" | awk '{print $3}') + break + fi + done < "$OUTPUT_FILE" + + # Output the Launch Digest to verify + echo "Launch Digest: $launch_digest" + + # Use igvmmeasure utility to calculate the expected measurement + local expected_measurement=$launch_digest + echo -e "\nExpected Measurement (igvmmeasure): ${expected_measurement}" + + # Parse the measurement out of the snp report + scp_guest_command "${GUEST_USER}@localhost:$HOME/attestation-report.bin" "$SETUP_WORKING_DIR/AMDSEV/svsm" + + cd "$SETUP_WORKING_DIR"/AMDSEV/svsm + # Assign the output of the hexdump command to a variable + snpguest_report_measurement=$(hexdump -s 0x90 -n 48 -v -e '48/1 "%02X"' attestation-report.bin) + + # Print the variable to verify its content + echo "$snpguest_report_measurement" echo -e "Measurement from SNP Attestation Report: ${snpguest_report_measurement}\n" # Compare the expected measurement to the guest report measurement - [[ "${expected_measurement}" == "${snpguest_report_measurement}" ]] \ - && echo -e "The expected measurement matches the snp guest report measurement!" \ - || { >&2 echo -e "FAIL: measurements do not match"; return 1; } + if [[ "${expected_measurement}" == "${snpguest_report_measurement}" ]]; then + echo -e "The expected measurement matches the SNP guest report measurement!" + else + >&2 echo -e "FAIL: Measurements do not match" + return 1 + fi } + ############################################################################### # Main @@ -1147,6 +1278,10 @@ main() { IMAGE="${2}" SKIP_IMAGE_CREATE=true shift; shift + ;; + -svsm) + SVSM=false + shift ;; setup-host) @@ -1223,8 +1358,11 @@ main() { # TEMPORARY until sev-snp-measure is updated to pass in TCB kernel modifier flags # Changes in AMDESE/linux set debug_swap on by default and affect the measurement - sudo modprobe -r kvm_amd - sudo modprobe kvm_amd debug_swap=0 + if [ "$SVSM" = true ]; then + sudo modprobe -r kvm_amd + sudo modprobe kvm_amd debug_swap=0 + fi + setup_and_launch_guest wait_and_retry_command verify_snp_guest @@ -1235,12 +1373,17 @@ main() { ;; attest-guest) + if [ "$SVSM" = true ]; then install_rust install_sev_snp_measure install_dependencies wait_and_retry_command verify_snp_guest setup_guest_attestation - attest_guest + else + wait_and_retry_command verify_snp_guest + setup_svsm_guest_attestation + fi + attest_guest ;; stop-guests)