tls_server.adb 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. -- tls_server.adb
  2. --
  3. -- Copyright (C) 2006-2023 wolfSSL Inc.
  4. --
  5. -- This file is part of wolfSSL.
  6. --
  7. -- wolfSSL is free software; you can redistribute it and/or modify
  8. -- it under the terms of the GNU General Public License as published by
  9. -- the Free Software Foundation; either version 2 of the License, or
  10. -- (at your option) any later version.
  11. --
  12. -- wolfSSL is distributed in the hope that it will be useful,
  13. -- but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. -- GNU General Public License for more details.
  16. --
  17. -- You should have received a copy of the GNU General Public License
  18. -- along with this program; if not, write to the Free Software
  19. -- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
  20. --
  21. -- Ada Standard Library packages.
  22. with Ada.Characters.Handling;
  23. with Ada.Strings.Bounded;
  24. with Ada.Text_IO.Bounded_IO;
  25. with SPARK_Terminal; pragma Elaborate_All (SPARK_Terminal);
  26. package body Tls_Server with SPARK_Mode is
  27. use type WolfSSL.Mode_Type;
  28. use type WolfSSL.Byte_Index;
  29. use type WolfSSL.Byte_Array;
  30. use type WolfSSL.Subprogram_Result;
  31. Success : WolfSSL.Subprogram_Result renames WolfSSL.Success;
  32. procedure Put (Char : Character) is
  33. begin
  34. Ada.Text_IO.Put (Char);
  35. end Put;
  36. procedure Put (Text : String) is
  37. begin
  38. Ada.Text_IO.Put (Text);
  39. end Put;
  40. procedure Put_Line (Text : String) is
  41. begin
  42. Ada.Text_IO.Put_Line (Text);
  43. end Put_Line;
  44. procedure New_Line is
  45. begin
  46. Ada.Text_IO.New_Line;
  47. end New_Line;
  48. subtype Exit_Status is SPARK_Terminal.Exit_Status;
  49. Exit_Status_Success : Exit_Status renames SPARK_Terminal.Exit_Status_Success;
  50. Exit_Status_Failure : Exit_Status renames SPARK_Terminal.Exit_Status_Failure;
  51. procedure Set (Status : Exit_Status) with Global => null is
  52. begin
  53. SPARK_Terminal.Set_Exit_Status (Status);
  54. end Set;
  55. subtype Port_Type is SPARK_Sockets.Port_Type;
  56. subtype Level_Type is SPARK_Sockets.Level_Type;
  57. subtype Socket_Type is SPARK_Sockets.Socket_Type;
  58. subtype Option_Name is SPARK_Sockets.Option_Name;
  59. subtype Option_Type is SPARK_Sockets.Option_Type;
  60. subtype Family_Type is SPARK_Sockets.Family_Type;
  61. subtype Sock_Addr_Type is SPARK_Sockets.Sock_Addr_Type;
  62. subtype Inet_Addr_Type is SPARK_Sockets.Inet_Addr_Type;
  63. Socket_Error : exception renames SPARK_Sockets.Socket_Error;
  64. Reuse_Address : Option_Name renames SPARK_Sockets.Reuse_Address;
  65. Socket_Level : Level_Type renames SPARK_Sockets.Socket_Level;
  66. Family_Inet : Family_Type renames SPARK_Sockets.Family_Inet;
  67. Any_Inet_Addr : Inet_Addr_Type renames SPARK_Sockets.Any_Inet_Addr;
  68. CERT_FILE : constant String := "../../../certs/server-cert.pem";
  69. KEY_FILE : constant String := "../../../certs/server-key.pem";
  70. CA_FILE : constant String := "../../../certs/client-cert.pem";
  71. subtype Byte_Array is WolfSSL.Byte_Array;
  72. Reply : constant Byte_Array := "I hear ya fa shizzle!";
  73. procedure Run (Ssl : in out WolfSSL.WolfSSL_Type;
  74. Ctx : in out WolfSSL.Context_Type;
  75. L : in out SPARK_Sockets.Optional_Socket;
  76. C : in out SPARK_Sockets.Optional_Socket) is
  77. A : Sock_Addr_Type;
  78. P : constant Port_Type := 11111;
  79. Ch : Character;
  80. Result : WolfSSL.Subprogram_Result;
  81. Shall_Continue : Boolean := True;
  82. Input : WolfSSL.Read_Result;
  83. Output : WolfSSL.Write_Result;
  84. Option : Option_Type;
  85. begin
  86. Result := WolfSSL.Initialize;
  87. if Result /= Success then
  88. Put_Line ("ERROR: Failed to initialize the WolfSSL library.");
  89. return;
  90. end if;
  91. SPARK_Sockets.Create_Socket (Socket => L);
  92. if not L.Exists then
  93. Put_Line ("ERROR: Failed to create socket.");
  94. return;
  95. end if;
  96. Option := (Name => Reuse_Address, Enabled => True);
  97. Result := SPARK_Sockets.Set_Socket_Option (Socket => L.Socket,
  98. Level => Socket_Level,
  99. Option => Option);
  100. if Result /= Success then
  101. Put_Line ("ERROR: Failed to set socket option.");
  102. SPARK_Sockets.Close_Socket (L);
  103. return;
  104. end if;
  105. A := (Family => Family_Inet,
  106. Addr => Any_Inet_Addr,
  107. Port => P);
  108. Result := SPARK_Sockets.Bind_Socket (Socket => L.Socket,
  109. Address => A);
  110. if Result /= Success then
  111. Put_Line ("ERROR: Failed to bind socket.");
  112. SPARK_Sockets.Close_Socket (L);
  113. return;
  114. end if;
  115. Result := SPARK_Sockets.Listen_Socket (Socket => L.Socket,
  116. Length => 5);
  117. if Result /= Success then
  118. Put_Line ("ERROR: Failed to configure listener socket.");
  119. SPARK_Sockets.Close_Socket (L);
  120. return;
  121. end if;
  122. -- Create and initialize WOLFSSL_CTX.
  123. WolfSSL.Create_Context (Method => WolfSSL.TLSv1_3_Server_Method,
  124. Context => Ctx);
  125. if not WolfSSL.Is_Valid (Ctx) then
  126. Put_Line ("ERROR: failed to create WOLFSSL_CTX.");
  127. SPARK_Sockets.Close_Socket (L);
  128. Set (Exit_Status_Failure);
  129. return;
  130. end if;
  131. -- Require mutual authentication.
  132. WolfSSL.Set_Verify
  133. (Context => Ctx,
  134. Mode => WolfSSL.Verify_Peer & WolfSSL.Verify_Fail_If_No_Peer_Cert);
  135. -- Load server certificates into WOLFSSL_CTX.
  136. Result := WolfSSL.Use_Certificate_File (Context => Ctx,
  137. File => CERT_FILE,
  138. Format => WolfSSL.Format_Pem);
  139. if Result /= Success then
  140. Put ("ERROR: failed to load ");
  141. Put (CERT_FILE);
  142. Put (", please check the file.");
  143. New_Line;
  144. SPARK_Sockets.Close_Socket (L);
  145. WolfSSL.Free (Context => Ctx);
  146. Set (Exit_Status_Failure);
  147. return;
  148. end if;
  149. -- Load server key into WOLFSSL_CTX.
  150. Result := WolfSSL.Use_Private_Key_File (Context => Ctx,
  151. File => KEY_FILE,
  152. Format => WolfSSL.Format_Pem);
  153. if Result /= Success then
  154. Put ("ERROR: failed to load ");
  155. Put (KEY_FILE);
  156. Put (", please check the file.");
  157. New_Line;
  158. SPARK_Sockets.Close_Socket (L);
  159. WolfSSL.Free (Context => Ctx);
  160. Set (Exit_Status_Failure);
  161. return;
  162. end if;
  163. -- Load client certificate as "trusted" into WOLFSSL_CTX.
  164. Result := WolfSSL.Load_Verify_Locations (Context => Ctx,
  165. File => CA_FILE,
  166. Path => "");
  167. if Result /= Success then
  168. Put ("ERROR: failed to load ");
  169. Put (CA_FILE);
  170. Put (", please check the file.");
  171. New_Line;
  172. SPARK_Sockets.Close_Socket (L);
  173. WolfSSL.Free (Context => Ctx);
  174. Set (Exit_Status_Failure);
  175. return;
  176. end if;
  177. while Shall_Continue loop
  178. pragma Loop_Invariant (not C.Exists);
  179. pragma Loop_Invariant (not WolfSSL.Is_Valid (Ssl));
  180. pragma Loop_Invariant (WolfSSL.Is_Valid (Ctx));
  181. Put_Line ("Waiting for a connection...");
  182. SPARK_Sockets.Accept_Socket (Server => L.Socket,
  183. Socket => C,
  184. Address => A,
  185. Result => Result);
  186. if Result /= Success then
  187. Put_Line ("ERROR: failed to accept the connection.");
  188. SPARK_Sockets.Close_Socket (L);
  189. WolfSSL.Free (Context => Ctx);
  190. return;
  191. end if;
  192. -- Create a WOLFSSL object.
  193. WolfSSL.Create_WolfSSL (Context => Ctx, Ssl => Ssl);
  194. if not WolfSSL.Is_Valid (Ssl) then
  195. Put_Line ("ERROR: failed to create WOLFSSL object.");
  196. SPARK_Sockets.Close_Socket (L);
  197. SPARK_Sockets.Close_Socket (C);
  198. WolfSSL.Free (Context => Ctx);
  199. Set (Exit_Status_Failure);
  200. return;
  201. end if;
  202. -- Attach wolfSSL to the socket.
  203. Result := WolfSSL.Attach (Ssl => Ssl,
  204. Socket => SPARK_Sockets.To_C (C.Socket));
  205. if Result /= Success then
  206. Put_Line ("ERROR: Failed to set the file descriptor.");
  207. WolfSSL.Free (Ssl);
  208. SPARK_Sockets.Close_Socket (L);
  209. SPARK_Sockets.Close_Socket (C);
  210. WolfSSL.Free (Context => Ctx);
  211. Set (Exit_Status_Failure);
  212. return;
  213. end if;
  214. -- Establish TLS connection.
  215. Result := WolfSSL.Accept_Connection (Ssl);
  216. if Result /= Success then
  217. Put_Line ("Accept error.");
  218. WolfSSL.Free (Ssl);
  219. SPARK_Sockets.Close_Socket (L);
  220. SPARK_Sockets.Close_Socket (C);
  221. WolfSSL.Free (Context => Ctx);
  222. Set (Exit_Status_Failure);
  223. return;
  224. end if;
  225. Put_Line ("Client connected successfully.");
  226. Input := WolfSSL.Read (Ssl);
  227. if not Input.Success then
  228. Put_Line ("Read error.");
  229. WolfSSL.Free (Ssl);
  230. SPARK_Sockets.Close_Socket (L);
  231. SPARK_Sockets.Close_Socket (C);
  232. WolfSSL.Free (Context => Ctx);
  233. Set (Exit_Status_Failure);
  234. return;
  235. end if;
  236. -- Print to stdout any data the client sends.
  237. for I in Input.Buffer'Range loop
  238. Ch := Character (Input.Buffer (I));
  239. if Ada.Characters.Handling.Is_Graphic (Ch) then
  240. Put (Ch);
  241. else
  242. null;
  243. -- Ignore the "newline" characters at end of message.
  244. end if;
  245. end loop;
  246. New_Line;
  247. -- Check for server shutdown command.
  248. if Input.Last >= 8 then
  249. if Input.Buffer (1 .. 8) = "shutdown" then
  250. Put_Line ("Shutdown command issued!");
  251. Shall_Continue := False;
  252. end if;
  253. end if;
  254. Output := WolfSSL.Write (Ssl, Reply);
  255. if not Output.Success then
  256. Put_Line ("ERROR: write failure.");
  257. elsif Output.Bytes_Written /= Reply'Length then
  258. Put_Line ("ERROR: failed to write full response.");
  259. end if;
  260. for I in 1 .. 3 loop
  261. Result := WolfSSL.Shutdown (Ssl);
  262. exit when Result = Success;
  263. delay 0.001; -- Delay is expressed in seconds.
  264. end loop;
  265. if Result /= Success then
  266. Put_Line ("ERROR: Failed to shutdown WolfSSL context.");
  267. end if;
  268. WolfSSL.Free (Ssl);
  269. SPARK_Sockets.Close_Socket (C);
  270. Put_Line ("Shutdown complete.");
  271. end loop;
  272. SPARK_Sockets.Close_Socket (L);
  273. WolfSSL.Free (Context => Ctx);
  274. Result := WolfSSL.Finalize;
  275. if Result /= Success then
  276. Put_Line ("ERROR: Failed to finalize the WolfSSL library.");
  277. return;
  278. end if;
  279. end Run;
  280. end Tls_Server;