From c446fad9546b92c623fe6c9ea90fd148663dc8e7 Mon Sep 17 00:00:00 2001 From: Robert Nagy Date: Sat, 10 Jul 2021 00:50:56 +0200 Subject: [PATCH 1/5] tls: move legacy code into own file --- lib/_tls_common.js | 5 +- lib/internal/streams/duplexpair.js | 51 -------- lib/internal/tls/legacy.js | 123 ++++++++++++++++++ .../{tls.js => tls/secure-context.js} | 27 ---- lib/tls.js | 51 +------- src/node_native_module.cc | 3 +- test/parallel/test-tls-parse-cert-string.js | 2 +- 7 files changed, 133 insertions(+), 129 deletions(-) delete mode 100644 lib/internal/streams/duplexpair.js create mode 100644 lib/internal/tls/legacy.js rename lib/internal/{tls.js => tls/secure-context.js} (92%) diff --git a/lib/_tls_common.js b/lib/_tls_common.js index 5ca6d65181d0ae..7fe1c20ecd4f8d 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/legacy'); 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 ec92cbe8716df4..00000000000000 --- 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/legacy.js b/lib/internal/tls/legacy.js new file mode 100644 index 00000000000000..35364e0ad2001d --- /dev/null +++ b/lib/internal/tls/legacy.js @@ -0,0 +1,123 @@ +'use strict'; + +const EventEmitter = require('events'); +const { Duplex } = require('stream'); +const internalUtil = require('internal/util'); + +const { + ArrayIsArray, + ArrayPrototypeForEach, + ArrayPrototypePush, + StringPrototypeIndexOf, + StringPrototypeSlice, + StringPrototypeSplit, + ObjectCreate, + 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 = 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(); + } +} + +// 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 = internalUtil.deprecate( + parseCertString, + 'tls.parseCertString() is deprecated. ' + + 'Please use querystring.parse() instead.', + 'DEP0076'); + +exports.createSecurePair = internalUtil.deprecate( + function createSecurePair(...args) { + return ReflectConstruct(SecurePair, args); + }, + 'tls.createSecurePair() is deprecated. Please use ' + + 'tls.TLSSocket instead.', 'DEP0064'); 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 0a9eea8f3eb026..50a68df092c981 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/tls.js b/lib/tls.js index 2282fd33008868..611ac3ed99692a 100644 --- a/lib/tls.js +++ b/lib/tls.js @@ -32,7 +32,6 @@ const { ArrayPrototypeSome, ObjectDefineProperty, ObjectFreeze, - ReflectConstruct, RegExpPrototypeTest, StringFromCharCode, StringPrototypeCharCodeAt, @@ -50,19 +49,17 @@ 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 { parseCertString, createSecurePair } = require('internal/tls/legacy'); // Allow {CLIENT_RENEG_LIMIT} client-initiated session renegotiations // every {CLIENT_RENEG_WINDOW} seconds. An error event is emitted if more @@ -300,53 +297,11 @@ 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; exports.Server = _tls_wrap.Server; exports.createServer = _tls_wrap.createServer; exports.connect = _tls_wrap.connect; - -exports.createSecurePair = internalUtil.deprecate( - function createSecurePair(...args) { - return ReflectConstruct(SecurePair, args); - }, - 'tls.createSecurePair() is deprecated. Please use ' + - 'tls.TLSSocket instead.', 'DEP0064'); +exports.parseCertString = parseCertString; +exports.createSecurePair = createSecurePair; diff --git a/src/node_native_module.cc b/src/node_native_module.cc index a1aff0a9c74889..7c5102525de7e2 100644 --- a/src/node_native_module.cc +++ b/src/node_native_module.cc @@ -99,7 +99,8 @@ void NativeModuleLoader::InitializeModuleCategories() { "tls", "_tls_common", "_tls_wrap", - "internal/tls", + "internal/tls/index", + "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 f5412cad4074c4..d2216f19924ef9 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 internalTLS = require('internal/tls/legacy'); const tls = require('tls'); const noOutput = common.mustNotCall(); From 694677a45efd2468ed341e52455cf0ae2423b529 Mon Sep 17 00:00:00 2001 From: Robert Nagy Date: Sat, 10 Jul 2021 10:09:34 +0200 Subject: [PATCH 2/5] fixup --- lib/internal/tls/legacy.js | 15 ++++----------- lib/tls.js | 13 +++++++++++-- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/lib/internal/tls/legacy.js b/lib/internal/tls/legacy.js index 35364e0ad2001d..8cc1c4fffa6e06 100644 --- a/lib/internal/tls/legacy.js +++ b/lib/internal/tls/legacy.js @@ -109,15 +109,8 @@ function parseCertString(s) { return out; } -exports.parseCertString = internalUtil.deprecate( - parseCertString, - 'tls.parseCertString() is deprecated. ' + - 'Please use querystring.parse() instead.', - 'DEP0076'); +exports.parseCertString = parseCertString; -exports.createSecurePair = internalUtil.deprecate( - function createSecurePair(...args) { - return ReflectConstruct(SecurePair, args); - }, - 'tls.createSecurePair() is deprecated. Please use ' + - 'tls.TLSSocket instead.', 'DEP0064'); +exports.createSecurePair = function createSecurePair(...args) { + return ReflectConstruct(SecurePair, args); +}; diff --git a/lib/tls.js b/lib/tls.js index 611ac3ed99692a..f8fecd73556a03 100644 --- a/lib/tls.js +++ b/lib/tls.js @@ -303,5 +303,14 @@ exports.TLSSocket = _tls_wrap.TLSSocket; exports.Server = _tls_wrap.Server; exports.createServer = _tls_wrap.createServer; exports.connect = _tls_wrap.connect; -exports.parseCertString = parseCertString; -exports.createSecurePair = createSecurePair; + +exports.parseCertString = internalUtil.deprecate( + parseCertString, + 'tls.parseCertString() is deprecated. ' + + 'Please use querystring.parse() instead.', + 'DEP0076'); + +exports.createSecurePair = internalUtil.deprecate( + createSecurePair, + 'tls.createSecurePair() is deprecated. Please use ' + + 'tls.TLSSocket instead.', 'DEP0064'); From be942d6ee968df22a81108bf87df5c8be525671b Mon Sep 17 00:00:00 2001 From: Robert Nagy Date: Sat, 10 Jul 2021 10:32:39 +0200 Subject: [PATCH 3/5] fixup --- lib/internal/tls/legacy.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/internal/tls/legacy.js b/lib/internal/tls/legacy.js index 8cc1c4fffa6e06..5e9c72be202ff7 100644 --- a/lib/internal/tls/legacy.js +++ b/lib/internal/tls/legacy.js @@ -2,7 +2,6 @@ const EventEmitter = require('events'); const { Duplex } = require('stream'); -const internalUtil = require('internal/util'); const { ArrayIsArray, From 61c0d47cb23d718773eadbd6c4522c3fc5b01b51 Mon Sep 17 00:00:00 2001 From: Robert Nagy Date: Sat, 10 Jul 2021 15:16:59 +0200 Subject: [PATCH 4/5] fixup --- lib/internal/tls/legacy.js | 6 ++++-- src/node_native_module.cc | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/internal/tls/legacy.js b/lib/internal/tls/legacy.js index 5e9c72be202ff7..106993261dde34 100644 --- a/lib/internal/tls/legacy.js +++ b/lib/internal/tls/legacy.js @@ -2,6 +2,8 @@ const EventEmitter = require('events'); const { Duplex } = require('stream'); +const _tls_wrap = require('_tls_wrap'); +const _tls_common = require('_tls_common'); const { ArrayIsArray, @@ -58,7 +60,7 @@ class DuplexPair { } class SecurePair extends EventEmitter { - constructor(secureContext = exports.createSecureContext(), + constructor(secureContext = _tls_common.createSecureContext(), isServer = false, requestCert = !isServer, rejectUnauthorized = false, @@ -70,7 +72,7 @@ class SecurePair extends EventEmitter { this.credentials = secureContext; this.encrypted = socket1; - this.cleartext = new exports.TLSSocket(socket2, { + this.cleartext = new _tls_wrap.TLSSocket(socket2, { secureContext, isServer, requestCert, diff --git a/src/node_native_module.cc b/src/node_native_module.cc index 7c5102525de7e2..7c471a32aed87a 100644 --- a/src/node_native_module.cc +++ b/src/node_native_module.cc @@ -99,7 +99,7 @@ void NativeModuleLoader::InitializeModuleCategories() { "tls", "_tls_common", "_tls_wrap", - "internal/tls/index", + "internal/tls/legacy", "internal/tls/secure-context", "internal/http2/core", "internal/http2/compat", From c3bcce7123a2d773a841e35bd60a553af883812e Mon Sep 17 00:00:00 2001 From: Robert Nagy Date: Sat, 10 Jul 2021 21:39:39 +0200 Subject: [PATCH 5/5] fixup --- lib/_tls_common.js | 2 +- lib/internal/tls/parse-cert-string.js | 35 +++++++++++++++++++ .../tls/{legacy.js => secure-pair.js} | 31 ---------------- lib/tls.js | 3 +- src/node_native_module.cc | 3 +- test/parallel/test-tls-parse-cert-string.js | 10 +++--- 6 files changed, 45 insertions(+), 39 deletions(-) create mode 100644 lib/internal/tls/parse-cert-string.js rename lib/internal/tls/{legacy.js => secure-pair.js} (69%) diff --git a/lib/_tls_common.js b/lib/_tls_common.js index 7fe1c20ecd4f8d..21b22a42507c5b 100644 --- a/lib/_tls_common.js +++ b/lib/_tls_common.js @@ -56,7 +56,7 @@ const { const { parseCertString, -} = require('internal/tls/legacy'); +} = require('internal/tls/parse-cert-string'); function toV(which, v, def) { if (v == null) v = def; diff --git a/lib/internal/tls/parse-cert-string.js b/lib/internal/tls/parse-cert-string.js new file mode 100644 index 00000000000000..a499df886097b4 --- /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/legacy.js b/lib/internal/tls/secure-pair.js similarity index 69% rename from lib/internal/tls/legacy.js rename to lib/internal/tls/secure-pair.js index 106993261dde34..b3f0930a3c7118 100644 --- a/lib/internal/tls/legacy.js +++ b/lib/internal/tls/secure-pair.js @@ -6,13 +6,6 @@ const _tls_wrap = require('_tls_wrap'); const _tls_common = require('_tls_common'); const { - ArrayIsArray, - ArrayPrototypeForEach, - ArrayPrototypePush, - StringPrototypeIndexOf, - StringPrototypeSlice, - StringPrototypeSplit, - ObjectCreate, Symbol, ReflectConstruct, } = primordials; @@ -88,30 +81,6 @@ class SecurePair extends EventEmitter { } } -// 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; - exports.createSecurePair = function createSecurePair(...args) { return ReflectConstruct(SecurePair, args); }; diff --git a/lib/tls.js b/lib/tls.js index f8fecd73556a03..683736460b1ef7 100644 --- a/lib/tls.js +++ b/lib/tls.js @@ -59,7 +59,8 @@ const { URL } = require('internal/url'); const { canonicalizeIP } = internalBinding('cares_wrap'); const _tls_common = require('_tls_common'); const _tls_wrap = require('_tls_wrap'); -const { parseCertString, createSecurePair } = require('internal/tls/legacy'); +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 diff --git a/src/node_native_module.cc b/src/node_native_module.cc index 7c471a32aed87a..2642982330e8cf 100644 --- a/src/node_native_module.cc +++ b/src/node_native_module.cc @@ -99,7 +99,8 @@ void NativeModuleLoader::InitializeModuleCategories() { "tls", "_tls_common", "_tls_wrap", - "internal/tls/legacy", + "internal/tls/secure-pair", + "internal/tls/parse-cert-string", "internal/tls/secure-context", "internal/http2/core", "internal/http2/compat", diff --git a/test/parallel/test-tls-parse-cert-string.js b/test/parallel/test-tls-parse-cert-string.js index d2216f19924ef9..c1f32524d578b5 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/legacy'); +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();