2121
2222'use strict' ;
2323
24+ const tls = require ( 'tls' ) ;
25+
2426const {
25- ArrayIsArray,
26- ArrayPrototypeFilter,
27- ArrayPrototypeForEach,
28- ArrayPrototypeJoin,
2927 ArrayPrototypePush,
3028 ObjectCreate,
3129 StringPrototypeReplace,
32- StringPrototypeSplit,
33- StringPrototypeStartsWith,
3430} = primordials ;
3531
36- const { parseCertString } = require ( 'internal/tls' ) ;
37- const { isArrayBufferView } = require ( 'internal/util/types' ) ;
38- const tls = require ( 'tls' ) ;
3932const {
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+
4639const {
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' ) ;
5348
5449const {
55- validateString,
5650 validateInteger,
57- validateInt32,
5851} = require ( 'internal/validators' ) ;
5952
6053const {
61- toBuf
62- } = require ( 'internal/crypto/util' ) ;
54+ configSecureContext,
55+ parseCertString,
56+ } = require ( 'internal/tls' ) ;
6357
6458function toV ( which , v , def ) {
6559 if ( v == null ) v = def ;
@@ -70,7 +64,10 @@ function toV(which, v, def) {
7064 throw new ERR_TLS_INVALID_PROTOCOL_VERSION ( v , which ) ;
7165}
7266
73- const { SecureContext : NativeSecureContext } = internalBinding ( 'crypto' ) ;
67+ const {
68+ SecureContext : NativeSecureContext ,
69+ } = internalBinding ( 'crypto' ) ;
70+
7471function SecureContext ( secureProtocol , secureOptions , minVersion , maxVersion ) {
7572 if ( ! ( this instanceof SecureContext ) ) {
7673 return new SecureContext ( secureProtocol , secureOptions , minVersion ,
@@ -95,93 +92,14 @@ function SecureContext(secureProtocol, secureOptions, minVersion, maxVersion) {
9592 }
9693}
9794
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 ) {
16196 if ( ! options ) options = { } ;
16297
16398 const {
164- ca,
165- cert,
166- ciphers,
167- clientCertEngine,
168- crl,
169- dhparam,
170- ecdhCurve = tls . DEFAULT_ECDH_CURVE ,
17199 honorCipherOrder,
172- key,
173100 minVersion,
174101 maxVersion,
175- passphrase,
176- pfx,
177- privateKeyIdentifier,
178- privateKeyEngine,
179102 secureProtocol,
180- sessionIdContext,
181- sessionTimeout,
182- sigalgs,
183- singleUse,
184- ticketKeys,
185103 } = options ;
186104
187105 let { secureOptions } = options ;
@@ -192,196 +110,15 @@ exports.createSecureContext = function createSecureContext(options) {
192110 const c = new SecureContext ( secureProtocol , secureOptions ,
193111 minVersion , maxVersion ) ;
194112
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 ) ;
377114
378115 return c ;
379- } ;
116+ }
380117
381118// Translate some fields from the handle's C-friendly format into more idiomatic
382119// javascript object representations before passing them back to the user. Can
383120// be used on any cert object, but changing the name would be semver-major.
384- exports . translatePeerCertificate = function translatePeerCertificate ( c ) {
121+ function translatePeerCertificate ( c ) {
385122 if ( ! c )
386123 return null ;
387124
@@ -404,4 +141,10 @@ exports.translatePeerCertificate = function translatePeerCertificate(c) {
404141 } ) ;
405142 }
406143 return c ;
144+ }
145+
146+ module . exports = {
147+ SecureContext,
148+ createSecureContext,
149+ translatePeerCertificate,
407150} ;
0 commit comments