-
Notifications
You must be signed in to change notification settings - Fork 51
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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]> (cherry picked from commit 1cad3e5) Signed-off-by: Greg Kurz <[email protected]>
- Loading branch information
1 parent
28f7379
commit b04635e
Showing
5 changed files
with
554 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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----- |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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)" |
Oops, something went wrong.