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