Skip to content

Commit b20409e

Browse files
aduh95danielleadams
authored andcommitted
tls: refactor to use more primordials
PR-URL: #36266 Reviewed-By: Rich Trott <rtrott@gmail.com>
1 parent 9cb53f6 commit b20409e

File tree

4 files changed

+91
-59
lines changed

4 files changed

+91
-59
lines changed

lib/_tls_common.js

+9-6
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ const {
2525
ArrayIsArray,
2626
ArrayPrototypeFilter,
2727
ArrayPrototypeJoin,
28+
ArrayPrototypePush,
2829
ObjectCreate,
30+
StringPrototypeReplace,
2931
StringPrototypeSplit,
3032
StringPrototypeStartsWith,
3133
} = primordials;
@@ -392,12 +394,13 @@ exports.translatePeerCertificate = function translatePeerCertificate(c) {
392394
c.infoAccess = ObjectCreate(null);
393395

394396
// XXX: More key validation?
395-
info.replace(/([^\n:]*):([^\n]*)(?:\n|$)/g, (all, key, val) => {
396-
if (key in c.infoAccess)
397-
c.infoAccess[key].push(val);
398-
else
399-
c.infoAccess[key] = [val];
400-
});
397+
StringPrototypeReplace(info, /([^\n:]*):([^\n]*)(?:\n|$)/g,
398+
(all, key, val) => {
399+
if (key in c.infoAccess)
400+
ArrayPrototypePush(c.infoAccess[key], val);
401+
else
402+
c.infoAccess[key] = [val];
403+
});
401404
}
402405
return c;
403406
};

lib/_tls_wrap.js

+35-25
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,18 @@
2222
'use strict';
2323

2424
const {
25+
ArrayPrototypeForEach,
26+
ArrayPrototypeJoin,
27+
ArrayPrototypePush,
28+
FunctionPrototype,
2529
ObjectAssign,
2630
ObjectDefineProperty,
2731
ObjectSetPrototypeOf,
32+
ReflectApply,
2833
RegExp,
34+
RegExpPrototypeTest,
35+
StringPrototypeReplace,
36+
StringPrototypeSlice,
2937
Symbol,
3038
SymbolFor,
3139
} = primordials;
@@ -96,7 +104,7 @@ const kPskIdentityHint = Symbol('pskidentityhint');
96104
const kPendingSession = Symbol('pendingSession');
97105
const kIsVerified = Symbol('verified');
98106

99-
const noop = () => {};
107+
const noop = FunctionPrototype;
100108

101109
let ipServernameWarned = false;
102110
let tlsTracingWarned = false;
@@ -408,7 +416,8 @@ function onerror(err) {
408416
owner.destroy(err);
409417
} else if (owner._tlsOptions.isServer &&
410418
owner._rejectUnauthorized &&
411-
/peer did not return a certificate/.test(err.message)) {
419+
RegExpPrototypeTest(/peer did not return a certificate/,
420+
err.message)) {
412421
// Ignore server's authorization errors
413422
owner.destroy();
414423
} else {
@@ -496,14 +505,14 @@ function TLSSocket(socket, opts) {
496505
// distinguishable from regular ones.
497506
this.encrypted = true;
498507

499-
net.Socket.call(this, {
508+
ReflectApply(net.Socket, this, [{
500509
handle: this._wrapHandle(wrap),
501510
allowHalfOpen: socket ? socket.allowHalfOpen : tlsOptions.allowHalfOpen,
502511
pauseOnCreate: tlsOptions.pauseOnConnect,
503512
manualStart: true,
504513
highWaterMark: tlsOptions.highWaterMark,
505514
onread: !socket ? tlsOptions.onread : null,
506-
});
515+
}]);
507516

508517
// Proxy for API compatibility
509518
this.ssl = this._handle; // C++ TLSWrap object
@@ -535,7 +544,7 @@ const proxiedMethods = [
535544
function makeMethodProxy(name) {
536545
return function methodProxy(...args) {
537546
if (this._parent[name])
538-
return this._parent[name].apply(this._parent, args);
547+
return ReflectApply(this._parent[name], this._parent, args);
539548
};
540549
}
541550
for (const proxiedMethod of proxiedMethods) {
@@ -993,12 +1002,12 @@ TLSSocket.prototype.getCertificate = function() {
9931002
function makeSocketMethodProxy(name) {
9941003
return function socketMethodProxy(...args) {
9951004
if (this._handle)
996-
return this._handle[name].apply(this._handle, args);
1005+
return ReflectApply(this._handle[name], this._handle, args);
9971006
return null;
9981007
};
9991008
}
10001009

1001-
[
1010+
ArrayPrototypeForEach([
10021011
'getCipher',
10031012
'getSharedSigalgs',
10041013
'getEphemeralKeyInfo',
@@ -1009,7 +1018,7 @@ function makeSocketMethodProxy(name) {
10091018
'getTLSTicket',
10101019
'isSessionReused',
10111020
'enableTrace',
1012-
].forEach((method) => {
1021+
], (method) => {
10131022
TLSSocket.prototype[method] = makeSocketMethodProxy(method);
10141023
});
10151024

@@ -1209,7 +1218,7 @@ function Server(options, listener) {
12091218
}
12101219

12111220
// constructor call
1212-
net.Server.call(this, options, tlsConnectionListener);
1221+
ReflectApply(net.Server, this, [options, tlsConnectionListener]);
12131222

12141223
if (listener) {
12151224
this.on('secureConnection', listener);
@@ -1309,10 +1318,10 @@ Server.prototype.setSecureContext = function(options) {
13091318
if (options.sessionIdContext) {
13101319
this.sessionIdContext = options.sessionIdContext;
13111320
} else {
1312-
this.sessionIdContext = crypto.createHash('sha1')
1313-
.update(process.argv.join(' '))
1314-
.digest('hex')
1315-
.slice(0, 32);
1321+
this.sessionIdContext = StringPrototypeSlice(
1322+
crypto.createHash('sha1')
1323+
.update(ArrayPrototypeJoin(process.argv, ' '))
1324+
.digest('hex'), 0, 32);
13161325
}
13171326

13181327
if (options.sessionTimeout)
@@ -1399,10 +1408,10 @@ Server.prototype.setOptions = deprecate(function(options) {
13991408
if (options.sessionIdContext) {
14001409
this.sessionIdContext = options.sessionIdContext;
14011410
} else {
1402-
this.sessionIdContext = crypto.createHash('sha1')
1403-
.update(process.argv.join(' '))
1404-
.digest('hex')
1405-
.slice(0, 32);
1411+
this.sessionIdContext = StringPrototypeSlice(
1412+
crypto.createHash('sha1')
1413+
.update(ArrayPrototypeJoin(process.argv, ' '))
1414+
.digest('hex'), 0, 32);
14061415
}
14071416
if (options.pskCallback) this[kPskCallback] = options.pskCallback;
14081417
if (options.pskIdentityHint) this[kPskIdentityHint] = options.pskIdentityHint;
@@ -1414,11 +1423,12 @@ Server.prototype.addContext = function(servername, context) {
14141423
throw new ERR_TLS_REQUIRED_SERVER_NAME();
14151424
}
14161425

1417-
const re = new RegExp('^' +
1418-
servername.replace(/([.^$+?\-\\[\]{}])/g, '\\$1')
1419-
.replace(/\*/g, '[^.]*') +
1420-
'$');
1421-
this._contexts.push([re, tls.createSecureContext(context).context]);
1426+
const re = new RegExp('^' + StringPrototypeReplace(
1427+
StringPrototypeReplace(servername, /([.^$+?\-\\[\]{}])/g, '\\$1'),
1428+
/\*/g, '[^.]*'
1429+
) + '$');
1430+
ArrayPrototypePush(this._contexts,
1431+
[re, tls.createSecureContext(context).context]);
14221432
};
14231433

14241434
Server.prototype[EE.captureRejectionSymbol] = function(
@@ -1429,16 +1439,16 @@ Server.prototype[EE.captureRejectionSymbol] = function(
14291439
sock.destroy(err);
14301440
break;
14311441
default:
1432-
net.Server.prototype[SymbolFor('nodejs.rejection')]
1433-
.call(this, err, event, sock);
1442+
ReflectApply(net.Server.prototype[SymbolFor('nodejs.rejection')], this,
1443+
[err, event, sock]);
14341444
}
14351445
};
14361446

14371447
function SNICallback(servername, callback) {
14381448
const contexts = this.server._contexts;
14391449

14401450
for (const elem of contexts) {
1441-
if (elem[0].test(servername)) {
1451+
if (RegExpPrototypeTest(elem[0], servername)) {
14421452
callback(null, elem[1]);
14431453
return;
14441454
}

lib/internal/tls.js

+9-5
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,27 @@
22

33
const {
44
ArrayIsArray,
5+
ArrayPrototypePush,
6+
StringPrototypeIndexOf,
7+
StringPrototypeSlice,
8+
StringPrototypeSplit,
59
ObjectCreate,
610
} = primordials;
711

812
// Example:
913
// C=US\nST=CA\nL=SF\nO=Joyent\nOU=Node.js\nCN=ca1\nemailAddress=ry@clouds.org
1014
function parseCertString(s) {
1115
const out = ObjectCreate(null);
12-
for (const part of s.split('\n')) {
13-
const sepIndex = part.indexOf('=');
16+
for (const part of StringPrototypeSplit(s, '\n')) {
17+
const sepIndex = StringPrototypeIndexOf(part, '=');
1418
if (sepIndex > 0) {
15-
const key = part.slice(0, sepIndex);
16-
const value = part.slice(sepIndex + 1);
19+
const key = StringPrototypeSlice(part, 0, sepIndex);
20+
const value = StringPrototypeSlice(part, sepIndex + 1);
1721
if (key in out) {
1822
if (!ArrayIsArray(out[key])) {
1923
out[key] = [out[key]];
2024
}
21-
out[key].push(value);
25+
ArrayPrototypePush(out[key], value);
2226
} else {
2327
out[key] = value;
2428
}

lib/tls.js

+38-23
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,22 @@
2424
const {
2525
Array,
2626
ArrayIsArray,
27+
ArrayPrototypeIncludes,
28+
ArrayPrototypeJoin,
29+
ArrayPrototypePush,
30+
ArrayPrototypeReduce,
31+
ArrayPrototypeSome,
2732
ObjectDefineProperty,
2833
ObjectFreeze,
34+
RegExpPrototypeTest,
2935
StringFromCharCode,
3036
StringPrototypeCharCodeAt,
37+
StringPrototypeEndsWith,
38+
StringPrototypeIncludes,
3139
StringPrototypeReplace,
40+
StringPrototypeSlice,
3241
StringPrototypeSplit,
42+
StringPrototypeStartsWith,
3343
} = primordials;
3444

3545
const {
@@ -107,7 +117,7 @@ ObjectDefineProperty(exports, 'rootCertificates', {
107117
// ("\x06spdy/2\x08http/1.1\x08http/1.0")
108118
function convertProtocols(protocols) {
109119
const lens = new Array(protocols.length);
110-
const buff = Buffer.allocUnsafe(protocols.reduce((p, c, i) => {
120+
const buff = Buffer.allocUnsafe(ArrayPrototypeReduce(protocols, (p, c, i) => {
111121
const len = Buffer.byteLength(c);
112122
if (len > 255) {
113123
throw new ERR_OUT_OF_RANGE('The byte length of the protocol at index ' +
@@ -138,7 +148,7 @@ exports.convertALPNProtocols = function convertALPNProtocols(protocols, out) {
138148
};
139149

140150
function unfqdn(host) {
141-
return host.replace(/[.]$/, '');
151+
return StringPrototypeReplace(host, /[.]$/, '');
142152
}
143153

144154
// String#toLowerCase() is locale-sensitive so we use
@@ -165,15 +175,15 @@ function check(hostParts, pattern, wildcards) {
165175
return false;
166176

167177
// Pattern has empty components, e.g. "bad..example.com".
168-
if (patternParts.includes(''))
178+
if (ArrayPrototypeIncludes(patternParts, ''))
169179
return false;
170180

171181
// RFC 6125 allows IDNA U-labels (Unicode) in names but we have no
172182
// good way to detect their encoding or normalize them so we simply
173183
// reject them. Control characters and blanks are rejected as well
174184
// because nothing good can come from accepting them.
175-
const isBad = (s) => /[^\u0021-\u007F]/u.test(s);
176-
if (patternParts.some(isBad))
185+
const isBad = (s) => RegExpPrototypeTest(/[^\u0021-\u007F]/u, s);
186+
if (ArrayPrototypeSome(patternParts, isBad))
177187
return false;
178188

179189
// Check host parts from right to left first.
@@ -184,12 +194,13 @@ function check(hostParts, pattern, wildcards) {
184194

185195
const hostSubdomain = hostParts[0];
186196
const patternSubdomain = patternParts[0];
187-
const patternSubdomainParts = patternSubdomain.split('*');
197+
const patternSubdomainParts = StringPrototypeSplit(patternSubdomain, '*');
188198

189199
// Short-circuit when the subdomain does not contain a wildcard.
190200
// RFC 6125 does not allow wildcard substitution for components
191201
// containing IDNA A-labels (Punycode) so match those verbatim.
192-
if (patternSubdomainParts.length === 1 || patternSubdomain.includes('xn--'))
202+
if (patternSubdomainParts.length === 1 ||
203+
StringPrototypeIncludes(patternSubdomain, 'xn--'))
193204
return hostSubdomain === patternSubdomain;
194205

195206
if (!wildcards)
@@ -208,10 +219,10 @@ function check(hostParts, pattern, wildcards) {
208219
if (prefix.length + suffix.length > hostSubdomain.length)
209220
return false;
210221

211-
if (!hostSubdomain.startsWith(prefix))
222+
if (!StringPrototypeStartsWith(hostSubdomain, prefix))
212223
return false;
213224

214-
if (!hostSubdomain.endsWith(suffix))
225+
if (!StringPrototypeEndsWith(hostSubdomain, suffix))
215226
return false;
216227

217228
return true;
@@ -228,28 +239,30 @@ exports.checkServerIdentity = function checkServerIdentity(hostname, cert) {
228239
hostname = '' + hostname;
229240

230241
if (altNames) {
231-
for (const name of altNames.split(', ')) {
232-
if (name.startsWith('DNS:')) {
233-
dnsNames.push(name.slice(4));
234-
} else if (name.startsWith('URI:')) {
242+
for (const name of StringPrototypeSplit(altNames, ', ')) {
243+
if (StringPrototypeStartsWith(name, 'DNS:')) {
244+
ArrayPrototypePush(dnsNames, StringPrototypeSlice(name, 4));
245+
} else if (StringPrototypeStartsWith(name, 'URI:')) {
235246
let uri;
236247
try {
237-
uri = new URL(name.slice(4));
248+
uri = new URL(StringPrototypeSlice(name, 4));
238249
} catch {
239-
uri = url.parse(name.slice(4));
250+
const slicedName = StringPrototypeSlice(name, 4);
251+
uri = url.parse(slicedName);
240252
if (!urlWarningEmitted && !process.noDeprecation) {
241253
urlWarningEmitted = true;
242254
process.emitWarning(
243-
`The URI ${name.slice(4)} found in cert.subjectaltname ` +
255+
`The URI ${slicedName} found in cert.subjectaltname ` +
244256
'is not a valid URI, and is supported in the tls module ' +
245257
'solely for compatibility.',
246258
'DeprecationWarning', 'DEP0109');
247259
}
248260
}
249261

250-
uriNames.push(uri.hostname); // TODO(bnoordhuis) Also use scheme.
251-
} else if (name.startsWith('IP Address:')) {
252-
ips.push(canonicalizeIP(name.slice(11)));
262+
// TODO(bnoordhuis) Also use scheme.
263+
ArrayPrototypePush(uriNames, uri.hostname);
264+
} else if (StringPrototypeStartsWith(name, 'IP Address:')) {
265+
ArrayPrototypePush(ips, canonicalizeIP(StringPrototypeSlice(name, 11)));
253266
}
254267
}
255268
}
@@ -263,17 +276,19 @@ exports.checkServerIdentity = function checkServerIdentity(hostname, cert) {
263276
hostname = unfqdn(hostname); // Remove trailing dot for error messages.
264277

265278
if (net.isIP(hostname)) {
266-
valid = ips.includes(canonicalizeIP(hostname));
279+
valid = ArrayPrototypeIncludes(ips, canonicalizeIP(hostname));
267280
if (!valid)
268-
reason = `IP: ${hostname} is not in the cert's list: ${ips.join(', ')}`;
281+
reason = `IP: ${hostname} is not in the cert's list: ` +
282+
ArrayPrototypeJoin(ips, ', ');
269283
// TODO(bnoordhuis) Also check URI SANs that are IP addresses.
270284
} else if (hasAltNames || subject) {
271285
const hostParts = splitHost(hostname);
272286
const wildcard = (pattern) => check(hostParts, pattern, true);
273287

274288
if (hasAltNames) {
275289
const noWildcard = (pattern) => check(hostParts, pattern, false);
276-
valid = dnsNames.some(wildcard) || uriNames.some(noWildcard);
290+
valid = ArrayPrototypeSome(dnsNames, wildcard) ||
291+
ArrayPrototypeSome(uriNames, noWildcard);
277292
if (!valid)
278293
reason =
279294
`Host: ${hostname}. is not in the cert's altnames: ${altNames}`;
@@ -282,7 +297,7 @@ exports.checkServerIdentity = function checkServerIdentity(hostname, cert) {
282297
const cn = subject.CN;
283298

284299
if (ArrayIsArray(cn))
285-
valid = cn.some(wildcard);
300+
valid = ArrayPrototypeSome(cn, wildcard);
286301
else if (cn)
287302
valid = wildcard(cn);
288303

0 commit comments

Comments
 (0)