1+ -- tls_client.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+
122-- Ada Standard Library packages.
223with Ada.Characters.Handling ;
324with Ada.Command_Line ;
425with Ada.Strings.Bounded ;
526with Ada.Text_IO.Bounded_IO ;
27+ with Interfaces.C ;
628
729-- GNAT Library packages.
830with GNAT.Sockets ;
@@ -18,16 +40,35 @@ package body Tls_Client is
1840
1941 use all type WolfSSL.Subprogram_Result;
2042
43+ subtype Byte_Type is WolfSSL.Byte_Type;
44+
2145 package Messages is new Ada.Strings.Bounded.Generic_Bounded_Length (Max => 200 );
2246 use all type Messages.Bounded_String;
2347
48+ package Integer_IO is new Ada.Text_IO.Integer_IO (Integer);
49+
2450 package Messages_IO is new Ada.Text_IO.Bounded_IO (Messages);
2551
52+ procedure Put (Text : String) is
53+ begin
54+ Ada.Text_IO.Put (Text);
55+ end Put ;
56+
57+ procedure Put (Number : Integer) is
58+ begin
59+ Integer_IO.Put (Item => Number, Width => 0 , Base => 10 );
60+ end Put ;
61+
2662 procedure Put_Line (Text : String) is
2763 begin
2864 Ada.Text_IO.Put_Line (Text);
2965 end Put_Line ;
3066
67+ procedure New_Line is
68+ begin
69+ Ada.Text_IO.New_Line;
70+ end New_Line ;
71+
3172 procedure Put_Line (Text : Messages.Bounded_String) is
3273 begin
3374 Messages_IO.Put_Line (Text);
@@ -65,17 +106,164 @@ package body Tls_Client is
65106
66107 Any_Inet_Addr : Inet_Addr_Type renames GNAT.Sockets.Any_Inet_Addr;
67108
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" ;
109+ CERT_FILE : constant String := " ../certs/client -cert.pem" ;
110+ KEY_FILE : constant String := " ../certs/client -key.pem" ;
111+ CA_FILE : constant String := " ../certs/ca -cert.pem" ;
71112
72113 subtype Byte_Array is WolfSSL.Byte_Array;
73114
115+ function Argument_Count return Natural is
116+ begin
117+ return Ada.Command_Line.Argument_Count;
118+ end Argument_Count ;
119+
120+ function Argument (Number : Positive) return String is
121+ begin
122+ return Ada.Command_Line.Argument (Number);
123+ end Argument ;
124+
74125 procedure Run is
75126 A : Sock_Addr_Type;
76127 C : Socket_Type; -- Client socket.
128+ D : Byte_Array (1 .. 200 );
129+ P : constant Port_Type := 11111 ;
130+
131+ Ssl : WolfSSL.WolfSSL_Type;
132+ Ctx : WolfSSL.Context_Type;
133+
134+ Bytes_Written : Integer;
135+
136+ Count : WolfSSL.Byte_Index;
137+
138+ Text : String (1 .. 200 );
139+ Last : Integer;
140+
141+ Input : WolfSSL.Read_Result;
142+
143+ Result : WolfSSL.Subprogram_Result;
77144 begin
78- null ; -- work in progress.
145+ if Argument_Count /= 1 then
146+ Put_Line (" usage: tcl_client <IPv4 address>" );
147+ return ;
148+ end if ;
149+ GNAT.Sockets.Create_Socket (Socket => C);
150+
151+ A := (Family => Family_Inet,
152+ Addr => GNAT.Sockets.Inet_Addr (Argument (1 )),
153+ Port => P);
154+
155+ GNAT.Sockets.Connect_Socket (Socket => C,
156+ Server => A);
157+
158+ -- Create and initialize WOLFSSL_CTX.
159+ WolfSSL.Create_Context (Method => WolfSSL.TLSv1_3_Client_Method,
160+ Context => Ctx);
161+ if not WolfSSL.Is_Valid (Ctx) then
162+ Put_Line (" ERROR: failed to create WOLFSSL_CTX." );
163+ Set (Exit_Status_Failure);
164+ return ;
165+ end if ;
166+
167+ -- Load client certificate into WOLFSSL_CTX.
168+ Result := WolfSSL.Use_Certificate_File (Context => Ctx,
169+ File => CERT_FILE,
170+ Format => WolfSSL.Format_Pem);
171+ if Result = Failure then
172+ Put (" ERROR: failed to load " );
173+ Put (CERT_FILE);
174+ Put (" , please check the file." );
175+ New_Line;
176+ Set (Exit_Status_Failure);
177+ return ;
178+ end if ;
179+
180+ -- Load client key into WOLFSSL_CTX.
181+ Result := WolfSSL.Use_Private_Key_File (Context => Ctx,
182+ File => KEY_FILE,
183+ Format => WolfSSL.Format_Pem);
184+ if Result = Failure then
185+ Put (" ERROR: failed to load " );
186+ Put (KEY_FILE);
187+ Put (" , please check the file." );
188+ New_Line;
189+ Set (Exit_Status_Failure);
190+ return ;
191+ end if ;
192+
193+ -- Load CA certificate into WOLFSSL_CTX.
194+ Result := WolfSSL.Load_Verify_Locations (Context => Ctx,
195+ File => CA_FILE,
196+ Path => " " );
197+ if Result = Failure then
198+ Put (" ERROR: failed to load " );
199+ Put (CA_FILE);
200+ Put (" , please check the file." );
201+ New_Line;
202+ Set (Exit_Status_Failure);
203+ return ;
204+ end if ;
205+
206+ -- Create a WOLFSSL object.
207+ WolfSSL.Create_WolfSSL (Context => Ctx, Ssl => Ssl);
208+ if not WolfSSL.Is_Valid (Ssl) then
209+ Put_Line (" ERROR: failed to create WOLFSSL object." );
210+ Set (Exit_Status_Failure);
211+ return ;
212+ end if ;
213+
214+ -- Attach wolfSSL to the socket.
215+ Result := WolfSSL.Attach (Ssl => Ssl,
216+ Socket => GNAT.Sockets.To_C (C));
217+ if Result = Failure then
218+ Put_Line (" ERROR: Failed to set the file descriptor." );
219+ Set (Exit_Status_Failure);
220+ return ;
221+ end if ;
222+
223+ Result := WolfSSL.Connect (Ssl);
224+ if Result = Failure then
225+ Put_Line (" ERROR: failed to connect to wolfSSL." );
226+ Set (Exit_Status_Failure);
227+ return ;
228+ end if ;
229+
230+ Put (" Message for server: " );
231+ Ada.Text_IO.Get_Line (Text, Last);
232+
233+ Interfaces.C.To_C (Item => Text (1 .. Last),
234+ Target => D,
235+ Count => Count,
236+ Append_Nul => False);
237+ Bytes_Written := WolfSSL.Write (Ssl => Ssl,
238+ Data => D (1 .. Count));
239+ if Bytes_Written < Last then
240+ Put (" ERROR: failed to write entire message" );
241+ New_Line;
242+ Put (Bytes_Written);
243+ Put (" bytes of " );
244+ Put (Last);
245+ Put (" bytes were sent" );
246+ New_Line;
247+ return ;
248+ end if ;
249+
250+ Input := WolfSSL.Read (Ssl);
251+ if Input.Result /= Success then
252+ Put_Line (" Read error." );
253+ Set (Exit_Status_Failure);
254+ return ;
255+ end if ;
256+ Interfaces.C.To_Ada (Item => Input.Buffer,
257+ Target => Text,
258+ Count => Last,
259+ Trim_Nul => False);
260+ Put (" Server: " );
261+ Put (Text (1 .. Last));
262+ New_Line;
263+
264+ GNAT.Sockets.Close_Socket (C);
265+ WolfSSL.Free (Ssl);
266+ WolfSSL.Free (Context => Ctx);
79267 end Run ;
80268
81269end Tls_Client ;
0 commit comments