@@ -614,8 +614,9 @@ async fn rebinding_old_prepare(
614614 Ok ( ( ) )
615615}
616616
617- #[ cfg( not( feature = "spdm_attestation" ) ) ]
618617
618+
619+ #[ cfg( not( feature = "spdm_attestation" ) ) ]
619620async fn rebinding_new_prepare (
620621 transport : TransportType ,
621622 info : & RebindingInfo ,
@@ -654,6 +655,8 @@ async fn rebinding_new_prepare(
654655 Ok ( ( ) )
655656}
656657
658+
659+
657660pub fn write_rebinding_session_token ( rebind_token : & [ u8 ] ) -> Result < ( ) , MigrationResult > {
658661 if rebind_token. len ( ) != 32 {
659662 return Err ( MigrationResult :: InvalidParameter ) ;
@@ -810,3 +813,185 @@ async fn tls_session_read_exact(
810813 }
811814 Ok ( ( ) )
812815}
816+
817+ #[ cfg( test) ]
818+ mod test {
819+ use super :: * ;
820+ use alloc:: vec;
821+
822+ /// Build a minimal valid MIGTD_DATA blob containing one TDINFO_STRUCT entry.
823+ fn build_migtd_data ( tdinfo : & [ u8 ] ) -> Vec < u8 > {
824+ let mut buf = Vec :: new ( ) ;
825+ buf. extend_from_slice ( MIGTD_DATA_SIGNATURE ) ; // "MIGTDATA"
826+ buf. extend_from_slice ( & 0x00010000u32 . to_le_bytes ( ) ) ; // version
827+ buf. extend_from_slice ( & 0u32 . to_le_bytes ( ) ) ; // length placeholder
828+ buf. extend_from_slice ( & 1u32 . to_le_bytes ( ) ) ; // num_entries = 1
829+ // Entry: type 0 (TDINFO)
830+ buf. extend_from_slice ( & MIGTD_DATA_TYPE_TDINFO . to_le_bytes ( ) ) ;
831+ buf. extend_from_slice ( & ( tdinfo. len ( ) as u32 ) . to_le_bytes ( ) ) ;
832+ buf. extend_from_slice ( tdinfo) ;
833+ // Patch length
834+ let total = buf. len ( ) as u32 ;
835+ buf[ 12 ..16 ] . copy_from_slice ( & total. to_le_bytes ( ) ) ;
836+ buf
837+ }
838+
839+ /// Create a 512-byte TDINFO_STRUCT with known mrowner and mrownerconfig.
840+ fn make_tdinfo ( mrowner : & [ u8 ; 48 ] , mrownerconfig : & [ u8 ; 48 ] ) -> Vec < u8 > {
841+ let mut tdinfo = vec ! [ 0u8 ; 512 ] ;
842+ // mrowner at offset 112..160
843+ tdinfo[ 112 ..160 ] . copy_from_slice ( mrowner) ;
844+ // mrownerconfig at offset 160..208
845+ tdinfo[ 160 ..208 ] . copy_from_slice ( mrownerconfig) ;
846+ tdinfo
847+ }
848+
849+ // --- InitData tests ---
850+
851+ #[ test]
852+ fn test_initdata_read_write_roundtrip ( ) {
853+ let mrowner = [ 0xAAu8 ; 48 ] ;
854+ let mrownerconfig = [ 0xBBu8 ; 48 ] ;
855+ let tdinfo = make_tdinfo ( & mrowner, & mrownerconfig) ;
856+
857+ let data = build_migtd_data ( & tdinfo) ;
858+ let init = InitData :: read_from_bytes ( & data) . expect ( "should parse valid MIGTD_DATA" ) ;
859+
860+ assert_eq ! ( init. init_tdinfo. len( ) , 512 ) ;
861+ assert_eq ! ( init. init_tdinfo, tdinfo) ;
862+
863+ // Round-trip: write back and re-parse
864+ let mut buf = Vec :: new ( ) ;
865+ init. write_into_bytes ( & mut buf) ;
866+ let init2 = InitData :: read_from_bytes ( & buf) . expect ( "round-trip should parse" ) ;
867+ assert_eq ! ( init2. init_tdinfo, tdinfo) ;
868+ }
869+
870+ #[ test]
871+ fn test_initdata_mrowner_mrownerconfig ( ) {
872+ let mrowner = [ 0x11u8 ; 48 ] ;
873+ let mrownerconfig = [ 0x22u8 ; 48 ] ;
874+ let tdinfo = make_tdinfo ( & mrowner, & mrownerconfig) ;
875+ let data = build_migtd_data ( & tdinfo) ;
876+
877+ let init = InitData :: read_from_bytes ( & data) . unwrap ( ) ;
878+ assert_eq ! ( init. mrowner( ) , & mrowner) ;
879+ assert_eq ! ( init. mrownerconfig( ) , & mrownerconfig) ;
880+ }
881+
882+ #[ test]
883+ fn test_initdata_rejects_bad_signature ( ) {
884+ let tdinfo = vec ! [ 0u8 ; 512 ] ;
885+ let mut data = build_migtd_data ( & tdinfo) ;
886+ data[ 0 ] = b'X' ; // corrupt signature
887+ assert ! ( InitData :: read_from_bytes( & data) . is_none( ) ) ;
888+ }
889+
890+ #[ test]
891+ fn test_initdata_rejects_bad_version ( ) {
892+ let tdinfo = vec ! [ 0u8 ; 512 ] ;
893+ let mut data = build_migtd_data ( & tdinfo) ;
894+ data[ 8 ..12 ] . copy_from_slice ( & 0x00020000u32 . to_le_bytes ( ) ) ; // wrong version
895+ assert ! ( InitData :: read_from_bytes( & data) . is_none( ) ) ;
896+ }
897+
898+ #[ test]
899+ fn test_initdata_rejects_multiple_entries ( ) {
900+ let tdinfo = vec ! [ 0u8 ; 512 ] ;
901+ let mut data = build_migtd_data ( & tdinfo) ;
902+ data[ 16 ..20 ] . copy_from_slice ( & 2u32 . to_le_bytes ( ) ) ; // num_entries = 2
903+ assert ! ( InitData :: read_from_bytes( & data) . is_none( ) ) ;
904+ }
905+
906+ #[ test]
907+ fn test_initdata_rejects_wrong_type ( ) {
908+ let tdinfo = vec ! [ 0u8 ; 512 ] ;
909+ let mut data = build_migtd_data ( & tdinfo) ;
910+ data[ 20 ..24 ] . copy_from_slice ( & 1u32 . to_le_bytes ( ) ) ; // type 1 instead of 0
911+ assert ! ( InitData :: read_from_bytes( & data) . is_none( ) ) ;
912+ }
913+
914+ #[ test]
915+ fn test_initdata_rejects_short_tdinfo ( ) {
916+ let tdinfo = vec ! [ 0u8 ; 256 ] ; // too small (< 512)
917+ let data = build_migtd_data ( & tdinfo) ;
918+ assert ! ( InitData :: read_from_bytes( & data) . is_none( ) ) ;
919+ }
920+
921+ #[ test]
922+ fn test_initdata_rejects_empty ( ) {
923+ assert ! ( InitData :: read_from_bytes( & [ ] ) . is_none( ) ) ;
924+ assert ! ( InitData :: read_from_bytes( & [ 0u8 ; 10 ] ) . is_none( ) ) ;
925+ }
926+
927+ // --- RebindingInfo tests ---
928+
929+ /// Build a minimal RebindingInfo byte buffer.
930+ fn build_rebinding_info (
931+ mig_request_id : u64 ,
932+ rebinding_src : u8 ,
933+ has_init_data : u8 ,
934+ uuid : [ u64 ; 4 ] ,
935+ binding_handle : u64 ,
936+ init_data : Option < & [ u8 ] > ,
937+ ) -> Vec < u8 > {
938+ let mut buf = Vec :: new ( ) ;
939+ buf. extend_from_slice ( & mig_request_id. to_le_bytes ( ) ) ; // 0..8
940+ buf. push ( rebinding_src) ; // 8
941+ buf. push ( has_init_data) ; // 9
942+ buf. extend_from_slice ( & [ 0u8 ; 6 ] ) ; // 10..16 reserved
943+ for u in & uuid {
944+ buf. extend_from_slice ( & u. to_le_bytes ( ) ) ; // 16..48
945+ }
946+ buf. extend_from_slice ( & binding_handle. to_le_bytes ( ) ) ; // 48..56
947+ if let Some ( data) = init_data {
948+ buf. extend_from_slice ( data) ;
949+ }
950+ buf
951+ }
952+
953+ #[ test]
954+ fn test_rebinding_info_no_init_data ( ) {
955+ let buf = build_rebinding_info ( 42 , 1 , 0 , [ 1 , 2 , 3 , 4 ] , 99 , None ) ;
956+ let info = RebindingInfo :: read_from_bytes ( & buf) . expect ( "should parse" ) ;
957+ assert_eq ! ( info. mig_request_id, 42 ) ;
958+ assert_eq ! ( info. rebinding_src, 1 ) ;
959+ assert_eq ! ( info. has_init_data, 0 ) ;
960+ assert_eq ! ( info. target_td_uuid, [ 1 , 2 , 3 , 4 ] ) ;
961+ assert_eq ! ( info. binding_handle, 99 ) ;
962+ assert ! ( info. init_migtd_data. is_none( ) ) ;
963+ }
964+
965+ #[ test]
966+ fn test_rebinding_info_with_init_data ( ) {
967+ let tdinfo = make_tdinfo ( & [ 0xCAu8 ; 48 ] , & [ 0xFEu8 ; 48 ] ) ;
968+ let migtd_data = build_migtd_data ( & tdinfo) ;
969+ let buf = build_rebinding_info ( 7 , 0 , 1 , [ 10 , 20 , 30 , 40 ] , 55 , Some ( & migtd_data) ) ;
970+ let info = RebindingInfo :: read_from_bytes ( & buf) . expect ( "should parse with init data" ) ;
971+ assert_eq ! ( info. mig_request_id, 7 ) ;
972+ assert_eq ! ( info. has_init_data, 1 ) ;
973+ let init = info. init_migtd_data . as_ref ( ) . unwrap ( ) ;
974+ assert_eq ! ( init. mrowner( ) , & [ 0xCAu8 ; 48 ] ) ;
975+ assert_eq ! ( init. mrownerconfig( ) , & [ 0xFEu8 ; 48 ] ) ;
976+ }
977+
978+ #[ test]
979+ fn test_rebinding_info_rejects_short_buffer ( ) {
980+ assert ! ( RebindingInfo :: read_from_bytes( & [ 0u8 ; 10 ] ) . is_none( ) ) ;
981+ assert ! ( RebindingInfo :: read_from_bytes( & [ 0u8 ; 55 ] ) . is_none( ) ) ; // 55 < 56
982+ }
983+
984+ #[ test]
985+ fn test_rebinding_info_rejects_nonzero_reserved ( ) {
986+ let mut buf = build_rebinding_info ( 1 , 0 , 0 , [ 0 ; 4 ] , 0 , None ) ;
987+ buf[ 10 ] = 0xFF ; // reserved byte not zero
988+ assert ! ( RebindingInfo :: read_from_bytes( & buf) . is_none( ) ) ;
989+ }
990+
991+ #[ test]
992+ fn test_rebinding_info_rejects_has_init_data_without_data ( ) {
993+ // has_init_data=1 but no data bytes following → InitData::read_from_bytes fails
994+ let buf = build_rebinding_info ( 1 , 0 , 1 , [ 0 ; 4 ] , 0 , None ) ;
995+ assert ! ( RebindingInfo :: read_from_bytes( & buf) . is_none( ) ) ;
996+ }
997+ }
0 commit comments