fix(ext/node): allow rejectUnauthorized: false in node:tls (#29245)

Fix #29228

Allow disable TLS cert verification using `options.rejectUnauthorized`.
If passed. `--unsafely-ignore-certificate-errors` overrides
`rejectUnauthorized: false`
This commit is contained in:
Divy Srivastava 2025-05-13 17:43:58 +05:30 committed by GitHub
parent 1022decc79
commit 6002d2624e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 195 additions and 9 deletions

View file

@ -181,12 +181,29 @@ async function startTls(
caCerts = [],
alpnProtocols = undefined,
} = { __proto__: null },
) {
return startTlsInternal(conn, {
hostname,
caCerts,
alpnProtocols,
});
}
function startTlsInternal(
conn,
{
hostname = "127.0.0.1",
caCerts = [],
alpnProtocols = undefined,
rejectUnauthorized,
},
) {
const { 0: rid, 1: localAddr, 2: remoteAddr } = op_tls_start({
rid: conn[internalRidSymbol],
hostname,
caCerts,
alpnProtocols,
rejectUnauthorized,
}, null);
return new TlsConn(rid, remoteAddr, localAddr);
}
@ -228,6 +245,7 @@ export {
listenTls,
loadTlsKeyPair,
startTls,
startTlsInternal,
TlsConn,
TlsListener,
};

View file

@ -188,6 +188,7 @@ pub struct StartTlsArgs {
ca_certs: Vec<String>,
hostname: String,
alpn_protocols: Option<Vec<String>>,
reject_unauthorized: Option<bool>,
}
#[op2]
@ -264,6 +265,7 @@ where
NP: NetPermissions + 'static,
{
let rid = args.rid;
let reject_unauthorized = args.reject_unauthorized.unwrap_or(true);
let hostname = match &*args.hostname {
"" => "localhost".to_string(),
n => n.to_string(),
@ -278,10 +280,15 @@ where
let hostname_dns = ServerName::try_from(hostname.to_string())
.map_err(|_| NetError::InvalidHostname(hostname))?;
let unsafely_ignore_certificate_errors = state
// --unsafely-ignore-certificate-errors overrides the `rejectUnauthorized` option.
let unsafely_ignore_certificate_errors = if reject_unauthorized {
state
.borrow()
.try_borrow::<UnsafelyIgnoreCertificateErrors>()
.and_then(|it| it.0.clone());
.and_then(|it| it.0.clone())
} else {
Some(Vec::new())
};
let root_cert_store = state
.borrow()

View file

@ -31,6 +31,7 @@ import {
isAnyArrayBuffer,
isArrayBufferView,
} from "ext:deno_node/internal/util/types.ts";
import { startTlsInternal } from "ext:deno_net/02_tls.js";
const kConnectOptions = Symbol("connect-options");
const kIsVerified = Symbol("verified");
@ -99,6 +100,7 @@ export class TLSSocket extends net.Socket {
}
tlsOptions.caCerts = caCerts;
tlsOptions.alpnProtocols = opts.ALPNProtocols;
tlsOptions.rejectUnauthorized = opts.rejectUnauthorized !== false;
super({
handle: _wrapHandle(tlsOptions, socket),
@ -163,7 +165,10 @@ export class TLSSocket extends net.Socket {
}
try {
const conn = await Deno.startTls(handle[kStreamBaseField], options);
const conn = await startTlsInternal(
handle[kStreamBaseField],
options,
);
try {
const hs = await conn.handshake();
if (hs.alpnProtocol) {

View file

@ -1206,6 +1206,9 @@
"test-tls-alert-handling.js",
"test-tls-alert.js",
"test-tls-client-renegotiation-limit.js",
"test-tls-connect-hwm-option.js",
"test-tls-connect-simple.js",
"test-tls-connect-timeout-option.js",
"test-tls-dhe.js",
"test-tls-ecdh-auto.js",
"test-tls-ecdh-multiple.js",

View file

@ -1,7 +1,7 @@
<!-- deno-fmt-ignore-file -->
# Remaining Node Tests
1169 tests out of 3993 have been ported from Node 23.9.0 (29.28% ported, 71.25% remaining).
1172 tests out of 3993 have been ported from Node 23.9.0 (29.35% ported, 71.17% remaining).
NOTE: This file should not be manually edited. Please edit `tests/node_compat/config.json` and run `deno task setup` in `tests/node_compat/runner` dir instead.
@ -2183,14 +2183,11 @@ NOTE: This file should not be manually edited. Please edit `tests/node_compat/co
- [parallel/test-tls-connect-allow-half-open-option.js](https://github.com/nodejs/node/tree/v23.9.0/test/parallel/test-tls-connect-allow-half-open-option.js)
- [parallel/test-tls-connect-given-socket.js](https://github.com/nodejs/node/tree/v23.9.0/test/parallel/test-tls-connect-given-socket.js)
- [parallel/test-tls-connect-hints-option.js](https://github.com/nodejs/node/tree/v23.9.0/test/parallel/test-tls-connect-hints-option.js)
- [parallel/test-tls-connect-hwm-option.js](https://github.com/nodejs/node/tree/v23.9.0/test/parallel/test-tls-connect-hwm-option.js)
- [parallel/test-tls-connect-memleak.js](https://github.com/nodejs/node/tree/v23.9.0/test/parallel/test-tls-connect-memleak.js)
- [parallel/test-tls-connect-no-host.js](https://github.com/nodejs/node/tree/v23.9.0/test/parallel/test-tls-connect-no-host.js)
- [parallel/test-tls-connect-pipe.js](https://github.com/nodejs/node/tree/v23.9.0/test/parallel/test-tls-connect-pipe.js)
- [parallel/test-tls-connect-secure-context.js](https://github.com/nodejs/node/tree/v23.9.0/test/parallel/test-tls-connect-secure-context.js)
- [parallel/test-tls-connect-simple.js](https://github.com/nodejs/node/tree/v23.9.0/test/parallel/test-tls-connect-simple.js)
- [parallel/test-tls-connect-stream-writes.js](https://github.com/nodejs/node/tree/v23.9.0/test/parallel/test-tls-connect-stream-writes.js)
- [parallel/test-tls-connect-timeout-option.js](https://github.com/nodejs/node/tree/v23.9.0/test/parallel/test-tls-connect-timeout-option.js)
- [parallel/test-tls-delayed-attach-error.js](https://github.com/nodejs/node/tree/v23.9.0/test/parallel/test-tls-delayed-attach-error.js)
- [parallel/test-tls-delayed-attach.js](https://github.com/nodejs/node/tree/v23.9.0/test/parallel/test-tls-delayed-attach.js)
- [parallel/test-tls-destroy-stream-12.js](https://github.com/nodejs/node/tree/v23.9.0/test/parallel/test-tls-destroy-stream-12.js)

View file

@ -0,0 +1,60 @@
// deno-fmt-ignore-file
// deno-lint-ignore-file
// Copyright Joyent and Node contributors. All rights reserved. MIT license.
// Taken from Node 23.9.0
// This file is automatically generated by `tests/node_compat/runner/setup.ts`. Do not modify this file manually.
'use strict';
const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');
const assert = require('assert');
const tls = require('tls');
const fixtures = require('../common/fixtures');
const pem = (n) => fixtures.readKey(`${n}.pem`);
let clients = 0;
const server = tls.createServer({
key: pem('agent1-key'),
cert: pem('agent1-cert')
}, common.mustCall(() => {
if (--clients === 0)
server.close();
}, 3));
server.listen(0, common.mustCall(() => {
clients++;
const highBob = tls.connect({
port: server.address().port,
rejectUnauthorized: false,
highWaterMark: 128000,
}, common.mustCall(() => {
assert.strictEqual(highBob.readableHighWaterMark, 128000);
highBob.end();
}));
clients++;
const defaultHighBob = tls.connect({
port: server.address().port,
rejectUnauthorized: false,
highWaterMark: undefined,
}, common.mustCall(() => {
assert.strictEqual(defaultHighBob.readableHighWaterMark, process.platform === 'win32' ? 16 * 1024 : 64 * 1024);
defaultHighBob.end();
}));
clients++;
const zeroHighBob = tls.connect({
port: server.address().port,
rejectUnauthorized: false,
highWaterMark: 0,
}, common.mustCall(() => {
assert.strictEqual(zeroHighBob.readableHighWaterMark, 0);
zeroHighBob.end();
}));
}));

View file

@ -0,0 +1,69 @@
// deno-fmt-ignore-file
// deno-lint-ignore-file
// Copyright Joyent and Node contributors. All rights reserved. MIT license.
// Taken from Node 23.9.0
// This file is automatically generated by `tests/node_compat/runner/setup.ts`. Do not modify this file manually.
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
'use strict';
const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');
const tls = require('tls');
const fixtures = require('../common/fixtures');
let serverConnected = 0;
const options = {
key: fixtures.readKey('agent1-key.pem'),
cert: fixtures.readKey('agent1-cert.pem')
};
const server = tls.Server(options, common.mustCall(function(socket) {
if (++serverConnected === 2) {
server.close(common.mustCall());
server.on('close', common.mustCall());
}
}, 2));
server.listen(0, function() {
const client1options = {
port: this.address().port,
rejectUnauthorized: false
};
const client1 = tls.connect(client1options, common.mustCall(function() {
client1.end();
}));
const client2options = {
port: this.address().port,
rejectUnauthorized: false
};
const client2 = tls.connect(client2options);
client2.on('secureConnect', common.mustCall(function() {
client2.end();
}));
});

View file

@ -0,0 +1,27 @@
// deno-fmt-ignore-file
// deno-lint-ignore-file
// Copyright Joyent and Node contributors. All rights reserved. MIT license.
// Taken from Node 23.9.0
// This file is automatically generated by `tests/node_compat/runner/setup.ts`. Do not modify this file manually.
'use strict';
const common = require('../common');
// This test verifies that `tls.connect()` honors the `timeout` option when the
// socket is internally created.
if (!common.hasCrypto)
common.skip('missing crypto');
const assert = require('assert');
const tls = require('tls');
const socket = tls.connect({
port: 42,
lookup: () => {},
timeout: 1000
});
assert.strictEqual(socket.timeout, 1000);