tls: move legacy code into own file

PR-URL: https://github.com/nodejs/node/pull/39333
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
This commit is contained in:
Robert Nagy 2021-07-10 00:50:56 +02:00
parent bb275ef2a4
commit 5960f16713
8 changed files with 142 additions and 129 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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,
};

View File

@ -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);
};

View File

@ -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');

View File

@ -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",

View File

@ -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();