Skip to content

Commit 59cc247

Browse files
authored
Confidential: Provide method to calculate firmware hash (#140)
Which is required to calculate and verify the measurement Also add test and test for compute_confidential_measure
1 parent e1704ef commit 59cc247

File tree

2 files changed

+77
-1
lines changed

2 files changed

+77
-1
lines changed

src/aleph/sdk/utils.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,21 @@ def get_vm_measure(sev_data: SEVMeasurement) -> Tuple[bytes, bytes]:
268268
return vm_measure, nonce
269269

270270

271+
def calculate_firmware_hash(firmware_path: Path) -> str:
272+
"""Calculate the hash of the firmware (OVMF) file to be used in validating the measurements
273+
274+
Returned as hex encoded string"""
275+
276+
# https://www.qemu.org/docs/master/system/i386/amd-memory-encryption.html
277+
# The value of GCTX.LD is SHA256(firmware_blob || kernel_hashes_blob || vmsas_blob), where:
278+
# firmware_blob is the content of the entire firmware flash file (for example, OVMF.fd). [...]
279+
# and verified again sevctl, see tests
280+
firmware_content = firmware_path.read_bytes()
281+
hash_calculator = hashlib.sha256(firmware_content)
282+
283+
return hash_calculator.hexdigest()
284+
285+
271286
def compute_confidential_measure(
272287
sev_info: SEVInfo, tik: bytes, expected_hash: str, nonce: bytes
273288
) -> hmac.HMAC:

tests/unit/test_utils.py

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import base64
12
import datetime
23

34
import pytest as pytest
@@ -18,7 +19,14 @@
1819
PersistentVolume,
1920
)
2021

21-
from aleph.sdk.utils import enum_as_str, get_message_type_value, parse_volume
22+
from aleph.sdk.types import SEVInfo
23+
from aleph.sdk.utils import (
24+
calculate_firmware_hash,
25+
compute_confidential_measure,
26+
enum_as_str,
27+
get_message_type_value,
28+
parse_volume,
29+
)
2230

2331

2432
def test_get_message_type_value():
@@ -174,3 +182,56 @@ def test_parse_persistent_volume():
174182
volume = parse_volume(volume)
175183
assert volume
176184
assert isinstance(volume, PersistentVolume)
185+
186+
187+
def test_calculate_firmware_hash(mocker):
188+
mock_path = mocker.Mock(
189+
read_bytes=mocker.Mock(return_value=b"abc"),
190+
)
191+
192+
assert (
193+
calculate_firmware_hash(mock_path)
194+
== "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
195+
)
196+
197+
198+
def test_compute_confidential_measure():
199+
"""Verify that we properly calculate the measurement we use agains the server
200+
201+
Validated against the sevctl command:
202+
$ RUST_LOG=trace sevctl measurement build --api-major 01 --api-minor 55 --build-id 24 --policy 1
203+
--tik ~/pycharm-aleph-sdk-python/decadecadecadecadecadecadecadecadecadecadecadecadecadecadecadeca_tik.bin
204+
--firmware /usr/share/ovmf/OVMF.fd --nonce URQNqJAqh/2ep4drjx/XvA
205+
206+
[2024-07-05T11:19:06Z DEBUG sevctl::measurement] firmware + table len=4194304 sha256: d06471f485c0a61aba5a431ec136b947be56907acf6ed96afb11788ae4525aeb
207+
[2024-07-05T11:19:06Z DEBUG sevctl::measurement] --tik base64: npOTEc4mtRGfXfB+G6EBdw==
208+
[2024-07-05T11:19:06Z DEBUG sevctl::measurement] --nonce base64: URQNqJAqh/2ep4drjx/XvA==
209+
[2024-07-05T11:19:06Z DEBUG sevctl::measurement] Raw measurement: BAE3GAEAAADQZHH0hcCmGrpaQx7BNrlHvlaQes9u2Wr7EXiK5FJa61EUDaiQKof9nqeHa48f17w=
210+
[2024-07-05T11:19:06Z DEBUG sevctl::measurement] Signed measurement: ls2jv10V3HVShVI/RHCo/a43WO0soLZf0huU9ZZstIw=
211+
[2024-07-05T11:19:06Z DEBUG sevctl::measurement] Measurement + nonce: ls2jv10V3HVShVI/RHCo/a43WO0soLZf0huU9ZZstIxRFA2okCqH/Z6nh2uPH9e8
212+
"""
213+
214+
tik = bytes.fromhex("9e939311ce26b5119f5df07e1ba10177")
215+
assert base64.b64encode(tik) == b"npOTEc4mtRGfXfB+G6EBdw=="
216+
expected_hash = "d06471f485c0a61aba5a431ec136b947be56907acf6ed96afb11788ae4525aeb"
217+
nonce = base64.b64decode("URQNqJAqh/2ep4drjx/XvA==")
218+
sev_info = SEVInfo.parse_obj(
219+
{
220+
"enabled": True,
221+
"api_major": 1,
222+
"api_minor": 55,
223+
"build_id": 24,
224+
"policy": 1,
225+
"state": "running",
226+
"handle": 1,
227+
}
228+
)
229+
230+
assert (
231+
base64.b64encode(
232+
compute_confidential_measure(
233+
sev_info, tik, expected_hash, nonce=nonce
234+
).digest()
235+
)
236+
== b"ls2jv10V3HVShVI/RHCo/a43WO0soLZf0huU9ZZstIw="
237+
)

0 commit comments

Comments
 (0)