21
21
22
22
'use strict' ;
23
23
24
+ const tls = require ( 'tls' ) ;
25
+
24
26
const {
25
- ArrayIsArray,
26
- ArrayPrototypeFilter,
27
- ArrayPrototypeForEach,
28
- ArrayPrototypeJoin,
29
27
ArrayPrototypePush,
30
28
ObjectCreate,
31
29
StringPrototypeReplace,
32
- StringPrototypeSplit,
33
- StringPrototypeStartsWith,
34
30
} = primordials ;
35
31
36
- const { parseCertString } = require ( 'internal/tls' ) ;
37
- const { isArrayBufferView } = require ( 'internal/util/types' ) ;
38
- const tls = require ( 'tls' ) ;
39
32
const {
40
- ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED ,
41
- ERR_INVALID_ARG_TYPE ,
42
- ERR_INVALID_ARG_VALUE ,
43
- ERR_TLS_INVALID_PROTOCOL_VERSION ,
44
- ERR_TLS_PROTOCOL_VERSION_CONFLICT ,
45
- } = require ( 'internal/errors' ) . codes ;
33
+ codes : {
34
+ ERR_TLS_INVALID_PROTOCOL_VERSION ,
35
+ ERR_TLS_PROTOCOL_VERSION_CONFLICT ,
36
+ } ,
37
+ } = require ( 'internal/errors' ) ;
38
+
46
39
const {
47
- SSL_OP_CIPHER_SERVER_PREFERENCE ,
48
- TLS1_VERSION ,
49
- TLS1_1_VERSION ,
50
- TLS1_2_VERSION ,
51
- TLS1_3_VERSION ,
52
- } = internalBinding ( 'constants' ) . crypto ;
40
+ crypto : {
41
+ SSL_OP_CIPHER_SERVER_PREFERENCE ,
42
+ TLS1_VERSION ,
43
+ TLS1_1_VERSION ,
44
+ TLS1_2_VERSION ,
45
+ TLS1_3_VERSION ,
46
+ } ,
47
+ } = internalBinding ( 'constants' ) ;
53
48
54
49
const {
55
- validateString,
56
50
validateInteger,
57
- validateInt32,
58
51
} = require ( 'internal/validators' ) ;
59
52
60
53
const {
61
- toBuf
62
- } = require ( 'internal/crypto/util' ) ;
54
+ configSecureContext,
55
+ parseCertString,
56
+ } = require ( 'internal/tls' ) ;
63
57
64
58
function toV ( which , v , def ) {
65
59
if ( v == null ) v = def ;
@@ -70,7 +64,10 @@ function toV(which, v, def) {
70
64
throw new ERR_TLS_INVALID_PROTOCOL_VERSION ( v , which ) ;
71
65
}
72
66
73
- const { SecureContext : NativeSecureContext } = internalBinding ( 'crypto' ) ;
67
+ const {
68
+ SecureContext : NativeSecureContext ,
69
+ } = internalBinding ( 'crypto' ) ;
70
+
74
71
function SecureContext ( secureProtocol , secureOptions , minVersion , maxVersion ) {
75
72
if ( ! ( this instanceof SecureContext ) ) {
76
73
return new SecureContext ( secureProtocol , secureOptions , minVersion ,
@@ -95,93 +92,14 @@ function SecureContext(secureProtocol, secureOptions, minVersion, maxVersion) {
95
92
}
96
93
}
97
94
98
- function validateKeyOrCertOption ( name , value ) {
99
- if ( typeof value !== 'string' && ! isArrayBufferView ( value ) ) {
100
- throw new ERR_INVALID_ARG_TYPE (
101
- `options.${ name } ` ,
102
- [ 'string' , 'Buffer' , 'TypedArray' , 'DataView' ] ,
103
- value
104
- ) ;
105
- }
106
- }
107
-
108
- exports . SecureContext = SecureContext ;
109
-
110
- function setKey ( context , key , passphrase ) {
111
- validateKeyOrCertOption ( 'key' , key ) ;
112
- if ( passphrase != null )
113
- validateString ( passphrase , 'options.passphrase' ) ;
114
- context . setKey ( key , passphrase ) ;
115
- }
116
-
117
- function processCiphers ( ciphers ) {
118
- ciphers = StringPrototypeSplit ( ciphers || tls . DEFAULT_CIPHERS , ':' ) ;
119
-
120
- const cipherList =
121
- ArrayPrototypeJoin (
122
- ArrayPrototypeFilter (
123
- ciphers ,
124
- ( cipher ) => {
125
- return cipher . length > 0 &&
126
- ! StringPrototypeStartsWith ( cipher , 'TLS_' ) ;
127
- } ) , ':' ) ;
128
-
129
- const cipherSuites =
130
- ArrayPrototypeJoin (
131
- ArrayPrototypeFilter (
132
- ciphers ,
133
- ( cipher ) => {
134
- return cipher . length > 0 &&
135
- StringPrototypeStartsWith ( cipher , 'TLS_' ) ;
136
- } ) , ':' ) ;
137
-
138
- // Specifying empty cipher suites for both TLS1.2 and TLS1.3 is invalid, its
139
- // not possible to handshake with no suites.
140
- if ( cipherSuites === '' && cipherList === '' )
141
- throw new ERR_INVALID_ARG_VALUE ( 'options.ciphers' , ciphers ) ;
142
-
143
- return { cipherList, cipherSuites } ;
144
- }
145
-
146
- function addCACerts ( context , certs ) {
147
- ArrayPrototypeForEach ( certs , ( cert ) => {
148
- validateKeyOrCertOption ( 'ca' , cert ) ;
149
- context . addCACert ( cert ) ;
150
- } ) ;
151
- }
152
-
153
- function setCerts ( context , certs ) {
154
- ArrayPrototypeForEach ( certs , ( cert ) => {
155
- validateKeyOrCertOption ( 'cert' , cert ) ;
156
- context . setCert ( cert ) ;
157
- } ) ;
158
- }
159
-
160
- exports . createSecureContext = function createSecureContext ( options ) {
95
+ function createSecureContext ( options ) {
161
96
if ( ! options ) options = { } ;
162
97
163
98
const {
164
- ca,
165
- cert,
166
- ciphers,
167
- clientCertEngine,
168
- crl,
169
- dhparam,
170
- ecdhCurve = tls . DEFAULT_ECDH_CURVE ,
171
99
honorCipherOrder,
172
- key,
173
100
minVersion,
174
101
maxVersion,
175
- passphrase,
176
- pfx,
177
- privateKeyIdentifier,
178
- privateKeyEngine,
179
102
secureProtocol,
180
- sessionIdContext,
181
- sessionTimeout,
182
- sigalgs,
183
- singleUse,
184
- ticketKeys,
185
103
} = options ;
186
104
187
105
let { secureOptions } = options ;
@@ -192,196 +110,15 @@ exports.createSecureContext = function createSecureContext(options) {
192
110
const c = new SecureContext ( secureProtocol , secureOptions ,
193
111
minVersion , maxVersion ) ;
194
112
195
- // Add CA before the cert to be able to load cert's issuer in C++ code.
196
- // NOTE(@jasnell): ca, cert, and key are permitted to be falsy, so do not
197
- // change the checks to !== undefined checks.
198
- if ( ca ) {
199
- if ( ArrayIsArray ( ca ) )
200
- addCACerts ( c . context , ca ) ;
201
- else
202
- addCACerts ( c . context , [ ca ] ) ;
203
- } else {
204
- c . context . addRootCerts ( ) ;
205
- }
206
-
207
- if ( cert ) {
208
- if ( ArrayIsArray ( cert ) )
209
- setCerts ( c . context , cert ) ;
210
- else
211
- setCerts ( c . context , [ cert ] ) ;
212
- }
213
-
214
- // Set the key after the cert.
215
- // `ssl_set_pkey` returns `0` when the key does not match the cert, but
216
- // `ssl_set_cert` returns `1` and nullifies the key in the SSL structure
217
- // which leads to the crash later on.
218
- if ( key ) {
219
- if ( ArrayIsArray ( key ) ) {
220
- for ( let i = 0 ; i < key . length ; ++ i ) {
221
- const val = key [ i ] ;
222
- // eslint-disable-next-line eqeqeq
223
- const pem = ( val != undefined && val . pem !== undefined ? val . pem : val ) ;
224
- setKey ( c . context , pem , val . passphrase || passphrase ) ;
225
- }
226
- } else {
227
- setKey ( c . context , key , passphrase ) ;
228
- }
229
- }
230
-
231
- if ( sigalgs !== undefined ) {
232
- validateString ( sigalgs , 'options.sigalgs' ) ;
233
-
234
- if ( sigalgs === '' )
235
- throw new ERR_INVALID_ARG_VALUE ( 'options.sigalgs' , sigalgs ) ;
236
-
237
- c . context . setSigalgs ( sigalgs ) ;
238
- }
239
-
240
- if ( privateKeyIdentifier !== undefined ) {
241
- if ( privateKeyEngine === undefined ) {
242
- // Engine is required when privateKeyIdentifier is present
243
- throw new ERR_INVALID_ARG_VALUE ( 'options.privateKeyEngine' ,
244
- privateKeyEngine ) ;
245
- }
246
- if ( key ) {
247
- // Both data key and engine key can't be set at the same time
248
- throw new ERR_INVALID_ARG_VALUE ( 'options.privateKeyIdentifier' ,
249
- privateKeyIdentifier ) ;
250
- }
251
-
252
- if ( typeof privateKeyIdentifier === 'string' &&
253
- typeof privateKeyEngine === 'string' ) {
254
- if ( c . context . setEngineKey )
255
- c . context . setEngineKey ( privateKeyIdentifier , privateKeyEngine ) ;
256
- else
257
- throw new ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED ( ) ;
258
- } else if ( typeof privateKeyIdentifier !== 'string' ) {
259
- throw new ERR_INVALID_ARG_TYPE ( 'options.privateKeyIdentifier' ,
260
- [ 'string' , 'undefined' ] ,
261
- privateKeyIdentifier ) ;
262
- } else {
263
- throw new ERR_INVALID_ARG_TYPE ( 'options.privateKeyEngine' ,
264
- [ 'string' , 'undefined' ] ,
265
- privateKeyEngine ) ;
266
- }
267
- }
268
-
269
- if ( ciphers != null )
270
- validateString ( ciphers , 'options.ciphers' ) ;
271
-
272
- // Work around an OpenSSL API quirk. cipherList is for TLSv1.2 and below,
273
- // cipherSuites is for TLSv1.3 (and presumably any later versions). TLSv1.3
274
- // cipher suites all have a standard name format beginning with TLS_, so split
275
- // the ciphers and pass them to the appropriate API.
276
- const { cipherList, cipherSuites } = processCiphers ( ciphers ) ;
277
-
278
- c . context . setCipherSuites ( cipherSuites ) ;
279
- c . context . setCiphers ( cipherList ) ;
280
-
281
- if ( cipherSuites === '' &&
282
- c . context . getMaxProto ( ) > TLS1_2_VERSION &&
283
- c . context . getMinProto ( ) < TLS1_3_VERSION ) {
284
- c . context . setMaxProto ( TLS1_2_VERSION ) ;
285
- }
286
-
287
- if ( cipherList === '' &&
288
- c . context . getMinProto ( ) < TLS1_3_VERSION &&
289
- c . context . getMaxProto ( ) > TLS1_2_VERSION ) {
290
- c . context . setMinProto ( TLS1_3_VERSION ) ;
291
- }
292
-
293
- validateString ( ecdhCurve , 'options.ecdhCurve' ) ;
294
- c . context . setECDHCurve ( ecdhCurve ) ;
295
-
296
- if ( dhparam !== undefined ) {
297
- validateKeyOrCertOption ( 'dhparam' , dhparam ) ;
298
- const warning = c . context . setDHParam ( dhparam ) ;
299
- if ( warning )
300
- process . emitWarning ( warning , 'SecurityWarning' ) ;
301
- }
302
-
303
- if ( crl !== undefined ) {
304
- if ( ArrayIsArray ( crl ) ) {
305
- for ( const val of crl ) {
306
- validateKeyOrCertOption ( 'crl' , val ) ;
307
- c . context . addCRL ( val ) ;
308
- }
309
- } else {
310
- validateKeyOrCertOption ( 'crl' , crl ) ;
311
- c . context . addCRL ( crl ) ;
312
- }
313
- }
314
-
315
- if ( sessionIdContext !== undefined ) {
316
- validateString ( sessionIdContext , 'options.sessionIdContext' ) ;
317
- c . context . setSessionIdContext ( sessionIdContext ) ;
318
- }
319
-
320
- if ( pfx !== undefined ) {
321
- if ( ArrayIsArray ( pfx ) ) {
322
- ArrayPrototypeForEach ( pfx , ( val ) => {
323
- const raw = val . buf ? val . buf : val ;
324
- const pass = val . passphrase || passphrase ;
325
- if ( pass !== undefined ) {
326
- c . context . loadPKCS12 ( toBuf ( raw ) , toBuf ( pass ) ) ;
327
- } else {
328
- c . context . loadPKCS12 ( toBuf ( raw ) ) ;
329
- }
330
- } ) ;
331
- } else if ( passphrase ) {
332
- c . context . loadPKCS12 ( toBuf ( pfx ) , toBuf ( passphrase ) ) ;
333
- } else {
334
- c . context . loadPKCS12 ( toBuf ( pfx ) ) ;
335
- }
336
- }
337
-
338
- // Do not keep read/write buffers in free list for OpenSSL < 1.1.0. (For
339
- // OpenSSL 1.1.0, buffers are malloced and freed without the use of a
340
- // freelist.)
341
- if ( singleUse ) {
342
- c . singleUse = true ;
343
- c . context . setFreeListLength ( 0 ) ;
344
- }
345
-
346
- if ( clientCertEngine !== undefined ) {
347
- if ( typeof c . context . setClientCertEngine !== 'function' )
348
- throw new ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED ( ) ;
349
- if ( typeof clientCertEngine !== 'string' ) {
350
- throw new ERR_INVALID_ARG_TYPE ( 'options.clientCertEngine' ,
351
- [ 'string' , 'null' , 'undefined' ] ,
352
- clientCertEngine ) ;
353
- }
354
- c . context . setClientCertEngine ( clientCertEngine ) ;
355
- }
356
-
357
- if ( ticketKeys !== undefined ) {
358
- if ( ! isArrayBufferView ( ticketKeys ) ) {
359
- throw new ERR_INVALID_ARG_TYPE (
360
- 'options.ticketKeys' ,
361
- [ 'Buffer' , 'TypedArray' , 'DataView' ] ,
362
- ticketKeys ) ;
363
- }
364
- if ( ticketKeys . byteLength !== 48 ) {
365
- throw new ERR_INVALID_ARG_VALUE (
366
- 'options.ticketKeys' ,
367
- ticketKeys . byteLength ,
368
- 'must be exactly 48 bytes' ) ;
369
- }
370
- c . context . setTicketKeys ( ticketKeys ) ;
371
- }
372
-
373
- if ( sessionTimeout !== undefined ) {
374
- validateInt32 ( sessionTimeout , 'options.sessionTimeout' ) ;
375
- c . context . setSessionTimeout ( sessionTimeout ) ;
376
- }
113
+ configSecureContext ( c . context , options ) ;
377
114
378
115
return c ;
379
- } ;
116
+ }
380
117
381
118
// Translate some fields from the handle's C-friendly format into more idiomatic
382
119
// javascript object representations before passing them back to the user. Can
383
120
// be used on any cert object, but changing the name would be semver-major.
384
- exports . translatePeerCertificate = function translatePeerCertificate ( c ) {
121
+ function translatePeerCertificate ( c ) {
385
122
if ( ! c )
386
123
return null ;
387
124
@@ -404,4 +141,10 @@ exports.translatePeerCertificate = function translatePeerCertificate(c) {
404
141
} ) ;
405
142
}
406
143
return c ;
144
+ }
145
+
146
+ module . exports = {
147
+ SecureContext,
148
+ createSecureContext,
149
+ translatePeerCertificate,
407
150
} ;
0 commit comments