Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How can I build Node.js using the system-installed OpenSSL instead of the OpenSSL version embedded in the Node.js source? #4493

Closed
2 tasks done
gouravkrosx opened this issue Oct 21, 2024 · 4 comments

Comments

@gouravkrosx
Copy link

gouravkrosx commented Oct 21, 2024

Node.js Version

18.20.4

NPM Version

10.7.0

Operating System

Linux lima-debian-12 6.1.0-26-cloud-arm64 #1 SMP Debian 6.1.112-1 (2024-09-30) aarch64 GNU/Linux

Subsystem

tls

Description

I found that Nodejs uses embedded statically linked OpenSSL. I want to rebuild Node on my local machine to use the system-installed OpenSSL. I want to override some OpenSSL functions using LD_PRELOAD that don't seem to be called with my current node setup. Can you provide the steps to do it? It would have been great if I could do this without building Nodejs from the sources. I tried LD_LIBRARY_PATH but it didn't work either.

Minimal Reproduction

No response

Output

No response

Before You Submit

  • I have looked for issues that already exist before submitting this
  • My issue follows the guidelines in the README file, and follows the 'How to ask a good question' guide at https://stackoverflow.com/help/how-to-ask
@RedYetiDev
Copy link
Member

RedYetiDev commented Oct 21, 2024

If I recall, configuring allows the "--shared-openssl" flag

@gouravkrosx
Copy link
Author

Thanks, was able to build it using:

./configure --shared-openssl \
  --shared-openssl-includes=/usr/include/openssl \
  --shared-openssl-libpath=/usr/lib
make -j$(nproc)

@gouravkrosx
Copy link
Author

Can you confirm with this log that I've configured the node to use system-specific OpenSSL.

Zen-1% ldd $(which node)
        linux-vdso.so.1 (0x00007ffdda9d9000)
        libcrypto.so.3 => /lib/x86_64-linux-gnu/libcrypto.so.3 (0x0000794d37c00000)
        libssl.so.3 => /lib/x86_64-linux-gnu/libssl.so.3 (0x0000794d3d0b5000)
        libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x0000794d37800000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x0000794d3cfcc000)
        libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x0000794d3cf9e000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x0000794d37400000)
        /lib64/ld-linux-x86-64.so.2 (0x0000794d3d173000)
Zen-1% node -p process.versions.openssl

3.0.13
Zen-1% openssl version
OpenSSL 3.0.13 30 Jan 2024 (Library: OpenSSL 3.0.13 30 Jan 2024)
Zen-1% 

@gouravkrosx
Copy link
Author

Hey @RedYetiDev Thanks, just a follow-up question. Since it now uses the system OpenSSL it should've called the SSL functions like
SSL_do_handshake & SSL_CTX_load_verify_locations since it is now using dynamically linked shared libraries, But it isn't, I've checked it by using a custom c function and used LD_PRELOAD.

#define _GNU_SOURCE
#include <dlfcn.h>
#include <openssl/ssl.h>
#include <stdio.h>

// Function pointer to hold the original SSL_CTX_load_verify_locations function
int (*original_SSL_CTX_load_verify_locations)(SSL_CTX *ctx, const char *CAfile, const char *CApath) = NULL;

// Function pointer to hold the original SSL_do_handshake function
int (*original_SSL_do_handshake)(SSL *ssl) = NULL;

// Custom SSL_CTX_load_verify_locations function
int SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile, const char *CApath) {
    // Load the original function if it hasn't been loaded yet
    if (!original_SSL_CTX_load_verify_locations) {
        original_SSL_CTX_load_verify_locations = (int (*)(SSL_CTX *, const char *, const char *))
            dlsym(RTLD_NEXT, "SSL_CTX_load_verify_locations");

        // Check for errors
        const char *error = dlerror();
        if (error != NULL) {
            fprintf(stderr, "Error loading original SSL_CTX_load_verify_locations: %s\n", error);
            return -1;
        }
    }

    // Override the CAfile with your own certificate
    const char *my_CAfile = "/home/bugs/Desktop/gk_workspace/tls-change-cert/keploy.crt";
    printf("\n\nOverriding CAfile with %s\n\n", my_CAfile);

    // Call the original function with the overridden CAfile
    return original_SSL_CTX_load_verify_locations(ctx, my_CAfile, CApath);
}

// Custom SSL_do_handshake function
int SSL_do_handshake(SSL *ssl) {
    // Load the original function if it hasn't been loaded yet
    if (!original_SSL_do_handshake) {
        original_SSL_do_handshake = (int (*)(SSL *))dlsym(RTLD_NEXT, "SSL_do_handshake");

        // Check for errors
        const char *error = dlerror();
        if (error != NULL) {
            fprintf(stderr, "Error loading original SSL_do_handshake: %s\n", error);
            return -1;
        }
    }

    // Print a message indicating the handshake is in progress
    printf("\n\nSSL handshake is going on...\n\n");

    // Call the original SSL_do_handshake function
    return original_SSL_do_handshake(ssl);
}

Compiling using: clang-14 -I/usr/include/openssl -L/usr/lib/aarch64-linux-gnu -fPIC -shared -o ssl_override.so ssl_override.c -lssl -lcrypto

Running the setup using: LD_PRELOAD=<path to ssl_override.so> node index.js

NODE APP:

const express = require('express');
const axios = require('axios');
const fs = require('fs');
const https = require('https');

const app = express();
const CERTIFICATE_PATH = './ninja.crt';

const httpsAgent = new https.Agent({
  ca: fs.readFileSync(CERTIFICATE_PATH), 
  keepAlive: false,
});

app.get('/catFact', async (req, res) => {
  try {
    const response = await axios.get('https://catfact.ninja/fact', { httpsAgent });
    res.status(200).json(response.data);
  } catch (error) {
    res.status(500).json({
      error: 'SSL certificate validation failed',
      details: error.message
    });
  }
});

const PORT = 8080;
app.listen(PORT, () => {
  console.log(`Server is running on http://0.0.0.0:${PORT}`);
});

The same setup worked for python application where the app is calling the SSL functions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants