tls_server.adb 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400
  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 or WolfSSL.Verify_Fail_If_No_Peer_Cert);
  165. -- Check verify is set correctly (GitHub #7461)
  166. if WolfSSL.Get_Verify(Context => Ctx) /= (WolfSSL.Verify_Peer or WolfSSL.Verify_Fail_If_No_Peer_Cert) then
  167. Put ("Error: Verify does not match requested");
  168. New_Line;
  169. return;
  170. end if;
  171. -- Load server certificates into WOLFSSL_CTX.
  172. Result := WolfSSL.Use_Certificate_File (Context => Ctx,
  173. File => CERT_FILE,
  174. Format => WolfSSL.Format_Pem);
  175. if Result /= Success then
  176. Put ("ERROR: failed to load ");
  177. Put (CERT_FILE);
  178. Put (", please check the file.");
  179. New_Line;
  180. SPARK_Sockets.Close_Socket (L);
  181. WolfSSL.Free (Context => Ctx);
  182. Set (Exit_Status_Failure);
  183. return;
  184. end if;
  185. -- Load server key into WOLFSSL_CTX.
  186. Result := WolfSSL.Use_Private_Key_File (Context => Ctx,
  187. File => KEY_FILE,
  188. Format => WolfSSL.Format_Pem);
  189. if Result /= Success then
  190. Put ("ERROR: failed to load ");
  191. Put (KEY_FILE);
  192. Put (", please check the file.");
  193. New_Line;
  194. SPARK_Sockets.Close_Socket (L);
  195. WolfSSL.Free (Context => Ctx);
  196. Set (Exit_Status_Failure);
  197. return;
  198. end if;
  199. -- Load client certificate as "trusted" into WOLFSSL_CTX.
  200. Result := WolfSSL.Load_Verify_Locations (Context => Ctx,
  201. File => CA_FILE,
  202. Path => "");
  203. if Result /= Success then
  204. Put ("ERROR: failed to load ");
  205. Put (CA_FILE);
  206. Put (", please check the file.");
  207. New_Line;
  208. SPARK_Sockets.Close_Socket (L);
  209. WolfSSL.Free (Context => Ctx);
  210. Set (Exit_Status_Failure);
  211. return;
  212. end if;
  213. while Shall_Continue loop
  214. pragma Loop_Invariant (not C.Exists);
  215. pragma Loop_Invariant (not WolfSSL.Is_Valid (Ssl));
  216. pragma Loop_Invariant (WolfSSL.Is_Valid (Ctx));
  217. if not DTLS then
  218. Put_Line ("Waiting for a connection...");
  219. SPARK_Sockets.Accept_Socket (Server => L.Socket,
  220. Socket => C,
  221. Address => A,
  222. Result => Result);
  223. if Result /= Success then
  224. Put_Line ("ERROR: failed to accept the connection.");
  225. SPARK_Sockets.Close_Socket (L);
  226. WolfSSL.Free (Context => Ctx);
  227. return;
  228. end if;
  229. end if;
  230. -- Create a WOLFSSL object.
  231. WolfSSL.Create_WolfSSL (Context => Ctx, Ssl => Ssl);
  232. if not WolfSSL.Is_Valid (Ssl) then
  233. Put_Line ("ERROR: failed to create WOLFSSL object.");
  234. SPARK_Sockets.Close_Socket (L);
  235. if not DTLS then
  236. SPARK_Sockets.Close_Socket (C);
  237. end if;
  238. WolfSSL.Free (Context => Ctx);
  239. Set (Exit_Status_Failure);
  240. return;
  241. end if;
  242. -- Attach wolfSSL to the socket.
  243. Result := WolfSSL.Attach
  244. (Ssl => Ssl,
  245. Socket => SPARK_Sockets.To_C (if DTLS then L.Socket else C.Socket));
  246. if Result /= Success then
  247. Put_Line ("ERROR: Failed to set the file descriptor.");
  248. WolfSSL.Free (Ssl);
  249. SPARK_Sockets.Close_Socket (L);
  250. if not DTLS then
  251. SPARK_Sockets.Close_Socket (C);
  252. end if;
  253. WolfSSL.Free (Context => Ctx);
  254. Set (Exit_Status_Failure);
  255. return;
  256. end if;
  257. -- Establish (D)TLS connection.
  258. Result := WolfSSL.Accept_Connection (Ssl);
  259. if Result /= Success then
  260. Put_Line ("Accept error.");
  261. WolfSSL.Free (Ssl);
  262. SPARK_Sockets.Close_Socket (L);
  263. if not DTLS then
  264. SPARK_Sockets.Close_Socket (C);
  265. end if;
  266. WolfSSL.Free (Context => Ctx);
  267. Set (Exit_Status_Failure);
  268. return;
  269. end if;
  270. Put_Line ("Client connected successfully.");
  271. Input := WolfSSL.Read (Ssl);
  272. if not Input.Success then
  273. Put_Line ("Read error.");
  274. WolfSSL.Free (Ssl);
  275. SPARK_Sockets.Close_Socket (L);
  276. if not DTLS then
  277. SPARK_Sockets.Close_Socket (C);
  278. end if;
  279. WolfSSL.Free (Context => Ctx);
  280. Set (Exit_Status_Failure);
  281. return;
  282. end if;
  283. -- Print to stdout any data the client sends.
  284. for I in Input.Buffer'Range loop
  285. Ch := Character (Input.Buffer (I));
  286. if Ada.Characters.Handling.Is_Graphic (Ch) then
  287. Put (Ch);
  288. else
  289. null;
  290. -- Ignore the "newline" characters at end of message.
  291. end if;
  292. end loop;
  293. New_Line;
  294. -- Check for server shutdown command.
  295. if Input.Last >= 8 then
  296. if Input.Buffer (1 .. 8) = "shutdown" then
  297. Put_Line ("Shutdown command issued!");
  298. Shall_Continue := False;
  299. end if;
  300. end if;
  301. Output := WolfSSL.Write (Ssl, Reply);
  302. if not Output.Success then
  303. Put_Line ("ERROR: write failure.");
  304. elsif Output.Bytes_Written /= Reply'Length then
  305. Put_Line ("ERROR: failed to write full response.");
  306. end if;
  307. for I in 1 .. 3 loop
  308. Result := WolfSSL.Shutdown (Ssl);
  309. exit when DTLS or Result = Success;
  310. delay 0.001; -- Delay is expressed in seconds.
  311. end loop;
  312. if not DTLS and then Result /= Success then
  313. Put_Line ("ERROR: Failed to shutdown WolfSSL context.");
  314. end if;
  315. WolfSSL.Free (Ssl);
  316. if DTLS then
  317. Shall_Continue := False;
  318. else
  319. SPARK_Sockets.Close_Socket (C);
  320. end if;
  321. Put_Line ("Shutdown complete.");
  322. end loop;
  323. SPARK_Sockets.Close_Socket (L);
  324. WolfSSL.Free (Context => Ctx);
  325. Result := WolfSSL.Finalize;
  326. if Result /= Success then
  327. Put_Line ("ERROR: Failed to finalize the WolfSSL library.");
  328. return;
  329. end if;
  330. end Run;
  331. end Tls_Server;