• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright Joyent, Inc. and other Node contributors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a
4// copy of this software and associated documentation files (the
5// "Software"), to deal in the Software without restriction, including
6// without limitation the rights to use, copy, modify, merge, publish,
7// distribute, sublicense, and/or sell copies of the Software, and to permit
8// persons to whom the Software is furnished to do so, subject to the
9// following conditions:
10//
11// The above copyright notice and this permission notice shall be included
12// in all copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20// USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22'use strict';
23
24const {
25  ObjectAssign,
26  ObjectDefineProperty,
27  ObjectSetPrototypeOf,
28  RegExp,
29  Symbol,
30} = primordials;
31
32const {
33  assertCrypto,
34  deprecate
35} = require('internal/util');
36
37assertCrypto();
38
39const { setImmediate } = require('timers');
40const assert = require('internal/assert');
41const crypto = require('crypto');
42const EE = require('events');
43const net = require('net');
44const tls = require('tls');
45const common = require('_tls_common');
46const JSStreamSocket = require('internal/js_stream_socket');
47const { Buffer } = require('buffer');
48let debug = require('internal/util/debuglog').debuglog('tls', (fn) => {
49  debug = fn;
50});
51const { TCP, constants: TCPConstants } = internalBinding('tcp_wrap');
52const tls_wrap = internalBinding('tls_wrap');
53const { Pipe, constants: PipeConstants } = internalBinding('pipe_wrap');
54const { owner_symbol } = require('internal/async_hooks').symbols;
55const { isArrayBufferView } = require('internal/util/types');
56const { SecureContext: NativeSecureContext } = internalBinding('crypto');
57const { connResetException, codes } = require('internal/errors');
58const {
59  ERR_INVALID_ARG_TYPE,
60  ERR_INVALID_ARG_VALUE,
61  ERR_INVALID_CALLBACK,
62  ERR_MULTIPLE_CALLBACK,
63  ERR_SOCKET_CLOSED,
64  ERR_TLS_DH_PARAM_SIZE,
65  ERR_TLS_HANDSHAKE_TIMEOUT,
66  ERR_TLS_INVALID_CONTEXT,
67  ERR_TLS_RENEGOTIATION_DISABLED,
68  ERR_TLS_REQUIRED_SERVER_NAME,
69  ERR_TLS_SESSION_ATTACK,
70  ERR_TLS_SNI_FROM_SERVER,
71  ERR_TLS_INVALID_STATE
72} = codes;
73const { onpskexchange: kOnPskExchange } = internalBinding('symbols');
74const {
75  getOptionValue,
76  getAllowUnauthorized,
77} = require('internal/options');
78const {
79  validateString,
80  validateBuffer,
81  validateUint32
82} = require('internal/validators');
83const traceTls = getOptionValue('--trace-tls');
84const tlsKeylog = getOptionValue('--tls-keylog');
85const { appendFile } = require('fs');
86const kConnectOptions = Symbol('connect-options');
87const kDisableRenegotiation = Symbol('disable-renegotiation');
88const kErrorEmitted = Symbol('error-emitted');
89const kHandshakeTimeout = Symbol('handshake-timeout');
90const kRes = Symbol('res');
91const kSNICallback = Symbol('snicallback');
92const kEnableTrace = Symbol('enableTrace');
93const kPskCallback = Symbol('pskcallback');
94const kPskIdentityHint = Symbol('pskidentityhint');
95const kPendingSession = Symbol('pendingSession');
96const kIsVerified = Symbol('verified');
97
98const noop = () => {};
99
100let ipServernameWarned = false;
101let tlsTracingWarned = false;
102
103// Server side times how long a handshake is taking to protect against slow
104// handshakes being used for DoS.
105function onhandshakestart(now) {
106  debug('server onhandshakestart');
107
108  const { lastHandshakeTime } = this;
109  assert(now >= lastHandshakeTime,
110         `now (${now}) < lastHandshakeTime (${lastHandshakeTime})`);
111
112  this.lastHandshakeTime = now;
113
114  // If this is the first handshake we can skip the rest of the checks.
115  if (lastHandshakeTime === 0)
116    return;
117
118  if ((now - lastHandshakeTime) >= tls.CLIENT_RENEG_WINDOW * 1000)
119    this.handshakes = 1;
120  else
121    this.handshakes++;
122
123  const owner = this[owner_symbol];
124
125  assert(owner._tlsOptions.isServer);
126
127  if (this.handshakes > tls.CLIENT_RENEG_LIMIT) {
128    owner._emitTLSError(new ERR_TLS_SESSION_ATTACK());
129    return;
130  }
131
132  if (owner[kDisableRenegotiation])
133    owner._emitTLSError(new ERR_TLS_RENEGOTIATION_DISABLED());
134}
135
136function onhandshakedone() {
137  debug('server onhandshakedone');
138
139  const owner = this[owner_symbol];
140  assert(owner._tlsOptions.isServer);
141
142  // `newSession` callback wasn't called yet
143  if (owner._newSessionPending) {
144    owner._securePending = true;
145    return;
146  }
147
148  owner._finishInit();
149}
150
151
152function loadSession(hello) {
153  debug('server onclienthello',
154        'sessionid.len', hello.sessionId.length,
155        'ticket?', hello.tlsTicket
156  );
157  const owner = this[owner_symbol];
158
159  let once = false;
160  function onSession(err, session) {
161    debug('server resumeSession callback(err %j, sess? %s)', err, !!session);
162    if (once)
163      return owner.destroy(new ERR_MULTIPLE_CALLBACK());
164    once = true;
165
166    if (err)
167      return owner.destroy(err);
168
169    if (owner._handle === null)
170      return owner.destroy(new ERR_SOCKET_CLOSED());
171
172    owner._handle.loadSession(session);
173    // Session is loaded. End the parser to allow handshaking to continue.
174    owner._handle.endParser();
175  }
176
177  if (hello.sessionId.length <= 0 ||
178      hello.tlsTicket ||
179      (owner.server &&
180      !owner.server.emit('resumeSession', hello.sessionId, onSession))) {
181    // Sessions without identifiers can't be resumed.
182    // Sessions with tickets can be resumed directly from the ticket, no server
183    // session storage is necessary.
184    // Without a call to a resumeSession listener, a session will never be
185    // loaded, so end the parser to allow handshaking to continue.
186    owner._handle.endParser();
187  }
188}
189
190
191function loadSNI(info) {
192  const owner = this[owner_symbol];
193  const servername = info.servername;
194  if (!servername || !owner._SNICallback)
195    return requestOCSP(owner, info);
196
197  let once = false;
198  owner._SNICallback(servername, (err, context) => {
199    if (once)
200      return owner.destroy(new ERR_MULTIPLE_CALLBACK());
201    once = true;
202
203    if (err)
204      return owner.destroy(err);
205
206    if (owner._handle === null)
207      return owner.destroy(new ERR_SOCKET_CLOSED());
208
209    // TODO(indutny): eventually disallow raw `SecureContext`
210    if (context)
211      owner._handle.sni_context = context.context || context;
212
213    requestOCSP(owner, info);
214  });
215}
216
217
218function requestOCSP(socket, info) {
219  if (!info.OCSPRequest || !socket.server)
220    return requestOCSPDone(socket);
221
222  let ctx = socket._handle.sni_context;
223
224  if (!ctx) {
225    ctx = socket.server._sharedCreds;
226
227    // TLS socket is using a `net.Server` instead of a tls.TLSServer.
228    // Some TLS properties like `server._sharedCreds` will not be present
229    if (!ctx)
230      return requestOCSPDone(socket);
231  }
232
233  // TODO(indutny): eventually disallow raw `SecureContext`
234  if (ctx.context)
235    ctx = ctx.context;
236
237  if (socket.server.listenerCount('OCSPRequest') === 0) {
238    return requestOCSPDone(socket);
239  }
240
241  let once = false;
242  const onOCSP = (err, response) => {
243    debug('server OCSPRequest done', 'handle?', !!socket._handle, 'once?', once,
244          'response?', !!response, 'err?', err);
245    if (once)
246      return socket.destroy(new ERR_MULTIPLE_CALLBACK());
247    once = true;
248
249    if (err)
250      return socket.destroy(err);
251
252    if (socket._handle === null)
253      return socket.destroy(new ERR_SOCKET_CLOSED());
254
255    if (response)
256      socket._handle.setOCSPResponse(response);
257    requestOCSPDone(socket);
258  };
259
260  debug('server oncertcb emit OCSPRequest');
261  socket.server.emit('OCSPRequest',
262                     ctx.getCertificate(),
263                     ctx.getIssuer(),
264                     onOCSP);
265}
266
267function requestOCSPDone(socket) {
268  debug('server certcb done');
269  try {
270    socket._handle.certCbDone();
271  } catch (e) {
272    debug('server certcb done errored', e);
273    socket.destroy(e);
274  }
275}
276
277function onnewsessionclient(sessionId, session) {
278  debug('client emit session');
279  const owner = this[owner_symbol];
280  if (owner[kIsVerified]) {
281    owner.emit('session', session);
282  } else {
283    owner[kPendingSession] = session;
284  }
285}
286
287function onnewsession(sessionId, session) {
288  debug('onnewsession');
289  const owner = this[owner_symbol];
290
291  // TODO(@sam-github) no server to emit the event on, but handshake won't
292  // continue unless newSessionDone() is called, should it be, or is that
293  // situation unreachable, or only occurring during shutdown?
294  if (!owner.server)
295    return;
296
297  let once = false;
298  const done = () => {
299    debug('onnewsession done');
300    if (once)
301      return;
302    once = true;
303
304    if (owner._handle === null)
305      return owner.destroy(new ERR_SOCKET_CLOSED());
306
307    this.newSessionDone();
308
309    owner._newSessionPending = false;
310    if (owner._securePending)
311      owner._finishInit();
312    owner._securePending = false;
313  };
314
315  owner._newSessionPending = true;
316  if (!owner.server.emit('newSession', sessionId, session, done))
317    done();
318}
319
320function onPskServerCallback(identity, maxPskLen) {
321  const owner = this[owner_symbol];
322  const ret = owner[kPskCallback](owner, identity);
323  if (ret == null)
324    return undefined;
325
326  let psk;
327  if (isArrayBufferView(ret)) {
328    psk = ret;
329  } else {
330    if (typeof ret !== 'object') {
331      throw new ERR_INVALID_ARG_TYPE(
332        'ret',
333        ['Object', 'Buffer', 'TypedArray', 'DataView'],
334        ret
335      );
336    }
337    psk = ret.psk;
338    validateBuffer(psk, 'psk');
339  }
340
341  if (psk.length > maxPskLen) {
342    throw new ERR_INVALID_ARG_VALUE(
343      'psk',
344      psk,
345      `Pre-shared key exceeds ${maxPskLen} bytes`
346    );
347  }
348
349  return psk;
350}
351
352function onPskClientCallback(hint, maxPskLen, maxIdentityLen) {
353  const owner = this[owner_symbol];
354  const ret = owner[kPskCallback](hint);
355  if (ret == null)
356    return undefined;
357
358  if (typeof ret !== 'object')
359    throw new ERR_INVALID_ARG_TYPE('ret', 'Object', ret);
360
361  validateBuffer(ret.psk, 'psk');
362  if (ret.psk.length > maxPskLen) {
363    throw new ERR_INVALID_ARG_VALUE(
364      'psk',
365      ret.psk,
366      `Pre-shared key exceeds ${maxPskLen} bytes`
367    );
368  }
369
370  validateString(ret.identity, 'identity');
371  if (Buffer.byteLength(ret.identity) > maxIdentityLen) {
372    throw new ERR_INVALID_ARG_VALUE(
373      'identity',
374      ret.identity,
375      `PSK identity exceeds ${maxIdentityLen} bytes`
376    );
377  }
378
379  return { psk: ret.psk, identity: ret.identity };
380}
381
382function onkeylog(line) {
383  debug('onkeylog');
384  this[owner_symbol].emit('keylog', line);
385}
386
387function onocspresponse(resp) {
388  debug('client onocspresponse');
389  this[owner_symbol].emit('OCSPResponse', resp);
390}
391
392function onerror(err) {
393  const owner = this[owner_symbol];
394  debug('%s onerror %s had? %j',
395        owner._tlsOptions.isServer ? 'server' : 'client', err,
396        owner._hadError);
397
398  if (owner._hadError)
399    return;
400
401  owner._hadError = true;
402
403  // Destroy socket if error happened before handshake's finish
404  if (!owner._secureEstablished) {
405    // When handshake fails control is not yet released,
406    // so self._tlsError will return null instead of actual error
407    owner.destroy(err);
408  } else if (owner._tlsOptions.isServer &&
409             owner._rejectUnauthorized &&
410             /peer did not return a certificate/.test(err.message)) {
411    // Ignore server's authorization errors
412    owner.destroy();
413  } else {
414    // Emit error
415    owner._emitTLSError(err);
416  }
417}
418
419// Used by both client and server TLSSockets to start data flowing from _handle,
420// read(0) causes a StreamBase::ReadStart, via Socket._read.
421function initRead(tlsSocket, socket) {
422  debug('%s initRead',
423        tlsSocket._tlsOptions.isServer ? 'server' : 'client',
424        'handle?', !!tlsSocket._handle,
425        'buffered?', !!socket && socket.readableLength
426  );
427  // If we were destroyed already don't bother reading
428  if (!tlsSocket._handle)
429    return;
430
431  // Socket already has some buffered data - emulate receiving it
432  if (socket && socket.readableLength) {
433    let buf;
434    while ((buf = socket.read()) !== null)
435      tlsSocket._handle.receive(buf);
436  }
437
438  tlsSocket.read(0);
439}
440
441/**
442 * Provides a wrap of socket stream to do encrypted communication.
443 */
444
445function TLSSocket(socket, opts) {
446  const tlsOptions = { ...opts };
447  let enableTrace = tlsOptions.enableTrace;
448
449  if (enableTrace == null) {
450    enableTrace = traceTls;
451
452    if (enableTrace && !tlsTracingWarned) {
453      tlsTracingWarned = true;
454      process.emitWarning('Enabling --trace-tls can expose sensitive data in ' +
455                          'the resulting log.');
456    }
457  } else if (typeof enableTrace !== 'boolean') {
458    throw new ERR_INVALID_ARG_TYPE(
459      'options.enableTrace', 'boolean', enableTrace);
460  }
461
462  if (tlsOptions.ALPNProtocols)
463    tls.convertALPNProtocols(tlsOptions.ALPNProtocols, tlsOptions);
464
465  this._tlsOptions = tlsOptions;
466  this._secureEstablished = false;
467  this._securePending = false;
468  this._newSessionPending = false;
469  this._controlReleased = false;
470  this.secureConnecting = true;
471  this._SNICallback = null;
472  this.servername = null;
473  this.alpnProtocol = null;
474  this.authorized = false;
475  this.authorizationError = null;
476  this[kRes] = null;
477  this[kIsVerified] = false;
478  this[kPendingSession] = null;
479
480  let wrap;
481  if ((socket instanceof net.Socket && socket._handle) || !socket) {
482    // 1. connected socket
483    // 2. no socket, one will be created with net.Socket().connect
484    wrap = socket;
485  } else {
486    // 3. socket has no handle so it is js not c++
487    // 4. unconnected sockets are wrapped
488    // TLS expects to interact from C++ with a net.Socket that has a C++ stream
489    // handle, but a JS stream doesn't have one. Wrap it up to make it look like
490    // a socket.
491    wrap = new JSStreamSocket(socket);
492  }
493
494  // Just a documented property to make secure sockets
495  // distinguishable from regular ones.
496  this.encrypted = true;
497
498  net.Socket.call(this, {
499    handle: this._wrapHandle(wrap),
500    allowHalfOpen: socket ? socket.allowHalfOpen : tlsOptions.allowHalfOpen,
501    pauseOnCreate: tlsOptions.pauseOnConnect,
502    // The readable flag is only needed if pauseOnCreate will be handled.
503    readable: tlsOptions.pauseOnConnect,
504    writable: false
505  });
506
507  // Proxy for API compatibility
508  this.ssl = this._handle;  // C++ TLSWrap object
509
510  this.on('error', this._tlsError);
511
512  this._init(socket, wrap);
513
514  // Make sure to setup all required properties like: `connecting` before
515  // starting the flow of the data
516  this.readable = true;
517  this.writable = true;
518
519  if (enableTrace && this._handle)
520    this._handle.enableTrace();
521
522  // Read on next tick so the caller has a chance to setup listeners
523  process.nextTick(initRead, this, socket);
524}
525ObjectSetPrototypeOf(TLSSocket.prototype, net.Socket.prototype);
526ObjectSetPrototypeOf(TLSSocket, net.Socket);
527exports.TLSSocket = TLSSocket;
528
529const proxiedMethods = [
530  'ref', 'unref', 'open', 'bind', 'listen', 'connect', 'bind6',
531  'connect6', 'getsockname', 'getpeername', 'setNoDelay', 'setKeepAlive',
532  'setSimultaneousAccepts', 'setBlocking',
533
534  // PipeWrap
535  'setPendingInstances',
536];
537
538// Proxy HandleWrap, PipeWrap and TCPWrap methods
539function makeMethodProxy(name) {
540  return function methodProxy(...args) {
541    if (this._parent[name])
542      return this._parent[name].apply(this._parent, args);
543  };
544}
545for (const proxiedMethod of proxiedMethods) {
546  tls_wrap.TLSWrap.prototype[proxiedMethod] =
547    makeMethodProxy(proxiedMethod);
548}
549
550tls_wrap.TLSWrap.prototype.close = function close(cb) {
551  let ssl;
552  if (this[owner_symbol]) {
553    ssl = this[owner_symbol].ssl;
554    this[owner_symbol].ssl = null;
555  }
556
557  // Invoke `destroySSL` on close to clean up possibly pending write requests
558  // that may self-reference TLSWrap, leading to leak
559  const done = () => {
560    if (ssl) {
561      ssl.destroySSL();
562      if (ssl._secureContext.singleUse) {
563        ssl._secureContext.context.close();
564        ssl._secureContext.context = null;
565      }
566    }
567    if (cb)
568      cb();
569  };
570
571  if (this._parentWrap && this._parentWrap._handle === this._parent) {
572    this._parentWrap.once('close', done);
573    return this._parentWrap.destroy();
574  }
575  return this._parent.close(done);
576};
577
578TLSSocket.prototype.disableRenegotiation = function disableRenegotiation() {
579  this[kDisableRenegotiation] = true;
580};
581
582TLSSocket.prototype._wrapHandle = function(wrap) {
583  let handle;
584
585  if (wrap)
586    handle = wrap._handle;
587
588  const options = this._tlsOptions;
589  if (!handle) {
590    handle = options.pipe ?
591      new Pipe(PipeConstants.SOCKET) :
592      new TCP(TCPConstants.SOCKET);
593    handle[owner_symbol] = this;
594  }
595
596  // Wrap socket's handle
597  const context = options.secureContext ||
598                  options.credentials ||
599                  tls.createSecureContext(options);
600  assert(handle.isStreamBase, 'handle must be a StreamBase');
601  if (!(context.context instanceof NativeSecureContext)) {
602    throw new ERR_TLS_INVALID_CONTEXT('context');
603  }
604  const res = tls_wrap.wrap(handle, context.context, !!options.isServer);
605  res._parent = handle;  // C++ "wrap" object: TCPWrap, JSStream, ...
606  res._parentWrap = wrap;  // JS object: net.Socket, JSStreamSocket, ...
607  res._secureContext = context;
608  res.reading = handle.reading;
609  this[kRes] = res;
610  defineHandleReading(this, handle);
611
612  this.on('close', onSocketCloseDestroySSL);
613
614  return res;
615};
616
617// This eliminates a cyclic reference to TLSWrap
618// Ref: https://github.com/nodejs/node/commit/f7620fb96d339f704932f9bb9a0dceb9952df2d4
619function defineHandleReading(socket, handle) {
620  ObjectDefineProperty(handle, 'reading', {
621    get: () => {
622      return socket[kRes].reading;
623    },
624    set: (value) => {
625      socket[kRes].reading = value;
626    }
627  });
628}
629
630function onSocketCloseDestroySSL() {
631  // Make sure we are not doing it on OpenSSL's stack
632  setImmediate(destroySSL, this);
633  this[kRes] = null;
634}
635
636function destroySSL(self) {
637  self._destroySSL();
638}
639
640TLSSocket.prototype._destroySSL = function _destroySSL() {
641  if (!this.ssl) return;
642  this.ssl.destroySSL();
643  if (this.ssl._secureContext.singleUse) {
644    this.ssl._secureContext.context.close();
645    this.ssl._secureContext.context = null;
646  }
647  this.ssl = null;
648  this[kPendingSession] = null;
649  this[kIsVerified] = false;
650};
651
652// Constructor guts, arbitrarily factored out.
653let warnOnTlsKeylog = true;
654let warnOnTlsKeylogError = true;
655TLSSocket.prototype._init = function(socket, wrap) {
656  const options = this._tlsOptions;
657  const ssl = this._handle;
658  this.server = options.server;
659
660  debug('%s _init',
661        options.isServer ? 'server' : 'client',
662        'handle?', !!ssl
663  );
664
665  // Clients (!isServer) always request a cert, servers request a client cert
666  // only on explicit configuration.
667  const requestCert = !!options.requestCert || !options.isServer;
668  const rejectUnauthorized = !!options.rejectUnauthorized;
669
670  this._requestCert = requestCert;
671  this._rejectUnauthorized = rejectUnauthorized;
672  if (requestCert || rejectUnauthorized)
673    ssl.setVerifyMode(requestCert, rejectUnauthorized);
674
675  // Only call .onkeylog if there is a keylog listener.
676  ssl.onkeylog = onkeylog;
677  this.on('newListener', keylogNewListener);
678
679  function keylogNewListener(event) {
680    if (event !== 'keylog')
681      return;
682
683    ssl.enableKeylogCallback();
684
685    // Remove this listener since it's no longer needed.
686    this.removeListener('newListener', keylogNewListener);
687  }
688
689  if (options.isServer) {
690    ssl.onhandshakestart = onhandshakestart;
691    ssl.onhandshakedone = onhandshakedone;
692    ssl.onclienthello = loadSession;
693    ssl.oncertcb = loadSNI;
694    ssl.onnewsession = onnewsession;
695    ssl.lastHandshakeTime = 0;
696    ssl.handshakes = 0;
697
698    if (this.server) {
699      if (this.server.listenerCount('resumeSession') > 0 ||
700          this.server.listenerCount('newSession') > 0) {
701        // Also starts the client hello parser as a side effect.
702        ssl.enableSessionCallbacks();
703      }
704      if (this.server.listenerCount('OCSPRequest') > 0)
705        ssl.enableCertCb();
706    }
707  } else {
708    ssl.onhandshakestart = noop;
709    ssl.onhandshakedone = () => {
710      debug('client onhandshakedone');
711      this._finishInit();
712    };
713    ssl.onocspresponse = onocspresponse;
714
715    if (options.session)
716      ssl.setSession(options.session);
717
718    ssl.onnewsession = onnewsessionclient;
719
720    // Only call .onnewsession if there is a session listener.
721    this.on('newListener', newListener);
722
723    function newListener(event) {
724      if (event !== 'session')
725        return;
726
727      ssl.enableSessionCallbacks();
728
729      // Remove this listener since it's no longer needed.
730      this.removeListener('newListener', newListener);
731    }
732  }
733
734  if (tlsKeylog) {
735    if (warnOnTlsKeylog) {
736      warnOnTlsKeylog = false;
737      process.emitWarning('Using --tls-keylog makes TLS connections insecure ' +
738        'by writing secret key material to file ' + tlsKeylog);
739    }
740    this.on('keylog', (line) => {
741      appendFile(tlsKeylog, line, { mode: 0o600 }, (err) => {
742        if (err && warnOnTlsKeylogError) {
743          warnOnTlsKeylogError = false;
744          process.emitWarning('Failed to write TLS keylog (this warning ' +
745            'will not be repeated): ' + err);
746        }
747      });
748    });
749  }
750
751  ssl.onerror = onerror;
752
753  // If custom SNICallback was given, or if
754  // there're SNI contexts to perform match against -
755  // set `.onsniselect` callback.
756  if (options.isServer &&
757      options.SNICallback &&
758      (options.SNICallback !== SNICallback ||
759       (options.server && options.server._contexts.length))) {
760    assert(typeof options.SNICallback === 'function');
761    this._SNICallback = options.SNICallback;
762    ssl.enableCertCb();
763  }
764
765  if (options.ALPNProtocols) {
766    // Keep reference in secureContext not to be GC-ed
767    ssl._secureContext.alpnBuffer = options.ALPNProtocols;
768    ssl.setALPNProtocols(ssl._secureContext.alpnBuffer);
769  }
770
771  if (options.pskCallback && ssl.enablePskCallback) {
772    if (typeof options.pskCallback !== 'function') {
773      throw new ERR_INVALID_ARG_TYPE('pskCallback',
774                                     'function',
775                                     options.pskCallback);
776    }
777
778    ssl[kOnPskExchange] = options.isServer ?
779      onPskServerCallback : onPskClientCallback;
780
781    this[kPskCallback] = options.pskCallback;
782    ssl.enablePskCallback();
783
784    if (options.pskIdentityHint) {
785      if (typeof options.pskIdentityHint !== 'string') {
786        throw new ERR_INVALID_ARG_TYPE(
787          'options.pskIdentityHint',
788          'string',
789          options.pskIdentityHint
790        );
791      }
792      ssl.setPskIdentityHint(options.pskIdentityHint);
793    }
794  }
795
796
797  if (options.handshakeTimeout > 0)
798    this.setTimeout(options.handshakeTimeout, this._handleTimeout);
799
800  if (socket instanceof net.Socket) {
801    this._parent = socket;
802
803    // To prevent assertion in afterConnect() and properly kick off readStart
804    this.connecting = socket.connecting || !socket._handle;
805    socket.once('connect', () => {
806      this.connecting = false;
807      this.emit('connect');
808    });
809  }
810
811  // Assume `tls.connect()`
812  if (wrap) {
813    wrap.on('error', (err) => this._emitTLSError(err));
814  } else {
815    assert(!socket);
816    this.connecting = true;
817  }
818};
819
820TLSSocket.prototype.renegotiate = function(options, callback) {
821  if (options === null || typeof options !== 'object')
822    throw new ERR_INVALID_ARG_TYPE('options', 'Object', options);
823  if (callback !== undefined && typeof callback !== 'function')
824    throw new ERR_INVALID_CALLBACK(callback);
825
826  debug('%s renegotiate()',
827        this._tlsOptions.isServer ? 'server' : 'client',
828        'destroyed?', this.destroyed
829  );
830
831  if (this.destroyed)
832    return;
833
834  let requestCert = !!this._requestCert;
835  let rejectUnauthorized = !!this._rejectUnauthorized;
836
837  if (options.requestCert !== undefined)
838    requestCert = !!options.requestCert;
839  if (options.rejectUnauthorized !== undefined)
840    rejectUnauthorized = !!options.rejectUnauthorized;
841
842  if (requestCert !== this._requestCert ||
843      rejectUnauthorized !== this._rejectUnauthorized) {
844    this._handle.setVerifyMode(requestCert, rejectUnauthorized);
845    this._requestCert = requestCert;
846    this._rejectUnauthorized = rejectUnauthorized;
847  }
848  // Ensure that we'll cycle through internal openssl's state
849  this.write('');
850
851  try {
852    this._handle.renegotiate();
853  } catch (err) {
854    if (callback) {
855      process.nextTick(callback, err);
856    }
857    return false;
858  }
859
860  // Ensure that we'll cycle through internal openssl's state
861  this.write('');
862
863  if (callback) {
864    this.once('secure', () => callback(null));
865  }
866
867  return true;
868};
869
870TLSSocket.prototype.exportKeyingMaterial = function(length, label, context) {
871  validateUint32(length, 'length', true);
872  validateString(label, 'label');
873  if (context !== undefined)
874    validateBuffer(context, 'context');
875
876  if (!this._secureEstablished)
877    throw new ERR_TLS_INVALID_STATE();
878
879  return this._handle.exportKeyingMaterial(length, label, context);
880};
881
882TLSSocket.prototype.setMaxSendFragment = function setMaxSendFragment(size) {
883  return this._handle.setMaxSendFragment(size) === 1;
884};
885
886TLSSocket.prototype._handleTimeout = function() {
887  this._emitTLSError(new ERR_TLS_HANDSHAKE_TIMEOUT());
888};
889
890TLSSocket.prototype._emitTLSError = function(err) {
891  const e = this._tlsError(err);
892  if (e)
893    this.emit('error', e);
894};
895
896TLSSocket.prototype._tlsError = function(err) {
897  this.emit('_tlsError', err);
898  if (this._controlReleased)
899    return err;
900  return null;
901};
902
903TLSSocket.prototype._releaseControl = function() {
904  if (this._controlReleased)
905    return false;
906  this._controlReleased = true;
907  this.removeListener('error', this._tlsError);
908  return true;
909};
910
911TLSSocket.prototype._finishInit = function() {
912  // Guard against getting onhandshakedone() after .destroy().
913  // * 1.2: If destroy() during onocspresponse(), then write of next handshake
914  // record fails, the handshake done info callbacks does not occur, and the
915  // socket closes.
916  // * 1.3: The OCSP response comes in the same record that finishes handshake,
917  // so even after .destroy(), the handshake done info callback occurs
918  // immediately after onocspresponse(). Ignore it.
919  if (!this._handle)
920    return;
921
922  this.alpnProtocol = this._handle.getALPNNegotiatedProtocol();
923  // The servername could be set by TLSWrap::SelectSNIContextCallback().
924  if (this.servername === null) {
925    this.servername = this._handle.getServername();
926  }
927
928  debug('%s _finishInit',
929        this._tlsOptions.isServer ? 'server' : 'client',
930        'handle?', !!this._handle,
931        'alpn', this.alpnProtocol,
932        'servername', this.servername);
933
934  this._secureEstablished = true;
935  if (this._tlsOptions.handshakeTimeout > 0)
936    this.setTimeout(0, this._handleTimeout);
937  this.emit('secure');
938};
939
940TLSSocket.prototype._start = function() {
941  debug('%s _start',
942        this._tlsOptions.isServer ? 'server' : 'client',
943        'handle?', !!this._handle,
944        'connecting?', this.connecting,
945        'requestOCSP?', !!this._tlsOptions.requestOCSP,
946  );
947  if (this.connecting) {
948    this.once('connect', this._start);
949    return;
950  }
951
952  // Socket was destroyed before the connection was established
953  if (!this._handle)
954    return;
955
956  if (this._tlsOptions.requestOCSP)
957    this._handle.requestOCSP();
958  this._handle.start();
959};
960
961TLSSocket.prototype.setServername = function(name) {
962  validateString(name, 'name');
963
964  if (this._tlsOptions.isServer) {
965    throw new ERR_TLS_SNI_FROM_SERVER();
966  }
967
968  this._handle.setServername(name);
969};
970
971TLSSocket.prototype.setSession = function(session) {
972  if (typeof session === 'string')
973    session = Buffer.from(session, 'latin1');
974  this._handle.setSession(session);
975};
976
977TLSSocket.prototype.getPeerCertificate = function(detailed) {
978  if (this._handle) {
979    return common.translatePeerCertificate(
980      this._handle.getPeerCertificate(detailed)) || {};
981  }
982
983  return null;
984};
985
986TLSSocket.prototype.getCertificate = function() {
987  if (this._handle) {
988    // It's not a peer cert, but the formatting is identical.
989    return common.translatePeerCertificate(
990      this._handle.getCertificate()) || {};
991  }
992
993  return null;
994};
995
996// Proxy TLSSocket handle methods
997function makeSocketMethodProxy(name) {
998  return function socketMethodProxy(...args) {
999    if (this._handle)
1000      return this._handle[name].apply(this._handle, args);
1001    return null;
1002  };
1003}
1004
1005[
1006  'getCipher',
1007  'getSharedSigalgs',
1008  'getEphemeralKeyInfo',
1009  'getFinished',
1010  'getPeerFinished',
1011  'getProtocol',
1012  'getSession',
1013  'getTLSTicket',
1014  'isSessionReused',
1015  'enableTrace',
1016].forEach((method) => {
1017  TLSSocket.prototype[method] = makeSocketMethodProxy(method);
1018});
1019
1020// TODO: support anonymous (nocert)
1021
1022
1023function onServerSocketSecure() {
1024  if (this._requestCert) {
1025    const verifyError = this._handle.verifyError();
1026    if (verifyError) {
1027      this.authorizationError = verifyError.code;
1028
1029      if (this._rejectUnauthorized)
1030        this.destroy();
1031    } else {
1032      this.authorized = true;
1033    }
1034  }
1035
1036  if (!this.destroyed && this._releaseControl()) {
1037    debug('server emit secureConnection');
1038    this.secureConnecting = false;
1039    this._tlsOptions.server.emit('secureConnection', this);
1040  }
1041}
1042
1043function onSocketTLSError(err) {
1044  if (!this._controlReleased && !this[kErrorEmitted]) {
1045    this[kErrorEmitted] = true;
1046    debug('server emit tlsClientError:', err);
1047    this._tlsOptions.server.emit('tlsClientError', err, this);
1048  }
1049}
1050
1051function onSocketKeylog(line) {
1052  this._tlsOptions.server.emit('keylog', line, this);
1053}
1054
1055function onSocketClose(err) {
1056  // Closed because of error - no need to emit it twice
1057  if (err)
1058    return;
1059
1060  // Emit ECONNRESET
1061  if (!this._controlReleased && !this[kErrorEmitted]) {
1062    this[kErrorEmitted] = true;
1063    const connReset = connResetException('socket hang up');
1064    this._tlsOptions.server.emit('tlsClientError', connReset, this);
1065  }
1066}
1067
1068function tlsConnectionListener(rawSocket) {
1069  debug('net.Server.on(connection): new TLSSocket');
1070  const socket = new TLSSocket(rawSocket, {
1071    secureContext: this._sharedCreds,
1072    isServer: true,
1073    server: this,
1074    requestCert: this.requestCert,
1075    rejectUnauthorized: this.rejectUnauthorized,
1076    handshakeTimeout: this[kHandshakeTimeout],
1077    ALPNProtocols: this.ALPNProtocols,
1078    SNICallback: this[kSNICallback] || SNICallback,
1079    enableTrace: this[kEnableTrace],
1080    pauseOnConnect: this.pauseOnConnect,
1081    pskCallback: this[kPskCallback],
1082    pskIdentityHint: this[kPskIdentityHint],
1083  });
1084
1085  socket.on('secure', onServerSocketSecure);
1086
1087  if (this.listenerCount('keylog') > 0)
1088    socket.on('keylog', onSocketKeylog);
1089
1090  socket[kErrorEmitted] = false;
1091  socket.on('close', onSocketClose);
1092  socket.on('_tlsError', onSocketTLSError);
1093}
1094
1095// AUTHENTICATION MODES
1096//
1097// There are several levels of authentication that TLS/SSL supports.
1098// Read more about this in "man SSL_set_verify".
1099//
1100// 1. The server sends a certificate to the client but does not request a
1101// cert from the client. This is common for most HTTPS servers. The browser
1102// can verify the identity of the server, but the server does not know who
1103// the client is. Authenticating the client is usually done over HTTP using
1104// login boxes and cookies and stuff.
1105//
1106// 2. The server sends a cert to the client and requests that the client
1107// also send it a cert. The client knows who the server is and the server is
1108// requesting the client also identify themselves. There are several
1109// outcomes:
1110//
1111//   A) verifyError returns null meaning the client's certificate is signed
1112//   by one of the server's CAs. The server now knows the client's identity
1113//   and the client is authorized.
1114//
1115//   B) For some reason the client's certificate is not acceptable -
1116//   verifyError returns a string indicating the problem. The server can
1117//   either (i) reject the client or (ii) allow the client to connect as an
1118//   unauthorized connection.
1119//
1120// The mode is controlled by two boolean variables.
1121//
1122// requestCert
1123//   If true the server requests a certificate from client connections. For
1124//   the common HTTPS case, users will want this to be false, which is what
1125//   it defaults to.
1126//
1127// rejectUnauthorized
1128//   If true clients whose certificates are invalid for any reason will not
1129//   be allowed to make connections. If false, they will simply be marked as
1130//   unauthorized but secure communication will continue. By default this is
1131//   true.
1132//
1133//
1134//
1135// Options:
1136// - requestCert. Send verify request. Default to false.
1137// - rejectUnauthorized. Boolean, default to true.
1138// - key. string.
1139// - cert: string.
1140// - clientCertEngine: string.
1141// - ca: string or array of strings.
1142// - sessionTimeout: integer.
1143//
1144// emit 'secureConnection'
1145//   function (tlsSocket) { }
1146//
1147//   "UNABLE_TO_GET_ISSUER_CERT", "UNABLE_TO_GET_CRL",
1148//   "UNABLE_TO_DECRYPT_CERT_SIGNATURE", "UNABLE_TO_DECRYPT_CRL_SIGNATURE",
1149//   "UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY", "CERT_SIGNATURE_FAILURE",
1150//   "CRL_SIGNATURE_FAILURE", "CERT_NOT_YET_VALID" "CERT_HAS_EXPIRED",
1151//   "CRL_NOT_YET_VALID", "CRL_HAS_EXPIRED" "ERROR_IN_CERT_NOT_BEFORE_FIELD",
1152//   "ERROR_IN_CERT_NOT_AFTER_FIELD", "ERROR_IN_CRL_LAST_UPDATE_FIELD",
1153//   "ERROR_IN_CRL_NEXT_UPDATE_FIELD", "OUT_OF_MEM",
1154//   "DEPTH_ZERO_SELF_SIGNED_CERT", "SELF_SIGNED_CERT_IN_CHAIN",
1155//   "UNABLE_TO_GET_ISSUER_CERT_LOCALLY", "UNABLE_TO_VERIFY_LEAF_SIGNATURE",
1156//   "CERT_CHAIN_TOO_LONG", "CERT_REVOKED" "INVALID_CA",
1157//   "PATH_LENGTH_EXCEEDED", "INVALID_PURPOSE" "CERT_UNTRUSTED",
1158//   "CERT_REJECTED"
1159//
1160function Server(options, listener) {
1161  if (!(this instanceof Server))
1162    return new Server(options, listener);
1163
1164  if (typeof options === 'function') {
1165    listener = options;
1166    options = {};
1167  } else if (options == null || typeof options === 'object') {
1168    options = options || {};
1169  } else {
1170    throw new ERR_INVALID_ARG_TYPE('options', 'Object', options);
1171  }
1172
1173  this._contexts = [];
1174  this.requestCert = options.requestCert === true;
1175  this.rejectUnauthorized = options.rejectUnauthorized !== false;
1176
1177  if (options.sessionTimeout)
1178    this.sessionTimeout = options.sessionTimeout;
1179
1180  if (options.ticketKeys)
1181    this.ticketKeys = options.ticketKeys;
1182
1183  if (options.ALPNProtocols)
1184    tls.convertALPNProtocols(options.ALPNProtocols, this);
1185
1186  this.setSecureContext(options);
1187
1188  this[kHandshakeTimeout] = options.handshakeTimeout || (120 * 1000);
1189  this[kSNICallback] = options.SNICallback;
1190  this[kPskCallback] = options.pskCallback;
1191  this[kPskIdentityHint] = options.pskIdentityHint;
1192
1193  if (typeof this[kHandshakeTimeout] !== 'number') {
1194    throw new ERR_INVALID_ARG_TYPE(
1195      'options.handshakeTimeout', 'number', options.handshakeTimeout);
1196  }
1197
1198  if (this[kSNICallback] && typeof this[kSNICallback] !== 'function') {
1199    throw new ERR_INVALID_ARG_TYPE(
1200      'options.SNICallback', 'function', options.SNICallback);
1201  }
1202
1203  if (this[kPskCallback] && typeof this[kPskCallback] !== 'function') {
1204    throw new ERR_INVALID_ARG_TYPE(
1205      'options.pskCallback', 'function', options.pskCallback);
1206  }
1207  if (this[kPskIdentityHint] && typeof this[kPskIdentityHint] !== 'string') {
1208    throw new ERR_INVALID_ARG_TYPE(
1209      'options.pskIdentityHint',
1210      'string',
1211      options.pskIdentityHint
1212    );
1213  }
1214
1215  // constructor call
1216  net.Server.call(this, options, tlsConnectionListener);
1217
1218  if (listener) {
1219    this.on('secureConnection', listener);
1220  }
1221
1222  this[kEnableTrace] = options.enableTrace;
1223}
1224
1225ObjectSetPrototypeOf(Server.prototype, net.Server.prototype);
1226ObjectSetPrototypeOf(Server, net.Server);
1227exports.Server = Server;
1228exports.createServer = function createServer(options, listener) {
1229  return new Server(options, listener);
1230};
1231
1232
1233Server.prototype.setSecureContext = function(options) {
1234  if (options === null || typeof options !== 'object')
1235    throw new ERR_INVALID_ARG_TYPE('options', 'Object', options);
1236
1237  if (options.pfx)
1238    this.pfx = options.pfx;
1239  else
1240    this.pfx = undefined;
1241
1242  if (options.key)
1243    this.key = options.key;
1244  else
1245    this.key = undefined;
1246
1247  if (options.passphrase)
1248    this.passphrase = options.passphrase;
1249  else
1250    this.passphrase = undefined;
1251
1252  if (options.cert)
1253    this.cert = options.cert;
1254  else
1255    this.cert = undefined;
1256
1257  if (options.clientCertEngine)
1258    this.clientCertEngine = options.clientCertEngine;
1259  else
1260    this.clientCertEngine = undefined;
1261
1262  if (options.ca)
1263    this.ca = options.ca;
1264  else
1265    this.ca = undefined;
1266
1267  if (options.minVersion)
1268    this.minVersion = options.minVersion;
1269  else
1270    this.minVersion = undefined;
1271
1272  if (options.maxVersion)
1273    this.maxVersion = options.maxVersion;
1274  else
1275    this.maxVersion = undefined;
1276
1277  if (options.secureProtocol)
1278    this.secureProtocol = options.secureProtocol;
1279  else
1280    this.secureProtocol = undefined;
1281
1282  if (options.crl)
1283    this.crl = options.crl;
1284  else
1285    this.crl = undefined;
1286
1287  this.sigalgs = options.sigalgs;
1288
1289  if (options.ciphers)
1290    this.ciphers = options.ciphers;
1291  else
1292    this.ciphers = undefined;
1293
1294  this.ecdhCurve = options.ecdhCurve;
1295
1296  if (options.dhparam)
1297    this.dhparam = options.dhparam;
1298  else
1299    this.dhparam = undefined;
1300
1301  if (options.honorCipherOrder !== undefined)
1302    this.honorCipherOrder = !!options.honorCipherOrder;
1303  else
1304    this.honorCipherOrder = true;
1305
1306  const secureOptions = options.secureOptions || 0;
1307
1308  if (secureOptions)
1309    this.secureOptions = secureOptions;
1310  else
1311    this.secureOptions = undefined;
1312
1313  if (options.sessionIdContext) {
1314    this.sessionIdContext = options.sessionIdContext;
1315  } else {
1316    this.sessionIdContext = crypto.createHash('sha1')
1317                                  .update(process.argv.join(' '))
1318                                  .digest('hex')
1319                                  .slice(0, 32);
1320  }
1321
1322  if (options.sessionTimeout)
1323    this.sessionTimeout = options.sessionTimeout;
1324
1325  if (options.ticketKeys)
1326    this.ticketKeys = options.ticketKeys;
1327
1328  this._sharedCreds = tls.createSecureContext({
1329    pfx: this.pfx,
1330    key: this.key,
1331    passphrase: this.passphrase,
1332    cert: this.cert,
1333    clientCertEngine: this.clientCertEngine,
1334    ca: this.ca,
1335    ciphers: this.ciphers,
1336    sigalgs: this.sigalgs,
1337    ecdhCurve: this.ecdhCurve,
1338    dhparam: this.dhparam,
1339    minVersion: this.minVersion,
1340    maxVersion: this.maxVersion,
1341    secureProtocol: this.secureProtocol,
1342    secureOptions: this.secureOptions,
1343    honorCipherOrder: this.honorCipherOrder,
1344    crl: this.crl,
1345    sessionIdContext: this.sessionIdContext,
1346    ticketKeys: this.ticketKeys,
1347    sessionTimeout: this.sessionTimeout
1348  });
1349};
1350
1351
1352Server.prototype._getServerData = function() {
1353  return {
1354    ticketKeys: this.getTicketKeys().toString('hex')
1355  };
1356};
1357
1358
1359Server.prototype._setServerData = function(data) {
1360  this.setTicketKeys(Buffer.from(data.ticketKeys, 'hex'));
1361};
1362
1363
1364Server.prototype.getTicketKeys = function getTicketKeys() {
1365  return this._sharedCreds.context.getTicketKeys();
1366};
1367
1368
1369Server.prototype.setTicketKeys = function setTicketKeys(keys) {
1370  this._sharedCreds.context.setTicketKeys(keys);
1371};
1372
1373
1374Server.prototype.setOptions = deprecate(function(options) {
1375  this.requestCert = options.requestCert === true;
1376  this.rejectUnauthorized = options.rejectUnauthorized !== false;
1377
1378  if (options.pfx) this.pfx = options.pfx;
1379  if (options.key) this.key = options.key;
1380  if (options.passphrase) this.passphrase = options.passphrase;
1381  if (options.cert) this.cert = options.cert;
1382  if (options.clientCertEngine)
1383    this.clientCertEngine = options.clientCertEngine;
1384  if (options.ca) this.ca = options.ca;
1385  if (options.minVersion) this.minVersion = options.minVersion;
1386  if (options.maxVersion) this.maxVersion = options.maxVersion;
1387  if (options.secureProtocol) this.secureProtocol = options.secureProtocol;
1388  if (options.crl) this.crl = options.crl;
1389  if (options.ciphers) this.ciphers = options.ciphers;
1390  if (options.ecdhCurve !== undefined)
1391    this.ecdhCurve = options.ecdhCurve;
1392  if (options.dhparam) this.dhparam = options.dhparam;
1393  if (options.sessionTimeout) this.sessionTimeout = options.sessionTimeout;
1394  if (options.ticketKeys) this.ticketKeys = options.ticketKeys;
1395  const secureOptions = options.secureOptions || 0;
1396  if (options.honorCipherOrder !== undefined)
1397    this.honorCipherOrder = !!options.honorCipherOrder;
1398  else
1399    this.honorCipherOrder = true;
1400  if (secureOptions) this.secureOptions = secureOptions;
1401  if (options.ALPNProtocols)
1402    tls.convertALPNProtocols(options.ALPNProtocols, this);
1403  if (options.sessionIdContext) {
1404    this.sessionIdContext = options.sessionIdContext;
1405  } else {
1406    this.sessionIdContext = crypto.createHash('sha1')
1407                                  .update(process.argv.join(' '))
1408                                  .digest('hex')
1409                                  .slice(0, 32);
1410  }
1411  if (options.pskCallback) this[kPskCallback] = options.pskCallback;
1412  if (options.pskIdentityHint) this[kPskIdentityHint] = options.pskIdentityHint;
1413}, 'Server.prototype.setOptions() is deprecated', 'DEP0122');
1414
1415// SNI Contexts High-Level API
1416Server.prototype.addContext = function(servername, context) {
1417  if (!servername) {
1418    throw new ERR_TLS_REQUIRED_SERVER_NAME();
1419  }
1420
1421  const re = new RegExp('^' +
1422                      servername.replace(/([.^$+?\-\\[\]{}])/g, '\\$1')
1423                                .replace(/\*/g, '[^.]*') +
1424                      '$');
1425  this._contexts.push([re, tls.createSecureContext(context).context]);
1426};
1427
1428Server.prototype[EE.captureRejectionSymbol] = function(
1429  err, event, sock) {
1430
1431  switch (event) {
1432    case 'secureConnection':
1433      sock.destroy(err);
1434      break;
1435    default:
1436      net.Server.prototype[Symbol.for('nodejs.rejection')]
1437        .call(this, err, event, sock);
1438  }
1439};
1440
1441function SNICallback(servername, callback) {
1442  const contexts = this.server._contexts;
1443
1444  for (const elem of contexts) {
1445    if (elem[0].test(servername)) {
1446      callback(null, elem[1]);
1447      return;
1448    }
1449  }
1450
1451  callback(null, undefined);
1452}
1453
1454
1455// Target API:
1456//
1457//  let s = tls.connect({port: 8000, host: "google.com"}, function() {
1458//    if (!s.authorized) {
1459//      s.destroy();
1460//      return;
1461//    }
1462//
1463//    // s.socket;
1464//
1465//    s.end("hello world\n");
1466//  });
1467//
1468//
1469function normalizeConnectArgs(listArgs) {
1470  const args = net._normalizeArgs(listArgs);
1471  const options = args[0];
1472  const cb = args[1];
1473
1474  // If args[0] was options, then normalize dealt with it.
1475  // If args[0] is port, or args[0], args[1] is host, port, we need to
1476  // find the options and merge them in, normalize's options has only
1477  // the host/port/path args that it knows about, not the tls options.
1478  // This means that options.host overrides a host arg.
1479  if (listArgs[1] !== null && typeof listArgs[1] === 'object') {
1480    ObjectAssign(options, listArgs[1]);
1481  } else if (listArgs[2] !== null && typeof listArgs[2] === 'object') {
1482    ObjectAssign(options, listArgs[2]);
1483  }
1484
1485  return cb ? [options, cb] : [options];
1486}
1487
1488function onConnectSecure() {
1489  const options = this[kConnectOptions];
1490
1491  // Check the size of DHE parameter above minimum requirement
1492  // specified in options.
1493  const ekeyinfo = this.getEphemeralKeyInfo();
1494  if (ekeyinfo.type === 'DH' && ekeyinfo.size < options.minDHSize) {
1495    const err = new ERR_TLS_DH_PARAM_SIZE(ekeyinfo.size);
1496    debug('client emit:', err);
1497    this.emit('error', err);
1498    this.destroy();
1499    return;
1500  }
1501
1502  let verifyError = this._handle.verifyError();
1503
1504  // Verify that server's identity matches it's certificate's names
1505  // Unless server has resumed our existing session
1506  if (!verifyError && !this.isSessionReused()) {
1507    const hostname = options.servername ||
1508                   options.host ||
1509                   (options.socket && options.socket._host) ||
1510                   'localhost';
1511    const cert = this.getPeerCertificate(true);
1512    verifyError = options.checkServerIdentity(hostname, cert);
1513  }
1514
1515  if (verifyError) {
1516    this.authorized = false;
1517    this.authorizationError = verifyError.code || verifyError.message;
1518
1519    if (options.rejectUnauthorized) {
1520      this.destroy(verifyError);
1521      return;
1522    }
1523    debug('client emit secureConnect. rejectUnauthorized: %s, ' +
1524          'authorizationError: %s', options.rejectUnauthorized,
1525          this.authorizationError);
1526    this.secureConnecting = false;
1527    this.emit('secureConnect');
1528  } else {
1529    this.authorized = true;
1530    debug('client emit secureConnect. authorized:', this.authorized);
1531    this.secureConnecting = false;
1532    this.emit('secureConnect');
1533  }
1534
1535  this[kIsVerified] = true;
1536  const session = this[kPendingSession];
1537  this[kPendingSession] = null;
1538  if (session)
1539    this.emit('session', session);
1540
1541  this.removeListener('end', onConnectEnd);
1542}
1543
1544function onConnectEnd() {
1545  // NOTE: This logic is shared with _http_client.js
1546  if (!this._hadError) {
1547    const options = this[kConnectOptions];
1548    this._hadError = true;
1549    const error = connResetException('Client network socket disconnected ' +
1550                                     'before secure TLS connection was ' +
1551                                     'established');
1552    error.path = options.path;
1553    error.host = options.host;
1554    error.port = options.port;
1555    error.localAddress = options.localAddress;
1556    this.destroy(error);
1557  }
1558}
1559
1560// Arguments: [port,] [host,] [options,] [cb]
1561exports.connect = function connect(...args) {
1562  args = normalizeConnectArgs(args);
1563  let options = args[0];
1564  const cb = args[1];
1565  const allowUnauthorized = getAllowUnauthorized();
1566
1567  options = {
1568    rejectUnauthorized: !allowUnauthorized,
1569    ciphers: tls.DEFAULT_CIPHERS,
1570    checkServerIdentity: tls.checkServerIdentity,
1571    minDHSize: 1024,
1572    ...options
1573  };
1574
1575  if (!options.keepAlive)
1576    options.singleUse = true;
1577
1578  assert(typeof options.checkServerIdentity === 'function');
1579  assert(typeof options.minDHSize === 'number',
1580         'options.minDHSize is not a number: ' + options.minDHSize);
1581  assert(options.minDHSize > 0,
1582         'options.minDHSize is not a positive number: ' +
1583         options.minDHSize);
1584
1585  const context = options.secureContext || tls.createSecureContext(options);
1586
1587  const tlssock = new TLSSocket(options.socket, {
1588    allowHalfOpen: options.allowHalfOpen,
1589    pipe: !!options.path,
1590    secureContext: context,
1591    isServer: false,
1592    requestCert: true,
1593    rejectUnauthorized: options.rejectUnauthorized !== false,
1594    session: options.session,
1595    ALPNProtocols: options.ALPNProtocols,
1596    requestOCSP: options.requestOCSP,
1597    enableTrace: options.enableTrace,
1598    pskCallback: options.pskCallback,
1599  });
1600
1601  tlssock[kConnectOptions] = options;
1602
1603  if (cb)
1604    tlssock.once('secureConnect', cb);
1605
1606  if (!options.socket) {
1607    // If user provided the socket, it's their responsibility to manage its
1608    // connectivity. If we created one internally, we connect it.
1609    if (options.timeout) {
1610      tlssock.setTimeout(options.timeout);
1611    }
1612
1613    tlssock.connect(options, tlssock._start);
1614  }
1615
1616  tlssock._releaseControl();
1617
1618  if (options.session)
1619    tlssock.setSession(options.session);
1620
1621  if (options.servername) {
1622    if (!ipServernameWarned && net.isIP(options.servername)) {
1623      process.emitWarning(
1624        'Setting the TLS ServerName to an IP address is not permitted by ' +
1625        'RFC 6066. This will be ignored in a future version.',
1626        'DeprecationWarning',
1627        'DEP0123'
1628      );
1629      ipServernameWarned = true;
1630    }
1631    tlssock.setServername(options.servername);
1632  }
1633
1634  if (options.socket)
1635    tlssock._start();
1636
1637  tlssock.on('secure', onConnectSecure);
1638  tlssock.once('end', onConnectEnd);
1639
1640  return tlssock;
1641};
1642