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

RMAG news

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();

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”
]
}]
]
}
],
}

Test Script

const engine = require(“../bin/binding.node”);
const test = async () => {
try {
engine.startConnection();
} catch (err) {
console.log(“Error occurred”, err);
}
};
test();

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!