Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit b0cbfe3

Browse filesBrowse files
pimterryaduh95
authored andcommitted
crypto: add crypto::GetSSLCtx API for addon access to OpenSSL contexts
This intended to replace usage of the unsupported _external field, offering an official API for native addons to access OpenSSL directly while reducing the JS API and internal field exposure. PR-URL: #62254 Reviewed-By: Anna Henningsen <anna@addaleax.net>
1 parent dc034a4 commit b0cbfe3
Copy full SHA for b0cbfe3

6 files changed

+172Lines changed: 172 additions & 0 deletions

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎src/crypto/crypto_context.cc‎

Copy file name to clipboardExpand all lines: src/crypto/crypto_context.cc
+25Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2371,5 +2371,30 @@ void UseExtraCaCerts(std::string_view file) {
23712371
extra_root_certs_file = file;
23722372
}
23732373

2374+
NODE_EXTERN SSL_CTX* GetSSLCtx(Local<Context> context, Local<Value> value) {
2375+
Environment* env = Environment::GetCurrent(context);
2376+
if (env == nullptr) return nullptr;
2377+
2378+
// TryCatchto swallow any exceptions from Get() (e.g. failing getters)
2379+
v8::TryCatch try_catch(env->isolate());
2380+
2381+
// Unwrap the .context property from the JS SecureContext wrapper
2382+
// (as returned by tls.createSecureContext()).
2383+
if (value->IsObject()) {
2384+
Local<Value> inner;
2385+
if (!value.As<v8::Object>()
2386+
->Get(context, FIXED_ONE_BYTE_STRING(env->isolate(), "context"))
2387+
.ToLocal(&inner)) {
2388+
return nullptr;
2389+
}
2390+
value = inner;
2391+
}
2392+
2393+
if (!SecureContext::HasInstance(env, value)) return nullptr;
2394+
SecureContext* sc = BaseObject::FromJSObject<SecureContext>(value);
2395+
if (sc == nullptr) return nullptr;
2396+
return sc->ctx().get();
2397+
}
2398+
23742399
} // namespace crypto
23752400
} // namespace node
Collapse file

‎src/node.h‎

Copy file name to clipboardExpand all lines: src/node.h
+16Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,8 @@
124124

125125
// Forward-declare libuv loop
126126
struct uv_loop_s;
127+
struct napi_module;
128+
struct ssl_ctx_st; // Forward declaration of SSL_CTX for OpenSSL.
127129

128130
// Forward-declare these functions now to stop MSVS from becoming
129131
// terminally confused when it's done in node_internals.h
@@ -1700,6 +1702,20 @@ NODE_DEPRECATED("Use v8::Object::Wrap()",
17001702
v8::Local<v8::Object> object,
17011703
void* wrappable));
17021704

1705+
namespace crypto {
1706+
1707+
// Returns the SSL_CTX* from a SecureContext JS object, as returned by
1708+
// tls.createSecureContext().
1709+
// Returns nullptr if the value is not a SecureContext instance,
1710+
// or if Node.js was built without OpenSSL.
1711+
//
1712+
// The returned pointer is not owned by the caller and must not be freed.
1713+
// It is valid only while the SecureContext JS object remains alive.
1714+
NODE_EXTERN struct ssl_ctx_st* GetSSLCtx(v8::Local<v8::Context> context,
1715+
v8::Local<v8::Value> secure_context);
1716+
1717+
} // namespace crypto
1718+
17031719
} // namespace node
17041720

17051721
#endif // SRC_NODE_H_
Collapse file

‎test/addons/addons.status‎

Copy file name to clipboardExpand all lines: test/addons/addons.status
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ openssl-binding/test: PASS,FLAKY
1212

1313
[$system==ibmi]
1414
openssl-binding/test: SKIP
15+
openssl-get-ssl-ctx/test: SKIP
1516
openssl-providers/test-default-only-config: SKIP
1617
openssl-providers/test-legacy-provider-config: SKIP
1718
openssl-providers/test-legacy-provider-inactive-config: SKIP
Collapse file
+52Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
#include <node.h>
2+
#include <openssl/ssl.h>
3+
4+
namespace {
5+
6+
// Test: extract SSL_CTX* from a SecureContext object via
7+
// node::crypto::GetSSLCtx.
8+
void GetSSLCtx(const v8::FunctionCallbackInfo<v8::Value>& args) {
9+
v8::Isolate* isolate = args.GetIsolate();
10+
v8::Local<v8::Context> context = isolate->GetCurrentContext();
11+
12+
SSL_CTX* ctx = node::crypto::GetSSLCtx(context, args[0]);
13+
if (ctx == nullptr) {
14+
isolate->ThrowException(v8::Exception::Error(
15+
v8::String::NewFromUtf8(
16+
isolate, "GetSSLCtx returned nullptr for a valid SecureContext")
17+
.ToLocalChecked()));
18+
return;
19+
}
20+
21+
// Verify the pointer is a valid SSL_CTX by calling an OpenSSL function.
22+
const SSL_METHOD* method = SSL_CTX_get_ssl_method(ctx);
23+
if (method == nullptr) {
24+
isolate->ThrowException(v8::Exception::Error(
25+
v8::String::NewFromUtf8(isolate,
26+
"SSL_CTX_get_ssl_method returned nullptr")
27+
.ToLocalChecked()));
28+
return;
29+
}
30+
31+
args.GetReturnValue().Set(true);
32+
}
33+
34+
// Test: passing a non-SecureContext value returns nullptr.
35+
void GetSSLCtxInvalid(const v8::FunctionCallbackInfo<v8::Value>& args) {
36+
v8::Isolate* isolate = args.GetIsolate();
37+
v8::Local<v8::Context> context = isolate->GetCurrentContext();
38+
39+
SSL_CTX* ctx = node::crypto::GetSSLCtx(context, args[0]);
40+
args.GetReturnValue().Set(ctx == nullptr);
41+
}
42+
43+
void Initialize(v8::Local<v8::Object> exports,
44+
v8::Local<v8::Value> module,
45+
v8::Local<v8::Context> context) {
46+
NODE_SET_METHOD(exports, "getSSLCtx", GetSSLCtx);
47+
NODE_SET_METHOD(exports, "getSSLCtxInvalid", GetSSLCtxInvalid);
48+
}
49+
50+
} // anonymous namespace
51+
52+
NODE_MODULE_CONTEXT_AWARE(NODE_GYP_MODULE_NAME, Initialize)
Collapse file
+29Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
'targets': [
3+
{
4+
'target_name': 'binding',
5+
'includes': ['../common.gypi'],
6+
'conditions': [
7+
['node_use_openssl=="true"', {
8+
'conditions': [
9+
['OS in "aix os400"', {
10+
'variables': {
11+
# Used to differentiate `AIX` and `OS400`(IBM i).
12+
'aix_variant_name': '<!(uname -s)',
13+
},
14+
'conditions': [
15+
[ '"<(aix_variant_name)"!="OS400"', { # Not `OS400`(IBM i)
16+
'sources': ['binding.cc'],
17+
'include_dirs': ['../../../deps/openssl/openssl/include'],
18+
}],
19+
],
20+
}, {
21+
'sources': ['binding.cc'],
22+
'include_dirs': ['../../../deps/openssl/openssl/include'],
23+
}],
24+
],
25+
}],
26+
],
27+
},
28+
],
29+
}
Collapse file
+49Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
'use strict';
2+
const common = require('../../common');
3+
if (!common.hasCrypto)
4+
common.skip('missing crypto');
5+
6+
const assert = require('assert');
7+
const tls = require('tls');
8+
const binding = require(`./build/${common.buildType}/binding`);
9+
10+
// Test 1: Pass a SecureContext to getSSLCtx.
11+
{
12+
const ctx = tls.createSecureContext();
13+
assert.strictEqual(binding.getSSLCtx(ctx), true);
14+
}
15+
16+
// Test 2: Passing a non-SecureContext should return nullptr.
17+
{
18+
assert.strictEqual(binding.getSSLCtxInvalid({}), true);
19+
}
20+
21+
// Test 3: Passing a number should return nullptr.
22+
{
23+
assert.strictEqual(binding.getSSLCtxInvalid(42), true);
24+
}
25+
26+
// Test 4: Passing undefined should return nullptr.
27+
{
28+
assert.strictEqual(binding.getSSLCtxInvalid(undefined), true);
29+
}
30+
31+
// Test 5: Passing null should return nullptr.
32+
{
33+
assert.strictEqual(binding.getSSLCtxInvalid(null), true);
34+
}
35+
36+
// Test 6: An object with a non-SecureContext .context property should return
37+
// nullptr.
38+
{
39+
assert.strictEqual(binding.getSSLCtxInvalid({ context: 'not a context' }), true);
40+
}
41+
42+
// Test 7: An object with a throwing .context getter should return nullptr
43+
// without propagating the exception.
44+
{
45+
const obj = {
46+
get context() { throw new Error('getter threw'); },
47+
};
48+
assert.strictEqual(binding.getSSLCtxInvalid(obj), true);
49+
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.