From 5960f16713af08892c487beb1c60849a84bfd001 Mon Sep 17 00:00:00 2001 From: Robert Nagy Date: Sat, 10 Jul 2021 00:50:56 +0200 Subject: [PATCH] tls: move legacy code into own file PR-URL: https://github.com/nodejs/node/pull/39333 Reviewed-By: Matteo Collina Reviewed-By: Antoine du Hamel --- lib/_tls_common.js | 5 +- lib/internal/streams/duplexpair.js | 51 ----------- lib/internal/tls/parse-cert-string.js | 35 ++++++++ .../{tls.js => tls/secure-context.js} | 27 ------ lib/internal/tls/secure-pair.js | 86 +++++++++++++++++++ lib/tls.js | 53 ++---------- src/node_native_module.cc | 4 +- test/parallel/test-tls-parse-cert-string.js | 10 +-- 8 files changed, 142 insertions(+), 129 deletions(-) delete mode 100644 lib/internal/streams/duplexpair.js create mode 100644 lib/internal/tls/parse-cert-string.js rename lib/internal/{tls.js => tls/secure-context.js} (92%) create mode 100644 lib/internal/tls/secure-pair.js diff --git a/lib/_tls_common.js b/lib/_tls_common.js index 5ca6d65181d..21b22a42507 100644 --- a/lib/_tls_common.js +++ b/lib/_tls_common.js @@ -52,8 +52,11 @@ const { const { configSecureContext, +} = require('internal/tls/secure-context'); + +const { parseCertString, -} = require('internal/tls'); +} = require('internal/tls/parse-cert-string'); function toV(which, v, def) { if (v == null) v = def; diff --git a/lib/internal/streams/duplexpair.js b/lib/internal/streams/duplexpair.js deleted file mode 100644 index ec92cbe8716..00000000000 --- a/lib/internal/streams/duplexpair.js +++ /dev/null @@ -1,51 +0,0 @@ -'use strict'; - -const { - Symbol, -} = primordials; - -const { Duplex } = require('stream'); - -const kCallback = Symbol('Callback'); -const kOtherSide = Symbol('Other'); - -class DuplexSocket extends Duplex { - constructor() { - super(); - this[kCallback] = null; - this[kOtherSide] = null; - } - - _read() { - const callback = this[kCallback]; - if (callback) { - this[kCallback] = null; - callback(); - } - } - - _write(chunk, encoding, callback) { - if (chunk.length === 0) { - process.nextTick(callback); - } else { - this[kOtherSide].push(chunk); - this[kOtherSide][kCallback] = callback; - } - } - - _final(callback) { - this[kOtherSide].on('end', callback); - this[kOtherSide].push(null); - } -} - -class DuplexPair { - constructor() { - this.socket1 = new DuplexSocket(); - this.socket2 = new DuplexSocket(); - this.socket1[kOtherSide] = this.socket2; - this.socket2[kOtherSide] = this.socket1; - } -} - -module.exports = DuplexPair; diff --git a/lib/internal/tls/parse-cert-string.js b/lib/internal/tls/parse-cert-string.js new file mode 100644 index 00000000000..a499df88609 --- /dev/null +++ b/lib/internal/tls/parse-cert-string.js @@ -0,0 +1,35 @@ +'use strict'; + +const { + ArrayIsArray, + ArrayPrototypeForEach, + ArrayPrototypePush, + StringPrototypeIndexOf, + StringPrototypeSlice, + StringPrototypeSplit, + ObjectCreate, +} = primordials; + +// Example: +// C=US\nST=CA\nL=SF\nO=Joyent\nOU=Node.js\nCN=ca1\nemailAddress=ry@clouds.org +function parseCertString(s) { + const out = ObjectCreate(null); + ArrayPrototypeForEach(StringPrototypeSplit(s, '\n'), (part) => { + const sepIndex = StringPrototypeIndexOf(part, '='); + if (sepIndex > 0) { + const key = StringPrototypeSlice(part, 0, sepIndex); + const value = StringPrototypeSlice(part, sepIndex + 1); + if (key in out) { + if (!ArrayIsArray(out[key])) { + out[key] = [out[key]]; + } + ArrayPrototypePush(out[key], value); + } else { + out[key] = value; + } + } + }); + return out; +} + +exports.parseCertString = parseCertString; diff --git a/lib/internal/tls.js b/lib/internal/tls/secure-context.js similarity index 92% rename from lib/internal/tls.js rename to lib/internal/tls/secure-context.js index 0a9eea8f3eb..50a68df092c 100644 --- a/lib/internal/tls.js +++ b/lib/internal/tls/secure-context.js @@ -5,12 +5,8 @@ const { ArrayPrototypeFilter, ArrayPrototypeForEach, ArrayPrototypeJoin, - ArrayPrototypePush, - StringPrototypeIndexOf, - StringPrototypeSlice, StringPrototypeSplit, StringPrototypeStartsWith, - ObjectCreate, } = primordials; const { @@ -42,28 +38,6 @@ const { }, } = internalBinding('constants'); -// Example: -// C=US\nST=CA\nL=SF\nO=Joyent\nOU=Node.js\nCN=ca1\nemailAddress=ry@clouds.org -function parseCertString(s) { - const out = ObjectCreate(null); - ArrayPrototypeForEach(StringPrototypeSplit(s, '\n'), (part) => { - const sepIndex = StringPrototypeIndexOf(part, '='); - if (sepIndex > 0) { - const key = StringPrototypeSlice(part, 0, sepIndex); - const value = StringPrototypeSlice(part, sepIndex + 1); - if (key in out) { - if (!ArrayIsArray(out[key])) { - out[key] = [out[key]]; - } - ArrayPrototypePush(out[key], value); - } else { - out[key] = value; - } - } - }); - return out; -} - function getDefaultEcdhCurve() { // We do it this way because DEFAULT_ECDH_CURVE can be // changed by users, so we need to grab the current @@ -340,5 +314,4 @@ function configSecureContext(context, options = {}, name = 'options') { module.exports = { configSecureContext, - parseCertString, }; diff --git a/lib/internal/tls/secure-pair.js b/lib/internal/tls/secure-pair.js new file mode 100644 index 00000000000..b3f0930a3c7 --- /dev/null +++ b/lib/internal/tls/secure-pair.js @@ -0,0 +1,86 @@ +'use strict'; + +const EventEmitter = require('events'); +const { Duplex } = require('stream'); +const _tls_wrap = require('_tls_wrap'); +const _tls_common = require('_tls_common'); + +const { + Symbol, + ReflectConstruct, +} = primordials; + +const kCallback = Symbol('Callback'); +const kOtherSide = Symbol('Other'); + +class DuplexSocket extends Duplex { + constructor() { + super(); + this[kCallback] = null; + this[kOtherSide] = null; + } + + _read() { + const callback = this[kCallback]; + if (callback) { + this[kCallback] = null; + callback(); + } + } + + _write(chunk, encoding, callback) { + if (chunk.length === 0) { + process.nextTick(callback); + } else { + this[kOtherSide].push(chunk); + this[kOtherSide][kCallback] = callback; + } + } + + _final(callback) { + this[kOtherSide].on('end', callback); + this[kOtherSide].push(null); + } +} + +class DuplexPair { + constructor() { + this.socket1 = new DuplexSocket(); + this.socket2 = new DuplexSocket(); + this.socket1[kOtherSide] = this.socket2; + this.socket2[kOtherSide] = this.socket1; + } +} + +class SecurePair extends EventEmitter { + constructor(secureContext = _tls_common.createSecureContext(), + isServer = false, + requestCert = !isServer, + rejectUnauthorized = false, + options = {}) { + super(); + const { socket1, socket2 } = new DuplexPair(); + + this.server = options.server; + this.credentials = secureContext; + + this.encrypted = socket1; + this.cleartext = new _tls_wrap.TLSSocket(socket2, { + secureContext, + isServer, + requestCert, + rejectUnauthorized, + ...options + }); + this.cleartext.once('secure', () => this.emit('secure')); + } + + destroy() { + this.cleartext.destroy(); + this.encrypted.destroy(); + } +} + +exports.createSecurePair = function createSecurePair(...args) { + return ReflectConstruct(SecurePair, args); +}; diff --git a/lib/tls.js b/lib/tls.js index 2282fd33008..683736460b1 100644 --- a/lib/tls.js +++ b/lib/tls.js @@ -32,7 +32,6 @@ const { ArrayPrototypeSome, ObjectDefineProperty, ObjectFreeze, - ReflectConstruct, RegExpPrototypeTest, StringFromCharCode, StringPrototypeCharCodeAt, @@ -50,19 +49,18 @@ const { } = require('internal/errors').codes; const internalUtil = require('internal/util'); internalUtil.assertCrypto(); -const internalTLS = require('internal/tls'); const { isArrayBufferView } = require('internal/util/types'); const net = require('net'); const { getOptionValue } = require('internal/options'); const { getRootCertificates, getSSLCiphers } = internalBinding('crypto'); const { Buffer } = require('buffer'); -const EventEmitter = require('events'); const { URL } = require('internal/url'); -const DuplexPair = require('internal/streams/duplexpair'); const { canonicalizeIP } = internalBinding('cares_wrap'); const _tls_common = require('_tls_common'); const _tls_wrap = require('_tls_wrap'); +const { createSecurePair } = require('internal/tls/secure-pair'); +const { parseCertString } = require('internal/tls/parse-cert-string'); // Allow {CLIENT_RENEG_LIMIT} client-initiated session renegotiations // every {CLIENT_RENEG_WINDOW} seconds. An error event is emitted if more @@ -300,43 +298,6 @@ exports.checkServerIdentity = function checkServerIdentity(hostname, cert) { } }; - -class SecurePair extends EventEmitter { - constructor(secureContext = exports.createSecureContext(), - isServer = false, - requestCert = !isServer, - rejectUnauthorized = false, - options = {}) { - super(); - const { socket1, socket2 } = new DuplexPair(); - - this.server = options.server; - this.credentials = secureContext; - - this.encrypted = socket1; - this.cleartext = new exports.TLSSocket(socket2, { - secureContext, - isServer, - requestCert, - rejectUnauthorized, - ...options - }); - this.cleartext.once('secure', () => this.emit('secure')); - } - - destroy() { - this.cleartext.destroy(); - this.encrypted.destroy(); - } -} - - -exports.parseCertString = internalUtil.deprecate( - internalTLS.parseCertString, - 'tls.parseCertString() is deprecated. ' + - 'Please use querystring.parse() instead.', - 'DEP0076'); - exports.createSecureContext = _tls_common.createSecureContext; exports.SecureContext = _tls_common.SecureContext; exports.TLSSocket = _tls_wrap.TLSSocket; @@ -344,9 +305,13 @@ exports.Server = _tls_wrap.Server; exports.createServer = _tls_wrap.createServer; exports.connect = _tls_wrap.connect; +exports.parseCertString = internalUtil.deprecate( + parseCertString, + 'tls.parseCertString() is deprecated. ' + + 'Please use querystring.parse() instead.', + 'DEP0076'); + exports.createSecurePair = internalUtil.deprecate( - function createSecurePair(...args) { - return ReflectConstruct(SecurePair, args); - }, + createSecurePair, 'tls.createSecurePair() is deprecated. Please use ' + 'tls.TLSSocket instead.', 'DEP0064'); diff --git a/src/node_native_module.cc b/src/node_native_module.cc index a1aff0a9c74..2642982330e 100644 --- a/src/node_native_module.cc +++ b/src/node_native_module.cc @@ -99,7 +99,9 @@ void NativeModuleLoader::InitializeModuleCategories() { "tls", "_tls_common", "_tls_wrap", - "internal/tls", + "internal/tls/secure-pair", + "internal/tls/parse-cert-string", + "internal/tls/secure-context", "internal/http2/core", "internal/http2/compat", "internal/policy/manifest", diff --git a/test/parallel/test-tls-parse-cert-string.js b/test/parallel/test-tls-parse-cert-string.js index f5412cad407..c1f32524d57 100644 --- a/test/parallel/test-tls-parse-cert-string.js +++ b/test/parallel/test-tls-parse-cert-string.js @@ -11,7 +11,7 @@ const { } = require('../common/hijackstdio'); const assert = require('assert'); // Flags: --expose-internals -const internalTLS = require('internal/tls'); +const { parseCertString } = require('internal/tls/parse-cert-string'); const tls = require('tls'); const noOutput = common.mustNotCall(); @@ -20,7 +20,7 @@ hijackStderr(noOutput); { const singles = 'C=US\nST=CA\nL=SF\nO=Node.js Foundation\nOU=Node.js\n' + 'CN=ca1\nemailAddress=ry@clouds.org'; - const singlesOut = internalTLS.parseCertString(singles); + const singlesOut = parseCertString(singles); assert.deepStrictEqual(singlesOut, { __proto__: null, C: 'US', @@ -36,7 +36,7 @@ hijackStderr(noOutput); { const doubles = 'OU=Domain Control Validated\nOU=PositiveSSL Wildcard\n' + 'CN=*.nodejs.org'; - const doublesOut = internalTLS.parseCertString(doubles); + const doublesOut = parseCertString(doubles); assert.deepStrictEqual(doublesOut, { __proto__: null, OU: [ 'Domain Control Validated', 'PositiveSSL Wildcard' ], @@ -46,7 +46,7 @@ hijackStderr(noOutput); { const invalid = 'fhqwhgads'; - const invalidOut = internalTLS.parseCertString(invalid); + const invalidOut = parseCertString(invalid); assert.deepStrictEqual(invalidOut, { __proto__: null }); } @@ -55,7 +55,7 @@ hijackStderr(noOutput); const expected = Object.create(null); expected.__proto__ = 'mostly harmless'; expected.hasOwnProperty = 'not a function'; - assert.deepStrictEqual(internalTLS.parseCertString(input), expected); + assert.deepStrictEqual(parseCertString(input), expected); } restoreStderr();