Skip to content

Commit 53ec358

Browse files
authored
test: add OpenSSL 3.x providers test
Add basic tests for providers when using OpenSSL 3.x. PR-URL: #44148 Reviewed-By: Michael Dawson <[email protected]> Reviewed-By: Rafael Gonzaga <[email protected]>
1 parent 83cd484 commit 53ec358

11 files changed

+303
-0
lines changed
+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#include <assert.h>
2+
#include <node.h>
3+
#include <openssl/provider.h>
4+
5+
namespace {
6+
7+
using v8::Array;
8+
using v8::Context;
9+
using v8::FunctionCallbackInfo;
10+
using v8::Isolate;
11+
using v8::Local;
12+
using v8::Object;
13+
using v8::String;
14+
using v8::Value;
15+
16+
#if OPENSSL_VERSION_MAJOR >= 3
17+
int collectProviders(OSSL_PROVIDER* provider, void* cbdata) {
18+
static_cast<std::vector<OSSL_PROVIDER*>*>(cbdata)->push_back(provider);
19+
return 1;
20+
}
21+
#endif
22+
23+
inline void GetProviders(const FunctionCallbackInfo<Value>& args) {
24+
Isolate* isolate = args.GetIsolate();
25+
std::vector<Local<Value>> arr = {};
26+
#if OPENSSL_VERSION_MAJOR >= 3
27+
std::vector<OSSL_PROVIDER*> providers;
28+
OSSL_PROVIDER_do_all(nullptr, &collectProviders, &providers);
29+
for (auto provider : providers) {
30+
arr.push_back(
31+
String::NewFromUtf8(isolate, OSSL_PROVIDER_get0_name(provider))
32+
.ToLocalChecked());
33+
}
34+
#endif
35+
args.GetReturnValue().Set(Array::New(isolate, arr.data(), arr.size()));
36+
}
37+
38+
inline void Initialize(Local<Object> exports,
39+
Local<Value> module,
40+
Local<Context> context) {
41+
NODE_SET_METHOD(exports, "getProviders", GetProviders);
42+
}
43+
44+
} // anonymous namespace
45+
46+
NODE_MODULE_CONTEXT_AWARE(NODE_GYP_MODULE_NAME, Initialize)
+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
{
2+
'targets': [
3+
{
4+
'target_name': 'binding',
5+
'includes': ['../common.gypi'],
6+
'conditions': [
7+
['node_use_openssl=="true"', {
8+
'conditions': [
9+
['OS=="aix"', {
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+
['OS=="mac"', {
27+
'xcode_settings': {
28+
'OTHER_CFLAGS+': [
29+
'-Wno-deprecated-declarations',
30+
],
31+
},
32+
}, {
33+
'cflags': ['-Wno-deprecated-declarations'],
34+
}],
35+
],
36+
},
37+
]
38+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
'use strict';
2+
3+
const common = require('../../common');
4+
if (!common.hasCrypto)
5+
common.skip('missing crypto');
6+
7+
if (!common.hasOpenSSL3)
8+
common.skip('this test requires OpenSSL 3.x');
9+
const assert = require('node:assert');
10+
const { createHash, getCiphers, getHashes } = require('node:crypto');
11+
const { debuglog } = require('node:util');
12+
const { getProviders } = require(`./build/${common.buildType}/binding`);
13+
14+
// For the providers defined here, the expectation is that the listed ciphers
15+
// and hash algorithms are only provided by the named provider. These are for
16+
// basic checks and are not intended to list evey cipher or hash algorithm
17+
// supported by the provider.
18+
const providers = {
19+
'default': {
20+
ciphers: ['des3-wrap'],
21+
hashes: ['sha512-256'],
22+
},
23+
'legacy': {
24+
ciphers: ['blowfish', 'idea'],
25+
hashes: ['md4', 'whirlpool'],
26+
},
27+
};
28+
29+
const debug = debuglog('test');
30+
31+
module.exports = {
32+
getCurrentProviders: getProviders,
33+
testProviderPresent,
34+
testProviderAbsent,
35+
};
36+
37+
function assertArrayDoesNotInclude(array, item, desc) {
38+
assert(!array.includes(item),
39+
`${desc} [${array}] unexpectedly includes "${item}"`);
40+
}
41+
42+
function assertArrayIncludes(array, item, desc) {
43+
assert(array.includes(item),
44+
`${desc} [${array}] does not include "${item}"`);
45+
}
46+
47+
function testProviderPresent(provider) {
48+
debug(`Checking '${provider}' is present`);
49+
assertArrayIncludes(getProviders(), provider, 'Loaded providers');
50+
for (const cipher of providers[provider].ciphers || []) {
51+
debug(`Checking '${cipher}' cipher is available`);
52+
assertArrayIncludes(getCiphers(), cipher, 'Available ciphers');
53+
}
54+
for (const hash of providers[provider].hashes || []) {
55+
debug(`Checking '${hash}' hash is available`);
56+
assertArrayIncludes(getHashes(), hash, 'Available hashes');
57+
createHash(hash);
58+
}
59+
}
60+
61+
function testProviderAbsent(provider) {
62+
debug(`Checking '${provider}' is absent`);
63+
assertArrayDoesNotInclude(getProviders(), provider, 'Loaded providers');
64+
for (const cipher of providers[provider].ciphers || []) {
65+
debug(`Checking '${cipher}' cipher is unavailable`);
66+
assertArrayDoesNotInclude(getCiphers(), cipher, 'Available ciphers');
67+
}
68+
for (const hash of providers[provider].hashes || []) {
69+
debug(`Checking '${hash}' hash is unavailable`);
70+
assertArrayDoesNotInclude(getHashes(), hash, 'Available hashes');
71+
assert.throws(() => { createHash(hash); }, { code: 'ERR_OSSL_EVP_UNSUPPORTED' });
72+
}
73+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
'use strict';
2+
3+
const common = require('../../common');
4+
const { path: fixture } = require('../../common/fixtures');
5+
const providers = require('./providers.cjs');
6+
7+
const assert = require('node:assert');
8+
const { fork } = require('node:child_process');
9+
const option = `--openssl-config=${fixture('openssl3-conf', 'default_only.cnf')}`;
10+
11+
if (!process.execArgv.includes(option)) {
12+
const cp = fork(__filename, { execArgv: [option] });
13+
cp.on('exit', common.mustCall((code, signal) => {
14+
assert.strictEqual(code, 0);
15+
assert.strictEqual(signal, null);
16+
}));
17+
return;
18+
}
19+
20+
providers.testProviderPresent('default');
21+
providers.testProviderAbsent('legacy');
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
'use strict';
2+
3+
const common = require('../../common');
4+
const { path: fixture } = require('../../common/fixtures');
5+
const providers = require('./providers.cjs');
6+
7+
const assert = require('node:assert');
8+
const { fork } = require('node:child_process');
9+
const option = `--openssl-config=${fixture('openssl3-conf', 'legacy_provider_enabled.cnf')}`;
10+
11+
if (!process.execArgv.includes(option)) {
12+
const cp = fork(__filename, { execArgv: [option] });
13+
cp.on('exit', common.mustCall((code, signal) => {
14+
assert.strictEqual(code, 0);
15+
assert.strictEqual(signal, null);
16+
}));
17+
return;
18+
}
19+
20+
providers.testProviderPresent('default');
21+
providers.testProviderPresent('legacy');
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
'use strict';
2+
3+
const common = require('../../common');
4+
const { path: fixture } = require('../../common/fixtures');
5+
const providers = require('./providers.cjs');
6+
7+
const assert = require('node:assert');
8+
const { fork } = require('node:child_process');
9+
const option = `--openssl-config=${fixture('openssl3-conf', 'legacy_provider_inactive.cnf')}`;
10+
11+
if (!process.execArgv.includes(option)) {
12+
const cp = fork(__filename, { execArgv: [option] });
13+
cp.on('exit', common.mustCall((code, signal) => {
14+
assert.strictEqual(code, 0);
15+
assert.strictEqual(signal, null);
16+
}));
17+
return;
18+
}
19+
20+
providers.testProviderPresent('default');
21+
providers.testProviderAbsent('legacy');
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
'use strict';
2+
3+
const common = require('../../common');
4+
const providers = require('./providers.cjs');
5+
const assert = require('node:assert');
6+
const { fork } = require('node:child_process');
7+
const { getFips } = require('node:crypto');
8+
9+
const option = '--openssl-legacy-provider';
10+
const execArgv = process.execArgv;
11+
if (!execArgv.includes(option)) {
12+
const cp = fork(__filename, { execArgv: [ option ] });
13+
cp.on('exit', common.mustCall((code, signal) => {
14+
assert.strictEqual(code, 0);
15+
assert.strictEqual(signal, null);
16+
}));
17+
return;
18+
}
19+
20+
// Enabling FIPS will make all legacy provider algorithms unavailable.
21+
if (getFips()) {
22+
common.skip('this test cannot be run in FIPS mode');
23+
}
24+
providers.testProviderPresent('legacy');
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
'use strict';
2+
3+
const common = require('../../common');
4+
const providers = require('./providers.cjs');
5+
const assert = require('node:assert');
6+
const { fork } = require('node:child_process');
7+
8+
const option = '--no-openssl-legacy-provider';
9+
if (!process.execArgv.includes(option)) {
10+
const cp = fork(__filename, { execArgv: [ option ] });
11+
cp.on('exit', common.mustCall((code, signal) => {
12+
assert.strictEqual(code, 0);
13+
assert.strictEqual(signal, null);
14+
}));
15+
return;
16+
}
17+
18+
providers.testProviderAbsent('legacy');
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
nodejs_conf = nodejs_init
2+
3+
[nodejs_init]
4+
providers = provider_sect
5+
6+
# List of providers to load
7+
[provider_sect]
8+
default = default_sect
9+
10+
[default_sect]
11+
activate = 1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
nodejs_conf = nodejs_init
2+
3+
[nodejs_init]
4+
providers = provider_sect
5+
6+
# List of providers to load
7+
[provider_sect]
8+
default = default_sect
9+
legacy = legacy_sect
10+
11+
[default_sect]
12+
activate = 1
13+
14+
[legacy_sect]
15+
activate = 1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
nodejs_conf = nodejs_init
2+
3+
[nodejs_init]
4+
providers = provider_sect
5+
6+
# List of providers to load
7+
[provider_sect]
8+
default = default_sect
9+
legacy = legacy_sect
10+
11+
[default_sect]
12+
activate = 1
13+
14+
[legacy_sect]
15+
# 'activate' line intentionally omitted -- legacy provider should not be loaded.

0 commit comments

Comments
 (0)