-- Tests for the serialization of data structures in SMG Protocol -- S.MG, 2018 with RNG; with Data_Structs; with Messages; use Messages; with Interfaces; use Interfaces; with System; with System.Storage_Elements; use System.Storage_Elements; with Ada.Text_IO; use Ada.Text_IO; package body Messages.Test_Serializing is procedure Serialize_Keyset_RSA is Msg : RSA_Msg; ReadK : Player_RSA; ReadC : Interfaces.Unsigned_16; WMsg : RSA_Msg; TypeID : constant Interfaces.Unsigned_8 := 251; begin Put_Line("Generating data for 5.1 RSA key set in RSA message."); -- fill message with random data RNG.Get_Octets(Msg); -- attempt read - it should fail begin Read_RKeys_RMsg( Msg, ReadC, ReadK ); exception when Invalid_Msg => if Msg(Msg'First) /= TypeID then Put_Line("PASS: exception correctly raised for invalid message"); else Put_Line("FAIL: exception raised on VALID message!"); end if; end; -- set correct type id Msg(Msg'First) := TypeID; -- attempt read + write and compare Read_RKeys_RMsg( Msg, ReadC, ReadK ); Write_RKeys_RMsg( ReadK, ReadC, RNG_PAD, WMsg ); -- check result (without trailing padding since that CAN be different!) if WMsg(1..520) /= Msg(1..520) then Put_Line("FAIL: read+write of RSA keys to RSA message."); for I in 1..520 loop if WMsg(I) /= Msg(I) then Put_Line("At " & Integer'Image(I) & " WMsg is " & Unsigned_8'Image(WMsg(I)) & " while Msg is " & Unsigned_8'Image(Msg(I))); end if; end loop; else Put_Line("PASS: read+write of RSA keys to RSA message."); end if; end Serialize_Keyset_RSA; procedure Serialize_Keyset_SS is Msg : Serpent_Msg; RMsg : RSA_Msg; KSet : Serpent_Keyset(5); LSB : Interfaces.Unsigned_8 := 16#01#; MSB : Interfaces.Unsigned_8 := 16#80#; LMSB : Interfaces.Unsigned_8 := 16#81#; Counter : Interfaces.Unsigned_16 := 101; NewSetS : Serpent_Keyset; NewSetR : Serpent_Keyset; NewCounterR: Interfaces.Unsigned_16:=0; NewCounterS: Interfaces.Unsigned_16:=0; begin Put_Line("Generating the Serpent Keys..."); -- fill a set of Serpent Keys for I in 1..KSet.N loop RNG.Get_Octets(KSet.Keys(Interfaces.Unsigned_8(I))); end loop; KSet.Flag := LSB; Put_Line("Writing the keys to messages..."); -- write keyset to serpent & rsa messages Write_SKeys_SMsg( KSet, Counter, RNG_PAD, Msg ); Write_SKeys_RMsg( KSet, Counter, RNG_PAD, RMsg ); Put_Line("Reading keys back from messages..."); -- read keyset from serpent and rsa messages Read_SKeys_SMsg( Msg, NewCounterS, NewSetS ); Read_SKeys_RMsg( RMsg, NewCounterR, NewSetR ); Put_Line("Comparing the keysets..."); -- compare the two keysets if NewCounterS /= Counter or NewCounterS /= Counter or NewSetS /= KSet or NewSetR /= KSet then Put_Line("FAIL: keysets are different!"); else Put_Line("PASS: keysets are the same!"); end if; Put_Line("Attempting to read from mangled message"); begin Msg(Msg'First) := Msg(Msg'First)+25; Read_SKeys_SMsg( Msg, Counter, NewSetS); Put_Line("FAIL: read failed to raise invalid message exception!"); exception when Invalid_Msg => Put_Line("PASS: exception correctly raised for invalid message"); end; end Serialize_Keyset_SS; procedure Serialize_Keys_Mgm is N_Burnt : Counter_8bits; Counter : Interfaces.Unsigned_16 := 16#EDA9#; Mgm_S : Keys_Mgm; Mgm_R : Keys_Mgm; Cnt_S : Interfaces.Unsigned_16:=0; Cnt_R : Interfaces.Unsigned_16:=0; O1 : Octets_1; SMsg : Serpent_Msg; RMsg : RSA_Msg; begin -- fill the struct with random stuff RNG.Get_Octets( O1 ); N_Burnt := Cast(O1); declare Mgm: Keys_Mgm(N_Burnt); begin RNG.Get_Octets( O1 ); Mgm.N_Server := O1(O1'First); RNG.Get_Octets( O1 ); Mgm.N_Client := O1(O1'First); RNG.Get_Octets( O1 ); Mgm.Key_ID := O1(O1'First); if N_Burnt > 0 then RNG.Get_Octets( Mgm.Burnt ); end if; -- write it to Serpent and RSA messages Write_KMgm_SMsg(Mgm, Counter, RNG_PAD, SMsg); Write_KMgm_RMsg(Mgm, Counter, RNG_PAD, RMsg); -- read it back from Serpent and RSA messages Read_KMgm_SMsg( SMsg, Cnt_S, Mgm_S ); Read_KMgm_RMsg( RMsg, Cnt_R, Mgm_R ); -- check results if Cnt_S /= Counter or Mgm_S.N_Burnt /= Mgm.N_Burnt or Mgm_S /= Mgm then Put_Line("FAIL: read/write key management struct to S msg."); else Put_Line("PASS: read/write key management struct to S msg."); end if; if Cnt_R /= Counter or Mgm_R.N_Burnt /= Mgm.N_Burnt or Mgm_R /= Mgm then Put_Line("FAIL: read/write key management struct to R msg."); Put_Line("Cnt_R is " & Unsigned_16'Image(Cnt_R)); Put_Line("Counter is " & Unsigned_16'Image(Counter)); Put_Line("Mgm_R.N_Burnt is " & Counter_8bits'Image(Mgm_R.N_Burnt)); Put_Line("Mgm.N_Burnt is " & Counter_8bits'Image(Mgm.N_Burnt)); else Put_Line("PASS: read/write key management struct to R msg."); end if; -- attempt mangled call - should raise exception begin SMsg(SMsg'First) := SMsg(SMsg'First) + 1; Read_KMgm_SMsg( SMsg, Cnt_S, Mgm_S); Put_Line("FAIL: Read_KMgm_SMsg failed to raise exception!"); exception when Invalid_Msg => Put_Line("PASS: Read_KMgm_SMsg correctly raised exception."); end; end; end Serialize_Keys_Mgm; procedure Serialize_File_Request( Reps: in Positive) is MaxSz: Positive := 340; O2 : Raw_Types.Octets_2; U16 : Interfaces.Unsigned_16; Counter : Interfaces.Unsigned_16; ReadCounter: Interfaces.Unsigned_16; Written: Natural; Msg : Raw_Types.Serpent_Msg; F_No, Sz: Text_Len; begin for I in 1 .. Reps loop -- generate a random size RNG.Get_Octets( O2 ); U16 := Raw_Types.Cast( O2 ); Sz := Text_Len( Positive(U16) mod MaxSz + 1); -- generate a random number of files RNG.Get_Octets( O2 ); U16 := Raw_Types.Cast( O2 ); -- make sure it's within Positive range i.e. not 0 if U16 = 0 then U16 := 1; end if; F_No := Text_Len( Positive(U16) mod Sz + 1 ); declare FR: Filenames(F_No, Sz); ReadFR: Filenames; O : Octets(1..Sz); Len : Positive := Sz / F_No; begin Put_Line("Generating test for File Request with " & Integer'Image(FR.F_No) & " filenames."); -- generate a random counter RNG.Get_Octets(O2); Counter := Raw_Types.Cast(O2); -- fill FR RNG.Get_Octets( O ); -- replace separators if any for I in O'Range loop if O(I) = 59 then O(I) := 69; end if; end loop; Octets_To_String( O, FR.S ); for I in FR.Starts'Range loop FR.Starts(I) := Interfaces.Unsigned_16( FR.Starts'First + Len*(I-FR.Starts'First)); end loop; -- write FR to message Write_File_Request(FR, Counter, RNG_PAD, Msg, Written); -- check how many filenames were written if Written /= FR.F_No then Put_Line("FAIL: only " & Natural'Image(Written) & " filenames written out of " & Natural'Image(FR.F_No)); else Put_Line("PASS: wrote " & Natural'Image(Written) & " filenames."); end if; -- read it from message and check result Read_File_Request(Msg, ReadCounter, ReadFR); if ReadCounter /= Counter then Put_Line("FAIL: ReadCounter is " & Unsigned_16'Image(ReadCounter) & " instead of expected " & Unsigned_16'Image(Counter) ); else Put_Line("PASS: ReadCounter was read correctly as " & Unsigned_16'Image(ReadCounter)); end if; if ReadFr.Sz /= FR.Sz then Put_Line("FAIL: Read FR.Sz = " & Text_Len'Image(ReadFr.Sz) & " while expected sz is " & Text_Len'Image(FR.Sz)); else Put_Line("PASS: Read FR.Sz as expected = " & Text_Len'Image(ReadFr.Sz)); end if; if ReadFr /= FR then Put_Line("FAIL: ReadFr different from FR."); else Put_Line("PASS: ReadFr as expected, same as FR."); end if; end; end loop; -- test with more files than can fit Put_Line("Test case for File Request with more files than fit."); declare F: Filenames(4, 16384); ReadF: Filenames; begin F.Starts(1) := Interfaces.Unsigned_16(F.S'First); F.Starts(2) := Interfaces.Unsigned_16(F.S'First + 342); F.Starts(3) := 16370; F.Starts(4) := 16380; Write_File_Request(F, Counter, RNG_PAD, Msg, Written); if Written /= 1 then Put_Line("FAIL: Written is " & Natural'Image(Written) & " instead of expected 1."); else Put_Line("PASS: Written is 1 out of 4, as expected."); end if; Read_File_Request(Msg, ReadCounter, ReadF); if ReadF.F_No /= 1 or ReadF.Starts(1) /= 1 or ReadF.Sz /= 342 then Put_Line("FAIL: F_No is " & Text_Len'Image(ReadF.F_No) & " Sz is " & Text_Len'Image(ReadF.Sz)); else Put_line("PASS: written 1 out of 4 correctly."); end if; end; end Serialize_File_Request; procedure Serialize_File_Chunk is Filename : String := "afile.png"; FC : File_Chunk( Len => 945, Count => 0, Name_Len => Filename'Length); ReadFC : File_Chunk; Msg : Raw_Types.Serpent_Msg; Pad : Raw_Types.Octets_8 := RNG_PAD; begin -- fill FC with random content FC.Filename := Filename; RNG.Get_Octets(FC.Content); -- write FC to message with random padding Write_File_Transfer( FC, Pad, Msg ); -- read FC and check Read_File_Transfer( Msg, ReadFC ); if FC /= ReadFC then Put_Line("FAIL: read/write file chunk."); else Put_Line("PASS: read/write file chunk."); end if; end Serialize_File_Chunk; procedure Serialize_Action is O2 : Raw_Types.Octets_2; U16: Interfaces.Unsigned_16; Len: Raw_Types.Text_Len; Counter: Interfaces.Unsigned_16; begin Put_Line("Generating a random action for testing."); -- generate random counter RNG.Get_Octets( O2 ); Counter := Raw_Types.Cast( O2 ); -- generate action length RNG.Get_Octets( O2 ); U16 := Raw_Types.Cast( O2 ); if U16 < 1 then U16 := 1; else if U16 + 5 > Raw_Types.Serpent_Msg'Length then U16 := Raw_Types.Serpent_Msg'Length - 5; end if; end if; Len := Raw_Types.Text_Len( U16 ); declare A: Raw_Types.Text_Octets( Len ); B: Raw_Types.Text_Octets; Msg: Raw_Types.Serpent_Msg; ReadC : Interfaces.Unsigned_16; begin RNG.Get_Octets( A.Content ); begin Write_Action( A, Counter, RNG_PAD, Msg ); Read_Action( Msg, ReadC, B ); if B /= A then Put_Line("FAIL: read/write of Action."); else Put_Line("PASS: read/write of Action."); end if; exception when Invalid_Msg => if Len + 5 > Raw_Types.Serpent_Msg'Length then Put_Line("PASS: exception correctly raised for Action too long"); else Put_Line("FAIL: exception INCORRECTLY raised at action r/w!"); end if; end; end; end Serialize_Action; procedure Converter_String_Octets is Len: constant Natural := 234; -- original values S: String(1..Len); O: Octets(1..Len); -- converted values CS: String(1..Len); CO: Octets(1..Len); begin -- original octets RNG.Get_Octets(O); Octets_To_String(O, CS); String_To_Octets(CS, CO); if CO /= O then Put_Line("FAIL: octets different after string/octets conversion."); else Put_Line("PASS: octets same after string/octets conversion."); end if; -- original string for I in S'Range loop S(I) := Character'Val(I mod 12); end loop; String_To_Octets(S, CO); Octets_To_String(CO, CS); if CS /= S then Put_Line("FAIL: string different after string/octets conversion."); else Put_Line("PASS: string same after string/octets conversion."); end if; end Converter_String_Octets; procedure Test_Padding is Msg : Raw_Types.Serpent_Msg := (others => 12); Old : Raw_Types.Serpent_Msg := Msg; Pos : Natural := 16; NewPos : Natural := Pos; Counter : Interfaces.Unsigned_16; U16 : Interfaces.Unsigned_16; O2 : Raw_Types.Octets_2; Pad : Raw_Types.Octets_8; Pass : Boolean; begin -- get random counter RNG.Get_Octets( O2 ); Counter := Raw_Types.Cast( O2 ); -- test with random padding Pad := RNG_PAD; Write_End( Msg, NewPos, Counter, Pad ); -- check NewPos and counter Pass := True; if NewPos /= Msg'Last + 1 then Put_Line("FAIL: incorrect Pos value after Write_End with rng."); Pass := False; end if; Read_U16(Msg, Pos, U16); if U16 /= Counter then Put_Line("FAIL: incorrect Counter by Write_End with rng."); Pass := False; end if; -- check that the padding is at least different... if Msg(Pos..Msg'Last) = Old(Pos..Old'Last) or Msg(Pos..Pos+Pad'Length-1) = Pad then Put_Line("FAIL: no padding written by Write_End with rng."); Pass := False; end if; if Pass then Put_Line("PASS: Write_End with rng."); end if; -- prepare for the next test Pass := True; Pos := Pos - 2; NewPos := Pos; Msg := Old; -- get random padding RNG.Get_Octets( Pad ); -- write with fixed padding and check Write_End( Msg, NewPos, Counter, Pad ); Pass := True; if NewPos = Msg'Last + 1 then -- check counter + padding Read_U16( Msg, Pos, U16 ); if U16 /= Counter then Put_Line("FAIL: Counter was not written by Write_End."); Pass := False; end if; for I in Pos..Msg'Last loop if Msg( I ) /= Pad( Pad'First + (I - Pos) mod Pad'Length ) then Put_Line("FAIL: Msg(" & Natural'Image(I) & ")=" & Unsigned_8'Image(Msg(I)) & " /= Pad(" & Natural'Image(Pad'First+(I-Pos) mod Pad'Length) & ") which is " & Unsigned_8'Image(Pad(Pad'First+(I-Pos) mod Pad'Length))); Pass := False; end if; end loop; else Put_Line("FAIL: Pos is wrong after call to Write_End."); Pass := False; end if; if Pass then Put_Line("PASS: test for Write_End with fixed padding."); end if; end Test_Padding; end Messages.Test_Serializing;