Skip to content

Commit a7dccd0

Browse files
jimmycannBridgeAR
authored andcommitted
tls: type checking for key, cert and ca options
PR-URL: #14807 Fixes: #12802 Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: Roman Reiss <[email protected]> Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Ruben Bridgewater <[email protected]>
1 parent 0097794 commit a7dccd0

File tree

3 files changed

+336
-10
lines changed

3 files changed

+336
-10
lines changed

lib/_tls_common.js

+24-10
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
'use strict';
2323

2424
const tls = require('tls');
25+
const errors = require('internal/errors');
2526

2627
const SSL_OP_CIPHER_SERVER_PREFERENCE =
2728
process.binding('constants').crypto.SSL_OP_CIPHER_SERVER_PREFERENCE;
@@ -52,6 +53,14 @@ function SecureContext(secureProtocol, secureOptions, context) {
5253
if (secureOptions) this.context.setOptions(secureOptions);
5354
}
5455

56+
function validateKeyCert(value, type) {
57+
if (typeof value !== 'string' && !ArrayBuffer.isView(value))
58+
throw new errors.TypeError(
59+
'ERR_INVALID_ARG_TYPE', type,
60+
['string', 'Buffer', 'TypedArray', 'DataView']
61+
);
62+
}
63+
5564
exports.SecureContext = SecureContext;
5665

5766

@@ -71,10 +80,12 @@ exports.createSecureContext = function createSecureContext(options, context) {
7180
// cert's issuer in C++ code.
7281
if (options.ca) {
7382
if (Array.isArray(options.ca)) {
74-
for (i = 0; i < options.ca.length; i++) {
75-
c.context.addCACert(options.ca[i]);
76-
}
83+
options.ca.forEach((ca) => {
84+
validateKeyCert(ca, 'ca');
85+
c.context.addCACert(ca);
86+
});
7787
} else {
88+
validateKeyCert(options.ca, 'ca');
7889
c.context.addCACert(options.ca);
7990
}
8091
} else {
@@ -83,9 +94,12 @@ exports.createSecureContext = function createSecureContext(options, context) {
8394

8495
if (options.cert) {
8596
if (Array.isArray(options.cert)) {
86-
for (i = 0; i < options.cert.length; i++)
87-
c.context.setCert(options.cert[i]);
97+
options.cert.forEach((cert) => {
98+
validateKeyCert(cert, 'cert');
99+
c.context.setCert(cert);
100+
});
88101
} else {
102+
validateKeyCert(options.cert, 'cert');
89103
c.context.setCert(options.cert);
90104
}
91105
}
@@ -96,12 +110,12 @@ exports.createSecureContext = function createSecureContext(options, context) {
96110
// which leads to the crash later on.
97111
if (options.key) {
98112
if (Array.isArray(options.key)) {
99-
for (i = 0; i < options.key.length; i++) {
100-
const key = options.key[i];
101-
const passphrase = key.passphrase || options.passphrase;
102-
c.context.setKey(key.pem || key, passphrase);
103-
}
113+
options.key.forEach((k) => {
114+
validateKeyCert(k.pem || k, 'key');
115+
c.context.setKey(k.pem || k, k.passphrase || options.passphrase);
116+
});
104117
} else {
118+
validateKeyCert(options.key, 'key');
105119
c.context.setKey(options.key, options.passphrase);
106120
}
107121
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
const fixtures = require('../common/fixtures');
5+
6+
if (!common.hasCrypto)
7+
common.skip('missing crypto');
8+
9+
const assert = require('assert');
10+
const https = require('https');
11+
12+
function toArrayBuffer(buf) {
13+
const ab = new ArrayBuffer(buf.length);
14+
const view = new Uint8Array(ab);
15+
return buf.map((b, i) => view[i] = b);
16+
}
17+
18+
function toDataView(buf) {
19+
const ab = new ArrayBuffer(buf.length);
20+
const view = new DataView(ab);
21+
return buf.map((b, i) => view[i] = b);
22+
}
23+
24+
const keyBuff = fixtures.readKey('agent1-key.pem');
25+
const certBuff = fixtures.readKey('agent1-cert.pem');
26+
const keyBuff2 = fixtures.readKey('ec-key.pem');
27+
const certBuff2 = fixtures.readKey('ec-cert.pem');
28+
const caCert = fixtures.readKey('ca1-cert.pem');
29+
const caCert2 = fixtures.readKey('ca2-cert.pem');
30+
const keyStr = keyBuff.toString();
31+
const certStr = certBuff.toString();
32+
const keyStr2 = keyBuff2.toString();
33+
const certStr2 = certBuff2.toString();
34+
const caCertStr = caCert.toString();
35+
const caCertStr2 = caCert2.toString();
36+
const keyArrBuff = toArrayBuffer(keyBuff);
37+
const certArrBuff = toArrayBuffer(certBuff);
38+
const caArrBuff = toArrayBuffer(caCert);
39+
const keyDataView = toDataView(keyBuff);
40+
const certDataView = toDataView(certBuff);
41+
const caArrDataView = toDataView(caCert);
42+
const invalidKeyRE = /^The "key" argument must be one of type string, Buffer, TypedArray, or DataView$/;
43+
const invalidCertRE = /^The "cert" argument must be one of type string, Buffer, TypedArray, or DataView$/;
44+
45+
// Checks to ensure https.createServer doesn't throw an error
46+
// Format ['key', 'cert']
47+
[
48+
[keyBuff, certBuff],
49+
[false, certBuff],
50+
[keyBuff, false],
51+
[keyStr, certStr],
52+
[false, certStr],
53+
[keyStr, false],
54+
[false, false],
55+
[keyArrBuff, certArrBuff],
56+
[keyArrBuff, false],
57+
[false, certArrBuff],
58+
[keyDataView, certDataView],
59+
[keyDataView, false],
60+
[false, certDataView],
61+
[[keyBuff, keyBuff2], [certBuff, certBuff2]],
62+
[[keyStr, keyStr2], [certStr, certStr2]],
63+
[[keyStr, keyStr2], false],
64+
[false, [certStr, certStr2]],
65+
[[{ pem: keyBuff }], false],
66+
[[{ pem: keyBuff }, { pem: keyBuff }], false]
67+
].map((params) => {
68+
assert.doesNotThrow(() => {
69+
https.createServer({
70+
key: params[0],
71+
cert: params[1]
72+
});
73+
});
74+
});
75+
76+
// Checks to ensure https.createServer predictably throws an error
77+
// Format ['key', 'cert', 'expected message']
78+
[
79+
[true, certBuff, invalidKeyRE],
80+
[keyBuff, true, invalidCertRE],
81+
[true, certStr, invalidKeyRE],
82+
[keyStr, true, invalidCertRE],
83+
[true, certArrBuff, invalidKeyRE],
84+
[keyArrBuff, true, invalidCertRE],
85+
[true, certDataView, invalidKeyRE],
86+
[keyDataView, true, invalidCertRE],
87+
[true, true, invalidCertRE],
88+
[true, false, invalidKeyRE],
89+
[false, true, invalidCertRE],
90+
[true, false, invalidKeyRE],
91+
[{ pem: keyBuff }, false, invalidKeyRE],
92+
[false, { pem: keyBuff }, invalidCertRE],
93+
[1, false, invalidKeyRE],
94+
[false, 1, invalidCertRE],
95+
[[keyBuff, true], [certBuff, certBuff2], invalidKeyRE],
96+
[[true, keyStr2], [certStr, certStr2], invalidKeyRE],
97+
[[keyBuff, keyBuff2], [true, certBuff2], invalidCertRE],
98+
[[keyStr, keyStr2], [certStr, true], invalidCertRE],
99+
[[true, false], [certBuff, certBuff2], invalidKeyRE],
100+
[[keyStr, keyStr2], [true, false], invalidCertRE],
101+
[[keyStr, keyStr2], true, invalidCertRE],
102+
[true, [certBuff, certBuff2], invalidKeyRE]
103+
].map((params) => {
104+
assert.throws(() => {
105+
https.createServer({
106+
key: params[0],
107+
cert: params[1]
108+
});
109+
}, common.expectsError({
110+
code: 'ERR_INVALID_ARG_TYPE',
111+
type: TypeError,
112+
message: params[2]
113+
}));
114+
});
115+
116+
// Checks to ensure https.createServer works with the CA parameter
117+
// Format ['key', 'cert', 'ca']
118+
[
119+
[keyBuff, certBuff, caCert],
120+
[keyBuff, certBuff, [caCert, caCert2]],
121+
[keyBuff, certBuff, caCertStr],
122+
[keyBuff, certBuff, [caCertStr, caCertStr2]],
123+
[keyBuff, certBuff, caArrBuff],
124+
[keyBuff, certBuff, caArrDataView],
125+
[keyBuff, certBuff, false],
126+
].map((params) => {
127+
assert.doesNotThrow(() => {
128+
https.createServer({
129+
key: params[0],
130+
cert: params[1],
131+
ca: params[2]
132+
});
133+
});
134+
});
135+
136+
// Checks to ensure https.createServer throws an error for CA assignment
137+
// Format ['key', 'cert', 'ca']
138+
[
139+
[keyBuff, certBuff, true],
140+
[keyBuff, certBuff, {}],
141+
[keyBuff, certBuff, 1],
142+
[keyBuff, certBuff, true],
143+
[keyBuff, certBuff, [caCert, true]]
144+
].map((params) => {
145+
assert.throws(() => {
146+
https.createServer({
147+
key: params[0],
148+
cert: params[1],
149+
ca: params[2]
150+
});
151+
}, common.expectsError({
152+
code: 'ERR_INVALID_ARG_TYPE',
153+
type: TypeError,
154+
message: /^The "ca" argument must be one of type string, Buffer, TypedArray, or DataView$/
155+
}));
156+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
const fixtures = require('../common/fixtures');
5+
6+
if (!common.hasCrypto)
7+
common.skip('missing crypto');
8+
9+
const assert = require('assert');
10+
const tls = require('tls');
11+
12+
function toArrayBuffer(buf) {
13+
const ab = new ArrayBuffer(buf.length);
14+
const view = new Uint8Array(ab);
15+
return buf.map((b, i) => view[i] = b);
16+
}
17+
18+
function toDataView(buf) {
19+
const ab = new ArrayBuffer(buf.length);
20+
const view = new DataView(ab);
21+
return buf.map((b, i) => view[i] = b);
22+
}
23+
24+
const keyBuff = fixtures.readKey('agent1-key.pem');
25+
const certBuff = fixtures.readKey('agent1-cert.pem');
26+
const keyBuff2 = fixtures.readKey('ec-key.pem');
27+
const certBuff2 = fixtures.readKey('ec-cert.pem');
28+
const caCert = fixtures.readKey('ca1-cert.pem');
29+
const caCert2 = fixtures.readKey('ca2-cert.pem');
30+
const keyStr = keyBuff.toString();
31+
const certStr = certBuff.toString();
32+
const keyStr2 = keyBuff2.toString();
33+
const certStr2 = certBuff2.toString();
34+
const caCertStr = caCert.toString();
35+
const caCertStr2 = caCert2.toString();
36+
const keyArrBuff = toArrayBuffer(keyBuff);
37+
const certArrBuff = toArrayBuffer(certBuff);
38+
const caArrBuff = toArrayBuffer(caCert);
39+
const keyDataView = toDataView(keyBuff);
40+
const certDataView = toDataView(certBuff);
41+
const caArrDataView = toDataView(caCert);
42+
const invalidKeyRE = /^The "key" argument must be one of type string, Buffer, TypedArray, or DataView$/;
43+
const invalidCertRE = /^The "cert" argument must be one of type string, Buffer, TypedArray, or DataView$/;
44+
45+
// Checks to ensure tls.createServer doesn't throw an error
46+
// Format ['key', 'cert']
47+
[
48+
[keyBuff, certBuff],
49+
[false, certBuff],
50+
[keyBuff, false],
51+
[keyStr, certStr],
52+
[false, certStr],
53+
[keyStr, false],
54+
[false, false],
55+
[keyArrBuff, certArrBuff],
56+
[keyArrBuff, false],
57+
[false, certArrBuff],
58+
[keyDataView, certDataView],
59+
[keyDataView, false],
60+
[false, certDataView],
61+
[[keyBuff, keyBuff2], [certBuff, certBuff2]],
62+
[[keyStr, keyStr2], [certStr, certStr2]],
63+
[[keyStr, keyStr2], false],
64+
[false, [certStr, certStr2]],
65+
[[{ pem: keyBuff }], false],
66+
[[{ pem: keyBuff }, { pem: keyBuff }], false]
67+
].map((params) => {
68+
assert.doesNotThrow(() => {
69+
tls.createServer({
70+
key: params[0],
71+
cert: params[1]
72+
});
73+
});
74+
});
75+
76+
// Checks to ensure tls.createServer predictably throws an error
77+
// Format ['key', 'cert', 'expected message']
78+
[
79+
[true, certBuff, invalidKeyRE],
80+
[keyBuff, true, invalidCertRE],
81+
[true, certStr, invalidKeyRE],
82+
[keyStr, true, invalidCertRE],
83+
[true, certArrBuff, invalidKeyRE],
84+
[keyArrBuff, true, invalidCertRE],
85+
[true, certDataView, invalidKeyRE],
86+
[keyDataView, true, invalidCertRE],
87+
[true, true, invalidCertRE],
88+
[true, false, invalidKeyRE],
89+
[false, true, invalidCertRE],
90+
[true, false, invalidKeyRE],
91+
[{ pem: keyBuff }, false, invalidKeyRE],
92+
[false, { pem: keyBuff }, invalidCertRE],
93+
[1, false, invalidKeyRE],
94+
[false, 1, invalidCertRE],
95+
[[keyBuff, true], [certBuff, certBuff2], invalidKeyRE],
96+
[[true, keyStr2], [certStr, certStr2], invalidKeyRE],
97+
[[keyBuff, keyBuff2], [true, certBuff2], invalidCertRE],
98+
[[keyStr, keyStr2], [certStr, true], invalidCertRE],
99+
[[true, false], [certBuff, certBuff2], invalidKeyRE],
100+
[[keyStr, keyStr2], [true, false], invalidCertRE],
101+
[[keyStr, keyStr2], true, invalidCertRE],
102+
[true, [certBuff, certBuff2], invalidKeyRE]
103+
].map((params) => {
104+
assert.throws(() => {
105+
tls.createServer({
106+
key: params[0],
107+
cert: params[1]
108+
});
109+
}, common.expectsError({
110+
code: 'ERR_INVALID_ARG_TYPE',
111+
type: TypeError,
112+
message: params[2]
113+
}));
114+
});
115+
116+
// Checks to ensure tls.createServer works with the CA parameter
117+
// Format ['key', 'cert', 'ca']
118+
[
119+
[keyBuff, certBuff, caCert],
120+
[keyBuff, certBuff, [caCert, caCert2]],
121+
[keyBuff, certBuff, caCertStr],
122+
[keyBuff, certBuff, [caCertStr, caCertStr2]],
123+
[keyBuff, certBuff, caArrBuff],
124+
[keyBuff, certBuff, caArrDataView],
125+
[keyBuff, certBuff, false],
126+
].map((params) => {
127+
assert.doesNotThrow(() => {
128+
tls.createServer({
129+
key: params[0],
130+
cert: params[1],
131+
ca: params[2]
132+
});
133+
});
134+
});
135+
136+
// Checks to ensure tls.createServer throws an error for CA assignment
137+
// Format ['key', 'cert', 'ca']
138+
[
139+
[keyBuff, certBuff, true],
140+
[keyBuff, certBuff, {}],
141+
[keyBuff, certBuff, 1],
142+
[keyBuff, certBuff, true],
143+
[keyBuff, certBuff, [caCert, true]]
144+
].map((params) => {
145+
assert.throws(() => {
146+
tls.createServer({
147+
key: params[0],
148+
cert: params[1],
149+
ca: params[2]
150+
});
151+
}, common.expectsError({
152+
code: 'ERR_INVALID_ARG_TYPE',
153+
type: TypeError,
154+
message: /^The "ca" argument must be one of type string, Buffer, TypedArray, or DataView$/
155+
}));
156+
});

0 commit comments

Comments
 (0)