Skip to content

Commit 00b90ad

Browse files
Updated README.md file. Added description of subprograms in the specification file of the WolfSSL package. Made it possible to get error codes through the WolfSSL API.
1 parent 71b28ca commit 00b90ad

6 files changed

Lines changed: 573 additions & 206 deletions

File tree

wrapper/Ada/README.md

Lines changed: 92 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,57 @@
11
# Ada Binding Example
2+
The source code for the Ada/SPARK binding of the WolfSSL library
3+
is the WolfSSL Ada package in the wolfssl.ads and wolfssl.adb files.
24

3-
Download and install the GNAT community edition compiler and studio:
5+
The source code here also demonstrates a TLS v1.3 server and client
6+
using the WolfSSL Ada binding. The implementation is cross-platform
7+
and compiles on Linux, Mac OS X and Windows.
8+
9+
Security: The WolfSSL Ada binding avoids usage of the
10+
Seconday Stack. The GNAT compiler has a number of hardening
11+
features for example Stack Scrubbing; the compiler can generate
12+
code to zero-out stack frames used by subprograms.
13+
Unfortunately this works well for the primary stack but not
14+
for the secondary stack. The GNAT User's Guide recommends
15+
avoiding the secondary stack using the restriction
16+
No_Secondary_Stack (see the GNAT configuration file gnat.adc
17+
which instructs compilation of the WolfSSL Ada binding under
18+
this restriction).
19+
20+
Portability: The WolfSSL Ada binding makes no usage of controlled types
21+
and has no dependency upon the Ada.Finalization package.
22+
Lighter Ada run-times for embedded systems often have
23+
the restriction No_Finalization. The WolfSSL Ada binding has
24+
been developed with maximum portability in mind.
25+
26+
Not only can the WolfSSL Ada binding be used in Ada applications but
27+
also SPARK applications (a subset of the Ada language suitable
28+
formal verification). To formally verify the Ada code in this repository
29+
open the client.gpr with GNAT Studio and then select
30+
SPARK -> Prove All Sources and use Proof Level 2.
31+
32+
Summary of SPARK analysis
33+
=========================
34+
35+
---------------------------------------------------------------------------------------------------------------
36+
SPARK Analysis results Total Flow CodePeer Provers Justified Unproved
37+
---------------------------------------------------------------------------------------------------------------
38+
Data Dependencies 2 2 . . . .
39+
Flow Dependencies . . . . . .
40+
Initialization 15 15 . . . .
41+
Non-Aliasing . . . . . .
42+
Run-time Checks 58 . . 58 (CVC4 85%, Trivial 15%) . .
43+
Assertions 6 . . 6 (CVC4) . .
44+
Functional Contracts 91 . . 91 (CVC4) . .
45+
LSP Verification . . . . . .
46+
Termination . . . . . .
47+
Concurrency . . . . . .
48+
---------------------------------------------------------------------------------------------------------------
49+
Total 172 17 (10%) . 155 (90%) . .
50+
51+
## Compiler and Build System installation
52+
53+
### GNAT Community Edition 2021
54+
Download and install the GNAT community Edition 2021 compiler and studio:
455
https://www.adacore.com/download
556

657
Linux Install:
@@ -14,9 +65,46 @@ chmod +x gnat-2021-20210519-x86_64-linux-bin
1465
export PATH="/opt/GNAT/2021/bin:$PATH"
1566
gprclean
1667
gprbuild default.gpr
68+
gprbuild client.gpr
1769

18-
19-
./c_tls_server_main
70+
cd obj/
2071
./tls_server_main &
21-
./c_tls_client_main 127.0.0.1
72+
./tls_client_main 127.0.0.1
2273
```
74+
75+
### GNAT FSF Compiler and GPRBuild manual installation
76+
In May 2022 AdaCore announced the end of the GNAT Community releases.
77+
Pre-built binaries for the GNAT FSF compiler and GPRBuild can be
78+
downloaded and manually installed from here:
79+
https://github.com/alire-project/GNAT-FSF-builds/releases
80+
Make sure the executables for the compiler and GPRBuild are on the PATH
81+
and use gprbuild to build the source code.
82+
83+
## Files
84+
The file c_tls_client_main.c and c_tls_server_main.c are the TLS v1.3
85+
server and client examples using the WolfSSL library implemented using
86+
the C programming language.
87+
88+
The translation of the C client example into the Ada/SPARK programming
89+
language can be found in the files:
90+
tls_client_main.adb
91+
tls_client.ads
92+
tls_client.adb
93+
94+
The translation of the C server example into the Ada/SPARK programming
95+
language can be found in the files:
96+
tls_server_main.adb
97+
tls_server.ads
98+
tls_server.adb
99+
100+
A feature of the Ada language that is not part of SPARK is exceptions.
101+
Some packages of the Ada standard library and GNAT specific packages
102+
provided by the GNAT compiler can therefore not be used directly but
103+
need to be put into wrapper packages that does not raise exceptions.
104+
The packages that provide access to sockets and command line arguments
105+
to applications implemented in the SPARK programming language can be
106+
found in the files:
107+
spark_sockets.ads
108+
spark_sockets.adb
109+
spark_terminal.ads
110+
spark_terminal.adb

wrapper/Ada/ada_binding.c

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,17 @@
2121

2222
/* wolfSSL */
2323
#include <wolfssl/wolfcrypt/settings.h>
24-
2524
#include <wolfssl/ssl.h>
2625

2726
/* These functions give access to the integer values of the enumeration
2827
constants used in WolfSSL. These functions make it possible
2928
for the WolfSSL implementation to change the values of the constants
3029
without the need to make a corresponding change in the Ada code. */
30+
extern int get_wolfssl_error_want_read(void);
31+
extern int get_wolfssl_error_want_write(void);
32+
extern int get_wolfssl_max_error_size (void);
3133
extern int get_wolfssl_success(void);
34+
extern int get_wolfssl_failure(void);
3235
extern int get_wolfssl_verify_none(void);
3336
extern int get_wolfssl_verify_peer(void);
3437
extern int get_wolfssl_verify_fail_if_no_peer_cert(void);
@@ -41,10 +44,26 @@ extern int get_wolfssl_filetype_asn1(void);
4144
extern int get_wolfssl_filetype_pem(void);
4245
extern int get_wolfssl_filetype_default(void);
4346

47+
extern int get_wolfssl_error_want_read(void) {
48+
return WOLFSSL_ERROR_WANT_READ;
49+
}
50+
51+
extern int get_wolfssl_error_want_write(void) {
52+
return WOLFSSL_ERROR_WANT_WRITE;
53+
}
54+
55+
extern int get_wolfssl_max_error_size(void) {
56+
return WOLFSSL_MAX_ERROR_SZ;
57+
}
58+
4459
extern int get_wolfssl_success(void) {
4560
return WOLFSSL_SUCCESS;
4661
}
4762

63+
extern int get_wolfssl_failure(void) {
64+
return WOLFSSL_FAILURE;
65+
}
66+
4867
extern int get_wolfssl_verify_none(void) {
4968
return WOLFSSL_VERIFY_NONE;
5069
}

wrapper/Ada/tls_client.adb

Lines changed: 37 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -32,21 +32,29 @@ package body Tls_Client with SPARK_Mode is
3232
use type WolfSSL.Mode_Type;
3333
use type WolfSSL.Byte_Index;
3434
use type WolfSSL.Byte_Array;
35+
use type WolfSSL.Subprogram_Result;
3536

36-
use all type WolfSSL.Subprogram_Result;
37+
subtype Byte_Index is WolfSSL.Byte_Index;
38+
39+
Success : WolfSSL.Subprogram_Result renames WolfSSL.Success;
3740

3841
subtype Byte_Type is WolfSSL.Byte_Type;
3942

40-
package Integer_IO is new Ada.Text_IO.Integer_IO (Integer);
43+
package Natural_IO is new Ada.Text_IO.Integer_IO (Natural);
4144

4245
procedure Put (Text : String) is
4346
begin
4447
Ada.Text_IO.Put (Text);
4548
end Put;
4649

47-
procedure Put (Number : Integer) is
50+
procedure Put (Number : Natural) is
51+
begin
52+
Natural_IO.Put (Item => Number, Width => 0, Base => 10);
53+
end Put;
54+
55+
procedure Put (Number : Byte_Index) is
4856
begin
49-
Integer_IO.Put (Item => Number, Width => 0, Base => 10);
57+
Natural_IO.Put (Item => Natural (Number), Width => 0, Base => 10);
5058
end Put;
5159

5260
procedure Put_Line (Text : String) is
@@ -120,19 +128,18 @@ package body Tls_Client with SPARK_Mode is
120128

121129
Addr : SPARK_Sockets.Optional_Inet_Addr;
122130

123-
Bytes_Written : Integer;
124-
125131
Count : WolfSSL.Byte_Index;
126132

127133
Text : String (1 .. 200);
128-
Last : Integer;
134+
Last : Natural;
129135

130-
Input : WolfSSL.Read_Result;
136+
Input : WolfSSL.Read_Result;
137+
Output : WolfSSL.Write_Result;
131138

132139
Result : WolfSSL.Subprogram_Result;
133140
begin
134141
Result := WolfSSL.Initialize;
135-
if Result = Failure then
142+
if Result /= Success then
136143
Put_Line ("ERROR: Failed to initialize the WolfSSL library.");
137144
return;
138145
end if;
@@ -162,7 +169,7 @@ package body Tls_Client with SPARK_Mode is
162169

163170
Result := SPARK_Sockets.Connect_Socket (Socket => C.Socket,
164171
Server => A);
165-
if Result = Failure then
172+
if Result /= Success then
166173
Put_Line ("ERROR: Failed to connect to server.");
167174
SPARK_Sockets.Close_Socket (C);
168175
Set (Exit_Status_Failure);
@@ -183,7 +190,7 @@ package body Tls_Client with SPARK_Mode is
183190
Result := WolfSSL.Use_Certificate_File (Context => Ctx,
184191
File => CERT_FILE,
185192
Format => WolfSSL.Format_Pem);
186-
if Result = Failure then
193+
if Result /= Success then
187194
Put ("ERROR: failed to load ");
188195
Put (CERT_FILE);
189196
Put (", please check the file.");
@@ -198,7 +205,7 @@ package body Tls_Client with SPARK_Mode is
198205
Result := WolfSSL.Use_Private_Key_File (Context => Ctx,
199206
File => KEY_FILE,
200207
Format => WolfSSL.Format_Pem);
201-
if Result = Failure then
208+
if Result /= Success then
202209
Put ("ERROR: failed to load ");
203210
Put (KEY_FILE);
204211
Put (", please check the file.");
@@ -213,7 +220,7 @@ package body Tls_Client with SPARK_Mode is
213220
Result := WolfSSL.Load_Verify_Locations (Context => Ctx,
214221
File => CA_FILE,
215222
Path => "");
216-
if Result = Failure then
223+
if Result /= Success then
217224
Put ("ERROR: failed to load ");
218225
Put (CA_FILE);
219226
Put (", please check the file.");
@@ -237,7 +244,7 @@ package body Tls_Client with SPARK_Mode is
237244
-- Attach wolfSSL to the socket.
238245
Result := WolfSSL.Attach (Ssl => Ssl,
239246
Socket => SPARK_Sockets.To_C (C.Socket));
240-
if Result = Failure then
247+
if Result /= Success then
241248
Put_Line ("ERROR: Failed to set the file descriptor.");
242249
SPARK_Sockets.Close_Socket (C);
243250
WolfSSL.Free (Ssl);
@@ -247,7 +254,7 @@ package body Tls_Client with SPARK_Mode is
247254
end if;
248255

249256
Result := WolfSSL.Connect (Ssl);
250-
if Result = Failure then
257+
if Result /= Success then
251258
Put_Line ("ERROR: failed to connect to wolfSSL.");
252259
SPARK_Sockets.Close_Socket (C);
253260
WolfSSL.Free (Ssl);
@@ -262,12 +269,21 @@ package body Tls_Client with SPARK_Mode is
262269
SPARK_Sockets.To_C (Item => Text (1 .. Last),
263270
Target => D,
264271
Count => Count);
265-
Bytes_Written := WolfSSL.Write (Ssl => Ssl,
266-
Data => D (1 .. Count));
267-
if Bytes_Written < Last then
272+
Output := WolfSSL.Write (Ssl => Ssl,
273+
Data => D (1 .. Count));
274+
if not Output.Success then
275+
Put ("ERROR: write failure");
276+
New_Line;
277+
SPARK_Sockets.Close_Socket (C);
278+
WolfSSL.Free (Ssl);
279+
WolfSSL.Free (Context => Ctx);
280+
return;
281+
end if;
282+
283+
if Natural (Output.Bytes_Written) < Last then
268284
Put ("ERROR: failed to write entire message");
269285
New_Line;
270-
Put (Bytes_Written);
286+
Put (Output.Bytes_Written);
271287
Put (" bytes of ");
272288
Put (Last);
273289
Put ("bytes were sent");
@@ -279,7 +295,7 @@ package body Tls_Client with SPARK_Mode is
279295
end if;
280296

281297
Input := WolfSSL.Read (Ssl);
282-
if Input.Result /= Success then
298+
if not Input.Success then
283299
Put_Line ("Read error.");
284300
Set (Exit_Status_Failure);
285301
SPARK_Sockets.Close_Socket (C);
@@ -304,7 +320,7 @@ package body Tls_Client with SPARK_Mode is
304320
WolfSSL.Free (Ssl);
305321
WolfSSL.Free (Context => Ctx);
306322
Result := WolfSSL.Finalize;
307-
if Result = Failure then
323+
if Result /= Success then
308324
Put_Line ("ERROR: Failed to finalize the WolfSSL library.");
309325
end if;
310326
end Run;

0 commit comments

Comments
 (0)