From 2050cc25c12dd2004dbbe52fa46b519fc3ccef66 Mon Sep 17 00:00:00 2001 From: Masaki Iwai Date: Sat, 26 Jul 2025 16:06:55 +0900 Subject: [PATCH] add C# examples using ML-KEM/ML-DSA --- CSharp/README.md | 47 +++ CSharp/wolfSSL-TLS-pq-Client/App.config | 6 + .../Properties/AssemblyInfo.cs | 36 +++ .../wolfSSL-TLS-Client.cs | 272 +++++++++++++++++ .../wolfSSL-TLS-Client.csproj | 124 ++++++++ CSharp/wolfSSL-TLS-pq-Server/App.config | 6 + .../Properties/AssemblyInfo.cs | 36 +++ .../wolfSSL-TLS-Server.cs | 289 ++++++++++++++++++ .../wolfSSL-TLS-Server.csproj | 124 ++++++++ .../wolfSSL-TLS-pq-ServerThreaded/App.config | 6 + .../Properties/AssemblyInfo.cs | 36 +++ .../wolfSSL-TLS-ServerThreaded.cs | 205 +++++++++++++ .../wolfSSL-TLS-ServerThreaded.csproj | 124 ++++++++ README.md | 9 + 14 files changed, 1320 insertions(+) create mode 100644 CSharp/README.md create mode 100644 CSharp/wolfSSL-TLS-pq-Client/App.config create mode 100644 CSharp/wolfSSL-TLS-pq-Client/Properties/AssemblyInfo.cs create mode 100644 CSharp/wolfSSL-TLS-pq-Client/wolfSSL-TLS-Client.cs create mode 100644 CSharp/wolfSSL-TLS-pq-Client/wolfSSL-TLS-Client.csproj create mode 100644 CSharp/wolfSSL-TLS-pq-Server/App.config create mode 100644 CSharp/wolfSSL-TLS-pq-Server/Properties/AssemblyInfo.cs create mode 100644 CSharp/wolfSSL-TLS-pq-Server/wolfSSL-TLS-Server.cs create mode 100644 CSharp/wolfSSL-TLS-pq-Server/wolfSSL-TLS-Server.csproj create mode 100644 CSharp/wolfSSL-TLS-pq-ServerThreaded/App.config create mode 100644 CSharp/wolfSSL-TLS-pq-ServerThreaded/Properties/AssemblyInfo.cs create mode 100644 CSharp/wolfSSL-TLS-pq-ServerThreaded/wolfSSL-TLS-ServerThreaded.cs create mode 100644 CSharp/wolfSSL-TLS-pq-ServerThreaded/wolfSSL-TLS-ServerThreaded.csproj diff --git a/CSharp/README.md b/CSharp/README.md new file mode 100644 index 000000000..829c4b7dd --- /dev/null +++ b/CSharp/README.md @@ -0,0 +1,47 @@ +# C# Wrapper Examples + +This directory contains examples that demonstrate using the C# wrapper. + +These assume the use of `wolfssl\wrapper\CSharp\wolfSSL_CSharp.sln`. + +## wolfSSL-TLS-pq + +wolfSSL Server and Client using PQC algorithms (ML-KEM / ML-DSA). + +### Build Options + +The following build options need to be added. + +#### for `wolfssl` Project + +``` +HAVE_MLKEM +WOLFSSL_WC_MLKEM +WOLFSSL_HAVE_MLKEM +WOLFSSL_DTLS_CH_FRAG +HAVE_DILITHIUM +WOLFSSL_WC_DILITHIUM +WOLFSSL_SHAKE128 +WOLFSSL_SHAKE256 +``` + +#### for `wolfSSL_CSharp` Project + +``` +HAVE_MLKEM +HAVE_MLDSA +``` + +If you want to execute `wolfCrypt-Test` Project as well, add these options to `wolfCrypt-Test` Project. + +### wolfSSL-TLS-pq-Server + +wolfSSL Server using ML-DSA-87. + +### wolfSSL-TLS-pq-ServerThreaded + +Threaded version of `wolfSSL-TLS-pq-Server`. + +### wolfSSL-TLS-pq-Client + +wolfSSL Client using ML-KEM-1024/ML-DSA-87. \ No newline at end of file diff --git a/CSharp/wolfSSL-TLS-pq-Client/App.config b/CSharp/wolfSSL-TLS-pq-Client/App.config new file mode 100644 index 000000000..a86c64659 --- /dev/null +++ b/CSharp/wolfSSL-TLS-pq-Client/App.config @@ -0,0 +1,6 @@ + + + + + + diff --git a/CSharp/wolfSSL-TLS-pq-Client/Properties/AssemblyInfo.cs b/CSharp/wolfSSL-TLS-pq-Client/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..203c30b04 --- /dev/null +++ b/CSharp/wolfSSL-TLS-pq-Client/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("wolfSSL-TLS-Client")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("wolfSSL")] +[assembly: AssemblyProduct("wolfSSL-TLS-Client")] +[assembly: AssemblyCopyright("Copyright wolfSSL 2020")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("05aad2b4-445e-4f0e-8e16-8f8512696505")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.1.0.0")] +[assembly: AssemblyFileVersion("1.1.0.0")] diff --git a/CSharp/wolfSSL-TLS-pq-Client/wolfSSL-TLS-Client.cs b/CSharp/wolfSSL-TLS-pq-Client/wolfSSL-TLS-Client.cs new file mode 100644 index 000000000..788c43e39 --- /dev/null +++ b/CSharp/wolfSSL-TLS-pq-Client/wolfSSL-TLS-Client.cs @@ -0,0 +1,272 @@ +/* wolfSSL-TLS-Client.cs + * + * Copyright (C) 2006-2025 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +using System; +using System.Runtime.InteropServices; +using System.Text; +using System.IO; +using System.Net; +using System.Net.Sockets; +using wolfSSL.CSharp; + +public class wolfSSL_TLS_Client +{ + /// + /// Example of a logging function + /// + /// level of log + /// message to log + public static void standard_log(int lvl, StringBuilder msg) + { + Console.WriteLine(msg); + } + + + private static void clean(IntPtr ssl, IntPtr ctx) + { + wolfssl.free(ssl); + wolfssl.CTX_free(ctx); + wolfssl.Cleanup(); + } + + /// + /// Verification callback + /// + /// 1=Verify Okay, 0=Failure + /// Certificate in WOLFSSL_X509_STORE_CTX format + private static int myVerify(int preverify, IntPtr x509_ctx) + { + int verify = preverify; + Console.WriteLine("myVerify is called."); + + /* example for overriding an error code */ + /* X509_STORE_CTX_get_error API can be enabled with + * OPENSSL_EXTRA_X509_SMALL or WOLFSSL_EXTRA */ + int error = wolfssl.X509_STORE_CTX_get_error(x509_ctx); + if (error == wolfcrypt.ASN_BEFORE_DATE_E) { + verify = 1; /* override error */ + } + + /* Can optionally override failures by returning non-zero value */ + return verify; + } + + /// + /// Checks if the SNI option was enabled via command line. + /// Must be enabled with ./configure --enable-sni when configuring + /// wolfSSL. + /// Parameters passed via command line + /// + private static int haveSNI(string[] args) + { + for (int i = 0; i < args.Length; i++) { + if (args[i] == "-S") { + Console.WriteLine("SNI IS ON"); + return i+1; + } + } + Console.WriteLine("SNI IS OFF"); + return -1; + } + + public static void Main(string[] args) + { + IntPtr ctx; + IntPtr ssl; + Socket tcp; + IntPtr sniHostName; + + /* These paths should be changed for use */ + string caCert = wolfssl.setPath("mldsa87_root_cert.pem"); + StringBuilder dhparam = new StringBuilder(wolfssl.setPath("dh2048.pem")); + + if (caCert == "" || dhparam.Length == 0) { + Console.WriteLine("Platform not supported."); + return; + } + + StringBuilder buff = new StringBuilder(1024); + StringBuilder reply = new StringBuilder("Hello, this is the wolfSSL C# wrapper"); + + //example of function used for setting logging + wolfssl.SetLogging(standard_log); + + wolfssl.Init(); + + Console.WriteLine("Calling ctx Init from wolfSSL"); + ctx = wolfssl.CTX_new(wolfssl.usev23_client()); + if (ctx == IntPtr.Zero) + { + Console.WriteLine("Error in creating ctx structure"); + return; + } + Console.WriteLine("Finished init of ctx .... now load in CA"); + + + if (!File.Exists(caCert)) + { + Console.WriteLine("Could not find CA cert file"); + wolfssl.CTX_free(ctx); + return; + } + + if (!File.Exists(dhparam.ToString())) { + Console.WriteLine("Could not find dh file"); + wolfssl.CTX_free(ctx); + return; + } + + if (wolfssl.CTX_load_verify_locations(ctx, caCert, null) + != wolfssl.SUCCESS) + { + Console.WriteLine("Error loading CA cert"); + wolfssl.CTX_free(ctx); + return; + } + + int sniArg = haveSNI(args); + if (sniArg >= 0) + { + string sniHostNameString = args[sniArg].Trim(); + sniHostName = Marshal.StringToHGlobalAnsi(sniHostNameString); + + ushort size = (ushort)sniHostNameString.Length; + + if (wolfssl.CTX_UseSNI(ctx, (byte)wolfssl.WOLFSSL_SNI_HOST_NAME, sniHostName, size) != wolfssl.SUCCESS) + { + Console.WriteLine("UseSNI failed"); + wolfssl.CTX_free(ctx); + return; + } + } + + StringBuilder ciphers = new StringBuilder(new String(' ', 4096)); + wolfssl.get_ciphers(ciphers, 4096); + Console.WriteLine("Ciphers : " + ciphers.ToString()); + + /* Uncomment Section to enable specific cipher suite */ +#if false + ciphers = new StringBuilder("ECDHE-ECDSA-AES128-GCM-SHA256"); + if (wolfssl.CTX_set_cipher_list(ctx, ciphers) != wolfssl.SUCCESS) + { + Console.WriteLine("ERROR CTX_set_cipher_list()"); + wolfssl.CTX_free(ctx); + return; + } +#endif + + short minDhKey = 128; + wolfssl.CTX_SetMinDhKey_Sz(ctx, minDhKey); + + /* Setup Verify Callback */ + if (wolfssl.CTX_set_verify(ctx, wolfssl.SSL_VERIFY_PEER, myVerify) + != wolfssl.SUCCESS) + { + Console.WriteLine("Error setting verify callback!"); + } + + + /* set up TCP socket */ + tcp = new Socket(AddressFamily.InterNetwork, SocketType.Stream, + ProtocolType.Tcp); + try + { + tcp.Connect("localhost", 11111); + } + catch (Exception e) + { + Console.WriteLine("tcp.Connect() error " + e.ToString()); + wolfssl.CTX_free(ctx); + return; + } + if (!tcp.Connected) + { + Console.WriteLine("tcp.Connect() failed!"); + tcp.Close(); + wolfssl.CTX_free(ctx); + return; + } + + Console.WriteLine("Connected TCP"); + ssl = wolfssl.new_ssl(ctx); + if (ssl == IntPtr.Zero) + { + Console.WriteLine("Error in creating ssl object"); + wolfssl.CTX_free(ctx); + return; + } + + if (wolfssl.UseKeyShare(ssl, wolfssl.NamedGroup.WOLFSSL_ML_KEM_1024) != wolfssl.SUCCESS) + { + Console.WriteLine("Error enabling ML-KEM key share"); + wolfssl.CTX_free(ctx); + return; + } + + Console.WriteLine("Connection made wolfSSL_connect "); + if (wolfssl.set_fd(ssl, tcp) != wolfssl.SUCCESS) + { + /* get and print out the error */ + Console.WriteLine(wolfssl.get_error(ssl)); + tcp.Close(); + clean(ssl, ctx); + return; + } + + wolfssl.SetTmpDH_file(ssl, dhparam, wolfssl.SSL_FILETYPE_PEM); + + if (wolfssl.connect(ssl) != wolfssl.SUCCESS) + { + /* get and print out the error */ + Console.WriteLine(wolfssl.get_error(ssl)); + tcp.Close(); + clean(ssl, ctx); + return; + } + + /* print out results of TLS/SSL accept */ + Console.WriteLine("SSL version is " + wolfssl.get_version(ssl)); + Console.WriteLine("SSL cipher suite is " + wolfssl.get_current_cipher(ssl)); + + + if (wolfssl.write(ssl, reply, reply.Length) != reply.Length) + { + Console.WriteLine("Error in write"); + tcp.Close(); + clean(ssl, ctx); + return; + } + + /* read and print out the message then reply */ + if (wolfssl.read(ssl, buff, 1023) < 0) + { + Console.WriteLine("Error in read"); + tcp.Close(); + clean(ssl, ctx); + return; + } + Console.WriteLine(buff); + + wolfssl.shutdown(ssl); + tcp.Close(); + clean(ssl, ctx); + } +} diff --git a/CSharp/wolfSSL-TLS-pq-Client/wolfSSL-TLS-Client.csproj b/CSharp/wolfSSL-TLS-pq-Client/wolfSSL-TLS-Client.csproj new file mode 100644 index 000000000..a7c8e0a41 --- /dev/null +++ b/CSharp/wolfSSL-TLS-pq-Client/wolfSSL-TLS-Client.csproj @@ -0,0 +1,124 @@ + + + + + Debug + AnyCPU + {B9DF2972-38F6-4B42-B228-E3C1A47DF8E8} + Exe + Properties + wolfSSL_TLS_Client + wolfSSL-TLS-Client + v4.8 + 512 + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + + AnyCPU + true + full + false + $(SolutionDir)$(Configuration)\$(Platform)\ + DEBUG;TRACE + prompt + 3 + + + AnyCPU + pdbonly + true + $(SolutionDir)$(Configuration)\$(Platform)\ + TRACE + prompt + 4 + + + + + + true + $(SolutionDir)$(Configuration)\$(Platform)\ + DEBUG;TRACE + 4 + full + x64 + prompt + MinimumRecommendedRules.ruleset + true + + + $(SolutionDir)$(Configuration)\$(Platform)\x64 + TRACE + true + pdbonly + x64 + prompt + MinimumRecommendedRules.ruleset + true + + + + + + + + + + + + + + + + + + + {52609808-0418-46d3-8e17-141927a1a39a} + wolfSSL_CSharp + + + + + False + Microsoft .NET Framework 4.5 %28x86 and x64%29 + true + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + false + + + + + + + + + diff --git a/CSharp/wolfSSL-TLS-pq-Server/App.config b/CSharp/wolfSSL-TLS-pq-Server/App.config new file mode 100644 index 000000000..a86c64659 --- /dev/null +++ b/CSharp/wolfSSL-TLS-pq-Server/App.config @@ -0,0 +1,6 @@ + + + + + + diff --git a/CSharp/wolfSSL-TLS-pq-Server/Properties/AssemblyInfo.cs b/CSharp/wolfSSL-TLS-pq-Server/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..079a12679 --- /dev/null +++ b/CSharp/wolfSSL-TLS-pq-Server/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("wolfSSL-TLS-Server")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("wolfSSL")] +[assembly: AssemblyProduct("wolfSSL-TLS-Server")] +[assembly: AssemblyCopyright("Copyright wolfSSL 2020")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("716e8f30-1318-4e3b-b788-d0380b397a4c")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.1.0.0")] +[assembly: AssemblyFileVersion("1.1.0.0")] diff --git a/CSharp/wolfSSL-TLS-pq-Server/wolfSSL-TLS-Server.cs b/CSharp/wolfSSL-TLS-pq-Server/wolfSSL-TLS-Server.cs new file mode 100644 index 000000000..08d19d4b4 --- /dev/null +++ b/CSharp/wolfSSL-TLS-pq-Server/wolfSSL-TLS-Server.cs @@ -0,0 +1,289 @@ +/* wolfSSL-TLS-Server.cs + * + * Copyright (C) 2006-2025 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +using System; +using System.Runtime.InteropServices; +using System.Text; +using System.IO; +using System.Net; +using System.Net.Sockets; +using wolfSSL.CSharp; + +public class wolfSSL_TLS_CSHarp +{ + /// + /// Example of a logging function + /// + /// level of log + /// message to log + public static void standard_log(int lvl, StringBuilder msg) + { + Console.WriteLine(msg); + } + + + private static void clean(IntPtr ssl, IntPtr ctx) + { + wolfssl.free(ssl); + wolfssl.CTX_free(ctx); + wolfssl.Cleanup(); + } + + /// + /// Checks if the SNI option was enabled via command line. + /// Must be enabled with ./configure --enable-sni when configuring + /// wolfSSL. + /// Parameters passed via command line + /// + private static bool haveSNI(string[] args) + { + bool sniON = false; + for (int i = 0; i < args.Length; i++) { + if (args[i] == "-S") { + sniON = true; + break; + } + } + Console.WriteLine("SNI IS: " + sniON); + return sniON; + } + + /// + /// Example of a SNI function call back + /// + /// pointer to ssl structure + /// alert code + /// context arg, can be set with the function wolfssl.CTX_set_servername_arg + /// + public static int my_sni_server_cb(IntPtr ssl, IntPtr ret, IntPtr exArg) { + /* Trivial callback just for testing */ + Console.WriteLine("my sni server callback"); + + return 0; + } + + public static void Main(string[] args) + { + IntPtr ctx; + IntPtr ssl; + Socket fd; + IntPtr arg_sni; + + /* These paths should be changed for use */ + string fileCert = wolfssl.setPath("mldsa87_entity_cert.pem"); + string fileKey = wolfssl.setPath("mldsa87_entity_key.pem"); + StringBuilder dhparam = new StringBuilder(wolfssl.setPath("dh2048.pem")); + + if (fileCert == "" || fileKey == "" || dhparam.Length == 0) { + Console.WriteLine("Platform not supported."); + return; + } + + StringBuilder buff = new StringBuilder(1024); + StringBuilder reply = new StringBuilder("Hello, this is the wolfSSL C# wrapper"); + + //example of function used for setting logging + wolfssl.SetLogging(standard_log); + + wolfssl.Init(); + + Console.WriteLine("Calling ctx Init from wolfSSL"); + ctx = wolfssl.CTX_new(wolfssl.usev23_server()); + if (ctx == IntPtr.Zero) + { + Console.WriteLine("Error in creating ctx structure"); + return; + } + Console.WriteLine("Finished init of ctx .... now load in cert and key"); + + if (!File.Exists(fileCert) || !File.Exists(fileKey)) + { + Console.WriteLine("Could not find cert or key file"); + wolfssl.CTX_free(ctx); + return; + } + + if (!File.Exists(dhparam.ToString())) { + Console.WriteLine("Could not find dh file"); + wolfssl.CTX_free(ctx); + return; + } + + if (wolfssl.CTX_use_certificate_file(ctx, fileCert, wolfssl.SSL_FILETYPE_PEM) != wolfssl.SUCCESS) + { + Console.WriteLine("Error in setting cert file"); + wolfssl.CTX_free(ctx); + return; + } + + if (wolfssl.CTX_use_PrivateKey_file(ctx, fileKey, wolfssl.SSL_FILETYPE_PEM) != wolfssl.SUCCESS) + { + Console.WriteLine("Error in setting key file"); + wolfssl.CTX_free(ctx); + return; + } + + StringBuilder ciphers = new StringBuilder(new String(' ', 4096)); + wolfssl.get_ciphers(ciphers, 4096); + Console.WriteLine("Ciphers : " + ciphers.ToString()); + + short minDhKey = 128; + wolfssl.CTX_SetMinDhKey_Sz(ctx, minDhKey); + + /* set up TCP socket */ + IPAddress ip = IPAddress.Parse("0.0.0.0"); /* bind to any */ + TcpListener tcp = new TcpListener(ip, 11111); + tcp.Start(); + + Console.WriteLine("Started TCP and waiting for a connection"); + fd = tcp.AcceptSocket(); + + ssl = wolfssl.new_ssl(ctx); + if (ssl == IntPtr.Zero) + { + Console.WriteLine("Error in creating ssl object"); + wolfssl.CTX_free(ctx); + return; + } + + if (haveSNI(args)) + { + // Allocating memory and setting SNI arg + int test_value = 32; + arg_sni = Marshal.AllocHGlobal(sizeof(int)); + Marshal.WriteInt32(arg_sni, test_value); + if (wolfssl.CTX_set_servername_arg(ctx, arg_sni) == wolfssl.FAILURE) { + Console.WriteLine("wolfssl.CTX_set_servername_arg failed"); + wolfssl.CTX_free(ctx); + return; + } + + // Setting SNI delegate + wolfssl.sni_delegate sni_cb = new wolfssl.sni_delegate(my_sni_server_cb); + wolfssl.CTX_set_servername_callback(ctx, sni_cb); + } + + Console.WriteLine("Connection made wolfSSL_accept "); + if (wolfssl.set_fd(ssl, fd) != wolfssl.SUCCESS) + { + /* get and print out the error */ + Console.WriteLine(wolfssl.get_error(ssl)); + tcp.Stop(); + clean(ssl, ctx); + return; + } + + if (wolfssl.SetTmpDH_file(ssl, dhparam, wolfssl.SSL_FILETYPE_PEM) != wolfssl.SUCCESS) + { + Console.WriteLine("Error in setting dh2048Pem"); + Console.WriteLine(wolfssl.get_error(ssl)); + tcp.Stop(); + clean(ssl, ctx); + return; + } + + if (wolfssl.accept(ssl) != wolfssl.SUCCESS) + { + /* get and print out the error */ + Console.WriteLine(wolfssl.get_error(ssl)); + tcp.Stop(); + clean(ssl, ctx); + return; + } + + /* get and print sni used by the client */ + if (haveSNI(args)) { + IntPtr data = IntPtr.Zero; + + ushort size = wolfssl.SNI_GetRequest(ssl, 0, ref data); + string dataStr = Marshal.PtrToStringAnsi(data); + Console.WriteLine("(SNI_GetRequest) Size of SNI used by client: " + size); + Console.WriteLine("(SNI_GetRequest) SNI used by client: " + dataStr); + } + + /* print out results of TLS/SSL accept */ + Console.WriteLine("SSL version is " + wolfssl.get_version(ssl)); + Console.WriteLine("SSL cipher suite is " + wolfssl.get_current_cipher(ssl)); + + /* read and print out the message then reply */ + if (wolfssl.read(ssl, buff, 1023) < 0) + { + Console.WriteLine("Error in read"); + tcp.Stop(); + clean(ssl, ctx); + return; + } + Console.WriteLine(buff); + + /* get and print sni from a sample buffer, can be used by using the raw client hello */ + if (haveSNI(args)) { + IntPtr result = Marshal.AllocHGlobal(32); + IntPtr inOutSz = Marshal.AllocHGlobal(sizeof(int)); + Marshal.WriteInt32(inOutSz, 32); + byte []buffer = { /* from TextMate website client hello example */ + 0x16, 0x03, 0x01, 0x00, 0xc6, 0x01, 0x00, 0x00, 0xc2, 0x03, 0x03, 0x52, + 0x8b, 0x7b, 0xca, 0x69, 0xec, 0x97, 0xd5, 0x08, 0x03, 0x50, 0xfe, 0x3b, + 0x99, 0xc3, 0x20, 0xce, 0xa5, 0xf6, 0x99, 0xa5, 0x71, 0xf9, 0x57, 0x7f, + 0x04, 0x38, 0xf6, 0x11, 0x0b, 0xb8, 0xd3, 0x00, 0x00, 0x5e, 0x00, 0xff, + 0xc0, 0x24, 0xc0, 0x23, 0xc0, 0x0a, 0xc0, 0x09, 0xc0, 0x07, 0xc0, 0x08, + 0xc0, 0x28, 0xc0, 0x27, 0xc0, 0x14, 0xc0, 0x13, 0xc0, 0x11, 0xc0, 0x12, + 0xc0, 0x26, 0xc0, 0x25, 0xc0, 0x2a, 0xc0, 0x29, 0xc0, 0x05, 0xc0, 0x04, + 0xc0, 0x02, 0xc0, 0x03, 0xc0, 0x0f, 0xc0, 0x0e, 0xc0, 0x0c, 0xc0, 0x0d, + 0x00, 0x3d, 0x00, 0x3c, 0x00, 0x2f, 0x00, 0x05, 0x00, 0x04, 0x00, 0x35, + 0x00, 0x0a, 0x00, 0x67, 0x00, 0x6b, 0x00, 0x33, 0x00, 0x39, 0x00, 0x16, + 0x00, 0xaf, 0x00, 0xae, 0x00, 0x8d, 0x00, 0x8c, 0x00, 0x8a, 0x00, 0x8b, + 0x00, 0xb1, 0x00, 0xb0, 0x00, 0x2c, 0x00, 0x3b, 0x01, 0x00, 0x00, 0x3b, + 0x00, 0x00, 0x00, 0x15, 0x00, 0x13, 0x00, 0x00, 0x10, 0x61, 0x70, 0x69, + 0x2e, 0x74, 0x65, 0x78, 0x74, 0x6d, 0x61, 0x74, 0x65, 0x2e, 0x6f, 0x72, + 0x67, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x06, 0x00, 0x17, 0x00, 0x18, 0x00, + 0x19, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, 0x00, 0x0d, 0x00, 0x0c, 0x00, + 0x0a, 0x05, 0x01, 0x04, 0x01, 0x02, 0x01, 0x04, 0x03, 0x02, 0x03 + }; + + int ret = wolfssl.SNI_GetFromBuffer(buffer, 1024, 0, result, inOutSz); + + if (ret != wolfssl.SUCCESS) { + Console.WriteLine("Error on reading SNI from buffer, ret value = " + ret); + tcp.Stop(); + clean(ssl, ctx); + return; + } + + string resultStr = Marshal.PtrToStringAnsi(result); + Console.WriteLine("(SNI_GetFromBuffer) SNI used by client: " + resultStr); + + } + + if (wolfssl.write(ssl, reply, reply.Length) != reply.Length) + { + Console.WriteLine("Error in write"); + tcp.Stop(); + clean(ssl, ctx); + return; + } + + wolfssl.shutdown(ssl); + fd.Close(); + tcp.Stop(); + + clean(ssl, ctx); + } +} diff --git a/CSharp/wolfSSL-TLS-pq-Server/wolfSSL-TLS-Server.csproj b/CSharp/wolfSSL-TLS-pq-Server/wolfSSL-TLS-Server.csproj new file mode 100644 index 000000000..9acd0511a --- /dev/null +++ b/CSharp/wolfSSL-TLS-pq-Server/wolfSSL-TLS-Server.csproj @@ -0,0 +1,124 @@ + + + + + Debug + AnyCPU + {8921AD35-4E62-4DAC-8FEE-8C9F8E57DDD2} + Exe + Properties + wolfSSL_TLS_Server + wolfSSL-TLS-Server + v4.8 + 512 + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + + AnyCPU + true + full + false + $(SolutionDir)$(Configuration)\$(Platform)\ + DEBUG;TRACE + prompt + 3 + + + AnyCPU + pdbonly + true + $(SolutionDir)$(Configuration)\$(Platform)\ + TRACE + prompt + 4 + + + + + + true + $(SolutionDir)$(Configuration)\$(Platform)\ + DEBUG;TRACE + 4 + full + x64 + prompt + MinimumRecommendedRules.ruleset + true + + + $(SolutionDir)$(Configuration)\$(Platform)\ + TRACE + true + pdbonly + x64 + prompt + MinimumRecommendedRules.ruleset + true + + + + + + + + + + + + + + + + + + + {52609808-0418-46d3-8e17-141927a1a39a} + wolfSSL_CSharp + + + + + False + Microsoft .NET Framework 4.5 %28x86 and x64%29 + true + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + false + + + + + + + + + diff --git a/CSharp/wolfSSL-TLS-pq-ServerThreaded/App.config b/CSharp/wolfSSL-TLS-pq-ServerThreaded/App.config new file mode 100644 index 000000000..a86c64659 --- /dev/null +++ b/CSharp/wolfSSL-TLS-pq-ServerThreaded/App.config @@ -0,0 +1,6 @@ + + + + + + diff --git a/CSharp/wolfSSL-TLS-pq-ServerThreaded/Properties/AssemblyInfo.cs b/CSharp/wolfSSL-TLS-pq-ServerThreaded/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..9391e05ec --- /dev/null +++ b/CSharp/wolfSSL-TLS-pq-ServerThreaded/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("wolfSSL-TLS-ServerThreaded")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("wolfSSL")] +[assembly: AssemblyProduct("wolfSSL-TLS-ServerThreaded")] +[assembly: AssemblyCopyright("Copyright wolfSSL 2020")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("716e8f30-1318-4e3b-b788-d0380b397a4c")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.1.0.0")] +[assembly: AssemblyFileVersion("1.1.0.0")] diff --git a/CSharp/wolfSSL-TLS-pq-ServerThreaded/wolfSSL-TLS-ServerThreaded.cs b/CSharp/wolfSSL-TLS-pq-ServerThreaded/wolfSSL-TLS-ServerThreaded.cs new file mode 100644 index 000000000..59484ce5e --- /dev/null +++ b/CSharp/wolfSSL-TLS-pq-ServerThreaded/wolfSSL-TLS-ServerThreaded.cs @@ -0,0 +1,205 @@ +/* wolfSSL-TLS-ServerThreaded.cs + * + * Copyright (C) 2006-2025 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + + +using System; +using System.Runtime.InteropServices; +using System.Text; +using System.IO; +using System.Net; +using System.Net.Sockets; +using System.Threading; + +using wolfSSL.CSharp; + +public class wolfSSL_TLS_ServerThread +{ + private IntPtr _ctx; + private Socket _fd; + + public wolfSSL_TLS_ServerThread(IntPtr ctx, Socket fd) + { + _ctx = ctx; + _fd = fd; + } + + private const int kEchoBufSz = 1024; + public void start_client() + { + StringBuilder buff = new StringBuilder(kEchoBufSz); + IntPtr ssl = wolfssl.new_ssl(_ctx); + if (ssl == IntPtr.Zero) + { + Console.WriteLine("Error in creating ssl object"); + return; + } + + if (wolfssl.set_fd(ssl, _fd) != wolfssl.SUCCESS) + { + /* get and print out the error */ + Console.WriteLine(wolfssl.get_error(ssl)); + _fd.Close(); + wolfssl.free(ssl); + return; + } + + Console.WriteLine("Starting TLS handshake"); + if (wolfssl.accept(ssl) != wolfssl.SUCCESS) + { + /* get and print out the error */ + Console.WriteLine("Failed " + wolfssl.get_error(ssl)); + _fd.Close(); + wolfssl.free(ssl); + return; + } + + /* print out results of TLS/SSL accept */ + Console.WriteLine("SSL version is " + wolfssl.get_version(ssl)); + Console.WriteLine("SSL cipher suite is " + wolfssl.get_current_cipher(ssl)); + + /* echo data until error */ + while (true) + { + /* read and print out the message then reply */ + if (wolfssl.read(ssl, buff, kEchoBufSz-1) < 0) + { + Console.WriteLine("Error in read"); + break; + } + Console.WriteLine(buff); + + if (wolfssl.write(ssl, buff, buff.Length) != buff.Length) + { + Console.WriteLine("Error in write"); + break; + } + } + + Console.WriteLine("Closing " + wolfssl.get_error(ssl)); + _fd.Close(); + wolfssl.free(ssl); + } +} + +public class wolfSSL_TLS_ServerThreaded +{ + /// + /// Example of a logging function + /// + /// level of log + /// message to log + public static void standard_log(int lvl, StringBuilder msg) + { + Console.WriteLine(msg); + } + + public static void Main(string[] args) + { + IntPtr ctx; + + /* These paths should be changed for use */ + string fileCert = wolfssl.setPath("mldsa87_entity_cert.pem"); + string fileKey = wolfssl.setPath("mldsa87_entity_key.pem"); + StringBuilder dhparam = new StringBuilder(wolfssl.setPath("dh2048.pem")); + + if (fileCert == "" || fileKey == "" || dhparam.Length == 0) { + Console.WriteLine("Platform not supported"); + return; + } + + /* example of function used for setting logging */ + wolfssl.SetLogging(standard_log); + wolfssl.Init(); + + Console.WriteLine("Calling ctx Init from wolfSSL"); + ctx = wolfssl.CTX_new(wolfssl.usev23_server()); + if (ctx == IntPtr.Zero) + { + Console.WriteLine("Error in creating ctx structure"); + return; + } + Console.WriteLine("Finished init of ctx .... now load in cert and key"); + + if (!File.Exists(fileCert) || !File.Exists(fileKey)) + { + Console.WriteLine("Could not find cert or key file"); + wolfssl.CTX_free(ctx); + return; + } + + if (!File.Exists(dhparam.ToString())) { + Console.WriteLine("Could not find dh file"); + wolfssl.CTX_free(ctx); + return; + } + + if (wolfssl.CTX_use_certificate_file(ctx, fileCert, wolfssl.SSL_FILETYPE_PEM) != wolfssl.SUCCESS) + { + Console.WriteLine("Error in setting cert file"); + wolfssl.CTX_free(ctx); + return; + } + + if (wolfssl.CTX_use_PrivateKey_file(ctx, fileKey, wolfssl.SSL_FILETYPE_PEM) != wolfssl.SUCCESS) + { + Console.WriteLine("Error in setting key file"); + wolfssl.CTX_free(ctx); + return; + } + + StringBuilder ciphers = new StringBuilder(new String(' ', 4096)); + wolfssl.get_ciphers(ciphers, 4096); + Console.WriteLine("Ciphers : " + ciphers.ToString()); + + short minDhKey = 128; + wolfssl.CTX_SetMinDhKey_Sz(ctx, minDhKey); + wolfssl.CTX_SetTmpDH_file(ctx, dhparam, wolfssl.SSL_FILETYPE_PEM); + + /* set up TCP socket */ + IPAddress ip = IPAddress.Parse("0.0.0.0"); /* bind to any */ + TcpListener tcp = new TcpListener(ip, 11111); + tcp.Start(); + + Console.WriteLine("Started TCP and waiting for a connection"); + + while (true) { + try + { + Socket fd = tcp.AcceptSocket(); + Console.WriteLine("Got client connection"); + + /* Spin up thread for client */ + wolfSSL_TLS_ServerThread thread = new wolfSSL_TLS_ServerThread(ctx, fd); + Thread thr = new Thread(new ThreadStart(thread.start_client)); + thr.Start(); + } + catch(Exception ex) + { + Console.WriteLine("Server Exception " + ex.ToString()); + break; + } + } + + tcp.Stop(); + wolfssl.CTX_free(ctx); + wolfssl.Cleanup(); + } +} diff --git a/CSharp/wolfSSL-TLS-pq-ServerThreaded/wolfSSL-TLS-ServerThreaded.csproj b/CSharp/wolfSSL-TLS-pq-ServerThreaded/wolfSSL-TLS-ServerThreaded.csproj new file mode 100644 index 000000000..5f49a9150 --- /dev/null +++ b/CSharp/wolfSSL-TLS-pq-ServerThreaded/wolfSSL-TLS-ServerThreaded.csproj @@ -0,0 +1,124 @@ + + + + + Debug + AnyCPU + {8ABD2E8F-AEE7-40ED-A966-900ACFAE555F} + Exe + Properties + wolfSSL_TLS_ServerThreaded + wolfSSL-TLS-ServerThreaded + v4.8 + 512 + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + + AnyCPU + true + full + false + $(SolutionDir)$(Configuration)\$(Platform)\ + DEBUG;TRACE + prompt + 3 + + + AnyCPU + pdbonly + true + $(SolutionDir)$(Configuration)\$(Platform)\ + TRACE + prompt + 4 + + + + + + true + $(SolutionDir)$(Configuration)\$(Platform)\ + DEBUG;TRACE + 4 + full + x64 + prompt + MinimumRecommendedRules.ruleset + true + + + $(SolutionDir)$(Configuration)\$(Platform)\ + TRACE + true + pdbonly + x64 + prompt + MinimumRecommendedRules.ruleset + true + + + + + + + + + + + + + + + + + + + {52609808-0418-46d3-8e17-141927a1a39a} + wolfSSL_CSharp + + + + + False + Microsoft .NET Framework 4.5 %28x86 and x64%29 + true + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + false + + + + + + + + + diff --git a/README.md b/README.md index 433785d34..09ecc3fa8 100644 --- a/README.md +++ b/README.md @@ -84,6 +84,15 @@ to encrypt files with different algorithms (aes, 3des, etc.) Please see the [crypto/README.md](crypto/README.md) for further usage and details. +
+ +#### CSharp (C# Wrapper Examples) + +This directory contains examples that demonstrate using the C# wrapper. + +Please see the [CSharp/README.md](CSharp/README.md) for further usage and details. + +
#### custom-io-callbacks (wolfSSL Custom IO Callbacks)