22//
33// SPDX-License-Identifier: Apache-2.0
44
5- pub use runtime_events:: { replay_events, RuntimeEvent } ;
5+ pub use dstack_types:: EventLogVersion ;
6+ pub use runtime_events:: {
7+ canonical_event_json_v2, replay_events, RuntimeEvent , DSTACK_RUNTIME_EVENT_TYPE ,
8+ } ;
69pub use tdx:: TdxEvent ;
710
811mod codecs;
912mod runtime_events;
10- mod tcg;
13+ pub mod tcg;
1114pub mod tdx;
1215pub mod tpm;
1316
1417#[ cfg( test) ]
1518mod tests {
1619 use super :: * ;
20+ use dstack_types:: EventLogVersion ;
21+ use ez_hash:: { Hasher , Sha384 } ;
22+ use tdx:: TdxEvent ;
1723
1824 #[ test]
1925 fn parse_ccel ( ) {
@@ -24,4 +30,56 @@ mod tests {
2430 let json = serde_json:: to_string_pretty ( & tdx_event_logs) . unwrap ( ) ;
2531 insta:: assert_snapshot!( json) ;
2632 }
33+
34+ #[ test]
35+ fn encode_runtime_events_roundtrip ( ) {
36+ // Synthesize a CCEL: sample boot-time bytes + encoded runtime events.
37+ // Decode with the same TcgEventLog parser and verify:
38+ // 1. all boot-time events are preserved
39+ // 2. runtime events appear with the expected pcrIndex / event_type / digest
40+ // 3. sha384(event_data) == digest (the property we document)
41+ let boot_raw = include_bytes ! ( "../samples/ccel.bin" ) ;
42+ let valid = tcg:: ccel_content_len ( boot_raw) . unwrap ( ) ;
43+
44+ let runtime_v1: TdxEvent = RuntimeEvent :: new (
45+ "app-id" . to_string ( ) ,
46+ vec ! [ 0xaa , 0xbb , 0xcc ] ,
47+ EventLogVersion :: V1 ,
48+ )
49+ . into ( ) ;
50+ let runtime_v2: TdxEvent = RuntimeEvent :: new (
51+ "compose-hash" . to_string ( ) ,
52+ vec ! [ 0xde , 0xad , 0xbe , 0xef ] ,
53+ EventLogVersion :: V2 ,
54+ )
55+ . into ( ) ;
56+ let runtime_events = vec ! [ runtime_v1. clone( ) , runtime_v2. clone( ) ] ;
57+
58+ let mut merged = boot_raw[ ..valid] . to_vec ( ) ;
59+ merged. extend_from_slice ( & tcg:: encode_runtime_events_as_tcg ( & runtime_events) ) ;
60+ merged. extend_from_slice ( & 0xFFFF_FFFFu32 . to_le_bytes ( ) ) ;
61+
62+ let parsed = tcg:: TcgEventLog :: decode ( & mut merged. as_slice ( ) ) . unwrap ( ) ;
63+ let boot_count = tcg:: TcgEventLog :: decode ( & mut boot_raw. as_slice ( ) )
64+ . unwrap ( )
65+ . event_logs
66+ . len ( ) ;
67+ assert_eq ! ( parsed. event_logs. len( ) , boot_count + 2 ) ;
68+
69+ // Convert and verify runtime tail matches what we put in.
70+ let converted = parsed. to_cc_event_log ( ) . unwrap ( ) ;
71+ let tail = & converted[ converted. len ( ) - 2 ..] ;
72+ for ( orig, got) in runtime_events. iter ( ) . zip ( tail. iter ( ) ) {
73+ assert_eq ! ( got. imr, orig. imr) ;
74+ assert_eq ! ( got. event_type, orig. event_type) ;
75+ assert_eq ! ( got. digest, orig. digest( ) ) ;
76+ // The event_payload carried in TdxEvent after TCG round-trip is the
77+ // hash_input bytes we stored as TCG event data.
78+ let runtime = orig. to_runtime_event ( ) . unwrap ( ) ;
79+ assert_eq ! ( got. event_payload, runtime. hash_input( ) ) ;
80+ // Property: sha384(event_data) == digest
81+ let h = Sha384 :: hash ( [ got. event_payload . as_slice ( ) ] ) ;
82+ assert_eq ! ( h. as_slice( ) , got. digest. as_slice( ) ) ;
83+ }
84+ }
2785}
0 commit comments