Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
98 commits
Select commit Hold shift + click to select a range
85c85d3
path: add `path/posix` and `path/win32` alias modules
ExE-Boss Aug 28, 2020
baa87c1
util: add `util/types` alias module
ExE-Boss Jun 27, 2020
d1baae3
readline: add getPrompt to get the current prompt
mattiasrunge May 31, 2020
59af919
querystring: reduce memory usage by Int8Array
sapics Jul 5, 2020
5c0ddbc
net: fix invalid write after end error
ronag Nov 8, 2020
8a6cabb
events: port some wpt tests
Ethan-Arrowood Jul 2, 2020
be220b2
tools: update ESLint to 7.13.0
lpinca Nov 8, 2020
1924255
async_hooks: fix leak in AsyncLocalStorage exit
Qard Oct 23, 2020
0b40568
http2: delay session.receive() by a tick
szmarczak Nov 5, 2020
9c6be3c
http2: allow setting the local window size of a session
Nov 10, 2020
a81dc9a
src,crypto: refactoring of crypto_context, SecureContext
jasnell Oct 15, 2020
49649a4
tools: fix config serialization w/ long strings
oleavr Nov 5, 2020
bf0550c
tools: enforce use of single quotes in editorconfig
aduh95 Nov 7, 2020
500e709
doc: update list styles for remark-parse@9 rendering
Trott Nov 9, 2020
63494e4
tools: update doc tools to remark-parse@9.0.0
Trott Nov 9, 2020
4140f49
util: fix to inspect getters that access this
RaisinTen Nov 9, 2020
d2c757a
deps: V8: cherry-pick 27e1ac1a79ff
oleavr Nov 6, 2020
098a5b1
deps: V8: cherry-pick 086eecbd96b6
oleavr Nov 6, 2020
4b7ba11
deps: V8: cherry-pick 4e077ff0444a
oleavr Nov 6, 2020
8ae3ffe
deps: V8: cherry-pick 1d0f426311d4
oleavr Nov 6, 2020
387d92f
http: onFinish will not be triggered again when finished
rickyes Oct 28, 2020
56f83e6
build: refactor configure.py to use argparse
RaisinTen Oct 22, 2020
5729478
src: add loop idle time in diagnostic report
gireeshpunathil Nov 3, 2020
841a281
doc: fix typo in debugger.md
Trott Nov 10, 2020
6a4cc43
test: replace var with const
Nov 9, 2020
fbe210b
build: conditionally clear vcinstalldir
bingenito Nov 6, 2020
122797e
src: remove duplicate logic for getting buffer
yashLadha Sep 9, 2020
34aa0c8
assert: refactor to use more primordials
aduh95 Nov 6, 2020
0b70822
child_process: refactor to use more primordials
aduh95 Nov 6, 2020
63a138e
crypto: fix passing TypedArray to webcrypto AES methods
aduh95 Nov 11, 2020
e54108f
cluster: refactor to use more primordials
aduh95 Nov 6, 2020
3be5e86
test: add util.inspect test for null maxStringLength
Trott Nov 11, 2020
75707f4
lib,tools: enforce access to prototype from primordials
aduh95 Nov 7, 2020
6678897
esm: refactor to use more primordials
aduh95 Nov 7, 2020
f7b2fce
vm: refactor to use more primordials
aduh95 Nov 7, 2020
1550073
events: disabled manual construction AbortSignal
RaisinTen Nov 12, 2020
9405cdd
test: improve test-stream-duplex-readable-end
lpinca Nov 9, 2020
6349b1d
dns: add a cancel() method to the promise Resolver
szmarczak Nov 11, 2020
eefc6aa
doc: document the error when cwd not exists in child_process.spawn
FeelyChau Jul 24, 2020
ed8af3a
perf_hooks: make nodeTiming a first-class object
mmomtchev Nov 5, 2020
cd33594
doc: move shigeki to emeritus
Trott Nov 12, 2020
e8a8513
doc: fix invalid link in worker_threads.md
Trott Nov 13, 2020
b17a83a
doc: claim ABI version for Electron v13
codebytere Nov 12, 2020
0ff384b
doc: esm docs consolidation and reordering
guybedford Nov 9, 2020
89da0c3
n-api: factor out calling pattern
Nov 13, 2020
eb9295b
promise: emit error on domain unhandled rejections
benjamingr Nov 11, 2020
9ce9b01
events: add max listener warning for EventTarget
jasnell Nov 6, 2020
27f1bc0
deps: upgrade npm to 7.0.11
darcyclarke Nov 13, 2020
272fc79
crypto: fix format warning in AdditionalConfig
RaisinTen Nov 10, 2020
7e7ddb1
tools: hide commit queue action link
aduh95 Nov 14, 2020
0fcbb1c
deps: V8: cherry-pick 3176bfd447a9
addaleax Oct 12, 2020
c19df17
test: add test for fs.read when offset key is null
mayankagarwals Nov 1, 2020
f9bbd35
test: make test-http2-client-jsstream-destroy.js reliable
Trott Nov 15, 2020
3d623d8
n-api: improve consistency of how we get context
mhdawson Nov 10, 2020
142cacd
doc: clarify text about process not responding
Trott Nov 14, 2020
a367c0d
timers: refactor to use more primordials
aduh95 Nov 15, 2020
4746649
test: deflake test-http-destroyed-socket-write2
lpinca Nov 14, 2020
77b47df
test: fix typo in inspector-helper.js
lpinca Nov 15, 2020
60874ba
build: try “python3” as a last resort for 3.x
oleavr Nov 5, 2020
76b1863
fs: filehandle read now accepts object as argument
branisha Nov 14, 2020
a8dab21
doc,url: fix url.hostname example
darkrishabh Jun 5, 2020
d8fcf2c
tools: remove bashisms from license builder script
aduh95 Nov 14, 2020
e48ec70
domain: improve deprecation warning text for DEP0097
addaleax Nov 16, 2020
15ff155
lib: add throws option to fs.f/l/statSync
amcasey Jun 3, 2020
24065b9
doc: mark modules implementation as stable
guybedford Oct 23, 2020
73bb54a
test: update wpt url and resource
watilde Nov 7, 2020
7086f2e
src: refactor using-declarations node_env_var.cc
RaisinTen Nov 15, 2020
bb29508
doc: add link for v8.takeCoverage()
Trott Nov 16, 2020
82f1cde
lib: remove primordials.SafePromise
aduh95 Nov 17, 2020
8390f8a
http: add support for abortsignal to http.request
benjamingr Nov 9, 2020
d6ea12e
lib: set abort-controller toStringTag
benjamingr Nov 14, 2020
3691ecc
fs: remove experimental from promises.rmdir recursive
andersk Nov 16, 2020
f0aed8c
http2: add support for TypedArray to getUnpackedSettings
aduh95 Nov 16, 2020
1a4d43f
lib: refactor to use more primordials
aduh95 Nov 15, 2020
fcc38a1
build: replace which with command -v
RaisinTen Nov 14, 2020
2d24912
tools: only use 2 cores for macos action
MylesBorins Nov 18, 2020
3ee556a
benchmark: fix build warnings
Nov 18, 2020
4ab4a99
doc: de-emphasize wrapping in napi_define_class
Nov 18, 2020
a6ef92b
tools: bump unist-util-find@1.0.1 to unist-util-find@1.0.2
Trott Nov 13, 2020
4e3883e
win,build,tools: support VS prerelease
baruchiro Nov 8, 2020
c23ee37
deps: upgrade npm to 7.0.12
ruyadorno Nov 17, 2020
a6a90af
doc: add compatibility/interop technical value
GeoffreyBooth Sep 22, 2020
8a0c3b9
http2: refactor to use more primordials
aduh95 Nov 16, 2020
28d7101
async_hooks: refactor to use more primordials
aduh95 Nov 18, 2020
545ac1f
doc: fix punctuation in v8.md
Trott Nov 20, 2020
bcbf176
errors: refactor to use more primordials
aduh95 Nov 18, 2020
5698cc0
n-api: fix test_async_context warnings
Nov 19, 2020
79b2ba6
n-api: clean up binding creation
Nov 18, 2020
48bf59b
http2: add support for AbortSignal to http2Session.request
MadaraUchiha Nov 10, 2020
5fa35f6
test: update comments in test-fs-read-offset-null
Trott Nov 17, 2020
8bbdbcc
doc: revise agent.destroy() text
Trott Nov 18, 2020
6d1b1c7
src: integrate URL::href() and use in inspector
watilde Nov 1, 2020
2fdf509
http: fix typo in comment
HollowMan6 Nov 20, 2020
42dfda8
doc: remove stray comma in url.md
Trott Nov 19, 2020
0fbade3
doc: add arm64 macOS as experimental
richardlau Nov 20, 2020
d16e862
deps: upgrade npm to 7.0.13
ruyadorno Nov 20, 2020
4a88c73
deps: upgrade npm to 7.0.14
nlf Nov 23, 2020
63e7dc1
2020-11-24, Version 15.3.0 (Current)
codebytere Nov 22, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
src,crypto: refactoring of crypto_context, SecureContext
Cleaup and improvement of crypto_context and SecureContext.

Signed-off-by: James M Snell <jasnell@gmail.com>

PR-URL: #35665
Reviewed-By: Alba Mendez <me@alba.sh>
Reviewed-By: Tobias Nießen <tniessen@tnie.de>
Reviewed-By: Rich Trott <rtrott@gmail.com>
Reviewed-By: Franziska Hinkelmann <franziska.hinkelmann@gmail.com>
  • Loading branch information
jasnell authored and codebytere committed Nov 22, 2020
commit a81dc9ae1817d8dde41ab4c5300db579c064b370
274 changes: 172 additions & 102 deletions lib/_tls_common.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@

const {
ArrayIsArray,
ArrayPrototypeFilter,
ArrayPrototypeJoin,
ObjectCreate,
StringPrototypeSplit,
StringPrototypeStartsWith,
} = primordials;

const { parseCertString } = require('internal/tls');
Expand All @@ -44,8 +48,15 @@ const {
TLS1_3_VERSION,
} = internalBinding('constants').crypto;

// Lazily loaded from internal/crypto/util.
let toBuf = null;
const {
validateString,
validateInteger,
validateInt32,
} = require('internal/validators');

const {
toBuf
} = require('internal/crypto/util');

function toV(which, v, def) {
if (v == null) v = def;
Expand Down Expand Up @@ -75,7 +86,10 @@ function SecureContext(secureProtocol, secureOptions, minVersion, maxVersion) {
toV('minimum', minVersion, tls.DEFAULT_MIN_VERSION),
toV('maximum', maxVersion, tls.DEFAULT_MAX_VERSION));

if (secureOptions) this.context.setOptions(secureOptions);
if (secureOptions) {
validateInteger(secureOptions, 'secureOptions');
this.context.setOptions(secureOptions);
}
}

function validateKeyOrCertOption(name, value) {
Expand All @@ -90,80 +104,136 @@ function validateKeyOrCertOption(name, value) {

exports.SecureContext = SecureContext;

function setKey(context, key, passphrase) {
validateKeyOrCertOption('key', key);
if (passphrase != null)
validateString(passphrase, 'options.passphrase');
context.setKey(key, passphrase);
}

function processCiphers(ciphers) {
ciphers = StringPrototypeSplit(ciphers || tls.DEFAULT_CIPHERS, ':');

const cipherList =
ArrayPrototypeJoin(
ArrayPrototypeFilter(
ciphers,
(cipher) => {
return cipher.length > 0 &&
!StringPrototypeStartsWith(cipher, 'TLS_');
}), ':');

const cipherSuites =
ArrayPrototypeJoin(
ArrayPrototypeFilter(
ciphers,
(cipher) => {
return cipher.length > 0 &&
StringPrototypeStartsWith(cipher, 'TLS_');
}), ':');

// Specifying empty cipher suites for both TLS1.2 and TLS1.3 is invalid, its
// not possible to handshake with no suites.
if (cipherSuites === '' && cipherList === '')
throw new ERR_INVALID_ARG_VALUE('options.ciphers', ciphers);

return { cipherList, cipherSuites };
}

function addCACerts(context, ...certs) {
for (const cert of certs) {
validateKeyOrCertOption('ca', cert);
context.addCACert(cert);
}
}

function setCerts(context, ...certs) {
for (const cert of certs) {
validateKeyOrCertOption('cert', cert);
context.setCert(cert);
}
}

exports.createSecureContext = function createSecureContext(options) {
if (!options) options = {};

let secureOptions = options.secureOptions;
if (options.honorCipherOrder)
const {
ca,
cert,
ciphers,
clientCertEngine,
crl,
dhparam,
ecdhCurve = tls.DEFAULT_ECDH_CURVE,
honorCipherOrder,
key,
minVersion,
maxVersion,
passphrase,
pfx,
privateKeyIdentifier,
privateKeyEngine,
secureProtocol,
sessionIdContext,
sessionTimeout,
sigalgs,
singleUse,
ticketKeys,
} = options;

let { secureOptions } = options;

if (honorCipherOrder)
secureOptions |= SSL_OP_CIPHER_SERVER_PREFERENCE;

const c = new SecureContext(options.secureProtocol, secureOptions,
options.minVersion, options.maxVersion);
const c = new SecureContext(secureProtocol, secureOptions,
minVersion, maxVersion);

// Add CA before the cert to be able to load cert's issuer in C++ code.
const { ca } = options;
// NOTE(@jasnell): ca, cert, and key are permitted to be falsy, so do not
// change the checks to !== undefined checks.
if (ca) {
if (ArrayIsArray(ca)) {
for (const val of ca) {
validateKeyOrCertOption('ca', val);
c.context.addCACert(val);
}
} else {
validateKeyOrCertOption('ca', ca);
c.context.addCACert(ca);
}
if (ArrayIsArray(ca))
addCACerts(c.context, ...ca);
else
addCACerts(c.context, ca);
} else {
c.context.addRootCerts();
}

const { cert } = options;
if (cert) {
if (ArrayIsArray(cert)) {
for (const val of cert) {
validateKeyOrCertOption('cert', val);
c.context.setCert(val);
}
} else {
validateKeyOrCertOption('cert', cert);
c.context.setCert(cert);
}
if (ArrayIsArray(cert))
setCerts(c.context, ...cert);
else
setCerts(c.context, cert);
}

// Set the key after the cert.
// `ssl_set_pkey` returns `0` when the key does not match the cert, but
// `ssl_set_cert` returns `1` and nullifies the key in the SSL structure
// which leads to the crash later on.
const key = options.key;
const passphrase = options.passphrase;
if (key) {
if (ArrayIsArray(key)) {
for (const val of key) {
// eslint-disable-next-line eqeqeq
const pem = (val != undefined && val.pem !== undefined ? val.pem : val);
validateKeyOrCertOption('key', pem);
c.context.setKey(pem, val.passphrase || passphrase);
setKey(c.context, pem, val.passphrase || passphrase);
}
} else {
validateKeyOrCertOption('key', key);
c.context.setKey(key, passphrase);
setKey(c.context, key, passphrase);
}
}

const sigalgs = options.sigalgs;
if (sigalgs !== undefined) {
if (typeof sigalgs !== 'string') {
if (typeof sigalgs !== 'string')
throw new ERR_INVALID_ARG_TYPE('options.sigalgs', 'string', sigalgs);
}

if (sigalgs === '') {
if (sigalgs === '')
throw new ERR_INVALID_ARG_VALUE('options.sigalgs', sigalgs);
}

c.context.setSigalgs(sigalgs);
}

const { privateKeyIdentifier, privateKeyEngine } = options;
if (privateKeyIdentifier !== undefined) {
if (privateKeyEngine === undefined) {
// Engine is required when privateKeyIdentifier is present
Expand Down Expand Up @@ -193,113 +263,113 @@ exports.createSecureContext = function createSecureContext(options) {
}
}

if (options.ciphers && typeof options.ciphers !== 'string') {
throw new ERR_INVALID_ARG_TYPE(
'options.ciphers', 'string', options.ciphers);
}
if (ciphers !== undefined)
validateString(ciphers, 'options.ciphers');

// Work around an OpenSSL API quirk. cipherList is for TLSv1.2 and below,
// cipherSuites is for TLSv1.3 (and presumably any later versions). TLSv1.3
// cipher suites all have a standard name format beginning with TLS_, so split
// the ciphers and pass them to the appropriate API.
const ciphers = (options.ciphers || tls.DEFAULT_CIPHERS).split(':');
const cipherList = ciphers.filter((_) => !_.match(/^TLS_/) &&
_.length > 0).join(':');
const cipherSuites = ciphers.filter((_) => _.match(/^TLS_/)).join(':');

if (cipherSuites === '' && cipherList === '') {
// Specifying empty cipher suites for both TLS1.2 and TLS1.3 is invalid, its
// not possible to handshake with no suites.
throw new ERR_INVALID_ARG_VALUE('options.ciphers', ciphers);
}
const { cipherList, cipherSuites } = processCiphers(ciphers);

c.context.setCipherSuites(cipherSuites);
c.context.setCiphers(cipherList);

if (cipherSuites === '' && c.context.getMaxProto() > TLS1_2_VERSION &&
c.context.getMinProto() < TLS1_3_VERSION)
if (cipherSuites === '' &&
c.context.getMaxProto() > TLS1_2_VERSION &&
c.context.getMinProto() < TLS1_3_VERSION) {
c.context.setMaxProto(TLS1_2_VERSION);
}

if (cipherList === '' && c.context.getMinProto() < TLS1_3_VERSION &&
c.context.getMaxProto() > TLS1_2_VERSION)
if (cipherList === '' &&
c.context.getMinProto() < TLS1_3_VERSION &&
c.context.getMaxProto() > TLS1_2_VERSION) {
c.context.setMinProto(TLS1_3_VERSION);
}

if (options.ecdhCurve === undefined)
c.context.setECDHCurve(tls.DEFAULT_ECDH_CURVE);
else if (options.ecdhCurve)
c.context.setECDHCurve(options.ecdhCurve);
validateString(ecdhCurve, 'options.ecdhCurve');
c.context.setECDHCurve(ecdhCurve);

if (options.dhparam) {
const warning = c.context.setDHParam(options.dhparam);
if (dhparam !== undefined) {
validateKeyOrCertOption('dhparam', dhparam);
const warning = c.context.setDHParam(dhparam);
if (warning)
process.emitWarning(warning, 'SecurityWarning');
}

if (options.crl) {
if (ArrayIsArray(options.crl)) {
for (const crl of options.crl) {
c.context.addCRL(crl);
if (crl !== undefined) {
if (ArrayIsArray(crl)) {
for (const val of crl) {
validateKeyOrCertOption('crl', val);
c.context.addCRL(val);
}
} else {
c.context.addCRL(options.crl);
validateKeyOrCertOption('crl', crl);
c.context.addCRL(crl);
}
}

if (options.sessionIdContext) {
c.context.setSessionIdContext(options.sessionIdContext);
if (sessionIdContext !== undefined) {
validateString(sessionIdContext, 'options.sessionIdContext');
c.context.setSessionIdContext(sessionIdContext);
}

if (options.pfx) {
if (!toBuf)
toBuf = require('internal/crypto/util').toBuf;

if (ArrayIsArray(options.pfx)) {
for (const pfx of options.pfx) {
const raw = pfx.buf ? pfx.buf : pfx;
const buf = toBuf(raw);
const passphrase = pfx.passphrase || options.passphrase;
if (passphrase) {
c.context.loadPKCS12(buf, toBuf(passphrase));
if (pfx !== undefined) {
if (ArrayIsArray(pfx)) {
for (const val of pfx) {
const raw = val.buf ? val.buf : val;
const pass = val.passphrase || passphrase;
if (pass !== undefined) {
c.context.loadPKCS12(toBuf(raw), toBuf(pass));
} else {
c.context.loadPKCS12(buf);
c.context.loadPKCS12(toBuf(raw));
}
}
} else if (passphrase) {
c.context.loadPKCS12(toBuf(pfx), toBuf(passphrase));
} else {
const buf = toBuf(options.pfx);
const passphrase = options.passphrase;
if (passphrase) {
c.context.loadPKCS12(buf, toBuf(passphrase));
} else {
c.context.loadPKCS12(buf);
}
c.context.loadPKCS12(toBuf(pfx));
}
}

// Do not keep read/write buffers in free list for OpenSSL < 1.1.0. (For
// OpenSSL 1.1.0, buffers are malloced and freed without the use of a
// freelist.)
if (options.singleUse) {
if (singleUse) {
c.singleUse = true;
c.context.setFreeListLength(0);
}

if (typeof options.clientCertEngine === 'string') {
if (c.context.setClientCertEngine)
c.context.setClientCertEngine(options.clientCertEngine);
else
if (clientCertEngine !== undefined) {
if (typeof c.context.setClientCertEngine !== 'function')
throw new ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED();
} else if (options.clientCertEngine != null) {
throw new ERR_INVALID_ARG_TYPE('options.clientCertEngine',
['string', 'null', 'undefined'],
options.clientCertEngine);
if (typeof clientCertEngine !== 'string') {
throw new ERR_INVALID_ARG_TYPE('options.clientCertEngine',
['string', 'null', 'undefined'],
clientCertEngine);
}
c.context.setClientCertEngine(clientCertEngine);
}

if (options.ticketKeys) {
c.context.setTicketKeys(options.ticketKeys);
if (ticketKeys !== undefined) {
if (!isArrayBufferView(ticketKeys)) {
throw new ERR_INVALID_ARG_TYPE(
'options.ticketKeys',
['Buffer', 'TypedArray', 'DataView'],
ticketKeys);
}
if (ticketKeys.byteLength !== 48) {
throw new ERR_INVALID_ARG_VALUE(
'options.ticketKeys',
ticketKeys.byteLenth,
'must be exactly 48 bytes');
}
c.context.setTicketKeys(ticketKeys);
}

if (options.sessionTimeout) {
c.context.setSessionTimeout(options.sessionTimeout);
if (sessionTimeout !== undefined) {
validateInt32(sessionTimeout, 'options.sessionTimeout');
c.context.setSessionTimeout(sessionTimeout);
}

return c;
Expand Down
Loading