@@ -81,6 +81,7 @@ pub struct IgvmSerializer<'a> {
8181 measurements : Vec < IgvmPlatformMeasurement > ,
8282 extra_init_headers : Vec < IgvmInitializationHeader > ,
8383 extra_directive_headers : Vec < IgvmDirectiveHeader > ,
84+ suppressed_corim_masks : Vec < u32 > ,
8485}
8586
8687impl < ' a > IgvmSerializer < ' a > {
@@ -104,6 +105,7 @@ impl<'a> IgvmSerializer<'a> {
104105 measurements : Vec :: new ( ) ,
105106 extra_init_headers : Vec :: new ( ) ,
106107 extra_directive_headers : Vec :: new ( ) ,
108+ suppressed_corim_masks : Vec :: new ( ) ,
107109 } ;
108110
109111 // Eagerly compute the launch measurement for every supported
@@ -301,6 +303,89 @@ impl<'a> IgvmSerializer<'a> {
301303 }
302304 }
303305
306+ /// Set the CoRIM signature for a platform while preserving its
307+ /// corresponding CoRIM document.
308+ ///
309+ /// On serialize, any in-file CoRIM document/signature pair for this
310+ /// platform's compatibility mask is suppressed and replaced with exactly
311+ /// one CoRIM document (the existing one) and one CoRIM signature.
312+ ///
313+ /// This keeps CoRIM document/signature ordering valid and avoids callers
314+ /// needing to reconstruct a full [`IgvmFile`] just to patch signatures.
315+ #[ cfg( feature = "corim" ) ]
316+ #[ cfg_attr( docsrs, doc( cfg( feature = "corim" ) ) ) ]
317+ pub fn set_corim_signature (
318+ & mut self ,
319+ platform : IgvmPlatformType ,
320+ signature : Vec < u8 > ,
321+ ) -> Result < & [ u8 ] , Error > {
322+ let compatibility_mask = self . lookup_compatibility_mask ( platform) ?;
323+
324+ let existing_document = self
325+ . existing_corim_document ( compatibility_mask)
326+ . ok_or_else ( || {
327+ Error :: CorimGeneration ( format ! (
328+ "no CoRIM document found for {platform:?} (compatibility mask 0x{compatibility_mask:X})"
329+ ) )
330+ } ) ?;
331+
332+ if !self . suppressed_corim_masks . contains ( & compatibility_mask) {
333+ self . suppressed_corim_masks . push ( compatibility_mask) ;
334+ }
335+
336+ self . extra_init_headers . retain ( |h| match h {
337+ IgvmInitializationHeader :: CorimDocument {
338+ compatibility_mask : mask,
339+ ..
340+ }
341+ | IgvmInitializationHeader :: CorimSignature {
342+ compatibility_mask : mask,
343+ ..
344+ } => * mask != compatibility_mask,
345+ _ => true ,
346+ } ) ;
347+
348+ self . extra_init_headers
349+ . push ( IgvmInitializationHeader :: CorimDocument {
350+ compatibility_mask,
351+ document : existing_document,
352+ } ) ;
353+ self . extra_init_headers
354+ . push ( IgvmInitializationHeader :: CorimSignature {
355+ compatibility_mask,
356+ signature,
357+ } ) ;
358+
359+ match self . extra_init_headers . last ( ) {
360+ Some ( IgvmInitializationHeader :: CorimSignature { signature, .. } ) => {
361+ Ok ( signature. as_slice ( ) )
362+ }
363+ _ => unreachable ! ( "just pushed a CorimSignature" ) ,
364+ }
365+ }
366+
367+ /// Resolve the effective CoRIM document for a compatibility mask,
368+ /// preferring staged serializer additions over the base file.
369+ fn existing_corim_document ( & self , compatibility_mask : u32 ) -> Option < Vec < u8 > > {
370+ if let Some ( document) = self . extra_init_headers . iter ( ) . rev ( ) . find_map ( |h| match h {
371+ IgvmInitializationHeader :: CorimDocument {
372+ compatibility_mask : mask,
373+ document,
374+ } if * mask == compatibility_mask => Some ( document. clone ( ) ) ,
375+ _ => None ,
376+ } ) {
377+ return Some ( document) ;
378+ }
379+
380+ self . file . initializations ( ) . iter ( ) . find_map ( |h| match h {
381+ IgvmInitializationHeader :: CorimDocument {
382+ compatibility_mask : mask,
383+ document,
384+ } if * mask == compatibility_mask => Some ( document. clone ( ) ) ,
385+ _ => None ,
386+ } )
387+ }
388+
304389 /// Resolve a [`LaunchMeasurement`]'s populated measurements and CES
305390 /// triples into the internal builder form, then build the CoRIM bytes.
306391 #[ cfg( feature = "corim" ) ]
@@ -400,6 +485,18 @@ impl<'a> IgvmSerializer<'a> {
400485 // Clone the file and append the extra headers so that
401486 // the original IgvmFile::serialize handles all the work.
402487 let mut file = self . file . clone ( ) ;
488+ file. initializations_mut ( ) . retain ( |h| {
489+ let mask = match h {
490+ IgvmInitializationHeader :: CorimDocument {
491+ compatibility_mask, ..
492+ }
493+ | IgvmInitializationHeader :: CorimSignature {
494+ compatibility_mask, ..
495+ } => * compatibility_mask,
496+ _ => return true ,
497+ } ;
498+ !self . suppressed_corim_masks . contains ( & mask)
499+ } ) ;
403500 file. initializations_mut ( )
404501 . extend ( self . extra_init_headers . iter ( ) . cloned ( ) ) ;
405502 file. directives_mut ( )
@@ -500,6 +597,36 @@ mod tests {
500597 . unwrap ( )
501598 }
502599
600+ fn make_vbs_file_with_corim ( document : Vec < u8 > , signature : Vec < u8 > ) -> IgvmFile {
601+ IgvmFile :: new (
602+ IgvmRevision :: V2 {
603+ arch : Arch :: X64 ,
604+ page_size : PAGE_SIZE_4K as u32 ,
605+ } ,
606+ vec ! [ new_platform( 0x1 , IgvmPlatformType :: VSM_ISOLATION ) ] ,
607+ vec ! [
608+ IgvmInitializationHeader :: CorimDocument {
609+ compatibility_mask: 0x1 ,
610+ document,
611+ } ,
612+ IgvmInitializationHeader :: CorimSignature {
613+ compatibility_mask: 0x1 ,
614+ signature,
615+ } ,
616+ ] ,
617+ vec ! [
618+ new_page_data( 0 , 1 , & [ 0xAA ; PAGE_SIZE_4K as usize ] ) ,
619+ new_page_data( 1 , 1 , & [ 0xBB ; PAGE_SIZE_4K as usize ] ) ,
620+ crate :: IgvmDirectiveHeader :: X64VbsVpContext {
621+ vtl: Vtl :: Vtl0 ,
622+ registers: vec![ X86Register :: Rip ( 0x1000 ) ] ,
623+ compatibility_mask: 0x1 ,
624+ } ,
625+ ] ,
626+ )
627+ . unwrap ( )
628+ }
629+
503630 fn new_snp_id_block ( mask : u32 , ld : [ u8 ; 48 ] ) -> crate :: IgvmDirectiveHeader {
504631 crate :: IgvmDirectiveHeader :: SnpIdBlock {
505632 compatibility_mask : mask,
@@ -797,6 +924,78 @@ mod tests {
797924 assert_eq ! ( file. directives( ) . len( ) , directive_count_before) ;
798925 }
799926
927+ #[ test]
928+ fn set_corim_signature_preserves_document_and_updates_signature ( ) {
929+ let original_document = b"existing-corim-document" . to_vec ( ) ;
930+ let original_signature = b"old-signature" . to_vec ( ) ;
931+ let new_signature = b"new-signature" . to_vec ( ) ;
932+
933+ let file = make_vbs_file_with_corim ( original_document. clone ( ) , original_signature) ;
934+ let mut serializer = IgvmSerializer :: new ( & file) . unwrap ( ) ;
935+
936+ serializer
937+ . set_corim_signature ( IgvmPlatformType :: VSM_ISOLATION , new_signature. clone ( ) )
938+ . unwrap ( ) ;
939+
940+ let mut output = Vec :: new ( ) ;
941+ serializer. serialize ( & mut output) . unwrap ( ) ;
942+
943+ let deserialized = IgvmFile :: new_from_binary ( & output, None ) . unwrap ( ) ;
944+ let mut found_document = None ;
945+ let mut found_signature = None ;
946+ let mut document_index = None ;
947+ let mut signature_index = None ;
948+ for ( idx, h) in deserialized. initializations ( ) . iter ( ) . enumerate ( ) {
949+ match h {
950+ IgvmInitializationHeader :: CorimDocument {
951+ compatibility_mask,
952+ document,
953+ } if * compatibility_mask == 0x1 => {
954+ found_document = Some ( document. clone ( ) ) ;
955+ document_index = Some ( idx) ;
956+ }
957+ IgvmInitializationHeader :: CorimSignature {
958+ compatibility_mask,
959+ signature,
960+ } if * compatibility_mask == 0x1 => {
961+ found_signature = Some ( signature. clone ( ) ) ;
962+ signature_index = Some ( idx) ;
963+ }
964+ _ => { }
965+ }
966+ }
967+
968+ assert_eq ! ( found_document, Some ( original_document) ) ;
969+ assert_eq ! ( found_signature, Some ( new_signature) ) ;
970+ assert ! ( document_index. is_some( ) ) ;
971+ assert ! ( signature_index. is_some( ) ) ;
972+ assert ! ( document_index. unwrap( ) < signature_index. unwrap( ) ) ;
973+ }
974+
975+ #[ test]
976+ fn set_corim_signature_requires_existing_document ( ) {
977+ let file = make_vbs_file ( ) ;
978+ let mut serializer = IgvmSerializer :: new ( & file) . unwrap ( ) ;
979+
980+ let err = serializer
981+ . set_corim_signature ( IgvmPlatformType :: VSM_ISOLATION , b"new-sig" . to_vec ( ) )
982+ . unwrap_err ( ) ;
983+ assert ! ( err. to_string( ) . contains( "no CoRIM document found" ) ) ;
984+ }
985+
986+ #[ test]
987+ fn file_not_mutated_after_set_corim_signature ( ) {
988+ let file = make_vbs_file_with_corim ( b"doc" . to_vec ( ) , b"sig" . to_vec ( ) ) ;
989+ let init_before = file. initializations ( ) . to_vec ( ) ;
990+
991+ let mut serializer = IgvmSerializer :: new ( & file) . unwrap ( ) ;
992+ serializer
993+ . set_corim_signature ( IgvmPlatformType :: VSM_ISOLATION , b"new-sig" . to_vec ( ) )
994+ . unwrap ( ) ;
995+
996+ assert_eq ! ( file. initializations( ) , init_before. as_slice( ) ) ;
997+ }
998+
800999 // -- Two-stage builder tests -------------------------------------
8011000
8021001 #[ test]
0 commit comments