Skip to content

Conversation

@gojimmypi
Copy link
Contributor

@gojimmypi gojimmypi commented Jul 1, 2025

Description

Summary: CSharp Wrapper Improvements

This PR enhances the C# wrapper and improves cross-platform compatibility, developer experience, and debugging support when using wolfSSL with .NET applications.


CSharp Wrapper Enhancements

  • New Structs and Functions

    • Added WOLFSSL_ALERT and WOLFSSL_ALERT_HISTORY structs to expose alert-level history to .NET apps.
    • Added new public method get_alert_history() in C# to retrieve and display alert codes/levels from the native wolfSSL context.
  • Improved Path Detection

    • Dynamically searches for the certs folder in parent directories to better support different working directories across Windows and Linux.
  • Sample Application Improvements

    • Enhanced logging and diagnostics in:
      • wolfSSL-TLS-Client
      • wolfSSL-TLS-PSK-Client
      • wolfSSL-TLS-Server
    • Added constant definitions for SERVER_NAME, SERVER_PORT, and cipher suite selection.
    • Introduced a new Visual Studio solution: wolfSSL_CSharp-Clients.sln to support concurrent client/server projects.
  • Documentation Updates

    • Updated README.md with:
      • Troubleshooting for pwsh.exe not recognized
      • Architecture mismatch errors (AnyCPU vs. x64)
      • Best practices for setting startup projects and debugging

Compatibility Improvements

  • Replaced #warning with #pragma message when compiling with MSVC (_MSC_VER) to prevent build interruptions.
  • Added Visual Studio 2015+ specific suppression for enum-type mismatch warnings (C5287) around wc_static_assert.
  • Updated the XINET_PTON macro to cast to PCWSTR or PCSTR based on Visual Studio version for better Windows API compliance.

Dynamic DLL Loading

  • Added wolfssl.LoadDLL() to locate and load wolfssl.dll at runtime.
  • Searches common subdirectories (e.g. Debug, Debug\\x64) when not found in the working directory.
  • Added SetVerbosity(true) for diagnostic output about the load process, DLL size, and timestamp.

Improved Path Resolution

  • setPath() now recursively searches parent directories for a certs folder.
  • Added platform-specific logging to help identify missing files or incorrect paths.

Verbose Debug Mode

  • New global flag in the C# wrapper enables detailed output for:
    • DLL discovery
    • Certificate path detection
    • Wrapper initialization behavior

Alert History & Diagnostics

  • Sample clients now retrieve and print TLS alert history after handshake failures using get_alert_history().
  • Improves post-failure analysis for SSL/TLS issues.

Other Fixes

  • Initialized unassigned local variables (keyTypeTemp, keySizeTemp) to eliminate compiler warnings.
  • Minor cleanup of whitespace, formatting, and redundant logic across several files.

MSVC Compatibility Enhancements

  • Replaced #warning with #pragma message(...) for MSVC (_MSC_VER) to suppress noisy or incompatible warnings during build:
    #ifndef WOLFSSL_IGNORE_FILE_WARN
        #if defined(_MSC_VER)
            #pragma message("file.c does not need to be compiled separately from ssl.c")
        #else
            #warning file.c does not need to be compiled separately from ssl.c
        #endif
    #endif

Fixes zd# n/a

Testing

How did you test?

Manually tested in VS2022, VS2008

Checklist

  • added tests
  • updated/added doxygen
  • updated appropriate READMEs
  • Updated manual and documentation

@gojimmypi gojimmypi self-assigned this Jul 1, 2025
@gojimmypi gojimmypi marked this pull request as draft July 1, 2025 04:18
@gojimmypi gojimmypi force-pushed the pr-csharp-improvements branch from a1bc0fb to 9c2ec0b Compare July 1, 2025 04:27
@gojimmypi gojimmypi marked this pull request as ready for review July 1, 2025 04:46
@gojimmypi gojimmypi marked this pull request as draft July 1, 2025 04:47
@gojimmypi
Copy link
Contributor Author

Jenkins retest this please.

For missing results, SSL_read input error -308, error state on socket

@gojimmypi gojimmypi force-pushed the pr-csharp-improvements branch from 9c2ec0b to 6f7aee2 Compare July 1, 2025 19:14
@gojimmypi gojimmypi added the For This Release Release version 5.8.2 label Jul 1, 2025
@gojimmypi gojimmypi requested a review from dgarske July 1, 2025 19:35
@gojimmypi gojimmypi marked this pull request as ready for review July 1, 2025 19:36
@devin-ai-integration
Copy link
Contributor

🛟 Devin Lifeguard found 1 likely issues in this PR

  • check-all-return-codes snippet snippet: Capture the bool returned by wolfssl.LoadDLL("") in the client and server files and abort or report an error when it is false, e.g. if (!wolfssl.LoadDLL("")) { Console.WriteLine("DLL load failed"); return; }.

@gojimmypi
please take a look at the above issues which Devin flagged. Devin will not fix these issues automatically.

@dgarske dgarske removed their assignment Jul 2, 2025
JacobBarthelmeh
JacobBarthelmeh previously approved these changes Jul 2, 2025
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR enhances the C# wolfSSL wrapper with dynamic DLL loading, improved path detection, verbose logging, and TLS alert history retrieval; adds a new Visual Studio solution for concurrent client/server projects; and applies MSVC compatibility fixes across native code.

  • Added SetVerbosity, LoadDLL, recursive setPath, and alert history support in wolfSSL.cs
  • Introduced WOLFSSL_ALERT, WOLFSSL_ALERT_HISTORY, and get_alert_history binding
  • Created wolfSSL_CSharp-Clients.sln and updated documentation for cross-platform builds
  • Replaced #warning with #pragma message for MSVC in multiple native source headers

Reviewed Changes

Copilot reviewed 27 out of 27 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
wrapper/CSharp/wolfSSL_CSharp/wolfSSL.cs Added verbose DLL loading, path search, alert history API
wrapper/CSharp/wolfSSL_CSharp/wolfCrypt.cs Updated comments on CPU architecture matching
wrapper/CSharp/wolfSSL_CSharp-Clients.sln New solution for concurrent client/server samples
wrapper/CSharp/README.md Expanded build and troubleshooting instructions
wrapper/CSharp/include.am Added new solution to distribution list
wolfssl/wolfio.h Updated XINET_PTON macro for MSVC version casting
wolfssl/wolfcrypt/sp.h Adjusted typedef condition for older MSVC
wolfssl/error-ssl.h Wrapped wc_static_assert in MSVC warning suppression
wolfcrypt/src/.c, src/.c Replaced #warning with #pragma message for MSVC builds
Comments suppressed due to low confidence (1)

wrapper/CSharp/wolfSSL_CSharp/wolfSSL.cs:81

  • Invalid C# preprocessor directive #pragma "Only DEBUG and RELEASE supported". In C#, use #error or #warning for conditional compilation messages, or update to a supported directive to avoid build errors.
#pragma "Only DEBUG and RELEASE supported"

@gojimmypi
Copy link
Contributor Author

@dgarske @JacobBarthelmeh sorry for the delay, I ended up down a rabbit hole & should be done by the end of the day.

I've implemented a new StringToAnsiPtr and I'm converting callbacks from

public static void standard_log(int lvl, StringBuilder msg)

to

public static void standard_log(int lvl, IntPtr msg) {

@gojimmypi gojimmypi marked this pull request as draft July 2, 2025 20:28
@gojimmypi
Copy link
Contributor Author

@dgarske @JacobBarthelmeh This PR has changed substantially since submitted. I've left the new changes in a separate commit for now.

I've addressed the compile issues for CE, but I have been still unable to figure out how to run native C wolfSSL in any of the CE emulators with the wolfSSL_CSharp C# wrapper class.

@dgarske please test on customer hardware. Thank you.

@gojimmypi gojimmypi marked this pull request as ready for review July 2, 2025 23:31
@devin-ai-integration
Copy link
Contributor

🛟 Devin Lifeguard found 1 likely issues in this PR

  • do-not-change-external-apis snippet: Re-introduce the original delegate (loggingCb with StringBuilder msg) and add a new one (e.g., loggingCbEx) that uses IntPtr; keep the old overloads that accept the original delegate and internally marshal to the new implementation.

@gojimmypi
please take a look at the above issues which Devin flagged. Devin will not fix these issues automatically.

@gojimmypi gojimmypi requested a review from dgarske July 3, 2025 18:38
@gojimmypi gojimmypi marked this pull request as ready for review July 3, 2025 18:39
@devin-ai-integration
Copy link
Contributor

🛟 Devin Lifeguard found 2 likely issues in this PR

  • do-not-change-external-apis snippet: Restore the original get_ciphers(StringBuilder …) overload and introduce a new overload (e.g. get_ciphers_ex(string …)), having the old method call the new one internally so existing user code keeps compiling.
  • no-memory-leaks snippet: After the call sequence that uses sniHostName, add Marshal.FreeHGlobal(sniHostName); (inside a finally block) to release the unmanaged memory allocated by wolfssl.StringToAnsiPtr.

@gojimmypi
please take a look at the above issues which Devin flagged. Devin will not fix these issues automatically.

Copy link
Contributor

@dgarske dgarske left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Running tests on customer hardware now. Please remove the .c/.h use of WindowsCE... it never existed and don't add a new construct. If needed use compiler provided _WIN32_WCE

#error This user_settings.h header is only designed for Windows
#endif

/* Optional WindowsCE, needed here for all CE configurations:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

wolfssl/wolfio.h Outdated
#define XINET_PTON(a,b,c) InetPton((a),(b),(c))
#else
#define XINET_PTON(a,b,c) InetPton((a),(PCWSTR)(b),(c))
#if (defined(_MSC_VER) && (_MSC_VER >= 1600)) || defined(WindowsCE)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove || defined(WindowsCE) or use the existing _WIN32_WCE instead...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without WindowsCE, the _WIN32_WCE is not automatically assigned for me, and I see these compile-time warnings:

2>c:\workspace\wolfssl-gojimmypi\src\ssl.c(1928) : warning C4133: 'function' : incompatible types - from 'PCSTR' to 'PCWSTR'
2>c:\workspace\wolfssl-gojimmypi\src\ssl.c(22180) : warning C4133: 'function' : incompatible types - from 'const char *' to 'PCWSTR'

I've removed the WindowsCE and added explicit known CE macros:

            #if (defined(_MSC_VER) && (_MSC_VER >= 1600)) || \
                 defined(_WIN32_WCE) || defined(WINCE) || defined(PocketPC)
                #define XINET_PTON(a,b,c)   InetPton((a),(PCWSTR)(b),(c))
            #else
                #define XINET_PTON(a,b,c)   InetPton((a),(PCSTR)(b),(c))
            #endif

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dgarske what do you think of revising the Windows API logic and first check for UNICODE like this:

#ifndef XINET_PTON
    #if defined(__WATCOMC__)
        #if defined(__OS2__) || defined(__NT__) && \
                (NTDDI_VERSION >= NTDDI_VISTA)
            #define XINET_PTON(a,b,c)   inet_pton((a),(b),(c))
        #else
            #define XINET_PTON(a,b,c)   *(unsigned *)(c) = inet_addr((b))
        #endif
    #elif defined(USE_WINDOWS_API) /* Windows-friendly definition */
        #if defined(UNICODE)
            /* Use Win API Pointer to a constant wide-character string */
            #define XINET_PTON(a,b,c)   InetPton((a),(PCWSTR)(b),(c))
        #elif defined(__MINGW64__) && !defined(UNICODE)
            #define XINET_PTON(a,b,c)   InetPton((a),(b),(c))
        #else
            #if (defined(_MSC_VER)  && (_MSC_VER >= 1600)) || defined(_WIN32_WCE)
                #define XINET_PTON(a,b,c)   InetPton((a),(PCWSTR)(b),(c))
            #else
                #define XINET_PTON(a,b,c)   InetPton((a),(PCSTR)(b),(c))
            #endif
        #endif
    #else
        #define XINET_PTON(a,b,c)   inet_pton((a),(b),(c))
    #endif
#endif

}
}
}
/* wolfCrypt-Test.cs
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file shows a full replace. Guessing a CRLF issue. Please try and avoid that change if possible.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the prior file was LF only. Windows / Visual Studio default is CRLF.

I'll revert for this PR, but I recommend we change line endings at some future time.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you saying this file specifically is different? If so go ahead and keep it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct. All of the other examples are CRLF. I'll change the wolfCrypt-Test.cs from LF to CRLF.

{
if (addr.AddressFamily == AddressFamily.InterNetwork)
{
tcp.Connect(new IPEndPoint(addr, SERVER_PORT));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this new logic needed? Where is the break;?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've been still trying to get my CE emulator to work and use the wolfssl-tls-client example.

Why is this new logic needed?

Because this:

tcp.Connect(SERVER_NAME, SERVER_PORT);

on WindowsCE gives this error (connect takes only 1 param on CE, 2 on others):

Error	1	No overload for method 'Connect' takes '2' arguments	C:\workspace\wolfssl-gojimmypi\wrapper\CSharp\wolfSSL-TLS-Client\wolfSSL-TLS-Client.cs	281	13	wolfSSL-TLS_CE_2008

Where is the break;?

added

Console.WriteLine("SSL cipher suite is " + wolfssl.get_current_cipher(ssl));

/* Optional code & level history */
show_alert_history(ssl);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This belongs at the end before cleanup.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved

}
#endif

public static void show_alert_history_code(WOLFSSL_ALERT h, string m)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make show_alert_history and show_alert_history_code private.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


namespace wolfSSL.CSharp
{
/********************************
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't these be part of the public class wolfssl? I'd prefer use wolfssl.WOLFSSL_ALERT, etc in the calling code.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't these be part of the public class wolfssl?

Yes, it was at one point, but there was a scoping problem. I'll see if I can move it back or document why not.

public static void show_alert_history_code(WOLFSSL_ALERT h, string m)
{
/* VS initializes .code and .level to zero; wolfSSL sets to -1 until there's a valid value. */
if ((h.code > 0) || (h.level > 0)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please cleanup example. You have if ((h.code > 0) || (h.level > 0)) twice.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, changed.

@dgarske dgarske removed their assignment Jul 3, 2025
@gojimmypi gojimmypi requested a review from dgarske July 3, 2025 20:05
@gojimmypi
Copy link
Contributor Author

Jenkins retest this please

For ERROR: Unable to tear down: java.io.IOException: Unexpected EOF; Python Remote call to wolf-linux-cloud-node no workspace for PRB-python-port #8458

wolfssl/wolfio.h Outdated

/* CE Not always reliably detected. Define our own _WIN32_WCE as needed. */
#if defined(_WIN32_WCE) || defined(WINCE) || defined(PocketPC)
#if !_WIN32_WCE
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please change this to #if !defined(_WIN32_WCE). Why add another macro WINCE or PocketPC here? Are those supposed to supplied by the compiler or optionally by the user?

Copy link
Contributor Author

@gojimmypi gojimmypi Jul 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will change this to only _WIN32_WCE. Neither that, nor WINCE have ever been auto-defined for me. I added them for likely completeness, although never actually tested.

edit: I'll remove this entire section and use only _WIN32_WCE for XINET_PTON detection of PCWSTR in this file.

    #elif defined(USE_WINDOWS_API) /* Windows-friendly definition */
        #if defined(__MINGW64__) && !defined(UNICODE)
            #define XINET_PTON(a,b,c)   InetPton((a),(b),(c))
        #else
            #if (defined(_MSC_VER) && (_MSC_VER >= 1600)) || defined(_WIN32_WCE)
                #define XINET_PTON(a,b,c)   InetPton((a),(PCWSTR)(b),(c))
            #else
                #define XINET_PTON(a,b,c)   InetPton((a),(PCSTR)(b),(c))
            #endif
        #endif

The PocketPC was auto-added at new project time here. I manually added the WindowsCE.

image

wolfssl/wolfio.h Outdated
#else
#define XINET_PTON(a,b,c) InetPton((a),(PCWSTR)(b),(c))
#if (defined(_MSC_VER) && (_MSC_VER >= 1600)) || \
defined(_WIN32_WCE) || defined(WINCE) || defined(PocketPC)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just use _WIN32_WCE. You don't need WINCE or PocketPC

Copy link
Contributor Author

@gojimmypi gojimmypi Jul 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I'll use only _WIN32_WCE. It may need to be manually defined for some projects.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, your logic a few lines up makes sure _WIN32_WCE is defined... So you can remove this duplicate logic.

[DllImport(wolfssl_dll)]
private extern static IntPtr wc_GetErrorString(int error);
public delegate void loggingCb(int lvl, string msg);
/* No Windows CE decorator for logging call-back */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this could break some users. I would prefer the logging continue to be duplicated. Technically its in wolfCrypt not wolfSSL. I don't want a refactor on this. Please duplicate the logging.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok. Do you have an example of what might be problematic & why the duplication is preferred?

I'd like to include a comment to avoid a future de-dupe.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WolfCrypt only users who are already calling wolfcrypt.setLogging

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm. Interesting.

What do you think of moving it all from wolfSSL to wolfcrypt, no duplicating, but including API references to maintain current functionality?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That’s fine. As long as we keep the existing API’s. I do not want to break compatibility

@dgarske dgarske removed their assignment Jul 3, 2025
@gojimmypi
Copy link
Contributor Author

@dgarske you removed the For This Release tag today; If I have more time on this PR, would you like the other examples cleaned up and expanded (e.g. add new alert history)? I also have some new examples that are missing, such as wolfSSL-DTLS-PSK-Client.

We may also consider moving some of the C# examples to https://github.com/wolfSSL/wolfssl-examples

@gojimmypi gojimmypi marked this pull request as draft July 4, 2025 16:46
@gojimmypi gojimmypi force-pushed the pr-csharp-improvements branch 2 times, most recently from 3086d2d to 5819622 Compare July 7, 2025 01:10
@gojimmypi gojimmypi force-pushed the pr-csharp-improvements branch from ea54abc to ed90c17 Compare July 23, 2025 00:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants