tls_server.adb 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  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. DTLS : Boolean;
  82. Shall_Continue : Boolean := True;
  83. Input : WolfSSL.Read_Result;
  84. Output : WolfSSL.Write_Result;
  85. Option : Option_Type;
  86. begin
  87. Result := WolfSSL.Initialize;
  88. if Result /= Success then
  89. Put_Line ("ERROR: Failed to initialize the WolfSSL library.");
  90. return;
  91. end if;
  92. if SPARK_Terminal.Argument_Count > 1
  93. or (SPARK_Terminal.Argument_Count = 1
  94. and then SPARK_Terminal.Argument (1) /= "--dtls")
  95. then
  96. Put_Line ("usage: tls_server_main [--dtls]");
  97. return;
  98. end if;
  99. DTLS := (SPARK_Terminal.Argument_Count = 1);
  100. if DTLS then
  101. SPARK_Sockets.Create_Datagram_Socket (Socket => L);
  102. else
  103. SPARK_Sockets.Create_Stream_Socket (Socket => L);
  104. end if;
  105. if not L.Exists then
  106. declare
  107. Mode : constant String := (if DTLS then "datagram" else "stream");
  108. begin
  109. Put_Line ("ERROR: Failed to create " & Mode & " socket.");
  110. return;
  111. end;
  112. end if;
  113. Option := (Name => Reuse_Address, Enabled => True);
  114. Result := SPARK_Sockets.Set_Socket_Option (Socket => L.Socket,
  115. Level => Socket_Level,
  116. Option => Option);
  117. if Result /= Success then
  118. Put_Line ("ERROR: Failed to set socket option.");
  119. SPARK_Sockets.Close_Socket (L);
  120. return;
  121. end if;
  122. A := (Family => Family_Inet,
  123. Addr => Any_Inet_Addr,
  124. Port => P);
  125. Result := SPARK_Sockets.Bind_Socket (Socket => L.Socket,
  126. Address => A);
  127. if Result /= Success then
  128. Put_Line ("ERROR: Failed to bind socket.");
  129. SPARK_Sockets.Close_Socket (L);
  130. return;
  131. end if;
  132. if DTLS then
  133. Result := SPARK_Sockets.Receive_Socket (Socket => L.Socket);
  134. else
  135. Result := SPARK_Sockets.Listen_Socket (Socket => L.Socket,
  136. Length => 5);
  137. end if;
  138. if Result /= Success then
  139. declare
  140. Operation : constant String := (if DTLS then "receiver" else "listener");
  141. begin
  142. Put_Line ("ERROR: Failed to configure " & Operation & " socket.");
  143. SPARK_Sockets.Close_Socket (L);
  144. return;
  145. end;
  146. end if;
  147. -- Create and initialize WOLFSSL_CTX.
  148. WolfSSL.Create_Context
  149. (Method =>
  150. (if DTLS then
  151. WolfSSL.DTLSv1_3_Server_Method
  152. else
  153. WolfSSL.TLSv1_3_Server_Method),
  154. Context => Ctx);
  155. if not WolfSSL.Is_Valid (Ctx) then
  156. Put_Line ("ERROR: failed to create WOLFSSL_CTX.");
  157. SPARK_Sockets.Close_Socket (L);
  158. Set (Exit_Status_Failure);
  159. return;
  160. end if;
  161. -- Require mutual authentication.
  162. WolfSSL.Set_Verify
  163. (Context => Ctx,
  164. Mode => WolfSSL.Verify_Peer & WolfSSL.Verify_Fail_If_No_Peer_Cert);
  165. -- Load server certificates into WOLFSSL_CTX.
  166. Result := WolfSSL.Use_Certificate_File (Context => Ctx,
  167. File => CERT_FILE,
  168. Format => WolfSSL.Format_Pem);
  169. if Result /= Success then
  170. Put ("ERROR: failed to load ");
  171. Put (CERT_FILE);
  172. Put (", please check the file.");
  173. New_Line;
  174. SPARK_Sockets.Close_Socket (L);
  175. WolfSSL.Free (Context => Ctx);
  176. Set (Exit_Status_Failure);
  177. return;
  178. end if;
  179. -- Load server key into WOLFSSL_CTX.
  180. Result := WolfSSL.Use_Private_Key_File (Context => Ctx,
  181. File => KEY_FILE,
  182. Format => WolfSSL.Format_Pem);
  183. if Result /= Success then
  184. Put ("ERROR: failed to load ");
  185. Put (KEY_FILE);
  186. Put (", please check the file.");
  187. New_Line;
  188. SPARK_Sockets.Close_Socket (L);
  189. WolfSSL.Free (Context => Ctx);
  190. Set (Exit_Status_Failure);
  191. return;
  192. end if;
  193. -- Load client certificate as "trusted" into WOLFSSL_CTX.
  194. Result := WolfSSL.Load_Verify_Locations (Context => Ctx,
  195. File => CA_FILE,
  196. Path => "");
  197. if Result /= Success then
  198. Put ("ERROR: failed to load ");
  199. Put (CA_FILE);
  200. Put (", please check the file.");
  201. New_Line;
  202. SPARK_Sockets.Close_Socket (L);
  203. WolfSSL.Free (Context => Ctx);
  204. Set (Exit_Status_Failure);
  205. return;
  206. end if;
  207. while Shall_Continue loop
  208. pragma Loop_Invariant (not C.Exists);
  209. pragma Loop_Invariant (not WolfSSL.Is_Valid (Ssl));
  210. pragma Loop_Invariant (WolfSSL.Is_Valid (Ctx));
  211. if not DTLS then
  212. Put_Line ("Waiting for a connection...");
  213. SPARK_Sockets.Accept_Socket (Server => L.Socket,
  214. Socket => C,
  215. Address => A,
  216. Result => Result);
  217. if Result /= Success then
  218. Put_Line ("ERROR: failed to accept the connection.");
  219. SPARK_Sockets.Close_Socket (L);
  220. WolfSSL.Free (Context => Ctx);
  221. return;
  222. end if;
  223. end if;
  224. -- Create a WOLFSSL object.
  225. WolfSSL.Create_WolfSSL (Context => Ctx, Ssl => Ssl);
  226. if not WolfSSL.Is_Valid (Ssl) then
  227. Put_Line ("ERROR: failed to create WOLFSSL object.");
  228. SPARK_Sockets.Close_Socket (L);
  229. if not DTLS then
  230. SPARK_Sockets.Close_Socket (C);
  231. end if;
  232. WolfSSL.Free (Context => Ctx);
  233. Set (Exit_Status_Failure);
  234. return;
  235. end if;
  236. -- Attach wolfSSL to the socket.
  237. Result := WolfSSL.Attach
  238. (Ssl => Ssl,
  239. Socket => SPARK_Sockets.To_C (if DTLS then L.Socket else C.Socket));
  240. if Result /= Success then
  241. Put_Line ("ERROR: Failed to set the file descriptor.");
  242. WolfSSL.Free (Ssl);
  243. SPARK_Sockets.Close_Socket (L);
  244. if not DTLS then
  245. SPARK_Sockets.Close_Socket (C);
  246. end if;
  247. WolfSSL.Free (Context => Ctx);
  248. Set (Exit_Status_Failure);
  249. return;
  250. end if;
  251. -- Establish (D)TLS connection.
  252. Result := WolfSSL.Accept_Connection (Ssl);
  253. if Result /= Success then
  254. Put_Line ("Accept error.");
  255. WolfSSL.Free (Ssl);
  256. SPARK_Sockets.Close_Socket (L);
  257. if not DTLS then
  258. SPARK_Sockets.Close_Socket (C);
  259. end if;
  260. WolfSSL.Free (Context => Ctx);
  261. Set (Exit_Status_Failure);
  262. return;
  263. end if;
  264. Put_Line ("Client connected successfully.");
  265. Input := WolfSSL.Read (Ssl);
  266. if not Input.Success then
  267. Put_Line ("Read error.");
  268. WolfSSL.Free (Ssl);
  269. SPARK_Sockets.Close_Socket (L);
  270. if not DTLS then
  271. SPARK_Sockets.Close_Socket (C);
  272. end if;
  273. WolfSSL.Free (Context => Ctx);
  274. Set (Exit_Status_Failure);
  275. return;
  276. end if;
  277. -- Print to stdout any data the client sends.
  278. for I in Input.Buffer'Range loop
  279. Ch := Character (Input.Buffer (I));
  280. if Ada.Characters.Handling.Is_Graphic (Ch) then
  281. Put (Ch);
  282. else
  283. null;
  284. -- Ignore the "newline" characters at end of message.
  285. end if;
  286. end loop;
  287. New_Line;
  288. -- Check for server shutdown command.
  289. if Input.Last >= 8 then
  290. if Input.Buffer (1 .. 8) = "shutdown" then
  291. Put_Line ("Shutdown command issued!");
  292. Shall_Continue := False;
  293. end if;
  294. end if;
  295. Output := WolfSSL.Write (Ssl, Reply);
  296. if not Output.Success then
  297. Put_Line ("ERROR: write failure.");
  298. elsif Output.Bytes_Written /= Reply'Length then
  299. Put_Line ("ERROR: failed to write full response.");
  300. end if;
  301. for I in 1 .. 3 loop
  302. Result := WolfSSL.Shutdown (Ssl);
  303. exit when DTLS or Result = Success;
  304. delay 0.001; -- Delay is expressed in seconds.
  305. end loop;
  306. if not DTLS and then Result /= Success then
  307. Put_Line ("ERROR: Failed to shutdown WolfSSL context.");
  308. end if;
  309. WolfSSL.Free (Ssl);
  310. if DTLS then
  311. Shall_Continue := False;
  312. else
  313. SPARK_Sockets.Close_Socket (C);
  314. end if;
  315. Put_Line ("Shutdown complete.");
  316. end loop;
  317. SPARK_Sockets.Close_Socket (L);
  318. WolfSSL.Free (Context => Ctx);
  319. Result := WolfSSL.Finalize;
  320. if Result /= Success then
  321. Put_Line ("ERROR: Failed to finalize the WolfSSL library.");
  322. return;
  323. end if;
  324. end Run;
  325. end Tls_Server;