Skip to content

Commit

Permalink
KATA-3442: Standalone Script for retrieval of RVPS From SE PODVM (#467)
Browse files Browse the repository at this point in the history
KATA-3442: Standalone Script for retrieval of RVPS From SE PODVM

Signed-off-by: Gaurav Kumar <[email protected]>
(cherry picked from commit 1cad3e5)
Signed-off-by: Greg Kurz <[email protected]>
  • Loading branch information
gauravkuredhat authored and gkurz committed Oct 31, 2024
1 parent 28f7379 commit b04635e
Show file tree
Hide file tree
Showing 5 changed files with 554 additions and 0 deletions.
193 changes: 193 additions & 0 deletions hack/Rvps-Extraction/GetRvps.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
#!/bin/bash
# Getting RVPS Parameters

function install_packages() {
echo "***Installing necessary packages for RVPS values extraction ***"
dnf install -y python3 python3-cryptography kmod
echo "***Installation Finished ***"
}

# Function to mount the image and extract se.img
function mount_and_extract_image() {
local img_path=$1

# Cleanup any previous files and directories
rm -rf se.img /mnt/myvm
mkdir /mnt/myvm

# Load nbd module and mount the image
modprobe nbd
if [ $? -ne 0 ]; then
echo "Error: Failed to load nbd module."
exit 1
fi

qemu-nbd -c /dev/nbd3 $img_path
if [ $? -ne 0 ]; then
echo "Error: Failed to connect to nbd device."
exit 1
fi


mount /dev/nbd3p1 /mnt/myvm
if [ $? -ne 0 ]; then
echo "Error: Failed to mount the image. Retrying..."
sleep 2
mount /dev/nbd3p1 /mnt/myvm
if [ $? -ne 0 ]; then
echo "Retrial for mounting failed. Please rerun the script"
exit 1
else
echo "Mounting on second attempt passed"
fi
fi
# Extract and process image
rm -rf $PWD/output-files
mkdir -p $PWD/output-files
rm -rf se.img
cp /mnt/myvm/se.img ./
mv se.img $PWD/output-files/

umount /mnt/myvm
qemu-nbd -d /dev/nbd3
}

# Function to generate se-sample and ibmse-policy.rego files
function generate_policy_files() {
local se_tag=$1
local se_image_phkh=$2

# Create se-sample file
cat <<EOF > $PWD/output-files/se-sample
{
"se.attestation_phkh": [
"$se_image_phkh"
],
"se.tag": [
"$se_tag"
],
"se.image_phkh": [
"$se_image_phkh"
],
"se.user_data": [
"00"
],
"se.version": [
"256"
]
}
EOF

# Create ibmse-policy.rego file
cat <<EOF > $PWD/output-files/ibmse-policy.rego
package policy
import rego.v1
default allow = false
converted_version := sprintf("%v", [input["se.version"]])
allow if {
input["se.attestation_phkh"] == "$se_image_phkh"
input["se.image_phkh"] == "$se_image_phkh"
input["se.tag"] == "$se_tag"
input["se.user_data"] == "00"
converted_version == "256"
}
EOF

}

# Main function
install_packages

PS3='Please enter your choice: '
options=("Generate the RVPS From Local Image from User pc" "Generate RVPS from Volume" "Quit")
select opt in "${options[@]}"
do
case $opt in
"Generate the RVPS From Local Image from User pc")
echo "Enter the Qcow2 image with Full path"
read -r img_path

mount_and_extract_image $img_path

$PWD/static-files/pvextract-hdr -o $PWD/output-files/hdr.bin $PWD/output-files/se.img

# Extract necessary values
se_tag=$(python3 $PWD/static-files/se_parse_hdr.py $PWD/output-files/hdr.bin $PWD/static-files/HKD.crt | grep se.tag | awk -F ":" '{ print $2 }')
se_image_phkh=$(python3 $PWD/static-files/se_parse_hdr.py $PWD/output-files/hdr.bin $PWD/static-files/HKD.crt | grep se.image_phkh | awk -F ":" '{ print $2 }')

echo "se.tag: $se_tag"
echo "se.image_phkh: $se_image_phkh"

generate_policy_files $se_tag $se_image_phkh

provenance=$(cat $PWD/output-files/se-sample | base64 --wrap=0)
echo "provenance = $provenance"

# Create se-message file
cat <<EOF > $PWD/output-files/se-message
{
"version" : "0.1.0",
"type": "sample",
"payload": "$provenance"
}
EOF

ls -lrt $PWD/output-files/hdr.bin $PWD/output-files/se-message $PWD/output-files/ibmse-policy.rego
;;

"Generate RVPS from Volume")
echo "Enter the Libvirt Pool Name"
read -r LIBVIRT_POOL
echo "Enter the Libvirt URI Name"
read -r LIBVIRT_URI
echo "Enter the Libvirt Volume Name"
read -r LIBVIRT_VOL

# Download the volume
echo "Downloading from PODVM Volume..."
rm -rf $PWD/PODVM-VOL-IMAGE
mkdir -p $PWD/PODVM-VOL-IMAGE
virsh -c $LIBVIRT_URI vol-download --vol $LIBVIRT_VOL --pool $LIBVIRT_POOL --file $PWD/PODVM-VOL-IMAGE/podvm_test.qcow2 --sparse
if [ $? -ne 0 ]; then
echo "Downloading Failed"
exit 1
fi

img_path=$PWD/PODVM-VOL-IMAGE/podvm_test.qcow2

mount_and_extract_image $img_path

$PWD/static-files/pvextract-hdr -o $PWD/output-files/hdr.bin $PWD/output-files/se.img

# Extract necessary values
se_tag=$(python3 $PWD/static-files/se_parse_hdr.py $PWD/output-files/hdr.bin $PWD/static-files/HKD.crt | grep se.tag | awk -F ":" '{ print $2 }')
se_image_phkh=$(python3 $PWD/static-files/se_parse_hdr.py $PWD/output-files/hdr.bin $PWD/static-files/HKD.crt | grep se.image_phkh | awk -F ":" '{ print $2 }')

echo "se.tag: $se_tag"
echo "se.image_phkh: $se_image_phkh"

generate_policy_files $se_tag $se_image_phkh

provenance=$(cat $PWD/output-files/se-sample | base64 --wrap=0)
echo "provenance = $provenance"

# Create se-message file
cat <<EOF > $PWD/output-files/se-message
{
"version" : "0.1.0",
"type": "sample",
"payload": "$provenance"
}
EOF

ls -lrt $PWD/output-files/hdr.bin $PWD/output-files/se-message $PWD/output-files/ibmse-policy.rego
;;

"Quit")
break
;;

*) echo "Invalid option: $REPLY";;
esac
done

71 changes: 71 additions & 0 deletions hack/Rvps-Extraction/RVPS_Reference.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@

# RVPS (Reference Value Provider Service) Usage

The RVPS (Reference Value Provider Service) values are used for remote attestation.

It is responsible for verifying, storing, and providing reference values. RVPS receives and verifies inputs from the software supply chain, stores the measurement values, and generates reference value claims for the Attestation Service.

This operation is performed based on the evidence verified by the Attestation Service (AS).

## RVPS Values

The values are:

1. `image_phkh`
2. `image_tag`
3. `se.version`
4. `se.tag`
5. `se.attestation_phk`

## Script Options

The script will help retrieve the RVPS via the following two options:

1. **Calculate the RVPS values based on the SE PODVM image stored locally** on the user’s machine where the script is being executed. The script will expect the absolute path of the SE PODVM image.

2. **Calculate the RVPS values based on the SE PODVM image uploaded to a libvirt volume**. The script will expect the following inputs:
- Libvirt Pool Name
- Libvirt URI Name
- Libvirt Volume Name

## Output

After successful execution, you will get `se-message` and `ibmse-policy.rego` in a directory called `output-files`. These files will contain the RVPS parameters.

## Prerequisites

The user needs to copy the `Rvps-Extraction` folder locally:

```bash
[root@a3elp36 Rvps-Extraction]# ls -lrt
total 8
drwxr-xr-x. 2 root root 65 Oct 19 16:52 static-files
-rwxr-xr-x. 1 root root 6078 Oct 19 16:52 GetRvps.sh
```

Once copied, the script can be executed as follows:

```bash
./GetRvps.sh
```

### Options
1. Generate the RVPS from a local image on the user’s PC
2. Generate RVPS from a volume
3. Quit

Once the script finishes, the output directory will be created, and the files will be copied to the same path where the script is executed. For example:

```bash
-rw-r--r--. 1 root root 640 Oct 9 13:25 /root/gaurav-rvps-test/COCO-1010/output-files/hdr.bin
-rw-r--r--. 1 root root 446 Oct 9 13:25 /root/gaurav-rvps-test/COCO-1010/output-files/ibmse-policy.rego
-rw-r--r--. 1 root root 561 Oct 9 13:25 /root/gaurav-rvps-test/COCO-1010/output-files/se-message
```

## Static Files

Some static files will also be used to generate the RVPS. These include:

- **`pvextract-hdr`**: This is used to extract the SE header from the PODVM SE image (input). It generates an intermediate file, `hdr.bin`, which will be used for further extraction.
- **`se_parse_hdr.py`**: A Python parser used to generate the actual RVPS values.
- **`HKD.crt`**: This certificate will vary between labs. The user needs to copy the same `HKD.crt` used to generate the uploaded PODVM SE image into this path.
24 changes: 24 additions & 0 deletions hack/Rvps-Extraction/static-files/HKD.crt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
-----BEGIN CERTIFICATE-----
MIID7jCCAdagAwIBAgIJBFlsRgUYzLtIMA0GCSqGSIb3DQEBDQUAMGMxCzAJBgNV
BAYTAlVTMQwwCgYDVQQKDANJQk0xEDAOBgNVBAsMB1Rlc3RpbmcxDDAKBgNVBAcM
A1BPSzELMAkGA1UECAwCTlkxGTAXBgNVBAMMEFFTYWZlIEhLIHNpZ25pbmcwHhcN
MjQwMjI4MTAzNjE4WhcNMjUwMjI3MTAzNjE4WjBbMQswCQYDVQQGEwJVUzEMMAoG
A1UECgwDSUJNMRAwDgYDVQQLDAdUZXN0aW5nMQwwCgYDVQQHDANQT0sxCzAJBgNV
BAgMAk5ZMREwDwYDVQQDDAhRc2FmZSBISzCBmzAQBgcqhkjOPQIBBgUrgQQAIwOB
hgAEAIs8F4mItSnho7Wx/ngnZTfsQ9LtSchfKvc1r6Op5vNKGOuiuJ30GTOZUoZD
M/MqioakC4EB0cpSTllh6qrYuxz2AUHgstGQNAFctkCKE3GqMEuFrcgazUvbV4JD
NXSl/KB6uaKCgAeOuxw37+WkWaUpNOvpsh/dCjZ3pJeWYjv92r6BozUwMzAOBgNV
HQ8BAf8EBAMCAwgwIQYDVR0fBBowGDAWoBSgEoYQaHR0cDovL3NvbWV3aGVyZTAN
BgkqhkiG9w0BAQ0FAAOCAgEAas/Vg/xdwA3BqroBY+aRAfd6hwMNdVjbooYjga9M
WeM6zDW+JOPuVYWij/yWGvRzKrmxwdpDrlEwQNFvh9uiwZorv6PCMnrF0Qprdwyl
rvUzwXV28xrRgJtCpU5PDw2NSXZse7nsZD9zxtEYu8RywhtVO6LnXViAeTZLn1jK
LMc+P1FlEA/+aVmNT3hr+sfFTDKn1oP4RbYJy4T9cbIGRgtRWpMyQaSqEX1bPytW
ZjdK+LU55bZceAIrfR0um+gGSB+rRdyDQU0g9BS0dDXxVhDkzKVrD/UG2dqXd106
Q3JeuROVwdd55dvwD5b+UmSS52oRlmTff1uJg6BF6tHWP7zh5rqLJdH3ds5AfITb
2tHK3M1KhwIivbtBzogWH+LaxEF3n5V2FCc8bx92zB81IhKycSLnmE9OZ602d/0j
BCU0hkh8BZS7o6A3sTHZHFh65jjFwRMQSDY43MLeNBWhdX8ymOcuiwVPWsHrrIBK
w01nAbpR4IedQgwc0SJtExsqWKGS6OEyaDV5QcZh97/PA8ddBmsaJyZESJuwj1hp
hq6jU/NtOT/J33vnoO0UWX8FaX58+4MCG638/fatMsdCUmt1OTw1b9Qry/p7pn56
53FvYE30z1G7Arsu7LzTaz8EfLzQ57MVKb9cj2/NKzqhh5PMIb+9SdznQGuDqj5F
++c=
-----END CERTIFICATE-----
104 changes: 104 additions & 0 deletions hack/Rvps-Extraction/static-files/pvextract-hdr
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
#!/bin/bash
#
# pvextract_hdr - extract an IBM Secure Execution header from the Image
#
# Sample:
# ./pvextract-hdr -o sehdr.bin se-image.bin
#
# Copyright IBM Corp. 2022
#
# s390-tools is free software; you can redistribute it and/or modify
# it under the terms of the MIT license. See LICENSE for details.

set -o pipefail
set -o nounset
set -e

XDUMP='od -A x -t x2z -v --endian=big'

def_output='sehdr.bin'
def_skip=0x14
def_len=0x4

usage() {
cat <<-EOF
Usage: $(basename "$0") [-o ${def_output}] [-s ${def_skip}] [-l ${def_len}] FILE
Extract the header of the SE-image located in FILE.
By default ${def_skip} pages will be skipped until starting to search
for the header. By default the search will be stopped after ${def_len} pages.
'${def_output}' is the default output file name.
EOF
}

function check_file() {
[ -e "$1" ] ||
{ echo "ERROR: File '$1' not found" >&2 && exit 1; }
}

function check_hdr_ver() {
local hdr_start="$1"
local input="$2"
${XDUMP} --skip-bytes $((hdr_start + 8)) --read-bytes 4 -- "$input" 2>/dev/null | grep -q "000 0100" ||
{ echo -n "WARNING: unknown hdr version " &&
${XDUMP} --skip-bytes $((hdr_start + 8)) --read_bytes 4 -- "$input" 2>/dev/null | awk '{print "0x" $2 $3}'; }
}

function require_command() {
local cmd="$1"

command -v "$cmd" >/dev/null 2>&1 || \
{ echo >&2 "ERROR: $cmd required but not installed."; exit 1; }
}

require_command od
require_command awk
require_command grep

output=${def_output}
parsed_skip=${def_skip}
parsed_len=${def_len}
# the last argument must be the input file
input="${*: -1}"
while getopts 'o:s:l:h' OPTION; do
case "$OPTION" in
o) output="$OPTARG" ;;
s) parsed_skip="$OPTARG" ;;
l) parsed_len="$OPTARG" ;;
h)
usage
exit 0
;;
:)
echo "ERROR: Must supply an argument to -$OPTARG." >&2
exit 1
;;
*)
usage
exit 1
;;
esac
done

#argument specify pages; convert to bytes
skip=$((parsed_skip * 0x1000))
len=$((parsed_len * 0x1000))

if [ $# -eq 0 ]; then
echo "ERROR: Input not set. Use '$(basename "$0") [FILE]' to specify the Input file" >&2
exit 1
fi

check_file "$input"
hdr_start=$(${XDUMP} --skip-bytes $((skip)) --read-bytes $((len)) -- "${input}" 2>/dev/null | grep IBMSecEx ||
{ echo ERROR: "${input} does not contain an SE header." >&2 && exit 1; })
hdr_start=$(echo "${hdr_start}" | awk '{print "0x" $1}' | cut -c 1-10)
echo "SE header found at offset ${hdr_start}"

check_hdr_ver "$hdr_start" "$input"

size=$(${XDUMP} --skip-bytes $((hdr_start + 12)) --read-bytes 4 -- "${input}" 2>/dev/null |
awk 'NR==1 {print "0x" $2 $3}')

dd if="${input}" of="${output}" bs=1 count=$((size)) skip=$((hdr_start)) status=none
echo "SE header written to '${output}' ($((size)) bytes)"
Loading

0 comments on commit b04635e

Please sign in to comment.