Skip to content

Commit 1cad3e5

Browse files
KATA-3442: Standalone Script for retrieval of RVPS From SE PODVM (#467)
KATA-3442: Standalone Script for retrieval of RVPS From SE PODVM Signed-off-by: Gaurav Kumar <[email protected]>
1 parent 393a726 commit 1cad3e5

File tree

5 files changed

+554
-0
lines changed

5 files changed

+554
-0
lines changed

hack/Rvps-Extraction/GetRvps.sh

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
#!/bin/bash
2+
# Getting RVPS Parameters
3+
4+
function install_packages() {
5+
echo "***Installing necessary packages for RVPS values extraction ***"
6+
dnf install -y python3 python3-cryptography kmod
7+
echo "***Installation Finished ***"
8+
}
9+
10+
# Function to mount the image and extract se.img
11+
function mount_and_extract_image() {
12+
local img_path=$1
13+
14+
# Cleanup any previous files and directories
15+
rm -rf se.img /mnt/myvm
16+
mkdir /mnt/myvm
17+
18+
# Load nbd module and mount the image
19+
modprobe nbd
20+
if [ $? -ne 0 ]; then
21+
echo "Error: Failed to load nbd module."
22+
exit 1
23+
fi
24+
25+
qemu-nbd -c /dev/nbd3 $img_path
26+
if [ $? -ne 0 ]; then
27+
echo "Error: Failed to connect to nbd device."
28+
exit 1
29+
fi
30+
31+
32+
mount /dev/nbd3p1 /mnt/myvm
33+
if [ $? -ne 0 ]; then
34+
echo "Error: Failed to mount the image. Retrying..."
35+
sleep 2
36+
mount /dev/nbd3p1 /mnt/myvm
37+
if [ $? -ne 0 ]; then
38+
echo "Retrial for mounting failed. Please rerun the script"
39+
exit 1
40+
else
41+
echo "Mounting on second attempt passed"
42+
fi
43+
fi
44+
# Extract and process image
45+
rm -rf $PWD/output-files
46+
mkdir -p $PWD/output-files
47+
rm -rf se.img
48+
cp /mnt/myvm/se.img ./
49+
mv se.img $PWD/output-files/
50+
51+
umount /mnt/myvm
52+
qemu-nbd -d /dev/nbd3
53+
}
54+
55+
# Function to generate se-sample and ibmse-policy.rego files
56+
function generate_policy_files() {
57+
local se_tag=$1
58+
local se_image_phkh=$2
59+
60+
# Create se-sample file
61+
cat <<EOF > $PWD/output-files/se-sample
62+
{
63+
"se.attestation_phkh": [
64+
"$se_image_phkh"
65+
],
66+
"se.tag": [
67+
"$se_tag"
68+
],
69+
"se.image_phkh": [
70+
"$se_image_phkh"
71+
],
72+
"se.user_data": [
73+
"00"
74+
],
75+
"se.version": [
76+
"256"
77+
]
78+
}
79+
EOF
80+
81+
# Create ibmse-policy.rego file
82+
cat <<EOF > $PWD/output-files/ibmse-policy.rego
83+
package policy
84+
import rego.v1
85+
default allow = false
86+
converted_version := sprintf("%v", [input["se.version"]])
87+
allow if {
88+
input["se.attestation_phkh"] == "$se_image_phkh"
89+
input["se.image_phkh"] == "$se_image_phkh"
90+
input["se.tag"] == "$se_tag"
91+
input["se.user_data"] == "00"
92+
converted_version == "256"
93+
}
94+
EOF
95+
96+
}
97+
98+
# Main function
99+
install_packages
100+
101+
PS3='Please enter your choice: '
102+
options=("Generate the RVPS From Local Image from User pc" "Generate RVPS from Volume" "Quit")
103+
select opt in "${options[@]}"
104+
do
105+
case $opt in
106+
"Generate the RVPS From Local Image from User pc")
107+
echo "Enter the Qcow2 image with Full path"
108+
read -r img_path
109+
110+
mount_and_extract_image $img_path
111+
112+
$PWD/static-files/pvextract-hdr -o $PWD/output-files/hdr.bin $PWD/output-files/se.img
113+
114+
# Extract necessary values
115+
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 }')
116+
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 }')
117+
118+
echo "se.tag: $se_tag"
119+
echo "se.image_phkh: $se_image_phkh"
120+
121+
generate_policy_files $se_tag $se_image_phkh
122+
123+
provenance=$(cat $PWD/output-files/se-sample | base64 --wrap=0)
124+
echo "provenance = $provenance"
125+
126+
# Create se-message file
127+
cat <<EOF > $PWD/output-files/se-message
128+
{
129+
"version" : "0.1.0",
130+
"type": "sample",
131+
"payload": "$provenance"
132+
}
133+
EOF
134+
135+
ls -lrt $PWD/output-files/hdr.bin $PWD/output-files/se-message $PWD/output-files/ibmse-policy.rego
136+
;;
137+
138+
"Generate RVPS from Volume")
139+
echo "Enter the Libvirt Pool Name"
140+
read -r LIBVIRT_POOL
141+
echo "Enter the Libvirt URI Name"
142+
read -r LIBVIRT_URI
143+
echo "Enter the Libvirt Volume Name"
144+
read -r LIBVIRT_VOL
145+
146+
# Download the volume
147+
echo "Downloading from PODVM Volume..."
148+
rm -rf $PWD/PODVM-VOL-IMAGE
149+
mkdir -p $PWD/PODVM-VOL-IMAGE
150+
virsh -c $LIBVIRT_URI vol-download --vol $LIBVIRT_VOL --pool $LIBVIRT_POOL --file $PWD/PODVM-VOL-IMAGE/podvm_test.qcow2 --sparse
151+
if [ $? -ne 0 ]; then
152+
echo "Downloading Failed"
153+
exit 1
154+
fi
155+
156+
img_path=$PWD/PODVM-VOL-IMAGE/podvm_test.qcow2
157+
158+
mount_and_extract_image $img_path
159+
160+
$PWD/static-files/pvextract-hdr -o $PWD/output-files/hdr.bin $PWD/output-files/se.img
161+
162+
# Extract necessary values
163+
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 }')
164+
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 }')
165+
166+
echo "se.tag: $se_tag"
167+
echo "se.image_phkh: $se_image_phkh"
168+
169+
generate_policy_files $se_tag $se_image_phkh
170+
171+
provenance=$(cat $PWD/output-files/se-sample | base64 --wrap=0)
172+
echo "provenance = $provenance"
173+
174+
# Create se-message file
175+
cat <<EOF > $PWD/output-files/se-message
176+
{
177+
"version" : "0.1.0",
178+
"type": "sample",
179+
"payload": "$provenance"
180+
}
181+
EOF
182+
183+
ls -lrt $PWD/output-files/hdr.bin $PWD/output-files/se-message $PWD/output-files/ibmse-policy.rego
184+
;;
185+
186+
"Quit")
187+
break
188+
;;
189+
190+
*) echo "Invalid option: $REPLY";;
191+
esac
192+
done
193+
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
2+
# RVPS (Reference Value Provider Service) Usage
3+
4+
The RVPS (Reference Value Provider Service) values are used for remote attestation.
5+
6+
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.
7+
8+
This operation is performed based on the evidence verified by the Attestation Service (AS).
9+
10+
## RVPS Values
11+
12+
The values are:
13+
14+
1. `image_phkh`
15+
2. `image_tag`
16+
3. `se.version`
17+
4. `se.tag`
18+
5. `se.attestation_phk`
19+
20+
## Script Options
21+
22+
The script will help retrieve the RVPS via the following two options:
23+
24+
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.
25+
26+
2. **Calculate the RVPS values based on the SE PODVM image uploaded to a libvirt volume**. The script will expect the following inputs:
27+
- Libvirt Pool Name
28+
- Libvirt URI Name
29+
- Libvirt Volume Name
30+
31+
## Output
32+
33+
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.
34+
35+
## Prerequisites
36+
37+
The user needs to copy the `Rvps-Extraction` folder locally:
38+
39+
```bash
40+
[root@a3elp36 Rvps-Extraction]# ls -lrt
41+
total 8
42+
drwxr-xr-x. 2 root root 65 Oct 19 16:52 static-files
43+
-rwxr-xr-x. 1 root root 6078 Oct 19 16:52 GetRvps.sh
44+
```
45+
46+
Once copied, the script can be executed as follows:
47+
48+
```bash
49+
./GetRvps.sh
50+
```
51+
52+
### Options
53+
1. Generate the RVPS from a local image on the user’s PC
54+
2. Generate RVPS from a volume
55+
3. Quit
56+
57+
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:
58+
59+
```bash
60+
-rw-r--r--. 1 root root 640 Oct 9 13:25 /root/gaurav-rvps-test/COCO-1010/output-files/hdr.bin
61+
-rw-r--r--. 1 root root 446 Oct 9 13:25 /root/gaurav-rvps-test/COCO-1010/output-files/ibmse-policy.rego
62+
-rw-r--r--. 1 root root 561 Oct 9 13:25 /root/gaurav-rvps-test/COCO-1010/output-files/se-message
63+
```
64+
65+
## Static Files
66+
67+
Some static files will also be used to generate the RVPS. These include:
68+
69+
- **`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.
70+
- **`se_parse_hdr.py`**: A Python parser used to generate the actual RVPS values.
71+
- **`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.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIID7jCCAdagAwIBAgIJBFlsRgUYzLtIMA0GCSqGSIb3DQEBDQUAMGMxCzAJBgNV
3+
BAYTAlVTMQwwCgYDVQQKDANJQk0xEDAOBgNVBAsMB1Rlc3RpbmcxDDAKBgNVBAcM
4+
A1BPSzELMAkGA1UECAwCTlkxGTAXBgNVBAMMEFFTYWZlIEhLIHNpZ25pbmcwHhcN
5+
MjQwMjI4MTAzNjE4WhcNMjUwMjI3MTAzNjE4WjBbMQswCQYDVQQGEwJVUzEMMAoG
6+
A1UECgwDSUJNMRAwDgYDVQQLDAdUZXN0aW5nMQwwCgYDVQQHDANQT0sxCzAJBgNV
7+
BAgMAk5ZMREwDwYDVQQDDAhRc2FmZSBISzCBmzAQBgcqhkjOPQIBBgUrgQQAIwOB
8+
hgAEAIs8F4mItSnho7Wx/ngnZTfsQ9LtSchfKvc1r6Op5vNKGOuiuJ30GTOZUoZD
9+
M/MqioakC4EB0cpSTllh6qrYuxz2AUHgstGQNAFctkCKE3GqMEuFrcgazUvbV4JD
10+
NXSl/KB6uaKCgAeOuxw37+WkWaUpNOvpsh/dCjZ3pJeWYjv92r6BozUwMzAOBgNV
11+
HQ8BAf8EBAMCAwgwIQYDVR0fBBowGDAWoBSgEoYQaHR0cDovL3NvbWV3aGVyZTAN
12+
BgkqhkiG9w0BAQ0FAAOCAgEAas/Vg/xdwA3BqroBY+aRAfd6hwMNdVjbooYjga9M
13+
WeM6zDW+JOPuVYWij/yWGvRzKrmxwdpDrlEwQNFvh9uiwZorv6PCMnrF0Qprdwyl
14+
rvUzwXV28xrRgJtCpU5PDw2NSXZse7nsZD9zxtEYu8RywhtVO6LnXViAeTZLn1jK
15+
LMc+P1FlEA/+aVmNT3hr+sfFTDKn1oP4RbYJy4T9cbIGRgtRWpMyQaSqEX1bPytW
16+
ZjdK+LU55bZceAIrfR0um+gGSB+rRdyDQU0g9BS0dDXxVhDkzKVrD/UG2dqXd106
17+
Q3JeuROVwdd55dvwD5b+UmSS52oRlmTff1uJg6BF6tHWP7zh5rqLJdH3ds5AfITb
18+
2tHK3M1KhwIivbtBzogWH+LaxEF3n5V2FCc8bx92zB81IhKycSLnmE9OZ602d/0j
19+
BCU0hkh8BZS7o6A3sTHZHFh65jjFwRMQSDY43MLeNBWhdX8ymOcuiwVPWsHrrIBK
20+
w01nAbpR4IedQgwc0SJtExsqWKGS6OEyaDV5QcZh97/PA8ddBmsaJyZESJuwj1hp
21+
hq6jU/NtOT/J33vnoO0UWX8FaX58+4MCG638/fatMsdCUmt1OTw1b9Qry/p7pn56
22+
53FvYE30z1G7Arsu7LzTaz8EfLzQ57MVKb9cj2/NKzqhh5PMIb+9SdznQGuDqj5F
23+
++c=
24+
-----END CERTIFICATE-----
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
#!/bin/bash
2+
#
3+
# pvextract_hdr - extract an IBM Secure Execution header from the Image
4+
#
5+
# Sample:
6+
# ./pvextract-hdr -o sehdr.bin se-image.bin
7+
#
8+
# Copyright IBM Corp. 2022
9+
#
10+
# s390-tools is free software; you can redistribute it and/or modify
11+
# it under the terms of the MIT license. See LICENSE for details.
12+
13+
set -o pipefail
14+
set -o nounset
15+
set -e
16+
17+
XDUMP='od -A x -t x2z -v --endian=big'
18+
19+
def_output='sehdr.bin'
20+
def_skip=0x14
21+
def_len=0x4
22+
23+
usage() {
24+
cat <<-EOF
25+
Usage: $(basename "$0") [-o ${def_output}] [-s ${def_skip}] [-l ${def_len}] FILE
26+
27+
Extract the header of the SE-image located in FILE.
28+
By default ${def_skip} pages will be skipped until starting to search
29+
for the header. By default the search will be stopped after ${def_len} pages.
30+
'${def_output}' is the default output file name.
31+
EOF
32+
}
33+
34+
function check_file() {
35+
[ -e "$1" ] ||
36+
{ echo "ERROR: File '$1' not found" >&2 && exit 1; }
37+
}
38+
39+
function check_hdr_ver() {
40+
local hdr_start="$1"
41+
local input="$2"
42+
${XDUMP} --skip-bytes $((hdr_start + 8)) --read-bytes 4 -- "$input" 2>/dev/null | grep -q "000 0100" ||
43+
{ echo -n "WARNING: unknown hdr version " &&
44+
${XDUMP} --skip-bytes $((hdr_start + 8)) --read_bytes 4 -- "$input" 2>/dev/null | awk '{print "0x" $2 $3}'; }
45+
}
46+
47+
function require_command() {
48+
local cmd="$1"
49+
50+
command -v "$cmd" >/dev/null 2>&1 || \
51+
{ echo >&2 "ERROR: $cmd required but not installed."; exit 1; }
52+
}
53+
54+
require_command od
55+
require_command awk
56+
require_command grep
57+
58+
output=${def_output}
59+
parsed_skip=${def_skip}
60+
parsed_len=${def_len}
61+
# the last argument must be the input file
62+
input="${*: -1}"
63+
while getopts 'o:s:l:h' OPTION; do
64+
case "$OPTION" in
65+
o) output="$OPTARG" ;;
66+
s) parsed_skip="$OPTARG" ;;
67+
l) parsed_len="$OPTARG" ;;
68+
h)
69+
usage
70+
exit 0
71+
;;
72+
:)
73+
echo "ERROR: Must supply an argument to -$OPTARG." >&2
74+
exit 1
75+
;;
76+
*)
77+
usage
78+
exit 1
79+
;;
80+
esac
81+
done
82+
83+
#argument specify pages; convert to bytes
84+
skip=$((parsed_skip * 0x1000))
85+
len=$((parsed_len * 0x1000))
86+
87+
if [ $# -eq 0 ]; then
88+
echo "ERROR: Input not set. Use '$(basename "$0") [FILE]' to specify the Input file" >&2
89+
exit 1
90+
fi
91+
92+
check_file "$input"
93+
hdr_start=$(${XDUMP} --skip-bytes $((skip)) --read-bytes $((len)) -- "${input}" 2>/dev/null | grep IBMSecEx ||
94+
{ echo ERROR: "${input} does not contain an SE header." >&2 && exit 1; })
95+
hdr_start=$(echo "${hdr_start}" | awk '{print "0x" $1}' | cut -c 1-10)
96+
echo "SE header found at offset ${hdr_start}"
97+
98+
check_hdr_ver "$hdr_start" "$input"
99+
100+
size=$(${XDUMP} --skip-bytes $((hdr_start + 12)) --read-bytes 4 -- "${input}" 2>/dev/null |
101+
awk 'NR==1 {print "0x" $2 $3}')
102+
103+
dd if="${input}" of="${output}" bs=1 count=$((size)) skip=$((hdr_start)) status=none
104+
echo "SE header written to '${output}' ($((size)) bytes)"

0 commit comments

Comments
 (0)