DEV Community

Vasyl K
Vasyl K

Posted on

SSL context creation crashes of c++ native module in Electron application

I am building a C++ native module to be used in an Electron application. The native module is responsible for communicating with a WebSocket server. I am using the WebSocketPP library and the following sample code:

index.cc

#include <websocketpp/config/asio_client.hpp>   // TLS
#include <websocketpp/client.hpp>
typedef websocketpp::client<websocketpp::config::asio_tls_client> client;
typedef websocketpp::config::asio_client::message_type::ptr message_ptr;
typedef websocketpp::lib::shared_ptr<boost::asio::ssl::context> context_ptr;
using websocketpp::lib::bind;
using websocketpp::lib::placeholders::_1;
using websocketpp::lib::placeholders::_2;
//
...
//
class WebSocketHandler
{
public:
    void set(const std::string &url, const std::string &token)
    {
        ws_url = url;
        authorizationHeader = "Bearer " + token;
        // Initialize ASIO
        _webSocket.init_asio();

        // Set logging to be pretty verbose (everything except message payloads)
        _webSocket.set_access_channels(websocketpp::log::alevel::all);
        _webSocket.clear_access_channels(websocketpp::log::alevel::frame_payload);

        // Set open handler
        _webSocket.set_open_handler(bind(&WebSocketHandler::on_open, this, std::placeholders::_1));

        // Set close handler
        _webSocket.set_close_handler(bind(&WebSocketHandler::on_close, this, std::placeholders::_1));

        // Set fail handler
        _webSocket.set_fail_handler(bind(&WebSocketHandler::on_fail, this, std::placeholders::_1));

        // Set message handler
        _webSocket.set_message_handler(bind(&WebSocketHandler::on_message, this, std::placeholders::_1, std::placeholders::_2));
        // Set TLS handler
        _webSocket.set_tls_init_handler(bind(&WebSocketHandler::on_tls_init, this, std::placeholders::_1));
    }

    void start()
    {
        websocketpp::lib::error_code ec;

        client::connection_ptr con = _webSocket.get_connection(ws_url, ec);
        if (ec)
        {
            std::cout << "Could not create connection because: " << ec.message() << std::endl;
            return;
        }

        // Set the authorization header
        con->replace_header("Authorization", authorizationHeader);

        // Connect to server
        _webSocket.connect(con);

        // Start the ASIO io_service run loop
        _thread.reset(new websocketpp::lib::thread(&client::run, &_webSocket));
    }

    void stop()
    {
        _webSocket.stop();
        if (_thread && _thread->joinable())
        {
            _thread->join();
        }
    }

private:
    context_ptr on_tls_init(websocketpp::connection_hdl hdl)
    {
        context_ptr ctx = websocketpp::lib::make_shared<boost::asio::ssl::context>(boost::asio::ssl::context::sslv23);  // crash at this line

        try {
            // Simplified SSL options for testing
            ctx->set_options(boost::asio::ssl::context::default_workarounds |
                             boost::asio::ssl::context::no_sslv2 |
                             boost::asio::ssl::context::no_sslv3 |
                             boost::asio::ssl::context::single_dh_use);
            std::cout << "SSL options set successfully" << std::endl;
        } catch (std::exception &e) {
            std::cout << "Exception during set_options: " << e.what() << std::endl;
        }

        return ctx;
    }

    void on_open(websocketpp::connection_hdl hdl)
    {
        std::cout << "connection opened" << std::endl;
    }

    void on_close(websocketpp::connection_hdl hdl)
    {
        std::cout << "connection closed" << std::endl;
    }

    void on_fail(websocketpp::connection_hdl hdl)
    {
        std::cout << "connection failed" << std::endl;
    }

    void on_message(websocketpp::connection_hdl hdl, client::message_ptr msg)
    {
        std::cout << "message arrived" << std::endl;
    }

    client _webSocket;
    std::string ws_url;
    std::string authorizationHeader;
};
//
...
//
WebSocketHandler handler;
handler.set("wss://echo.websocket.org/", "Token_xxxx");
handler.start();
....
handler.stop();
Enter fullscreen mode Exit fullscreen mode

binding.gyp

{
  "targets": [
    {
      "target_name": "binding",
      "include_dirs": [
        "<!@(node -p \"require('node-addon-api').include\")",
        "<(module_root_dir)/include"
      ],
      "conditions": [
        ['OS=="win"', {
          "sources": [
            "./src/index.cc"
          ],
          "configurations": {
            "Debug": {
              "msvs_settings": {
                "VCCLCompilerTool": {
                  "RuntimeLibrary": "0", 
                  "ExceptionHandling": "1"
                },
              },
            },
            "Release": {
              "msvs_settings": {
                "VCCLCompilerTool": {
                  "RuntimeLibrary": "0", 
                  "ExceptionHandling": "1"
                },
              },
            },
          },
          "libraries": [
            "-lws2_32",
            "-lShlwapi"
          ]
        }]
      ]
    }
  ],
}
Enter fullscreen mode Exit fullscreen mode

Test Script

const engine = require("../bin/binding.node");
const test = async () => {
    try {
        engine.startConnection();
    } catch (err) {
        console.log("Error occurred", err);
    }
};
test();
Enter fullscreen mode Exit fullscreen mode

Problem The module works correctly in a JavaScript test script but crashes in Electron at this line:

context_ptr ctx = websocketpp::lib::make_sharedboost::asio::ssl::context(boost::asio::ssl::context::sslv23);
I suspect the issue might be related to the way SSL libraries are linked. I feel linking SSL libraries statically might resolve the issue, but I am unsure how to achieve this. I tested with other several libraries based in boost but the result was same. It keeps crahsed in ssl context creation part only in electron application.

Environment

C++14/17
Electron v23(version upgrade doesn't help)
WebSocketPP 0.8.2
Node 16.14.2/18.x.x
Dependencies installed using vcpkg: OpenSSL, WebSocketPP, Boost
Question

How can I link SSL libraries statically in my project to potentially fix this issue? Are there any other possible solutions or insights regarding this problem?

Thank you for your assistance!

Top comments (0)