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.
This commit is contained in:
parent
71b28caa09
commit
00b90adc97
@ -1,6 +1,57 @@
|
||||
# Ada Binding Example
|
||||
The source code for the Ada/SPARK binding of the WolfSSL library
|
||||
is the WolfSSL Ada package in the wolfssl.ads and wolfssl.adb files.
|
||||
|
||||
Download and install the GNAT community edition compiler and studio:
|
||||
The source code here also demonstrates a TLS v1.3 server and client
|
||||
using the WolfSSL Ada binding. The implementation is cross-platform
|
||||
and compiles on Linux, Mac OS X and Windows.
|
||||
|
||||
Security: The WolfSSL Ada binding avoids usage of the
|
||||
Seconday Stack. The GNAT compiler has a number of hardening
|
||||
features for example Stack Scrubbing; the compiler can generate
|
||||
code to zero-out stack frames used by subprograms.
|
||||
Unfortunately this works well for the primary stack but not
|
||||
for the secondary stack. The GNAT User's Guide recommends
|
||||
avoiding the secondary stack using the restriction
|
||||
No_Secondary_Stack (see the GNAT configuration file gnat.adc
|
||||
which instructs compilation of the WolfSSL Ada binding under
|
||||
this restriction).
|
||||
|
||||
Portability: The WolfSSL Ada binding makes no usage of controlled types
|
||||
and has no dependency upon the Ada.Finalization package.
|
||||
Lighter Ada run-times for embedded systems often have
|
||||
the restriction No_Finalization. The WolfSSL Ada binding has
|
||||
been developed with maximum portability in mind.
|
||||
|
||||
Not only can the WolfSSL Ada binding be used in Ada applications but
|
||||
also SPARK applications (a subset of the Ada language suitable
|
||||
formal verification). To formally verify the Ada code in this repository
|
||||
open the client.gpr with GNAT Studio and then select
|
||||
SPARK -> Prove All Sources and use Proof Level 2.
|
||||
|
||||
Summary of SPARK analysis
|
||||
=========================
|
||||
|
||||
---------------------------------------------------------------------------------------------------------------
|
||||
SPARK Analysis results Total Flow CodePeer Provers Justified Unproved
|
||||
---------------------------------------------------------------------------------------------------------------
|
||||
Data Dependencies 2 2 . . . .
|
||||
Flow Dependencies . . . . . .
|
||||
Initialization 15 15 . . . .
|
||||
Non-Aliasing . . . . . .
|
||||
Run-time Checks 58 . . 58 (CVC4 85%, Trivial 15%) . .
|
||||
Assertions 6 . . 6 (CVC4) . .
|
||||
Functional Contracts 91 . . 91 (CVC4) . .
|
||||
LSP Verification . . . . . .
|
||||
Termination . . . . . .
|
||||
Concurrency . . . . . .
|
||||
---------------------------------------------------------------------------------------------------------------
|
||||
Total 172 17 (10%) . 155 (90%) . .
|
||||
|
||||
## Compiler and Build System installation
|
||||
|
||||
### GNAT Community Edition 2021
|
||||
Download and install the GNAT community Edition 2021 compiler and studio:
|
||||
https://www.adacore.com/download
|
||||
|
||||
Linux Install:
|
||||
@ -14,9 +65,46 @@ chmod +x gnat-2021-20210519-x86_64-linux-bin
|
||||
export PATH="/opt/GNAT/2021/bin:$PATH"
|
||||
gprclean
|
||||
gprbuild default.gpr
|
||||
gprbuild client.gpr
|
||||
|
||||
|
||||
./c_tls_server_main
|
||||
cd obj/
|
||||
./tls_server_main &
|
||||
./c_tls_client_main 127.0.0.1
|
||||
./tls_client_main 127.0.0.1
|
||||
```
|
||||
|
||||
### GNAT FSF Compiler and GPRBuild manual installation
|
||||
In May 2022 AdaCore announced the end of the GNAT Community releases.
|
||||
Pre-built binaries for the GNAT FSF compiler and GPRBuild can be
|
||||
downloaded and manually installed from here:
|
||||
https://github.com/alire-project/GNAT-FSF-builds/releases
|
||||
Make sure the executables for the compiler and GPRBuild are on the PATH
|
||||
and use gprbuild to build the source code.
|
||||
|
||||
## Files
|
||||
The file c_tls_client_main.c and c_tls_server_main.c are the TLS v1.3
|
||||
server and client examples using the WolfSSL library implemented using
|
||||
the C programming language.
|
||||
|
||||
The translation of the C client example into the Ada/SPARK programming
|
||||
language can be found in the files:
|
||||
tls_client_main.adb
|
||||
tls_client.ads
|
||||
tls_client.adb
|
||||
|
||||
The translation of the C server example into the Ada/SPARK programming
|
||||
language can be found in the files:
|
||||
tls_server_main.adb
|
||||
tls_server.ads
|
||||
tls_server.adb
|
||||
|
||||
A feature of the Ada language that is not part of SPARK is exceptions.
|
||||
Some packages of the Ada standard library and GNAT specific packages
|
||||
provided by the GNAT compiler can therefore not be used directly but
|
||||
need to be put into wrapper packages that does not raise exceptions.
|
||||
The packages that provide access to sockets and command line arguments
|
||||
to applications implemented in the SPARK programming language can be
|
||||
found in the files:
|
||||
spark_sockets.ads
|
||||
spark_sockets.adb
|
||||
spark_terminal.ads
|
||||
spark_terminal.adb
|
@ -21,14 +21,17 @@
|
||||
|
||||
/* wolfSSL */
|
||||
#include <wolfssl/wolfcrypt/settings.h>
|
||||
|
||||
#include <wolfssl/ssl.h>
|
||||
|
||||
/* These functions give access to the integer values of the enumeration
|
||||
constants used in WolfSSL. These functions make it possible
|
||||
for the WolfSSL implementation to change the values of the constants
|
||||
without the need to make a corresponding change in the Ada code. */
|
||||
extern int get_wolfssl_error_want_read(void);
|
||||
extern int get_wolfssl_error_want_write(void);
|
||||
extern int get_wolfssl_max_error_size (void);
|
||||
extern int get_wolfssl_success(void);
|
||||
extern int get_wolfssl_failure(void);
|
||||
extern int get_wolfssl_verify_none(void);
|
||||
extern int get_wolfssl_verify_peer(void);
|
||||
extern int get_wolfssl_verify_fail_if_no_peer_cert(void);
|
||||
@ -41,10 +44,26 @@ extern int get_wolfssl_filetype_asn1(void);
|
||||
extern int get_wolfssl_filetype_pem(void);
|
||||
extern int get_wolfssl_filetype_default(void);
|
||||
|
||||
extern int get_wolfssl_error_want_read(void) {
|
||||
return WOLFSSL_ERROR_WANT_READ;
|
||||
}
|
||||
|
||||
extern int get_wolfssl_error_want_write(void) {
|
||||
return WOLFSSL_ERROR_WANT_WRITE;
|
||||
}
|
||||
|
||||
extern int get_wolfssl_max_error_size(void) {
|
||||
return WOLFSSL_MAX_ERROR_SZ;
|
||||
}
|
||||
|
||||
extern int get_wolfssl_success(void) {
|
||||
return WOLFSSL_SUCCESS;
|
||||
}
|
||||
|
||||
extern int get_wolfssl_failure(void) {
|
||||
return WOLFSSL_FAILURE;
|
||||
}
|
||||
|
||||
extern int get_wolfssl_verify_none(void) {
|
||||
return WOLFSSL_VERIFY_NONE;
|
||||
}
|
||||
|
@ -32,21 +32,29 @@ package body Tls_Client with SPARK_Mode is
|
||||
use type WolfSSL.Mode_Type;
|
||||
use type WolfSSL.Byte_Index;
|
||||
use type WolfSSL.Byte_Array;
|
||||
use type WolfSSL.Subprogram_Result;
|
||||
|
||||
use all type WolfSSL.Subprogram_Result;
|
||||
subtype Byte_Index is WolfSSL.Byte_Index;
|
||||
|
||||
Success : WolfSSL.Subprogram_Result renames WolfSSL.Success;
|
||||
|
||||
subtype Byte_Type is WolfSSL.Byte_Type;
|
||||
|
||||
package Integer_IO is new Ada.Text_IO.Integer_IO (Integer);
|
||||
package Natural_IO is new Ada.Text_IO.Integer_IO (Natural);
|
||||
|
||||
procedure Put (Text : String) is
|
||||
begin
|
||||
Ada.Text_IO.Put (Text);
|
||||
end Put;
|
||||
|
||||
procedure Put (Number : Integer) is
|
||||
procedure Put (Number : Natural) is
|
||||
begin
|
||||
Integer_IO.Put (Item => Number, Width => 0, Base => 10);
|
||||
Natural_IO.Put (Item => Number, Width => 0, Base => 10);
|
||||
end Put;
|
||||
|
||||
procedure Put (Number : Byte_Index) is
|
||||
begin
|
||||
Natural_IO.Put (Item => Natural (Number), Width => 0, Base => 10);
|
||||
end Put;
|
||||
|
||||
procedure Put_Line (Text : String) is
|
||||
@ -120,19 +128,18 @@ package body Tls_Client with SPARK_Mode is
|
||||
|
||||
Addr : SPARK_Sockets.Optional_Inet_Addr;
|
||||
|
||||
Bytes_Written : Integer;
|
||||
|
||||
Count : WolfSSL.Byte_Index;
|
||||
|
||||
Text : String (1 .. 200);
|
||||
Last : Integer;
|
||||
Last : Natural;
|
||||
|
||||
Input : WolfSSL.Read_Result;
|
||||
Input : WolfSSL.Read_Result;
|
||||
Output : WolfSSL.Write_Result;
|
||||
|
||||
Result : WolfSSL.Subprogram_Result;
|
||||
begin
|
||||
Result := WolfSSL.Initialize;
|
||||
if Result = Failure then
|
||||
if Result /= Success then
|
||||
Put_Line ("ERROR: Failed to initialize the WolfSSL library.");
|
||||
return;
|
||||
end if;
|
||||
@ -162,7 +169,7 @@ package body Tls_Client with SPARK_Mode is
|
||||
|
||||
Result := SPARK_Sockets.Connect_Socket (Socket => C.Socket,
|
||||
Server => A);
|
||||
if Result = Failure then
|
||||
if Result /= Success then
|
||||
Put_Line ("ERROR: Failed to connect to server.");
|
||||
SPARK_Sockets.Close_Socket (C);
|
||||
Set (Exit_Status_Failure);
|
||||
@ -183,7 +190,7 @@ package body Tls_Client with SPARK_Mode is
|
||||
Result := WolfSSL.Use_Certificate_File (Context => Ctx,
|
||||
File => CERT_FILE,
|
||||
Format => WolfSSL.Format_Pem);
|
||||
if Result = Failure then
|
||||
if Result /= Success then
|
||||
Put ("ERROR: failed to load ");
|
||||
Put (CERT_FILE);
|
||||
Put (", please check the file.");
|
||||
@ -198,7 +205,7 @@ package body Tls_Client with SPARK_Mode is
|
||||
Result := WolfSSL.Use_Private_Key_File (Context => Ctx,
|
||||
File => KEY_FILE,
|
||||
Format => WolfSSL.Format_Pem);
|
||||
if Result = Failure then
|
||||
if Result /= Success then
|
||||
Put ("ERROR: failed to load ");
|
||||
Put (KEY_FILE);
|
||||
Put (", please check the file.");
|
||||
@ -213,7 +220,7 @@ package body Tls_Client with SPARK_Mode is
|
||||
Result := WolfSSL.Load_Verify_Locations (Context => Ctx,
|
||||
File => CA_FILE,
|
||||
Path => "");
|
||||
if Result = Failure then
|
||||
if Result /= Success then
|
||||
Put ("ERROR: failed to load ");
|
||||
Put (CA_FILE);
|
||||
Put (", please check the file.");
|
||||
@ -237,7 +244,7 @@ package body Tls_Client with SPARK_Mode is
|
||||
-- Attach wolfSSL to the socket.
|
||||
Result := WolfSSL.Attach (Ssl => Ssl,
|
||||
Socket => SPARK_Sockets.To_C (C.Socket));
|
||||
if Result = Failure then
|
||||
if Result /= Success then
|
||||
Put_Line ("ERROR: Failed to set the file descriptor.");
|
||||
SPARK_Sockets.Close_Socket (C);
|
||||
WolfSSL.Free (Ssl);
|
||||
@ -247,7 +254,7 @@ package body Tls_Client with SPARK_Mode is
|
||||
end if;
|
||||
|
||||
Result := WolfSSL.Connect (Ssl);
|
||||
if Result = Failure then
|
||||
if Result /= Success then
|
||||
Put_Line ("ERROR: failed to connect to wolfSSL.");
|
||||
SPARK_Sockets.Close_Socket (C);
|
||||
WolfSSL.Free (Ssl);
|
||||
@ -262,12 +269,21 @@ package body Tls_Client with SPARK_Mode is
|
||||
SPARK_Sockets.To_C (Item => Text (1 .. Last),
|
||||
Target => D,
|
||||
Count => Count);
|
||||
Bytes_Written := WolfSSL.Write (Ssl => Ssl,
|
||||
Data => D (1 .. Count));
|
||||
if Bytes_Written < Last then
|
||||
Output := WolfSSL.Write (Ssl => Ssl,
|
||||
Data => D (1 .. Count));
|
||||
if not Output.Success then
|
||||
Put ("ERROR: write failure");
|
||||
New_Line;
|
||||
SPARK_Sockets.Close_Socket (C);
|
||||
WolfSSL.Free (Ssl);
|
||||
WolfSSL.Free (Context => Ctx);
|
||||
return;
|
||||
end if;
|
||||
|
||||
if Natural (Output.Bytes_Written) < Last then
|
||||
Put ("ERROR: failed to write entire message");
|
||||
New_Line;
|
||||
Put (Bytes_Written);
|
||||
Put (Output.Bytes_Written);
|
||||
Put (" bytes of ");
|
||||
Put (Last);
|
||||
Put ("bytes were sent");
|
||||
@ -279,7 +295,7 @@ package body Tls_Client with SPARK_Mode is
|
||||
end if;
|
||||
|
||||
Input := WolfSSL.Read (Ssl);
|
||||
if Input.Result /= Success then
|
||||
if not Input.Success then
|
||||
Put_Line ("Read error.");
|
||||
Set (Exit_Status_Failure);
|
||||
SPARK_Sockets.Close_Socket (C);
|
||||
@ -304,7 +320,7 @@ package body Tls_Client with SPARK_Mode is
|
||||
WolfSSL.Free (Ssl);
|
||||
WolfSSL.Free (Context => Ctx);
|
||||
Result := WolfSSL.Finalize;
|
||||
if Result = Failure then
|
||||
if Result /= Success then
|
||||
Put_Line ("ERROR: Failed to finalize the WolfSSL library.");
|
||||
end if;
|
||||
end Run;
|
||||
|
@ -31,8 +31,9 @@ package body Tls_Server with SPARK_Mode is
|
||||
use type WolfSSL.Mode_Type;
|
||||
use type WolfSSL.Byte_Index;
|
||||
use type WolfSSL.Byte_Array;
|
||||
use type WolfSSL.Subprogram_Result;
|
||||
|
||||
use all type WolfSSL.Subprogram_Result;
|
||||
Success : WolfSSL.Subprogram_Result renames WolfSSL.Success;
|
||||
|
||||
procedure Put (Char : Character) is
|
||||
begin
|
||||
@ -106,13 +107,12 @@ package body Tls_Server with SPARK_Mode is
|
||||
Result : WolfSSL.Subprogram_Result;
|
||||
Shall_Continue : Boolean := True;
|
||||
|
||||
Bytes_Written : Integer;
|
||||
|
||||
Input : WolfSSL.Read_Result;
|
||||
Input : WolfSSL.Read_Result;
|
||||
Output : WolfSSL.Write_Result;
|
||||
Option : Option_Type;
|
||||
begin
|
||||
Result := WolfSSL.Initialize;
|
||||
if Result = Failure then
|
||||
if Result /= Success then
|
||||
Put_Line ("ERROR: Failed to initialize the WolfSSL library.");
|
||||
return;
|
||||
end if;
|
||||
@ -127,7 +127,7 @@ package body Tls_Server with SPARK_Mode is
|
||||
Result := SPARK_Sockets.Set_Socket_Option (Socket => L.Socket,
|
||||
Level => Socket_Level,
|
||||
Option => Option);
|
||||
if Result = Failure then
|
||||
if Result /= Success then
|
||||
Put_Line ("ERROR: Failed to set socket option.");
|
||||
SPARK_Sockets.Close_Socket (L);
|
||||
return;
|
||||
@ -138,7 +138,7 @@ package body Tls_Server with SPARK_Mode is
|
||||
Port => P);
|
||||
Result := SPARK_Sockets.Bind_Socket (Socket => L.Socket,
|
||||
Address => A);
|
||||
if Result = Failure then
|
||||
if Result /= Success then
|
||||
Put_Line ("ERROR: Failed to bind socket.");
|
||||
SPARK_Sockets.Close_Socket (L);
|
||||
return;
|
||||
@ -146,7 +146,7 @@ package body Tls_Server with SPARK_Mode is
|
||||
|
||||
Result := SPARK_Sockets.Listen_Socket (Socket => L.Socket,
|
||||
Length => 5);
|
||||
if Result = Failure then
|
||||
if Result /= Success then
|
||||
Put_Line ("ERROR: Failed to configure listener socket.");
|
||||
SPARK_Sockets.Close_Socket (L);
|
||||
return;
|
||||
@ -171,7 +171,7 @@ package body Tls_Server with SPARK_Mode is
|
||||
Result := WolfSSL.Use_Certificate_File (Context => Ctx,
|
||||
File => CERT_FILE,
|
||||
Format => WolfSSL.Format_Pem);
|
||||
if Result = Failure then
|
||||
if Result /= Success then
|
||||
Put ("ERROR: failed to load ");
|
||||
Put (CERT_FILE);
|
||||
Put (", please check the file.");
|
||||
@ -186,7 +186,7 @@ package body Tls_Server with SPARK_Mode is
|
||||
Result := WolfSSL.Use_Private_Key_File (Context => Ctx,
|
||||
File => KEY_FILE,
|
||||
Format => WolfSSL.Format_Pem);
|
||||
if Result = Failure then
|
||||
if Result /= Success then
|
||||
Put ("ERROR: failed to load ");
|
||||
Put (KEY_FILE);
|
||||
Put (", please check the file.");
|
||||
@ -201,7 +201,7 @@ package body Tls_Server with SPARK_Mode is
|
||||
Result := WolfSSL.Load_Verify_Locations (Context => Ctx,
|
||||
File => CA_FILE,
|
||||
Path => "");
|
||||
if Result = Failure then
|
||||
if Result /= Success then
|
||||
Put ("ERROR: failed to load ");
|
||||
Put (CA_FILE);
|
||||
Put (", please check the file.");
|
||||
@ -213,16 +213,16 @@ package body Tls_Server with SPARK_Mode is
|
||||
end if;
|
||||
|
||||
while Shall_Continue loop
|
||||
pragma Loop_Invariant (not C.Exists and
|
||||
not WolfSSL.Is_Valid (Ssl) and
|
||||
WolfSSL.Is_Valid (Ctx));
|
||||
pragma Loop_Invariant (not C.Exists);
|
||||
pragma Loop_Invariant (not WolfSSL.Is_Valid (Ssl));
|
||||
pragma Loop_Invariant (WolfSSL.Is_Valid (Ctx));
|
||||
|
||||
Put_Line ("Waiting for a connection...");
|
||||
SPARK_Sockets.Accept_Socket (Server => L.Socket,
|
||||
Socket => C,
|
||||
Address => A,
|
||||
Result => Result);
|
||||
if Result = Failure then
|
||||
if Result /= Success then
|
||||
Put_Line ("ERROR: failed to accept the connection.");
|
||||
SPARK_Sockets.Close_Socket (L);
|
||||
WolfSSL.Free (Context => Ctx);
|
||||
@ -243,7 +243,7 @@ package body Tls_Server with SPARK_Mode is
|
||||
-- Attach wolfSSL to the socket.
|
||||
Result := WolfSSL.Attach (Ssl => Ssl,
|
||||
Socket => SPARK_Sockets.To_C (C.Socket));
|
||||
if Result = Failure then
|
||||
if Result /= Success then
|
||||
Put_Line ("ERROR: Failed to set the file descriptor.");
|
||||
WolfSSL.Free (Ssl);
|
||||
SPARK_Sockets.Close_Socket (L);
|
||||
@ -255,7 +255,7 @@ package body Tls_Server with SPARK_Mode is
|
||||
|
||||
-- Establish TLS connection.
|
||||
Result := WolfSSL.Accept_Connection (Ssl);
|
||||
if Result = Failure then
|
||||
if Result /= Success then
|
||||
Put_Line ("Accept error.");
|
||||
WolfSSL.Free (Ssl);
|
||||
SPARK_Sockets.Close_Socket (L);
|
||||
@ -268,7 +268,7 @@ package body Tls_Server with SPARK_Mode is
|
||||
Put_Line ("Client connected successfully.");
|
||||
|
||||
Input := WolfSSL.Read (Ssl);
|
||||
if Input.Result /= Success then
|
||||
if not Input.Success then
|
||||
Put_Line ("Read error.");
|
||||
WolfSSL.Free (Ssl);
|
||||
SPARK_Sockets.Close_Socket (L);
|
||||
@ -298,13 +298,15 @@ package body Tls_Server with SPARK_Mode is
|
||||
end if;
|
||||
end if;
|
||||
|
||||
Bytes_Written := WolfSSL.Write (Ssl, Reply);
|
||||
if Bytes_Written /= Reply'Length then
|
||||
Put_Line ("ERROR: failed to write.");
|
||||
Output := WolfSSL.Write (Ssl, Reply);
|
||||
if not Output.Success then
|
||||
Put_Line ("ERROR: write failure.");
|
||||
elsif Output.Bytes_Written /= Reply'Length then
|
||||
Put_Line ("ERROR: failed to write full response.");
|
||||
end if;
|
||||
|
||||
Result := WolfSSL.Shutdown (Ssl);
|
||||
if Result = Failure then
|
||||
if Result /= Success then
|
||||
Put_Line ("ERROR: Failed to shutdown WolfSSL context.");
|
||||
end if;
|
||||
WolfSSL.Free (Ssl);
|
||||
@ -315,7 +317,7 @@ package body Tls_Server with SPARK_Mode is
|
||||
SPARK_Sockets.Close_Socket (L);
|
||||
WolfSSL.Free (Context => Ctx);
|
||||
Result := WolfSSL.Finalize;
|
||||
if Result = Failure then
|
||||
if Result /= Success then
|
||||
Put_Line ("ERROR: Failed to finalize the WolfSSL library.");
|
||||
return;
|
||||
end if;
|
||||
|
@ -26,11 +26,7 @@ package body WolfSSL is
|
||||
subtype size_t is Interfaces.C.size_t; use type size_t;
|
||||
|
||||
subtype long is Interfaces.C.long;
|
||||
|
||||
function Get_WolfSSL_Success return int with
|
||||
Convention => C,
|
||||
External_Name => "get_wolfssl_success",
|
||||
Import => True;
|
||||
subtype unsigned_long is Interfaces.C.unsigned_long;
|
||||
|
||||
WOLFSSL_SUCCESS : constant int := Get_WolfSSL_Success;
|
||||
|
||||
@ -47,21 +43,13 @@ package body WolfSSL is
|
||||
function Initialize return Subprogram_Result is
|
||||
Result : constant int := Initialize_WolfSSL;
|
||||
begin
|
||||
if Result = WOLFSSL_SUCCESS then
|
||||
return Success;
|
||||
else
|
||||
return Failure;
|
||||
end if;
|
||||
return Subprogram_Result (Result);
|
||||
end Initialize;
|
||||
|
||||
function Finalize return Subprogram_Result is
|
||||
Result : constant int := Finalize_WolfSSL;
|
||||
begin
|
||||
if Result = WOLFSSL_SUCCESS then
|
||||
return Success;
|
||||
else
|
||||
return Failure;
|
||||
end if;
|
||||
return Subprogram_Result (Result);
|
||||
end Finalize;
|
||||
|
||||
function Is_Valid (Context : Context_Type) return Boolean is
|
||||
@ -79,6 +67,16 @@ package body WolfSSL is
|
||||
return WolfTLSv1_2_Server_Method;
|
||||
end TLSv1_2_Server_Method;
|
||||
|
||||
function WolfTLSv1_2_Client_Method return Method_Type with
|
||||
Convention => C,
|
||||
External_Name => "wolfTLSv1_2_client_method",
|
||||
Import => True;
|
||||
|
||||
function TLSv1_2_Client_Method return Method_Type is
|
||||
begin
|
||||
return WolfTLSv1_2_Client_Method;
|
||||
end TLSv1_2_Client_Method;
|
||||
|
||||
function WolfTLSv1_3_Server_Method return Method_Type with
|
||||
Convention => C,
|
||||
External_Name => "wolfTLSv1_3_server_method",
|
||||
@ -198,11 +196,7 @@ package body WolfSSL is
|
||||
Count => C,
|
||||
Append_Nul => True);
|
||||
Result := Use_Certificate_File (Ctx, F (1 .. C), int (Format));
|
||||
if Result = WOLFSSL_SUCCESS then
|
||||
return Success;
|
||||
else
|
||||
return Failure;
|
||||
end if;
|
||||
return Subprogram_Result (Result);
|
||||
end Use_Certificate_File;
|
||||
|
||||
function Use_Certificate_Buffer (Context : Context_Type;
|
||||
@ -222,11 +216,7 @@ package body WolfSSL is
|
||||
begin
|
||||
Result := Use_Certificate_Buffer (Context, Input,
|
||||
Input'Length, int (Format));
|
||||
if Result = WOLFSSL_SUCCESS then
|
||||
return Success;
|
||||
else
|
||||
return Failure;
|
||||
end if;
|
||||
return Subprogram_Result (Result);
|
||||
end Use_Certificate_Buffer;
|
||||
|
||||
function Use_Private_Key_File (Context : Context_Type;
|
||||
@ -251,11 +241,7 @@ package body WolfSSL is
|
||||
Count => C,
|
||||
Append_Nul => True);
|
||||
Result := Use_Private_Key_File (Ctx, F (1 .. C), int (Format));
|
||||
if Result = WOLFSSL_SUCCESS then
|
||||
return Success;
|
||||
else
|
||||
return Failure;
|
||||
end if;
|
||||
return Subprogram_Result (Result);
|
||||
end Use_Private_Key_File;
|
||||
|
||||
function Use_Private_Key_Buffer (Context : Context_Type;
|
||||
@ -275,11 +261,7 @@ package body WolfSSL is
|
||||
begin
|
||||
Result := Use_Private_Key_Buffer (Context, Input,
|
||||
Input'Length, int (Format));
|
||||
if Result = WOLFSSL_SUCCESS then
|
||||
return Success;
|
||||
else
|
||||
return Failure;
|
||||
end if;
|
||||
return Subprogram_Result (Result);
|
||||
end Use_Private_Key_Buffer;
|
||||
|
||||
function Load_Verify_Locations1
|
||||
@ -375,11 +357,7 @@ package body WolfSSL is
|
||||
Path => P);
|
||||
end if;
|
||||
end if;
|
||||
if Result = WOLFSSL_SUCCESS then
|
||||
return Success;
|
||||
else
|
||||
return Failure;
|
||||
end if;
|
||||
return Subprogram_Result (Result);
|
||||
end Load_Verify_Locations;
|
||||
|
||||
function Load_Verify_Buffer
|
||||
@ -390,14 +368,6 @@ package body WolfSSL is
|
||||
Convention => C,
|
||||
External_Name => "wolfSSL_CTX_load_verify_buffer",
|
||||
Import => True;
|
||||
-- This function loads a CA certificate buffer into the WOLFSSL
|
||||
-- Context. It behaves like the non-buffered version, only differing
|
||||
-- in its ability to be called with a buffer as input instead of
|
||||
-- a file. The buffer is provided by the in argument of size sz.
|
||||
-- format specifies the format type of the buffer; SSL_FILETYPE_ASN1
|
||||
-- or SSL_FILETYPE_PEM. More than one CA certificate may be loaded
|
||||
-- per buffer as long as the format is in PEM. Please see
|
||||
-- the examples for proper usage.
|
||||
|
||||
function Load_Verify_Buffer (Context : Context_Type;
|
||||
Input : Byte_Array;
|
||||
@ -409,11 +379,7 @@ package body WolfSSL is
|
||||
Input => Input,
|
||||
Size => Input'Length,
|
||||
Format => int(Format));
|
||||
if Result = WOLFSSL_SUCCESS then
|
||||
return Success;
|
||||
else
|
||||
return Failure;
|
||||
end if;
|
||||
return Subprogram_Result (Result);
|
||||
end Load_Verify_Buffer;
|
||||
|
||||
function Is_Valid (Ssl : WolfSSL_Type) return Boolean is
|
||||
@ -454,11 +420,7 @@ package body WolfSSL is
|
||||
Count => C,
|
||||
Append_Nul => True);
|
||||
Result := Use_Certificate_File (Ssl, F (1 .. C), int (Format));
|
||||
if Result = WOLFSSL_SUCCESS then
|
||||
return Success;
|
||||
else
|
||||
return Failure;
|
||||
end if;
|
||||
return Subprogram_Result (Result);
|
||||
end Use_Certificate_File;
|
||||
|
||||
function Use_Certificate_Buffer (Ssl : WolfSSL_Type;
|
||||
@ -478,11 +440,7 @@ package body WolfSSL is
|
||||
begin
|
||||
Result := Use_Certificate_Buffer (Ssl, Input,
|
||||
Input'Length, int (Format));
|
||||
if Result = WOLFSSL_SUCCESS then
|
||||
return Success;
|
||||
else
|
||||
return Failure;
|
||||
end if;
|
||||
return Subprogram_Result (Result);
|
||||
end Use_Certificate_Buffer;
|
||||
|
||||
function Use_Private_Key_File (Ssl : WolfSSL_Type;
|
||||
@ -506,11 +464,7 @@ package body WolfSSL is
|
||||
Count => C,
|
||||
Append_Nul => True);
|
||||
Result := Use_Private_Key_File (Ssl, F (1 .. C), int (Format));
|
||||
if Result = WOLFSSL_SUCCESS then
|
||||
return Success;
|
||||
else
|
||||
return Failure;
|
||||
end if;
|
||||
return Subprogram_Result (Result);
|
||||
end Use_Private_Key_File;
|
||||
|
||||
function Use_Private_Key_Buffer (Ssl : WolfSSL_Type;
|
||||
@ -530,11 +484,7 @@ package body WolfSSL is
|
||||
begin
|
||||
Result := Use_Private_Key_Buffer (Ssl, Input,
|
||||
Input'Length, int (Format));
|
||||
if Result = WOLFSSL_SUCCESS then
|
||||
return Success;
|
||||
else
|
||||
return Failure;
|
||||
end if;
|
||||
return Subprogram_Result (Result);
|
||||
end Use_Private_Key_Buffer;
|
||||
|
||||
function WolfSSL_Set_Fd (Ssl : WolfSSL_Type; Fd : int) return int with
|
||||
@ -547,11 +497,7 @@ package body WolfSSL is
|
||||
return Subprogram_Result is
|
||||
Result : int := WolfSSL_Set_Fd (Ssl, int (Socket));
|
||||
begin
|
||||
if Result = WOLFSSL_SUCCESS then
|
||||
return Success;
|
||||
else
|
||||
return Failure;
|
||||
end if;
|
||||
return Subprogram_Result (Result);
|
||||
end Attach;
|
||||
|
||||
procedure WolfSSL_Keep_Arrays (Ssl : WolfSSL_Type) with
|
||||
@ -573,11 +519,7 @@ package body WolfSSL is
|
||||
return Subprogram_Result is
|
||||
Result : int := WolfSSL_Accept (Ssl);
|
||||
begin
|
||||
if Result = WOLFSSL_SUCCESS then
|
||||
return Success;
|
||||
else
|
||||
return Failure;
|
||||
end if;
|
||||
return Subprogram_Result (Result);
|
||||
end Accept_Connection;
|
||||
|
||||
procedure WolfSSL_Free_Arrays (Ssl : WolfSSL_Type) with
|
||||
@ -631,12 +573,14 @@ package body WolfSSL is
|
||||
Size : int;
|
||||
begin
|
||||
Size := WolfSSL_Read (Ssl, Data, int (Byte_Index'Last));
|
||||
if Size < 0 then
|
||||
return (Result => Failure, Last => 0);
|
||||
if Size <= 0 then
|
||||
return (Success => False,
|
||||
Last => 0,
|
||||
Code => Subprogram_Result (Size));
|
||||
else
|
||||
return (Result => Success,
|
||||
Last => Byte_Index (Size),
|
||||
Buffer => Data (1 .. Byte_Index (Size)));
|
||||
return (Success => True,
|
||||
Last => Byte_Index (Size),
|
||||
Buffer => Data (1 .. Byte_Index (Size)));
|
||||
end if;
|
||||
end Read;
|
||||
|
||||
@ -648,83 +592,39 @@ package body WolfSSL is
|
||||
Import => True;
|
||||
|
||||
function Write (Ssl : WolfSSL_Type;
|
||||
Data : Byte_Array) return Integer is
|
||||
Data : Byte_Array) return Write_Result is
|
||||
Size : constant int := Data'Length;
|
||||
Result : int;
|
||||
begin
|
||||
Result := WolfSSL_Write (Ssl, Data, Size);
|
||||
return Integer (Result);
|
||||
if Result > 0 then
|
||||
return (Success => True,
|
||||
Bytes_Written => Byte_Index (Result));
|
||||
else
|
||||
return (Success => False, Code => Subprogram_Result (Result));
|
||||
end if;
|
||||
end Write;
|
||||
|
||||
function WolfSSL_Shutdown (Ssl : WolfSSL_Type) return int with
|
||||
Convention => C,
|
||||
External_Name => "wolfSSL_shutdown",
|
||||
Import => True;
|
||||
-- This function shuts down an active SSL/TLS connection using
|
||||
-- the SSL session, ssl. This function will try to send a
|
||||
-- "close notify" alert to the peer. The calling application can
|
||||
-- choose to wait for the peer to send its "close notify" alert
|
||||
-- in response or just go ahead and shut down the underlying
|
||||
-- connection after directly calling wolfSSL_shutdown (to save
|
||||
-- resources). Either option is allowed by the TLS specification.
|
||||
-- If the underlying connection will be used again in the future,
|
||||
-- the complete two_directional shutdown procedure must be performed
|
||||
-- to keep synchronization intact between the peers.
|
||||
-- wolfSSL_shutdown() works with both blocking and non_blocking I/O.
|
||||
-- When the underlying I/O is non_blocking, wolfSSL_shutdown() will
|
||||
-- return an error if the underlying I/O could not satisfy the needs
|
||||
-- of wolfSSL_shutdown() to continue. In this case, a call to
|
||||
-- wolfSSL_get_error() will yield either SSL_ERROR_WANT_READ or
|
||||
-- SSL_ERROR_WANT_WRITE. The calling process must then repeat
|
||||
-- the call to wolfSSL_shutdown() when the underlying I/O is ready.
|
||||
|
||||
function Shutdown (Ssl : WolfSSL_Type) return Subprogram_Result is
|
||||
Result : constant int := WolfSSL_Shutdown (Ssl);
|
||||
begin
|
||||
if Result = WOLFSSL_SUCCESS then
|
||||
return Success;
|
||||
else
|
||||
return Failure;
|
||||
end if;
|
||||
return Subprogram_Result (Result);
|
||||
end Shutdown;
|
||||
|
||||
function WolfSSL_Connect (Ssl : WolfSSL_Type) return int with
|
||||
Convention => C,
|
||||
External_Name => "wolfSSL_connect",
|
||||
Import => True;
|
||||
-- This function is called on the client side and initiates
|
||||
-- an SSL/TLS handshake with a server. When this function is called,
|
||||
-- the underlying communication channel has already been set up.
|
||||
-- wolfSSL_connect() works with both blocking and non_blocking I/O.
|
||||
-- When the underlying I/O is non_blocking, wolfSSL_connect() will
|
||||
-- return when the underlying I/O could not satisfy the needs
|
||||
-- of wolfSSL_connect to continue the handshake. In this case,
|
||||
-- a call to wolfSSL_get_error() will yield either
|
||||
-- SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE. The calling process
|
||||
-- must then repeat the call to wolfSSL_connect() when
|
||||
-- the underlying I/O is ready and wolfSSL will pick up where
|
||||
-- it left off. When using a non_blocking socket, nothing needs
|
||||
-- to be done, but select() can be used to check for the required
|
||||
-- condition. If the underlying I/O is blocking, wolfSSL_connect()
|
||||
-- will only return once the handshake has been finished or an error
|
||||
-- occurred. wolfSSL takes a different approach to certificate
|
||||
-- verification than OpenSSL does. The default policy for the client
|
||||
-- is to verify the server, this means that if you don't load CAs
|
||||
-- to verify the server you'll get a connect error,
|
||||
-- unable to verify (_155). It you want to mimic OpenSSL behavior
|
||||
-- of having SSL_connect succeed even if verifying the server fails
|
||||
-- and reducing security you can do this by calling:
|
||||
-- SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, 0); before calling
|
||||
-- SSL_new(); Though it's not recommended.
|
||||
|
||||
function Connect (Ssl : WolfSSL_Type) return Subprogram_Result is
|
||||
Result : constant int := WolfSSL_Connect (Ssl);
|
||||
begin
|
||||
if Result = WOLFSSL_SUCCESS then
|
||||
return Success;
|
||||
else
|
||||
return Failure;
|
||||
end if;
|
||||
return Subprogram_Result (Result);
|
||||
end Connect;
|
||||
|
||||
procedure WolfSSL_Free (Ssl : WolfSSL_Type) with
|
||||
@ -740,4 +640,49 @@ package body WolfSSL is
|
||||
Ssl := null;
|
||||
end Free;
|
||||
|
||||
function WolfSSL_Get_Error (Ssl : WolfSSL_Type;
|
||||
Ret : int) return int with
|
||||
Convention => C,
|
||||
External_Name => "wolfSSL_get_error",
|
||||
Import => True;
|
||||
|
||||
function Get_Error (Ssl : WolfSSL_Type;
|
||||
Result : Subprogram_Result) return Error_Code is
|
||||
begin
|
||||
return Error_Code (WolfSSL_Get_Error (Ssl, int (Result)));
|
||||
end Get_Error;
|
||||
|
||||
procedure WolfSSL_Error_String (Error : unsigned_long;
|
||||
Data : out Byte_Array;
|
||||
Size : unsigned_long) with
|
||||
Convention => C,
|
||||
External_Name => "wolfSSL_ERR_error_string_n",
|
||||
Import => True;
|
||||
|
||||
function Error (Code : Error_Code) return Error_Message is
|
||||
S : String (1 .. Error_Message_Index'Last);
|
||||
B : Byte_Array (1 .. size_t (Error_Message_Index'Last));
|
||||
C : Natural;
|
||||
begin
|
||||
WolfSSL_Error_String (Error => unsigned_long (Code),
|
||||
Data => B,
|
||||
Size => unsigned_long (B'Last));
|
||||
Interfaces.C.To_Ada (Item => B,
|
||||
Target => S,
|
||||
Count => C,
|
||||
Trim_Nul => True);
|
||||
return (Last => C,
|
||||
Text => S (1 .. C));
|
||||
end Error;
|
||||
|
||||
function Get_WolfSSL_Max_Error_Size return int with
|
||||
Convention => C,
|
||||
External_Name => "get_wolfssl_max_error_size",
|
||||
Import => True;
|
||||
|
||||
function Max_Error_Size return Natural is
|
||||
begin
|
||||
return Natural (Get_WolfSSL_Max_Error_Size);
|
||||
end Max_Error_Size;
|
||||
|
||||
end WolfSSL;
|
||||
|
@ -25,13 +25,18 @@ with Interfaces.C;
|
||||
-- the API of this package is used correctly.
|
||||
package WolfSSL with SPARK_Mode is
|
||||
|
||||
type Subprogram_Result is (Success, Failure);
|
||||
type Subprogram_Result is new Integer;
|
||||
Success : constant Subprogram_Result;
|
||||
Failure : constant Subprogram_Result;
|
||||
|
||||
function Initialize return Subprogram_Result;
|
||||
-- Must be called before usage of the WolfSSL library.
|
||||
-- Initializes the wolfSSL library for use. Must be called once per
|
||||
-- application and before any other call to the library.
|
||||
|
||||
function Finalize return Subprogram_Result;
|
||||
-- Must be called before application exit to cleanup resources.
|
||||
-- Un-initializes the wolfSSL library from further use.
|
||||
-- Doesn't have to be called, though it will free any resources
|
||||
-- used by the library.
|
||||
|
||||
subtype char_array is Interfaces.C.char_array; -- Remove?
|
||||
|
||||
@ -40,45 +45,86 @@ package WolfSSL with SPARK_Mode is
|
||||
subtype Byte_Array is Interfaces.C.char_array;
|
||||
|
||||
type Context_Type is limited private;
|
||||
-- Instances of this type are called SSL Contexts.
|
||||
|
||||
function Is_Valid (Context : Context_Type) return Boolean;
|
||||
-- Indicates if the SSL Context has successfully been initialized.
|
||||
-- If initialized, the SSL Context has allocated resources
|
||||
-- that needs to be deallocated before application exit.
|
||||
|
||||
type Method_Type is limited private;
|
||||
|
||||
function TLSv1_2_Server_Method return Method_Type;
|
||||
-- This function is used to indicate that the application is a server
|
||||
-- and will only support the TLS 1.2 protocol.
|
||||
|
||||
function TLSv1_2_Client_Method return Method_Type;
|
||||
-- This function is used to indicate that the application is a client
|
||||
-- and will only support the TLS 1.2 protocol.
|
||||
|
||||
function TLSv1_3_Server_Method return Method_Type;
|
||||
-- This function is used to indicate that the application is a server
|
||||
-- and will only support the TLS 1.3 protocol.
|
||||
|
||||
function TLSv1_3_Client_Method return Method_Type;
|
||||
-- This function is used to indicate that the application is a client
|
||||
-- and will only support the TLS 1.3 protocol.
|
||||
|
||||
procedure Create_Context (Method : Method_Type;
|
||||
Context : out Context_Type);
|
||||
-- Create and initialize a WolfSSL context.
|
||||
-- This function creates a new SSL context, taking a desired SSL/TLS
|
||||
-- protocol method for input.
|
||||
-- If successful Is_Valid (Context) = True, otherwise False.
|
||||
|
||||
procedure Free (Context : in out Context_Type) with
|
||||
Pre => Is_Valid (Context),
|
||||
Post => not Is_Valid (Context);
|
||||
-- This function frees an allocated SSL Context object.
|
||||
|
||||
type Mode_Type is private;
|
||||
|
||||
function "&" (Left, Right : Mode_Type) return Mode_Type;
|
||||
|
||||
Verify_None : constant Mode_Type;
|
||||
-- Client mode: the client will not verify the certificate received
|
||||
-- from the server and the handshake will continue as normal.
|
||||
--
|
||||
-- Server mode: the server will not send a certificate request to
|
||||
-- the client. As such, client verification will not be enabled.
|
||||
|
||||
Verify_Peer : constant Mode_Type;
|
||||
-- Client mode: the client will verify the certificate received from
|
||||
-- the server during the handshake. This is turned on by default
|
||||
-- in wolfSSL, therefore, using this option has no effect.
|
||||
--
|
||||
-- Server mode: the server will send a certificate request to
|
||||
-- the client and verify the client certificate received.
|
||||
|
||||
Verify_Fail_If_No_Peer_Cert : constant Mode_Type;
|
||||
-- Client mode: no effect when used on the client side.
|
||||
--
|
||||
-- Server mode: the verification will fail on the server side if
|
||||
-- the client fails to send a certificate when requested to do so
|
||||
-- (when using Verify_Peer on the SSL server).
|
||||
|
||||
Verify_Client_Once : constant Mode_Type;
|
||||
|
||||
Verify_Post_Handshake : constant Mode_Type;
|
||||
|
||||
Verify_Fail_Except_Psk : constant Mode_Type;
|
||||
-- Client mode: no effect when used on the client side.
|
||||
--
|
||||
-- Server mode: the verification is the same as
|
||||
-- Verify_Fail_If_No_Peer_Cert except in the case of a PSK connection.
|
||||
-- If a PSK connection is being made then the connection
|
||||
-- will go through without a peer cert.
|
||||
|
||||
Verify_Default : constant Mode_Type;
|
||||
|
||||
procedure Set_Verify (Context : Context_Type;
|
||||
Mode : Mode_Type) with
|
||||
Pre => Is_Valid (Context);
|
||||
-- This function sets the verification method for remote peers
|
||||
|
||||
type File_Format is private;
|
||||
|
||||
@ -91,115 +137,334 @@ package WolfSSL with SPARK_Mode is
|
||||
Format : File_Format)
|
||||
return Subprogram_Result with
|
||||
Pre => Is_Valid (Context);
|
||||
-- This function loads a certificate file into the SSL context.
|
||||
-- The file is provided by the file argument. The format argument
|
||||
-- specifies the format type of the file, either ASN1 or
|
||||
-- PEM file types. Please see the examples for proper usage.
|
||||
|
||||
function Use_Certificate_Buffer (Context : Context_Type;
|
||||
Input : char_array;
|
||||
Format : File_Format)
|
||||
return Subprogram_Result with
|
||||
Pre => Is_Valid (Context);
|
||||
-- This function loads a certificate buffer into the SSL Context.
|
||||
-- It behaves like the non-buffered version (Use_Certificate_File),
|
||||
-- only differing in its ability to be called with a buffer as input
|
||||
-- instead of a file. The buffer is provided by the Input argument.
|
||||
-- Format specifies the format type of the buffer; ASN1 or PEM.
|
||||
-- Please see the examples for proper usage.
|
||||
|
||||
function Use_Private_Key_File (Context : Context_Type;
|
||||
File : String;
|
||||
Format : File_Format)
|
||||
return Subprogram_Result with
|
||||
Pre => Is_Valid (Context);
|
||||
-- This function loads a private key file into the SSL context.
|
||||
-- The file is provided by the File argument. The Format argument
|
||||
-- specifies the format type of the file - ASN1 or PEM.
|
||||
-- Please see the examples for proper usage.
|
||||
|
||||
function Use_Private_Key_Buffer (Context : Context_Type;
|
||||
Input : Byte_Array;
|
||||
Format : File_Format)
|
||||
return Subprogram_Result with
|
||||
Pre => Is_Valid (Context);
|
||||
-- This function loads a private key buffer into the SSL Context.
|
||||
-- It behaves like the non-buffered version (Use_Private_Key_File),
|
||||
-- only differing in its ability to be called with a buffer as input
|
||||
-- instead of a file. The buffer is provided by the Input argument.
|
||||
-- Format specifies the format type of the buffer; ASN1 or PEM.
|
||||
-- Please see the examples for proper usage.
|
||||
|
||||
function Load_Verify_Locations (Context : Context_Type;
|
||||
File : String;
|
||||
Path : String)
|
||||
return Subprogram_Result with
|
||||
Pre => Is_Valid (Context);
|
||||
-- This function loads PEM-formatted CA certificate files into
|
||||
-- the SSL context. These certificates will be treated as trusted
|
||||
-- root certificates and used to verify certs received from peers
|
||||
-- during the SSL handshake. The root certificate file,
|
||||
-- provided by the File argument, may be a single certificate or
|
||||
-- a file containing multiple certificates. If multiple CA certs
|
||||
-- are included in the same file, wolfSSL will load them in the same
|
||||
-- order they are presented in the file. The path argument is
|
||||
-- a pointer to the name of a directory that contains certificates
|
||||
-- of trusted root CAs. If the value of File is not empty "",
|
||||
-- path may be specified as "" if not needed. If path is specified
|
||||
-- and NO_WOLFSSL_DIR was not defined when building the library,
|
||||
-- wolfSSL will load all CA certificates located in the given
|
||||
-- directory. This function will attempt to load all files in
|
||||
-- the directory. This function expects PEM formatted CERT_TYPE file
|
||||
-- with header "--BEGIN CERTIFICATE--".
|
||||
|
||||
function Load_Verify_Buffer (Context : Context_Type;
|
||||
Input : Byte_Array;
|
||||
Format : File_Format)
|
||||
return Subprogram_Result with
|
||||
Pre => Is_Valid (Context);
|
||||
-- This function loads a CA certificate buffer into the SSL
|
||||
-- Context. It behaves like the non-buffered version, only differing
|
||||
-- in its ability to be called with a buffer as input instead of
|
||||
-- a file. The buffer is provided by the Input argument.
|
||||
-- Format specifies the format type of the buffer; ASN1 or PEM.
|
||||
-- More than one CA certificate may be loaded
|
||||
-- per buffer as long as the format is in PEM.
|
||||
-- Please see the examples for proper usage.
|
||||
|
||||
type WolfSSL_Type is limited private;
|
||||
-- Instances of this type are called SSL Sessions.
|
||||
|
||||
function Is_Valid (Ssl : WolfSSL_Type) return Boolean;
|
||||
-- Indicates if the SSL Session has successfully been initialized.
|
||||
-- If initialized, the SSL Session has allocated resources
|
||||
-- that needs to be deallocated before application exit.
|
||||
|
||||
procedure Create_WolfSSL (Context : Context_Type;
|
||||
Ssl : out WolfSSL_Type) with
|
||||
Pre => Is_Valid (Context);
|
||||
|
||||
-- This function creates a new SSL session, taking an already created
|
||||
-- SSL context as input.
|
||||
-- If successful Is_Valid (Ssl) = True, otherwise False.
|
||||
|
||||
function Use_Certificate_File (Ssl : WolfSSL_Type;
|
||||
File : String;
|
||||
Format : File_Format)
|
||||
return Subprogram_Result with
|
||||
Pre => Is_Valid (Ssl);
|
||||
-- This function loads a certificate file into the SSL session.
|
||||
-- The certificate file is provided by the file argument.
|
||||
-- The format argument specifies the format type of the file
|
||||
-- either ASN1 or PEM.
|
||||
|
||||
function Use_Certificate_Buffer (Ssl : WolfSSL_Type;
|
||||
Input : char_array;
|
||||
Format : File_Format)
|
||||
return Subprogram_Result with
|
||||
Pre => Is_Valid (Ssl);
|
||||
-- This function loads a certificate buffer into the SSL session
|
||||
-- object. It behaves like the non-buffered version, only differing
|
||||
-- in its ability to be called with a buffer as input instead
|
||||
-- of a file. The buffer is provided by the Input argument.
|
||||
-- Format specifies the format type of the buffer; ASN1 or PEM.
|
||||
-- Please see the examples for proper usage.
|
||||
|
||||
function Use_Private_Key_File (Ssl : WolfSSL_Type;
|
||||
File : String;
|
||||
Format : File_Format)
|
||||
return Subprogram_Result with
|
||||
Pre => Is_Valid (Ssl);
|
||||
-- This function loads a private key file into the SSL session.
|
||||
-- The key file is provided by the File argument. The Format argument
|
||||
-- specifies the format type of the file - ASN1 or PEM.
|
||||
|
||||
function Use_Private_Key_Buffer (Ssl : WolfSSL_Type;
|
||||
Input : Byte_Array;
|
||||
Format : File_Format)
|
||||
return Subprogram_Result with
|
||||
Pre => Is_Valid (Ssl);
|
||||
-- This function loads a private key buffer into the SSL session
|
||||
-- object. It behaves like the non-buffered version, only differing
|
||||
-- in its ability to be called with a buffer as input instead
|
||||
-- of a file. The buffer is provided by the Input argument.
|
||||
-- Format specifies the format type of the buffer; ASN1 or PEM.
|
||||
-- Please see the examples for proper usage.
|
||||
|
||||
-- Attach wolfSSL to the socket.
|
||||
function Attach (Ssl : WolfSSL_Type;
|
||||
Socket : Integer)
|
||||
return Subprogram_Result with
|
||||
Pre => Is_Valid (Ssl);
|
||||
-- Attach wolfSSL to the socket.
|
||||
--
|
||||
-- This function assigns a file descriptor (Socket) as
|
||||
-- the input/output facility for the SSL connection.
|
||||
-- Typically this will be a socket file descriptor.
|
||||
|
||||
procedure Keep_Arrays (Ssl : WolfSSL_Type) with
|
||||
Pre => Is_Valid (Ssl);
|
||||
-- Don't free temporary arrays at end of handshake.
|
||||
-- Normally, at the end of the SSL handshake, wolfSSL frees
|
||||
-- temporary arrays. Calling this function before the handshake
|
||||
-- begins will prevent wolfSSL from freeing temporary arrays.
|
||||
-- Temporary arrays may be needed for things such as
|
||||
-- wolfSSL_get_keys() or PSK hints. When the user is done with
|
||||
-- temporary arrays, either Free_Arrays(..) may be called to free
|
||||
-- the resources immediately, or alternatively the resources will
|
||||
-- be freed when the associated SSL object is freed.
|
||||
|
||||
procedure Free_Arrays (Ssl : WolfSSL_Type) with
|
||||
Pre => Is_Valid (Ssl);
|
||||
-- User doesn't need temporary arrays anymore, Free.
|
||||
-- Normally, at the end of the SSL handshake, wolfSSL frees temporary
|
||||
-- arrays. If Keep_Arrays(..) has been called before the handshake,
|
||||
-- wolfSSL will not free temporary arrays. This function explicitly
|
||||
-- frees temporary arrays and should be called when the user is done
|
||||
-- with temporary arrays and does not want to wait for the SSL object
|
||||
-- to be freed to free these resources.
|
||||
|
||||
function Accept_Connection (Ssl : WolfSSL_Type)
|
||||
return Subprogram_Result with
|
||||
Pre => Is_Valid (Ssl);
|
||||
-- The name of this function is not Accept (..) because the word
|
||||
-- "accept" is a reserved keyword in the Ada language.
|
||||
--
|
||||
-- This function is called on the server side and waits for an
|
||||
-- SSL client to initiate the SSL/TLS handshake. When this function
|
||||
-- is called, the underlying communication channel has already been
|
||||
-- set up. This function works with both blocking and
|
||||
-- non-blocking I/O. When the underlying I/O is non-blocking,
|
||||
-- Accept_Connection (..) will return when the underlying I/O could
|
||||
-- not satisfy the needs of Accept_Connection (..) to continue
|
||||
-- the handshake. In this case, a call to Get_Error(..) will
|
||||
-- yield either Error_Want_Read or Error_Want_Write.
|
||||
-- The calling process must then repeat the call to
|
||||
-- Accept_Connection (..) when data is available to read and
|
||||
-- wolfSSL will pick up where it left off. When using a
|
||||
-- non_blocking socket, nothing needs to be done, but select() can
|
||||
-- be used to check for the required condition.
|
||||
-- If the underlying I/O is blocking, Accept_Connection (..) will
|
||||
-- only return once the handshake has been finished or
|
||||
-- an error occurred.
|
||||
|
||||
-- This record type has discriminants with default values to be able
|
||||
-- to compile this code under the restriction no secondary stack.
|
||||
type Read_Result (Result : Subprogram_Result := Failure;
|
||||
Last : Byte_Index := Byte_Index'Last) is record
|
||||
case Result is
|
||||
when Success => Buffer : Byte_Array (1 .. Last);
|
||||
when Failure => null;
|
||||
-- to compile this code under the restriction No Secondary Stack.
|
||||
type Read_Result (Success : Boolean := False;
|
||||
Last : Byte_Index := Byte_Index'Last) is record
|
||||
case Success is
|
||||
when True => Buffer : Byte_Array (1 .. Last);
|
||||
when False => Code : Subprogram_Result; -- Error code
|
||||
end case;
|
||||
end record;
|
||||
|
||||
function Read (Ssl : WolfSSL_Type) return Read_Result with
|
||||
Pre => Is_Valid (Ssl);
|
||||
-- This function reads a number of bytes from the SSL session (ssl)
|
||||
-- internal read buffer into the buffer data. The bytes read are
|
||||
-- removed from the internal receive buffer.
|
||||
-- If necessary Read(..) will negotiate an SSL/TLS session
|
||||
-- if the handshake has not already
|
||||
-- been performed yet by Connect(..) or Accept_Connection (..).
|
||||
-- The SSL/TLS protocol uses SSL records which have a maximum size
|
||||
-- of 16kB (the max record size can be controlled by the
|
||||
-- MAX_RECORD_SIZE define in /wolfssl/internal.h). As such, wolfSSL
|
||||
-- needs to read an entire SSL record internally before it is able
|
||||
-- to process and decrypt the record. Because of this, a call to
|
||||
-- Read(..) will only be able to return the maximum buffer
|
||||
-- size which has been decrypted at the time of calling. There may
|
||||
-- be additional not-yet-decrypted data waiting in the internal
|
||||
-- wolfSSL receive buffer which will be retrieved and decrypted with
|
||||
-- the next call to Read(..).
|
||||
|
||||
-- This record type has discriminants with default values to be able
|
||||
-- to compile this code under the restriction No Secondary Stack.
|
||||
type Write_Result (Success : Boolean := False) is record
|
||||
case Success is
|
||||
when True => Bytes_Written : Byte_Index;
|
||||
when False => Code : Subprogram_Result; -- Error code
|
||||
end case;
|
||||
end record;
|
||||
|
||||
-- The number of bytes written is returned.
|
||||
function Write (Ssl : WolfSSL_Type;
|
||||
Data : Byte_Array) return Integer with
|
||||
Data : Byte_Array) return Write_Result with
|
||||
Pre => Is_Valid (Ssl);
|
||||
-- The number of bytes written is returned.
|
||||
-- This function writes bytes from the buffer, Data,
|
||||
-- to the SSL connection, ssl. If necessary, Write(..) will
|
||||
-- negotiate an SSL/TLS session if the handshake has not already
|
||||
-- been performed yet by Connect(..) or Accept_Connection(..).
|
||||
-- Write(..) works with both blocking and non-blocking I/O.
|
||||
-- When the underlying I/O is non-blocking, Write(..) will return
|
||||
-- when the underlying I/O could not satisfy the needs of Write(..)
|
||||
-- to continue. In this case, a call to Get_Error(..) will
|
||||
-- yield either Error_Want_Read or Error_Want_Write.
|
||||
-- The calling process must then repeat the call to Write(..)
|
||||
-- when the underlying I/O is ready. If the underlying I/O is
|
||||
-- blocking, Write(..) will only return once the buffer data
|
||||
-- has been completely written or an error occurred.
|
||||
|
||||
function Shutdown (Ssl : WolfSSL_Type) return Subprogram_Result with
|
||||
Pre => Is_Valid (Ssl);
|
||||
-- This function shuts down an active SSL/TLS connection using
|
||||
-- the SSL session, ssl. This function will try to send a
|
||||
-- "close notify" alert to the peer. The calling application can
|
||||
-- choose to wait for the peer to send its "close notify" alert
|
||||
-- in response or just go ahead and shut down the underlying
|
||||
-- connection after directly calling wolfSSL_shutdown (to save
|
||||
-- resources). Either option is allowed by the TLS specification.
|
||||
-- If the underlying connection will be used again in the future,
|
||||
-- the complete two_directional shutdown procedure must be performed
|
||||
-- to keep synchronization intact between the peers.
|
||||
-- Shutdown(..) works with both blocking and non_blocking I/O.
|
||||
-- When the underlying I/O is non_blocking, Shutdown(..) will
|
||||
-- return an error if the underlying I/O could not satisfy the needs
|
||||
-- of Shutdown(..) to continue. In this case, a call to
|
||||
-- Get_Error(..) will yield either Error_Want_Read or
|
||||
-- Error_Want_Write. The calling process must then repeat
|
||||
-- the call to Shutdown() when the underlying I/O is ready.
|
||||
|
||||
procedure Free (Ssl : in out WolfSSL_Type) with
|
||||
Pre => Is_Valid (Ssl),
|
||||
Post => not Is_Valid (Ssl);
|
||||
-- Frees the resources allocated by the SSL session object.
|
||||
|
||||
function Connect (Ssl : WolfSSL_Type) return Subprogram_Result with
|
||||
Pre => Is_Valid (Ssl);
|
||||
-- This function is called on the client side and initiates
|
||||
-- an SSL/TLS handshake with a server. When this function is called,
|
||||
-- the underlying communication channel has already been set up.
|
||||
-- Connect(..) works with both blocking and non_blocking I/O.
|
||||
-- When the underlying I/O is non_blocking, Connect(..) will
|
||||
-- return when the underlying I/O could not satisfy the needs
|
||||
-- of wolfSSL_connect to continue the handshake. In this case,
|
||||
-- a call to Get_Error(..) will yield either
|
||||
-- Error_Want_Read or SSL_ERROR_WANT_WRITE. The calling process
|
||||
-- must then repeat the call to Connect(..) when
|
||||
-- the underlying I/O is ready and wolfSSL will pick up where
|
||||
-- it left off. When using a non_blocking socket, nothing needs
|
||||
-- to be done, but select() can be used to check for the required
|
||||
-- condition. If the underlying I/O is blocking, Connect(..)
|
||||
-- will only return once the handshake has been finished or an error
|
||||
-- occurred. wolfSSL takes a different approach to certificate
|
||||
-- verification than OpenSSL does. The default policy for the client
|
||||
-- is to verify the server, this means that if you don't load CAs
|
||||
-- to verify the server you'll get a connect error,
|
||||
-- unable to verify. It you want to mimic OpenSSL behavior
|
||||
-- of having SSL_connect succeed even if verifying the server fails
|
||||
-- and reducing security you can do this by calling:
|
||||
-- Set_Verify (Ctx, Verify_None, 0); before calling
|
||||
-- Create_WolfSSL(...); Though it's not recommended.
|
||||
|
||||
type Error_Code is new Integer;
|
||||
|
||||
Error_Want_Read : constant Error_Code;
|
||||
Error_Want_Write : constant Error_Code;
|
||||
|
||||
function Get_Error (Ssl : WolfSSL_Type;
|
||||
Result : Subprogram_Result) return Error_Code;
|
||||
-- This function returns a unique error code describing why
|
||||
-- the previous API function call (Connect, Accept_Connection,
|
||||
-- Read, Write, etc.) resulted in an error return code.
|
||||
-- After Get_Error is called and returns the unique error code,
|
||||
-- wolfSSL_ERR_error_string() may be called to get a human readable
|
||||
-- error string.
|
||||
|
||||
subtype Error_Message_Index is Natural range 0 .. 80;
|
||||
-- The default error message length is 80 in WolfSSL unless
|
||||
-- configured to another value. See the result
|
||||
-- of the Max_Error_Size function.
|
||||
|
||||
type Error_Message (Last : Error_Message_Index := 0) is record
|
||||
Text : String (1 .. Last);
|
||||
end record;
|
||||
|
||||
function Error (Code : Error_Code) return Error_Message;
|
||||
-- This function converts an error code returned by Get_Error(..)
|
||||
-- into a more human readable error string. Code is the error code
|
||||
-- returned by Get_error(). The maximum length of error strings is
|
||||
-- 80 characters by default, as defined by MAX_ERROR_SZ
|
||||
-- is wolfssl/wolfcrypt/error.h.
|
||||
|
||||
function Max_Error_Size return Natural;
|
||||
-- Returns the value of the defined MAX_ERROR_SZ integer
|
||||
-- in wolfssl/wolfcrypt/error.h.
|
||||
|
||||
private
|
||||
pragma SPARK_Mode (Off);
|
||||
@ -306,4 +571,36 @@ private
|
||||
Format_Default : constant File_Format :=
|
||||
File_Format (WolfSSL_Filetype_Default);
|
||||
|
||||
function Get_WolfSSL_Success return int with
|
||||
Convention => C,
|
||||
External_Name => "get_wolfssl_success",
|
||||
Import => True;
|
||||
|
||||
function Get_WolfSSL_Failure return int with
|
||||
Convention => C,
|
||||
External_Name => "get_wolfssl_failure",
|
||||
Import => True;
|
||||
|
||||
Success : constant Subprogram_Result :=
|
||||
Subprogram_Result (Get_WolfSSL_Success);
|
||||
|
||||
Failure : constant Subprogram_Result :=
|
||||
Subprogram_Result (Get_WolfSSL_Failure);
|
||||
|
||||
function Get_WolfSSL_Error_Want_Read return int with
|
||||
Convention => C,
|
||||
External_Name => "get_wolfssl_error_want_read",
|
||||
Import => True;
|
||||
|
||||
function Get_WolfSSL_Error_Want_Write return int with
|
||||
Convention => C,
|
||||
External_Name => "get_wolfssl_error_want_write",
|
||||
Import => True;
|
||||
|
||||
Error_Want_Read : constant Error_Code :=
|
||||
Error_Code (Get_WolfSSL_Error_Want_Read);
|
||||
|
||||
Error_Want_Write : constant Error_Code :=
|
||||
Error_Code (Get_WolfSSL_Error_Want_Write);
|
||||
|
||||
end WolfSSL;
|
||||
|
Loading…
x
Reference in New Issue
Block a user