doc: improvements to console.markdown copy
[platform/upstream/nodejs.git] / lib / _tls_wrap.js
1 'use strict';
2
3 const assert = require('assert');
4 const crypto = require('crypto');
5 const net = require('net');
6 const tls = require('tls');
7 const util = require('util');
8 const common = require('_tls_common');
9 const StreamWrap = require('_stream_wrap').StreamWrap;
10 const Buffer = require('buffer').Buffer;
11 const Duplex = require('stream').Duplex;
12 const debug = util.debuglog('tls');
13 const Timer = process.binding('timer_wrap').Timer;
14 const tls_wrap = process.binding('tls_wrap');
15 const TCP = process.binding('tcp_wrap').TCP;
16 const Pipe = process.binding('pipe_wrap').Pipe;
17 const defaultSessionIdContext = getDefaultSessionIdContext();
18
19 function getDefaultSessionIdContext() {
20   var defaultText = process.argv.join(' ');
21   /* SSL_MAX_SID_CTX_LENGTH is 128 bits */
22   if (process.config.variables.openssl_fips) {
23     return crypto.createHash('sha1')
24       .update(defaultText)
25       .digest('hex').slice(0, 32);
26   } else {
27     return crypto.createHash('md5')
28       .update(defaultText)
29       .digest('hex');
30   }
31 }
32
33 function onhandshakestart() {
34   debug('onhandshakestart');
35
36   var self = this;
37   var ssl = self._handle;
38   var now = Timer.now();
39
40   assert(now >= ssl.lastHandshakeTime);
41
42   if ((now - ssl.lastHandshakeTime) >= tls.CLIENT_RENEG_WINDOW * 1000) {
43     ssl.handshakes = 0;
44   }
45
46   var first = (ssl.lastHandshakeTime === 0);
47   ssl.lastHandshakeTime = now;
48   if (first) return;
49
50   if (++ssl.handshakes > tls.CLIENT_RENEG_LIMIT) {
51     // Defer the error event to the next tick. We're being called from OpenSSL's
52     // state machine and OpenSSL is not re-entrant. We cannot allow the user's
53     // callback to destroy the connection right now, it would crash and burn.
54     setImmediate(function() {
55       var err = new Error('TLS session renegotiation attack detected.');
56       self._emitTLSError(err);
57     });
58   }
59 }
60
61
62 function onhandshakedone() {
63   // for future use
64   debug('onhandshakedone');
65   this._finishInit();
66 }
67
68
69 function loadSession(self, hello, cb) {
70   var once = false;
71   function onSession(err, session) {
72     if (once)
73       return cb(new Error('TLS session callback was called 2 times'));
74     once = true;
75
76     if (err)
77       return cb(err);
78
79     if (!self._handle)
80       return cb(new Error('Socket is closed'));
81
82     // NOTE: That we have disabled OpenSSL's internal session storage in
83     // `node_crypto.cc` and hence its safe to rely on getting servername only
84     // from clienthello or this place.
85     var ret = self._handle.loadSession(session);
86
87     cb(null, ret);
88   }
89
90   if (hello.sessionId.length <= 0 ||
91       hello.tlsTicket ||
92       self.server &&
93       !self.server.emit('resumeSession', hello.sessionId, onSession)) {
94     cb(null);
95   }
96 }
97
98
99 function loadSNI(self, servername, cb) {
100   if (!servername || !self._SNICallback)
101     return cb(null);
102
103   var once = false;
104   self._SNICallback(servername, function(err, context) {
105     if (once)
106       return cb(new Error('TLS SNI callback was called 2 times'));
107     once = true;
108
109     if (err)
110       return cb(err);
111
112     if (!self._handle)
113       return cb(new Error('Socket is closed'));
114
115     // TODO(indutny): eventually disallow raw `SecureContext`
116     if (context)
117       self._handle.sni_context = context.context || context;
118
119     cb(null, self._handle.sni_context);
120   });
121 }
122
123
124 function requestOCSP(self, hello, ctx, cb) {
125   if (!hello.OCSPRequest || !self.server)
126     return cb(null);
127
128   if (!ctx)
129     ctx = self.server._sharedCreds;
130   if (ctx.context)
131     ctx = ctx.context;
132
133   if (self.server.listenerCount('OCSPRequest') === 0) {
134     return cb(null);
135   } else {
136     self.server.emit('OCSPRequest',
137                      ctx.getCertificate(),
138                      ctx.getIssuer(),
139                      onOCSP);
140   }
141
142   var once = false;
143   function onOCSP(err, response) {
144     if (once)
145       return cb(new Error('TLS OCSP callback was called 2 times'));
146     once = true;
147
148     if (err)
149       return cb(err);
150
151     if (!self._handle)
152       return cb(new Error('Socket is closed'));
153
154     if (response)
155       self._handle.setOCSPResponse(response);
156     cb(null);
157   }
158 }
159
160
161 function onclienthello(hello) {
162   var self = this;
163
164   loadSession(self, hello, function(err, session) {
165     if (err)
166       return self.destroy(err);
167
168     self._handle.endParser();
169   });
170 }
171
172
173 function oncertcb(info) {
174   var self = this;
175   var servername = info.servername;
176
177   loadSNI(self, servername, function(err, ctx) {
178     if (err)
179       return self.destroy(err);
180     requestOCSP(self, info, ctx, function(err) {
181       if (err)
182         return self.destroy(err);
183
184       if (!self._handle)
185         return self.destroy(new Error('Socket is closed'));
186
187       self._handle.certCbDone();
188     });
189   });
190 }
191
192
193 function onnewsession(key, session) {
194   if (!this.server)
195     return;
196
197   var self = this;
198   var once = false;
199
200   this._newSessionPending = true;
201   if (!this.server.emit('newSession', key, session, done))
202     done();
203
204   function done() {
205     if (once)
206       return;
207     once = true;
208
209     if (!self._handle)
210       return self.destroy(new Error('Socket is closed'));
211
212     self._handle.newSessionDone();
213
214     self._newSessionPending = false;
215     if (self._securePending)
216       self._finishInit();
217     self._securePending = false;
218   }
219 }
220
221
222 function onocspresponse(resp) {
223   this.emit('OCSPResponse', resp);
224 }
225
226 function initRead(tls, wrapped) {
227   // If we were destroyed already don't bother reading
228   if (!tls._handle)
229     return;
230
231   // Socket already has some buffered data - emulate receiving it
232   if (wrapped && wrapped._readableState && wrapped._readableState.length) {
233     var buf;
234     while ((buf = wrapped.read()) !== null)
235       tls._handle.receive(buf);
236   }
237
238   tls.read(0);
239 }
240
241 /**
242  * Provides a wrap of socket stream to do encrypted communication.
243  */
244
245 function TLSSocket(socket, options) {
246   if (options === undefined)
247     this._tlsOptions = {};
248   else
249     this._tlsOptions = options;
250   this._secureEstablished = false;
251   this._securePending = false;
252   this._newSessionPending = false;
253   this._controlReleased = false;
254   this._SNICallback = null;
255   this.servername = null;
256   this.npnProtocol = null;
257   this.authorized = false;
258   this.authorizationError = null;
259
260   // Wrap plain JS Stream into StreamWrap
261   var wrap;
262   if (!(socket instanceof net.Socket) && socket instanceof Duplex)
263     wrap = new StreamWrap(socket);
264   else if ((socket instanceof net.Socket) && !socket._handle)
265     wrap = new StreamWrap(socket);
266   else
267     wrap = socket;
268
269   // Just a documented property to make secure sockets
270   // distinguishable from regular ones.
271   this.encrypted = true;
272
273   net.Socket.call(this, {
274     handle: this._wrapHandle(wrap),
275     allowHalfOpen: socket && socket.allowHalfOpen,
276     readable: false,
277     writable: false
278   });
279
280   // Proxy for API compatibility
281   this.ssl = this._handle;
282
283   this.on('error', this._emitTLSError);
284
285   this._init(socket, wrap);
286
287   // Make sure to setup all required properties like: `_connecting` before
288   // starting the flow of the data
289   this.readable = true;
290   this.writable = true;
291
292   // Read on next tick so the caller has a chance to setup listeners
293   process.nextTick(initRead, this, socket);
294 }
295 util.inherits(TLSSocket, net.Socket);
296 exports.TLSSocket = TLSSocket;
297
298 var proxiedMethods = [
299   'ref', 'unref', 'open', 'bind', 'listen', 'connect', 'bind6',
300   'connect6', 'getsockname', 'getpeername', 'setNoDelay', 'setKeepAlive',
301   'setSimultaneousAccepts', 'setBlocking',
302
303   // PipeWrap
304   'setPendingInstances'
305 ];
306
307 // Proxy HandleWrap, PipeWrap and TCPWrap methods
308 proxiedMethods.forEach(function(name) {
309   tls_wrap.TLSWrap.prototype[name] = function methodProxy() {
310     if (this._parent[name])
311       return this._parent[name].apply(this._parent, arguments);
312   };
313 });
314
315 tls_wrap.TLSWrap.prototype.close = function closeProxy(cb) {
316   if (this._parentWrap && this._parentWrap._handle === this._parent) {
317     this._parentWrap.once('close', cb);
318     return this._parentWrap.destroy();
319   }
320   return this._parent.close(cb);
321 };
322
323 TLSSocket.prototype._wrapHandle = function(wrap) {
324   var res;
325   var handle;
326
327   if (wrap)
328     handle = wrap._handle;
329
330   var options = this._tlsOptions;
331   if (!handle) {
332     handle = options.pipe ? new Pipe() : new TCP();
333     handle.owner = this;
334   }
335
336   // Wrap socket's handle
337   var context = options.secureContext ||
338                 options.credentials ||
339                 tls.createSecureContext();
340   res = tls_wrap.wrap(handle._externalStream,
341                       context.context,
342                       !!options.isServer);
343   res._parent = handle;
344   res._parentWrap = wrap;
345   res._secureContext = context;
346   res.reading = handle.reading;
347   Object.defineProperty(handle, 'reading', {
348     get: function readingGetter() {
349       return res.reading;
350     },
351     set: function readingSetter(value) {
352       res.reading = value;
353     }
354   });
355
356   this.on('close', function() {
357     // Make sure we are not doing it on OpenSSL's stack
358     setImmediate(destroySSL, this);
359     res = null;
360   });
361
362   return res;
363 };
364
365 function destroySSL(self) {
366   self._destroySSL();
367 }
368
369 TLSSocket.prototype._destroySSL = function _destroySSL() {
370   if (!this.ssl) return;
371   this.ssl.destroySSL();
372   if (this.ssl._secureContext.singleUse) {
373     this.ssl._secureContext.context.close();
374     this.ssl._secureContext.context = null;
375   }
376   this.ssl = null;
377 };
378
379 TLSSocket.prototype._init = function(socket, wrap) {
380   var self = this;
381   var options = this._tlsOptions;
382   var ssl = this._handle;
383
384   // lib/net.js expect this value to be non-zero if write hasn't been flushed
385   // immediately
386   // TODO(indutny): rewise this solution, it might be 1 before handshake and
387   // represent real writeQueueSize during regular writes.
388   ssl.writeQueueSize = 1;
389
390   this.server = options.server;
391
392   // Move the server to TLSSocket, otherwise both `socket.destroy()` and
393   // `TLSSocket.destroy()` will decrement number of connections of the TLS
394   // server, leading to misfiring `server.close()` callback
395   if (socket && socket.server === this.server)
396     socket.server = null;
397
398   // For clients, we will always have either a given ca list or be using
399   // default one
400   var requestCert = !!options.requestCert || !options.isServer,
401       rejectUnauthorized = !!options.rejectUnauthorized;
402
403   this._requestCert = requestCert;
404   this._rejectUnauthorized = rejectUnauthorized;
405   if (requestCert || rejectUnauthorized)
406     ssl.setVerifyMode(requestCert, rejectUnauthorized);
407
408   if (options.isServer) {
409     ssl.onhandshakestart = onhandshakestart.bind(this);
410     ssl.onhandshakedone = onhandshakedone.bind(this);
411     ssl.onclienthello = onclienthello.bind(this);
412     ssl.oncertcb = oncertcb.bind(this);
413     ssl.onnewsession = onnewsession.bind(this);
414     ssl.lastHandshakeTime = 0;
415     ssl.handshakes = 0;
416
417     if (this.server) {
418       if (this.server.listenerCount('resumeSession') > 0 ||
419           this.server.listenerCount('newSession') > 0) {
420         ssl.enableSessionCallbacks();
421       }
422       if (this.server.listenerCount('OCSPRequest') > 0)
423         ssl.enableCertCb();
424     }
425   } else {
426     ssl.onhandshakestart = function() {};
427     ssl.onhandshakedone = this._finishInit.bind(this);
428     ssl.onocspresponse = onocspresponse.bind(this);
429
430     if (options.session)
431       ssl.setSession(options.session);
432   }
433
434   ssl.onerror = function(err) {
435     if (self._writableState.errorEmitted)
436       return;
437
438     // Destroy socket if error happened before handshake's finish
439     if (!self._secureEstablished) {
440       self.destroy(self._tlsError(err));
441     } else if (options.isServer &&
442                rejectUnauthorized &&
443                /peer did not return a certificate/.test(err.message)) {
444       // Ignore server's authorization errors
445       self.destroy();
446     } else {
447       // Throw error
448       self._emitTLSError(err);
449     }
450
451     self._writableState.errorEmitted = true;
452   };
453
454   // If custom SNICallback was given, or if
455   // there're SNI contexts to perform match against -
456   // set `.onsniselect` callback.
457   if (process.features.tls_sni &&
458       options.isServer &&
459       options.SNICallback &&
460       options.server &&
461       (options.SNICallback !== SNICallback ||
462        options.server._contexts.length)) {
463     assert(typeof options.SNICallback === 'function');
464     this._SNICallback = options.SNICallback;
465     ssl.enableCertCb();
466   }
467
468   if (process.features.tls_npn && options.NPNProtocols)
469     ssl.setNPNProtocols(options.NPNProtocols);
470
471   if (options.handshakeTimeout > 0)
472     this.setTimeout(options.handshakeTimeout, this._handleTimeout);
473
474   if (socket instanceof net.Socket) {
475     this._parent = socket;
476
477     // To prevent assertion in afterConnect() and properly kick off readStart
478     this._connecting = socket._connecting || !socket._handle;
479     socket.once('connect', function() {
480       self._connecting = false;
481       self.emit('connect');
482     });
483   }
484
485   // Assume `tls.connect()`
486   if (wrap) {
487     wrap.on('error', function(err) {
488       self._emitTLSError(err);
489     });
490   } else {
491     assert(!socket);
492     this._connecting = true;
493   }
494 };
495
496 TLSSocket.prototype.renegotiate = function(options, callback) {
497   var requestCert = this._requestCert,
498       rejectUnauthorized = this._rejectUnauthorized;
499
500   if (this.destroyed)
501     return;
502
503   if (typeof options.requestCert !== 'undefined')
504     requestCert = !!options.requestCert;
505   if (typeof options.rejectUnauthorized !== 'undefined')
506     rejectUnauthorized = !!options.rejectUnauthorized;
507
508   if (requestCert !== this._requestCert ||
509       rejectUnauthorized !== this._rejectUnauthorized) {
510     this._handle.setVerifyMode(requestCert, rejectUnauthorized);
511     this._requestCert = requestCert;
512     this._rejectUnauthorized = rejectUnauthorized;
513   }
514   if (!this._handle.renegotiate()) {
515     if (callback) {
516       process.nextTick(callback, new Error('Failed to renegotiate'));
517     }
518     return false;
519   }
520
521   // Ensure that we'll cycle through internal openssl's state
522   this.write('');
523
524   if (callback) {
525     this.once('secure', function() {
526       callback(null);
527     });
528   }
529
530   return true;
531 };
532
533 TLSSocket.prototype.setMaxSendFragment = function setMaxSendFragment(size) {
534   return this._handle.setMaxSendFragment(size) == 1;
535 };
536
537 TLSSocket.prototype.getTLSTicket = function getTLSTicket() {
538   return this._handle.getTLSTicket();
539 };
540
541 TLSSocket.prototype._handleTimeout = function() {
542   this._emitTLSError(new Error('TLS handshake timeout'));
543 };
544
545 TLSSocket.prototype._emitTLSError = function(err) {
546   var e = this._tlsError(err);
547   if (e)
548     this.emit('error', e);
549 };
550
551 TLSSocket.prototype._tlsError = function(err) {
552   this.emit('_tlsError', err);
553   if (this._controlReleased)
554     return err;
555   return null;
556 };
557
558 TLSSocket.prototype._releaseControl = function() {
559   if (this._controlReleased)
560     return false;
561   this._controlReleased = true;
562   this.removeListener('error', this._emitTLSError);
563   return true;
564 };
565
566 TLSSocket.prototype._finishInit = function() {
567   // `newSession` callback wasn't called yet
568   if (this._newSessionPending) {
569     this._securePending = true;
570     return;
571   }
572
573   if (process.features.tls_npn) {
574     this.npnProtocol = this._handle.getNegotiatedProtocol();
575   }
576
577   if (process.features.tls_sni && this._tlsOptions.isServer) {
578     this.servername = this._handle.getServername();
579   }
580
581   debug('secure established');
582   this._secureEstablished = true;
583   if (this._tlsOptions.handshakeTimeout > 0)
584     this.setTimeout(0, this._handleTimeout);
585   this.emit('secure');
586 };
587
588 TLSSocket.prototype._start = function() {
589   if (this._connecting) {
590     this.once('connect', function() {
591       this._start();
592     });
593     return;
594   }
595
596   // Socket was destroyed before the connection was established
597   if (!this._handle)
598     return;
599
600   debug('start');
601   if (this._tlsOptions.requestOCSP)
602     this._handle.requestOCSP();
603   this._handle.start();
604 };
605
606 TLSSocket.prototype.setServername = function(name) {
607   this._handle.setServername(name);
608 };
609
610 TLSSocket.prototype.setSession = function(session) {
611   if (typeof session === 'string')
612     session = new Buffer(session, 'binary');
613   this._handle.setSession(session);
614 };
615
616 TLSSocket.prototype.getPeerCertificate = function(detailed) {
617   if (this._handle) {
618     return common.translatePeerCertificate(
619         this._handle.getPeerCertificate(detailed));
620   }
621
622   return null;
623 };
624
625 TLSSocket.prototype.getSession = function() {
626   if (this._handle) {
627     return this._handle.getSession();
628   }
629
630   return null;
631 };
632
633 TLSSocket.prototype.isSessionReused = function() {
634   if (this._handle) {
635     return this._handle.isSessionReused();
636   }
637
638   return null;
639 };
640
641 TLSSocket.prototype.getCipher = function(err) {
642   if (this._handle) {
643     return this._handle.getCurrentCipher();
644   } else {
645     return null;
646   }
647 };
648
649 // TODO: support anonymous (nocert) and PSK
650
651
652 // AUTHENTICATION MODES
653 //
654 // There are several levels of authentication that TLS/SSL supports.
655 // Read more about this in "man SSL_set_verify".
656 //
657 // 1. The server sends a certificate to the client but does not request a
658 // cert from the client. This is common for most HTTPS servers. The browser
659 // can verify the identity of the server, but the server does not know who
660 // the client is. Authenticating the client is usually done over HTTP using
661 // login boxes and cookies and stuff.
662 //
663 // 2. The server sends a cert to the client and requests that the client
664 // also send it a cert. The client knows who the server is and the server is
665 // requesting the client also identify themselves. There are several
666 // outcomes:
667 //
668 //   A) verifyError returns null meaning the client's certificate is signed
669 //   by one of the server's CAs. The server know's the client idenity now
670 //   and the client is authorized.
671 //
672 //   B) For some reason the client's certificate is not acceptable -
673 //   verifyError returns a string indicating the problem. The server can
674 //   either (i) reject the client or (ii) allow the client to connect as an
675 //   unauthorized connection.
676 //
677 // The mode is controlled by two boolean variables.
678 //
679 // requestCert
680 //   If true the server requests a certificate from client connections. For
681 //   the common HTTPS case, users will want this to be false, which is what
682 //   it defaults to.
683 //
684 // rejectUnauthorized
685 //   If true clients whose certificates are invalid for any reason will not
686 //   be allowed to make connections. If false, they will simply be marked as
687 //   unauthorized but secure communication will continue. By default this is
688 //   true.
689 //
690 //
691 //
692 // Options:
693 // - requestCert. Send verify request. Default to false.
694 // - rejectUnauthorized. Boolean, default to true.
695 // - key. string.
696 // - cert: string.
697 // - ca: string or array of strings.
698 // - sessionTimeout: integer.
699 //
700 // emit 'secureConnection'
701 //   function (tlsSocket) { }
702 //
703 //   "UNABLE_TO_GET_ISSUER_CERT", "UNABLE_TO_GET_CRL",
704 //   "UNABLE_TO_DECRYPT_CERT_SIGNATURE", "UNABLE_TO_DECRYPT_CRL_SIGNATURE",
705 //   "UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY", "CERT_SIGNATURE_FAILURE",
706 //   "CRL_SIGNATURE_FAILURE", "CERT_NOT_YET_VALID" "CERT_HAS_EXPIRED",
707 //   "CRL_NOT_YET_VALID", "CRL_HAS_EXPIRED" "ERROR_IN_CERT_NOT_BEFORE_FIELD",
708 //   "ERROR_IN_CERT_NOT_AFTER_FIELD", "ERROR_IN_CRL_LAST_UPDATE_FIELD",
709 //   "ERROR_IN_CRL_NEXT_UPDATE_FIELD", "OUT_OF_MEM",
710 //   "DEPTH_ZERO_SELF_SIGNED_CERT", "SELF_SIGNED_CERT_IN_CHAIN",
711 //   "UNABLE_TO_GET_ISSUER_CERT_LOCALLY", "UNABLE_TO_VERIFY_LEAF_SIGNATURE",
712 //   "CERT_CHAIN_TOO_LONG", "CERT_REVOKED" "INVALID_CA",
713 //   "PATH_LENGTH_EXCEEDED", "INVALID_PURPOSE" "CERT_UNTRUSTED",
714 //   "CERT_REJECTED"
715 //
716 function Server(/* [options], listener */) {
717   var options, listener;
718
719   if (arguments[0] !== null && typeof arguments[0] === 'object') {
720     options = arguments[0];
721     listener = arguments[1];
722   } else if (typeof arguments[0] === 'function') {
723     options = {};
724     listener = arguments[0];
725   }
726
727   if (!(this instanceof Server)) return new Server(options, listener);
728
729   this._contexts = [];
730
731   var self = this;
732
733   // Handle option defaults:
734   this.setOptions(options);
735
736   var sharedCreds = tls.createSecureContext({
737     pfx: self.pfx,
738     key: self.key,
739     passphrase: self.passphrase,
740     cert: self.cert,
741     ca: self.ca,
742     ciphers: self.ciphers,
743     ecdhCurve: self.ecdhCurve,
744     dhparam: self.dhparam,
745     secureProtocol: self.secureProtocol,
746     secureOptions: self.secureOptions,
747     honorCipherOrder: self.honorCipherOrder,
748     crl: self.crl,
749     sessionIdContext: self.sessionIdContext
750   });
751   this._sharedCreds = sharedCreds;
752
753   var timeout = options.handshakeTimeout || (120 * 1000);
754
755   if (typeof timeout !== 'number') {
756     throw new TypeError('handshakeTimeout must be a number');
757   }
758
759   if (self.sessionTimeout) {
760     sharedCreds.context.setSessionTimeout(self.sessionTimeout);
761   }
762
763   if (self.ticketKeys) {
764     sharedCreds.context.setTicketKeys(self.ticketKeys);
765   }
766
767   // constructor call
768   net.Server.call(this, function(raw_socket) {
769     var socket = new TLSSocket(raw_socket, {
770       secureContext: sharedCreds,
771       isServer: true,
772       server: self,
773       requestCert: self.requestCert,
774       rejectUnauthorized: self.rejectUnauthorized,
775       handshakeTimeout: timeout,
776       NPNProtocols: self.NPNProtocols,
777       SNICallback: options.SNICallback || SNICallback
778     });
779
780     socket.on('secure', function() {
781       if (socket._requestCert) {
782         var verifyError = socket._handle.verifyError();
783         if (verifyError) {
784           socket.authorizationError = verifyError.code;
785
786           if (socket._rejectUnauthorized)
787             socket.destroy();
788         } else {
789           socket.authorized = true;
790         }
791       }
792
793       if (!socket.destroyed && socket._releaseControl())
794         self.emit('secureConnection', socket);
795     });
796
797     var errorEmitted = false;
798     socket.on('close', function(err) {
799       // Closed because of error - no need to emit it twice
800       if (err)
801         return;
802
803       // Emit ECONNRESET
804       if (!socket._controlReleased && !errorEmitted) {
805         errorEmitted = true;
806         var connReset = new Error('socket hang up');
807         connReset.code = 'ECONNRESET';
808         self.emit('clientError', connReset, socket);
809       }
810     });
811
812     socket.on('_tlsError', function(err) {
813       if (!socket._controlReleased && !errorEmitted) {
814         errorEmitted = true;
815         self.emit('clientError', err, socket);
816       }
817     });
818   });
819
820   if (listener) {
821     this.on('secureConnection', listener);
822   }
823 }
824
825 util.inherits(Server, net.Server);
826 exports.Server = Server;
827 exports.createServer = function(options, listener) {
828   return new Server(options, listener);
829 };
830
831
832 Server.prototype._getServerData = function() {
833   return {
834     ticketKeys: this.getTicketKeys().toString('hex')
835   };
836 };
837
838
839 Server.prototype._setServerData = function(data) {
840   this.setTicketKeys(new Buffer(data.ticketKeys, 'hex'));
841 };
842
843
844 Server.prototype.getTicketKeys = function getTicketKeys(keys) {
845   return this._sharedCreds.context.getTicketKeys(keys);
846 };
847
848
849 Server.prototype.setTicketKeys = function setTicketKeys(keys) {
850   this._sharedCreds.context.setTicketKeys(keys);
851 };
852
853
854 Server.prototype.setOptions = function(options) {
855   if (typeof options.requestCert === 'boolean') {
856     this.requestCert = options.requestCert;
857   } else {
858     this.requestCert = false;
859   }
860
861   if (typeof options.rejectUnauthorized === 'boolean') {
862     this.rejectUnauthorized = options.rejectUnauthorized;
863   } else {
864     this.rejectUnauthorized = false;
865   }
866
867   if (options.pfx) this.pfx = options.pfx;
868   if (options.key) this.key = options.key;
869   if (options.passphrase) this.passphrase = options.passphrase;
870   if (options.cert) this.cert = options.cert;
871   if (options.ca) this.ca = options.ca;
872   if (options.secureProtocol) this.secureProtocol = options.secureProtocol;
873   if (options.crl) this.crl = options.crl;
874   if (options.ciphers) this.ciphers = options.ciphers;
875   if (options.ecdhCurve !== undefined)
876     this.ecdhCurve = options.ecdhCurve;
877   if (options.dhparam) this.dhparam = options.dhparam;
878   if (options.sessionTimeout) this.sessionTimeout = options.sessionTimeout;
879   if (options.ticketKeys) this.ticketKeys = options.ticketKeys;
880   var secureOptions = options.secureOptions || 0;
881   if (options.honorCipherOrder !== undefined)
882     this.honorCipherOrder = !!options.honorCipherOrder;
883   else
884     this.honorCipherOrder = true;
885   if (secureOptions) this.secureOptions = secureOptions;
886   if (options.NPNProtocols) tls.convertNPNProtocols(options.NPNProtocols, this);
887   if (options.sessionIdContext) {
888     this.sessionIdContext = options.sessionIdContext;
889   } else {
890     this.sessionIdContext = defaultSessionIdContext;
891   }
892 };
893
894 // SNI Contexts High-Level API
895 Server.prototype.addContext = function(servername, context) {
896   if (!servername) {
897     throw new Error('Servername is required parameter for Server.addContext');
898   }
899
900   var re = new RegExp('^' +
901                       servername.replace(/([\.^$+?\-\\[\]{}])/g, '\\$1')
902                                 .replace(/\*/g, '[^\.]*') +
903                       '$');
904   this._contexts.push([re, tls.createSecureContext(context).context]);
905 };
906
907 function SNICallback(servername, callback) {
908   var ctx;
909
910   this.server._contexts.some(function(elem) {
911     if (servername.match(elem[0]) !== null) {
912       ctx = elem[1];
913       return true;
914     }
915   });
916
917   callback(null, ctx);
918 }
919
920
921 // Target API:
922 //
923 //  var s = tls.connect({port: 8000, host: "google.com"}, function() {
924 //    if (!s.authorized) {
925 //      s.destroy();
926 //      return;
927 //    }
928 //
929 //    // s.socket;
930 //
931 //    s.end("hello world\n");
932 //  });
933 //
934 //
935 function normalizeConnectArgs(listArgs) {
936   var args = net._normalizeConnectArgs(listArgs);
937   var options = args[0];
938   var cb = args[1];
939
940   if (listArgs[1] !== null && typeof listArgs[1] === 'object') {
941     options = util._extend(options, listArgs[1]);
942   } else if (listArgs[2] !== null && typeof listArgs[2] === 'object') {
943     options = util._extend(options, listArgs[2]);
944   }
945
946   return (cb) ? [options, cb] : [options];
947 }
948
949 exports.connect = function(/* [port, host], options, cb */) {
950   var args = normalizeConnectArgs(arguments);
951   var options = args[0];
952   var cb = args[1];
953
954   var defaults = {
955     rejectUnauthorized: '0' !== process.env.NODE_TLS_REJECT_UNAUTHORIZED,
956     ciphers: tls.DEFAULT_CIPHERS,
957     checkServerIdentity: tls.checkServerIdentity
958   };
959
960   options = util._extend(defaults, options || {});
961   if (!options.keepAlive)
962     options.singleUse = true;
963
964   assert(typeof options.checkServerIdentity === 'function');
965
966   var hostname = options.servername ||
967                  options.host ||
968                  (options.socket && options.socket._host) ||
969                  'localhost',
970       NPN = {},
971       context = tls.createSecureContext(options);
972   tls.convertNPNProtocols(options.NPNProtocols, NPN);
973
974   var socket = new TLSSocket(options.socket, {
975     pipe: options.path && !options.port,
976     secureContext: context,
977     isServer: false,
978     requestCert: true,
979     rejectUnauthorized: options.rejectUnauthorized,
980     session: options.session,
981     NPNProtocols: NPN.NPNProtocols,
982     requestOCSP: options.requestOCSP
983   });
984
985   if (cb)
986     socket.once('secureConnect', cb);
987
988   if (!options.socket) {
989     var connect_opt;
990     if (options.path && !options.port) {
991       connect_opt = { path: options.path };
992     } else {
993       connect_opt = {
994         port: options.port,
995         host: options.host,
996         localAddress: options.localAddress
997       };
998     }
999     socket.connect(connect_opt, function() {
1000       socket._start();
1001     });
1002   }
1003
1004   socket._releaseControl();
1005
1006   if (options.session)
1007     socket.setSession(options.session);
1008
1009   if (options.servername)
1010     socket.setServername(options.servername);
1011
1012   if (options.socket)
1013     socket._start();
1014
1015   socket.on('secure', function() {
1016     var verifyError = socket._handle.verifyError();
1017
1018     // Verify that server's identity matches it's certificate's names
1019     // Unless server has resumed our existing session
1020     if (!verifyError && !socket.isSessionReused()) {
1021       var cert = socket.getPeerCertificate();
1022       verifyError = options.checkServerIdentity(hostname, cert);
1023     }
1024
1025     if (verifyError) {
1026       socket.authorized = false;
1027       socket.authorizationError = verifyError.code || verifyError.message;
1028
1029       if (options.rejectUnauthorized) {
1030         socket.destroy(verifyError);
1031         return;
1032       } else {
1033         socket.emit('secureConnect');
1034       }
1035     } else {
1036       socket.authorized = true;
1037       socket.emit('secureConnect');
1038     }
1039
1040     // Uncork incoming data
1041     socket.removeListener('end', onHangUp);
1042   });
1043
1044   function onHangUp() {
1045     // NOTE: This logic is shared with _http_client.js
1046     if (!socket._hadError) {
1047       socket._hadError = true;
1048       var error = new Error('socket hang up');
1049       error.code = 'ECONNRESET';
1050       socket.destroy(error);
1051     }
1052   }
1053   socket.once('end', onHangUp);
1054
1055   return socket;
1056 };