3 const assert = require('assert');
4 const EventEmitter = require('events');
5 const stream = require('stream');
6 const tls = require('tls');
7 const util = require('util');
8 const common = require('_tls_common');
9 const debug = util.debuglog('tls-legacy');
10 const Buffer = require('buffer').Buffer;
11 const Timer = process.binding('timer_wrap').Timer;
12 var Connection = null;
14 Connection = process.binding('crypto').Connection;
16 throw new Error('node.js not compiled with openssl crypto support.');
19 function SlabBuffer() {
24 SlabBuffer.prototype.create = function create() {
26 this.pool = new Buffer(tls.SLAB_BUFFER_SIZE);
28 this.remaining = this.pool.length;
32 SlabBuffer.prototype.use = function use(context, fn, size) {
33 if (this.remaining === 0) {
38 var actualSize = this.remaining;
40 if (size !== null) actualSize = Math.min(size, actualSize);
42 var bytes = fn.call(context, this.pool, this.offset, actualSize);
45 this.remaining -= bytes;
48 assert(this.remaining >= 0);
54 var slabBuffer = null;
57 // Base class of both CleartextStream and EncryptedStream
58 function CryptoStream(pair, options) {
59 stream.Duplex.call(this, options);
63 this._pendingEncoding = '';
64 this._pendingCallback = null;
65 this._doneFlag = false;
66 this._retryAfterPartial = false;
67 this._halfRead = false;
68 this._sslOutCb = null;
69 this._resumingSession = false;
71 this._destroyed = false;
73 this._finished = false;
74 this._opposite = null;
76 if (slabBuffer === null) slabBuffer = new SlabBuffer();
77 this._buffer = slabBuffer;
79 this.once('finish', onCryptoStreamFinish);
81 // net.Socket calls .onend too
82 this.once('end', onCryptoStreamEnd);
84 util.inherits(CryptoStream, stream.Duplex);
87 function onCryptoStreamFinish() {
88 this._finished = true;
90 if (this === this.pair.cleartext) {
91 debug('cleartext.onfinish');
93 // Generate close notify
94 // NOTE: first call checks if client has sent us shutdown,
95 // second call enqueues shutdown into the BIO.
96 if (this.pair.ssl.shutdownSSL() !== 1) {
97 if (this.pair.ssl && this.pair.ssl.error)
98 return this.pair.error();
100 this.pair.ssl.shutdownSSL();
103 if (this.pair.ssl && this.pair.ssl.error)
104 return this.pair.error();
107 debug('encrypted.onfinish');
110 // Try to read just to get sure that we won't miss EOF
111 if (this._opposite.readable) this._opposite.read(0);
113 if (this._opposite._ended) {
116 // No half-close, sorry
117 if (this === this.pair.cleartext) this._opposite._done();
122 function onCryptoStreamEnd() {
124 if (this === this.pair.cleartext) {
125 debug('cleartext.onend');
127 debug('encrypted.onend');
132 // NOTE: Called once `this._opposite` is set.
133 CryptoStream.prototype.init = function init() {
135 this._opposite.on('sslOutEnd', function() {
136 if (self._sslOutCb) {
137 var cb = self._sslOutCb;
138 self._sslOutCb = null;
145 CryptoStream.prototype._write = function write(data, encoding, cb) {
146 assert(this._pending === null);
149 if (!this.pair.ssl) return cb(null);
151 // When resuming session don't accept any new data.
152 // And do not put too much data into openssl, before writing it from encrypted
155 // TODO(indutny): Remove magic number, use watermark based limits
156 if (!this._resumingSession &&
157 this._opposite._internallyPendingBytes() < 128 * 1024) {
158 // Write current buffer now
160 if (this === this.pair.cleartext) {
161 debug('cleartext.write called with %d bytes', data.length);
162 written = this.pair.ssl.clearIn(data, 0, data.length);
164 debug('encrypted.write called with %d bytes', data.length);
165 written = this.pair.ssl.encIn(data, 0, data.length);
168 // Handle and report errors
169 if (this.pair.ssl && this.pair.ssl.error) {
170 return cb(this.pair.error(true));
173 // Force SSL_read call to cycle some states/data inside OpenSSL
174 this.pair.cleartext.read(0);
176 // Cycle encrypted data
177 if (this.pair.encrypted._internallyPendingBytes())
178 this.pair.encrypted.read(0);
180 // Get NPN and Server name when ready
181 this.pair.maybeInitFinished();
183 // Whole buffer was written
184 if (written === data.length) {
185 if (this === this.pair.cleartext) {
186 debug('cleartext.write succeed with ' + written + ' bytes');
188 debug('encrypted.write succeed with ' + written + ' bytes');
191 // Invoke callback only when all data read from opposite stream
192 if (this._opposite._halfRead) {
193 assert(this._sslOutCb === null);
199 } else if (written !== 0 && written !== -1) {
200 assert(!this._retryAfterPartial);
201 this._retryAfterPartial = true;
202 this._write(data.slice(written), encoding, cb);
203 this._retryAfterPartial = false;
207 debug('cleartext.write queue is full');
209 // Force SSL_read call to cycle some states/data inside OpenSSL
210 this.pair.cleartext.read(0);
213 // No write has happened
214 this._pending = data;
215 this._pendingEncoding = encoding;
216 this._pendingCallback = cb;
218 if (this === this.pair.cleartext) {
219 debug('cleartext.write queued with %d bytes', data.length);
221 debug('encrypted.write queued with %d bytes', data.length);
226 CryptoStream.prototype._writePending = function writePending() {
227 var data = this._pending,
228 encoding = this._pendingEncoding,
229 cb = this._pendingCallback;
231 this._pending = null;
232 this._pendingEncoding = '';
233 this._pendingCallback = null;
234 this._write(data, encoding, cb);
238 CryptoStream.prototype._read = function read(size) {
240 if (!this.pair.ssl) return this.push(null);
242 // Wait for session to be resumed
243 // Mark that we're done reading, but don't provide data or EOF
244 if (this._resumingSession || !this._reading) return this.push('');
247 if (this === this.pair.cleartext) {
248 debug('cleartext.read called with %d bytes', size);
249 out = this.pair.ssl.clearOut;
251 debug('encrypted.read called with %d bytes', size);
252 out = this.pair.ssl.encOut;
256 start = this._buffer.offset,
259 assert(last === this._buffer.offset);
260 var read = this._buffer.use(this.pair.ssl, out, size - bytesRead);
264 last = this._buffer.offset;
266 // Handle and report errors
267 if (this.pair.ssl && this.pair.ssl.error) {
272 !this._buffer.isFull &&
274 this.pair.ssl !== null);
276 // Get NPN and Server name when ready
277 this.pair.maybeInitFinished();
279 // Create new buffer if previous was filled up
280 var pool = this._buffer.pool;
281 if (this._buffer.isFull) this._buffer.create();
283 assert(bytesRead >= 0);
285 if (this === this.pair.cleartext) {
286 debug('cleartext.read succeed with %d bytes', bytesRead);
288 debug('encrypted.read succeed with %d bytes', bytesRead);
291 // Try writing pending data
292 if (this._pending !== null) this._writePending();
293 if (this._opposite._pending !== null) this._opposite._writePending();
295 if (bytesRead === 0) {
296 // EOF when cleartext has finished and we have nothing to read
297 if (this._opposite._finished && this._internallyPendingBytes() === 0 ||
298 this.pair.ssl && this.pair.ssl.receivedShutdown) {
299 // Perform graceful shutdown
302 // No half-open, sorry!
303 if (this === this.pair.cleartext) {
304 this._opposite._done();
308 } else if (!this.pair.ssl || !this.pair.ssl.receivedShutdown) {
317 // Give them requested data
318 this.push(pool.slice(start, start + bytesRead));
321 // Let users know that we've some internal data to read
322 var halfRead = this._internallyPendingBytes() !== 0;
324 // Smart check to avoid invoking 'sslOutEnd' in the most of the cases
325 if (this._halfRead !== halfRead) {
326 this._halfRead = halfRead;
328 // Notify listeners about internal data end
330 if (this === this.pair.cleartext) {
331 debug('cleartext.sslOutEnd');
333 debug('encrypted.sslOutEnd');
336 this.emit('sslOutEnd');
342 CryptoStream.prototype.setTimeout = function(timeout, callback) {
343 if (this.socket) this.socket.setTimeout(timeout, callback);
347 CryptoStream.prototype.setNoDelay = function(noDelay) {
348 if (this.socket) this.socket.setNoDelay(noDelay);
352 CryptoStream.prototype.setKeepAlive = function(enable, initialDelay) {
353 if (this.socket) this.socket.setKeepAlive(enable, initialDelay);
356 CryptoStream.prototype.__defineGetter__('bytesWritten', function() {
357 return this.socket ? this.socket.bytesWritten : 0;
360 CryptoStream.prototype.getPeerCertificate = function(detailed) {
362 return common.translatePeerCertificate(
363 this.pair.ssl.getPeerCertificate(detailed));
369 CryptoStream.prototype.getSession = function() {
371 return this.pair.ssl.getSession();
377 CryptoStream.prototype.isSessionReused = function() {
379 return this.pair.ssl.isSessionReused();
385 CryptoStream.prototype.getCipher = function(err) {
387 return this.pair.ssl.getCurrentCipher();
394 CryptoStream.prototype.end = function(chunk, encoding) {
395 if (this === this.pair.cleartext) {
396 debug('cleartext.end');
398 debug('encrypted.end');
401 // Write pending data first
402 if (this._pending !== null) this._writePending();
404 this.writable = false;
406 stream.Duplex.prototype.end.call(this, chunk, encoding);
410 CryptoStream.prototype.destroySoon = function(err) {
411 if (this === this.pair.cleartext) {
412 debug('cleartext.destroySoon');
414 debug('encrypted.destroySoon');
420 if (this._writableState.finished && this._opposite._ended) {
423 // Wait for both `finish` and `end` events to ensure that all data that
424 // was written on this side was read from the other side.
427 var finish = function() {
428 if (--waiting === 0) self.destroy();
430 this._opposite.once('end', finish);
431 if (!this._finished) {
432 this.once('finish', finish);
439 CryptoStream.prototype.destroy = function(err) {
440 if (this._destroyed) return;
441 this._destroyed = true;
442 this.readable = this.writable = false;
445 if (this === this.pair.cleartext) {
446 debug('cleartext.destroy');
448 debug('encrypted.destroy');
450 this._opposite.destroy();
452 process.nextTick(destroyNT, this, err ? true : false);
456 function destroyNT(self, hadErr) {
460 // Emit 'close' event
461 self.emit('close', hadErr);
465 CryptoStream.prototype._done = function() {
466 this._doneFlag = true;
468 if (this === this.pair.encrypted && !this.pair._secureEstablished)
469 return this.pair.error();
471 if (this.pair.cleartext._doneFlag &&
472 this.pair.encrypted._doneFlag &&
473 !this.pair._doneFlag) {
474 // If both streams are done:
480 // readyState is deprecated. Don't use it.
481 Object.defineProperty(CryptoStream.prototype, 'readyState', {
483 if (this._connecting) {
485 } else if (this.readable && this.writable) {
487 } else if (this.readable && !this.writable) {
489 } else if (!this.readable && this.writable) {
498 function CleartextStream(pair, options) {
499 CryptoStream.call(this, pair, options);
501 // This is a fake kludge to support how the http impl sits
502 // on top of net Sockets
505 readStop: function() {
506 self._reading = false;
508 readStart: function() {
509 if (self._reading && self._readableState.length > 0) return;
510 self._reading = true;
512 if (self._opposite.readable) self._opposite.read(0);
516 util.inherits(CleartextStream, CryptoStream);
519 CleartextStream.prototype._internallyPendingBytes = function() {
521 return this.pair.ssl.clearPending();
528 CleartextStream.prototype.address = function() {
529 return this.socket && this.socket.address();
533 CleartextStream.prototype.__defineGetter__('remoteAddress', function() {
534 return this.socket && this.socket.remoteAddress;
537 CleartextStream.prototype.__defineGetter__('remoteFamily', function() {
538 return this.socket && this.socket.remoteFamily;
541 CleartextStream.prototype.__defineGetter__('remotePort', function() {
542 return this.socket && this.socket.remotePort;
546 CleartextStream.prototype.__defineGetter__('localAddress', function() {
547 return this.socket && this.socket.localAddress;
551 CleartextStream.prototype.__defineGetter__('localPort', function() {
552 return this.socket && this.socket.localPort;
556 function EncryptedStream(pair, options) {
557 CryptoStream.call(this, pair, options);
559 util.inherits(EncryptedStream, CryptoStream);
562 EncryptedStream.prototype._internallyPendingBytes = function() {
564 return this.pair.ssl.encPending();
571 function onhandshakestart() {
572 debug('onhandshakestart');
576 var now = Timer.now();
578 assert(now >= ssl.lastHandshakeTime);
580 if ((now - ssl.lastHandshakeTime) >= tls.CLIENT_RENEG_WINDOW * 1000) {
584 var first = (ssl.lastHandshakeTime === 0);
585 ssl.lastHandshakeTime = now;
588 if (++ssl.handshakes > tls.CLIENT_RENEG_LIMIT) {
589 // Defer the error event to the next tick. We're being called from OpenSSL's
590 // state machine and OpenSSL is not re-entrant. We cannot allow the user's
591 // callback to destroy the connection right now, it would crash and burn.
592 setImmediate(function() {
593 var err = new Error('TLS session renegotiation attack detected.');
594 if (self.cleartext) self.cleartext.emit('error', err);
600 function onhandshakedone() {
602 debug('onhandshakedone');
606 function onclienthello(hello) {
610 this._resumingSession = true;
611 function callback(err, session) {
615 if (err) return self.socket.destroy(err);
617 self.ssl.loadSession(session);
618 self.ssl.endParser();
621 self._resumingSession = false;
622 self.cleartext.read(0);
623 self.encrypted.read(0);
626 if (hello.sessionId.length <= 0 ||
628 !this.server.emit('resumeSession', hello.sessionId, callback)) {
629 callback(null, null);
634 function onnewsession(key, session) {
635 if (!this.server) return;
640 if (!self.server.emit('newSession', key, session, done))
649 self.ssl.newSessionDone();
654 function onocspresponse(resp) {
655 this.emit('OCSPResponse', resp);
660 * Provides a pair of streams to do encrypted communication.
663 function SecurePair(context, isServer, requestCert, rejectUnauthorized,
665 if (!(this instanceof SecurePair)) {
666 return new SecurePair(context,
673 options || (options = {});
675 EventEmitter.call(this);
677 this.server = options.server;
678 this._secureEstablished = false;
679 this._isServer = isServer ? true : false;
680 this._encWriteState = true;
681 this._clearWriteState = true;
682 this._doneFlag = false;
683 this._destroying = false;
686 this.credentials = tls.createSecureContext();
688 this.credentials = context;
691 if (!this._isServer) {
692 // For clients, we will always have either a given ca list or be using
697 this._rejectUnauthorized = rejectUnauthorized ? true : false;
698 this._requestCert = requestCert ? true : false;
700 this.ssl = new Connection(this.credentials.context,
701 this._isServer ? true : false,
702 this._isServer ? this._requestCert :
704 this._rejectUnauthorized);
706 if (this._isServer) {
707 this.ssl.onhandshakestart = onhandshakestart.bind(this);
708 this.ssl.onhandshakedone = onhandshakedone.bind(this);
709 this.ssl.onclienthello = onclienthello.bind(this);
710 this.ssl.onnewsession = onnewsession.bind(this);
711 this.ssl.lastHandshakeTime = 0;
712 this.ssl.handshakes = 0;
714 this.ssl.onocspresponse = onocspresponse.bind(this);
717 if (process.features.tls_sni) {
718 if (this._isServer && options.SNICallback) {
719 this.ssl.setSNICallback(options.SNICallback);
721 this.servername = null;
724 if (process.features.tls_npn && options.NPNProtocols) {
725 this.ssl.setNPNProtocols(options.NPNProtocols);
726 this.npnProtocol = null;
729 /* Acts as a r/w stream to the cleartext side of the stream. */
730 this.cleartext = new CleartextStream(this, options.cleartext);
732 /* Acts as a r/w stream to the encrypted side of the stream. */
733 this.encrypted = new EncryptedStream(this, options.encrypted);
735 /* Let streams know about each other */
736 this.cleartext._opposite = this.encrypted;
737 this.encrypted._opposite = this.cleartext;
738 this.cleartext.init();
739 this.encrypted.init();
741 process.nextTick(securePairNT, this, options);
744 util.inherits(SecurePair, EventEmitter);
746 function securePairNT(self, options) {
747 /* The Connection may be destroyed by an abort call */
751 if (options.requestOCSP)
752 self.ssl.requestOCSP();
754 /* In case of cipher suite failures - SSL_accept/SSL_connect may fail */
755 if (self.ssl && self.ssl.error)
761 exports.createSecurePair = function(context,
764 rejectUnauthorized) {
765 var pair = new SecurePair(context,
773 SecurePair.prototype.maybeInitFinished = function() {
774 if (this.ssl && !this._secureEstablished && this.ssl.isInitFinished()) {
775 if (process.features.tls_npn) {
776 this.npnProtocol = this.ssl.getNegotiatedProtocol();
779 if (process.features.tls_sni) {
780 this.servername = this.ssl.getServername();
783 this._secureEstablished = true;
784 debug('secure established');
790 SecurePair.prototype.destroy = function() {
791 if (this._destroying) return;
793 if (!this._doneFlag) {
794 debug('SecurePair.destroy');
795 this._destroying = true;
797 // SecurePair should be destroyed only after it's streams
798 this.cleartext.destroy();
799 this.encrypted.destroy();
801 this._doneFlag = true;
802 this.ssl.error = null;
809 SecurePair.prototype.error = function(returnOnly) {
810 var err = this.ssl.error;
811 this.ssl.error = null;
813 if (!this._secureEstablished) {
814 // Emit ECONNRESET instead of zero return
815 if (!err || err.message === 'ZERO_RETURN') {
816 var connReset = new Error('socket hang up');
817 connReset.code = 'ECONNRESET';
818 connReset.sslError = err && err.message;
823 if (!returnOnly) this.emit('error', err);
824 } else if (this._isServer &&
825 this._rejectUnauthorized &&
826 /peer did not return a certificate/.test(err.message)) {
827 // Not really an error.
830 if (!returnOnly) this.cleartext.emit('error', err);
836 exports.pipe = function pipe(pair, socket) {
837 pair.encrypted.pipe(socket);
838 socket.pipe(pair.encrypted);
840 pair.encrypted.on('close', function() {
841 process.nextTick(pipeCloseNT, pair, socket);
845 var cleartext = pair.cleartext;
846 cleartext.socket = socket;
847 cleartext.encrypted = pair.encrypted;
848 cleartext.authorized = false;
850 // cycle the data whenever the socket drains, so that
851 // we can pull some more into it. normally this would
852 // be handled by the fact that pipe() triggers read() calls
853 // on writable.drain, but CryptoStreams are a bit more
854 // complicated. Since the encrypted side actually gets
855 // its data from the cleartext side, we have to give it a
856 // light kick to get in motion again.
857 socket.on('drain', function() {
858 if (pair.encrypted._pending)
859 pair.encrypted._writePending();
860 if (pair.cleartext._pending)
861 pair.cleartext._writePending();
862 pair.encrypted.read(0);
863 pair.cleartext.read(0);
866 function onerror(e) {
867 if (cleartext._controlReleased) {
868 cleartext.emit('error', e);
873 socket.removeListener('error', onerror);
874 socket.removeListener('timeout', ontimeout);
877 function ontimeout() {
878 cleartext.emit('timeout');
881 socket.on('error', onerror);
882 socket.on('close', onclose);
883 socket.on('timeout', ontimeout);
889 function pipeCloseNT(pair, socket) {
890 // Encrypted should be unpiped from socket to prevent possible
891 // write after destroy.
892 pair.encrypted.unpipe(socket);
893 socket.destroySoon();