Advertisement
Guest User

Untitled

a guest
Jun 22nd, 2017
62
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. var util = require('util');
  2. var stream = require("stream");
  3.  
  4. var debugLevel = parseInt(process.env.NODE_DEBUG, 16);
  5. function debug () {
  6.   if (debugLevel & 0x4) {
  7.     util.error.apply(this, arguments);
  8.   }
  9. }
  10.  
  11. /* Lazy Loaded crypto object */
  12. var SecStream = null;
  13.  
  14. /**
  15.  * Provides a Read and Write stream, wrapping an existing stream in an
  16.  * SSL/TLS connection.
  17.  *
  18.  * @param {Object} parent_stream Existing stream to wrap.
  19.  * @param {?Object} credentials   SSL Context to configure the SSL stream from, including
  20.  *                                the SSL Certificates.
  21.  * @param {?Boolean} is_server
  22.  */
  23.  
  24. function SecureStream(parent_stream, credentials, is_server)
  25. {
  26.   if (!(this instanceof SecureStream)) {
  27.     return new SecureStream(parent_stream, credentials, is_server);
  28.   }
  29.  
  30.   stream.Stream.call(this);
  31.  
  32.   var self = this;
  33.  
  34.   try {
  35.     SecStream = process.binding('crypto').SecureStream;
  36.   }
  37.   catch (e) {
  38.     throw new Error('node.js not compiled with openssl crypto support.');
  39.   }
  40.  
  41.   this._stream = parent_stream;
  42.  
  43.   this.writeable = true;
  44.   this.readable = true;
  45.   this._secureEstablished = false;
  46.   this._is_server = is_server ? true : false;
  47.   this._write_state = true;
  48.  
  49.   var crypto = require("crypto");
  50.  
  51.   if (!credentials) {
  52.     this.credentials = crypto.createCredentials();
  53.   }
  54.   else {
  55.     this.credentials = credentials;
  56.   }
  57.  
  58.   if (!this._is_server) {
  59.     /* For clients, we will always have either a given ca list or be using default one */
  60.     this.credentials.shouldVerify = true;
  61.   }
  62.  
  63.   this._secureEstablished = false;
  64.   this._encIn_pending = [];
  65.   this._clearIn_pending = [];
  66.  
  67.   this._ssl = new SecStream(this.credentials.context,
  68.                             this._is_server ? true : false,
  69.                             this.credentials.shouldVerify);
  70.  
  71.   this._stream.on('data', function(data) {
  72.     debug('client data');
  73.     self._read(data);
  74.   });
  75.  
  76.   this._stream.on('error', function(err) {
  77.     debug('client error');
  78.     self._error(err);
  79.   });
  80.  
  81.   this._stream.on('end', function() {
  82.     debug('client end');
  83.     self.writeable = false;
  84.     self.readable = false;
  85.     self.emit('end');
  86.   });
  87.  
  88.   this._stream.on('close', function() {
  89.     debug('client close');
  90.     self.emit('close');
  91.   });
  92.  
  93.   this._stream.on('drain', function() {
  94.     debug('client drain');
  95.     self._cycle();
  96.     self.emit('drain');
  97.   });
  98.  
  99.   process.nextTick(function() {
  100.     self._ssl.start();
  101.     self._cycle();
  102.   });
  103. }
  104.  
  105. util.inherits(SecureStream, stream.Stream);
  106. exports.SecureStream = SecureStream;
  107.  
  108. /**
  109.  * Attempt to cycle OpenSSLs buffers in various directions.
  110.  *
  111.  * An SSL Connection can be viewed as four separate piplines,
  112.  * interacting with one has no connection to the behavoir of
  113.  * any of the other 3 -- This might not sound reasonable,
  114.  * but consider things like mid-stream renegotiation of
  115.  * the ciphers.
  116.  *
  117.  * The four pipelines, using terminology of the client (server is just reversed):
  118.  *   1) Encrypted Output stream (Writing encrypted data to peer)
  119.  *   2) Encrypted Input stream (Reading encrypted data from peer)
  120.  *   3) Cleartext Output stream (Decrypted content from the peer)
  121.  *   4) Cleartext Input stream (Cleartext content to send to the peer)
  122.  *
  123.  * This function attempts to push any available data out of the Cleartext
  124.  * output stream (#3), and the Encrypted output stream (#1), and push them up
  125.  * to the consumer or the peer socket, respectively.
  126.  *
  127.  * It is called whenever we do something with OpenSSL -- post reciving content,
  128.  * trying to flush, trying to change ciphers, or shutting down the connection.
  129.  *
  130.  * Because it is also called everywhere, we also check if the connection
  131.  * has completed negotiation and emit 'secure' from here if it has.
  132.  */
  133. SecureStream.prototype._cycle = function() {
  134.   var rv;
  135.   var tmp;
  136.   var bytesRead;
  137.   var bytesWritten;
  138.   var chunkBytes;
  139.   var chunk = null;
  140.   var pool = null;
  141.  
  142.   while (this._encIn_pending.length > 0) {
  143.     tmp = this._encIn_pending.shift();
  144.  
  145.     try {
  146.      rv = this._ssl.encIn(tmp, 0, tmp.length);
  147.     } catch (e) {
  148.       return this._error(e);
  149.     }
  150.  
  151.     if (rv === 0) {
  152.       this._encIn_pending.unshift(tmp);
  153.       break;
  154.     }
  155.  
  156.     assert(rv === tmp.length);
  157.   }
  158.  
  159.   while (this._clearIn_pending.length > 0) {
  160.     tmp = this._clearIn_pending.shift();
  161.     try {
  162.       rv = this._ssl.clearIn(tmp, 0, tmp.length);
  163.     } catch (e) {
  164.       return this._error(e);
  165.     }
  166.  
  167.     if (rv === 0) {
  168.       this._clearIn_pending.unshift(tmp);
  169.       break;
  170.     }
  171.  
  172.     assert(rv === tmp.length);
  173.   }
  174.  
  175.   do {
  176.     bytesRead = 0;
  177.     chunkBytes = 0;
  178.     pool = new Buffer(4096);
  179.     pool.used = 0;
  180.     do {
  181.       try {
  182.         chunkBytes = this._ssl.clearOut(pool,
  183.                                         pool.used + bytesRead,
  184.                                         pool.length - pool.used - bytesRead);
  185.       } catch (e) {
  186.         return this._error(e);
  187.       }
  188.       if (chunkBytes >= 0) {
  189.         debug('clearOut read: '+ chunkBytes);
  190.         bytesRead += chunkBytes;
  191.       }
  192.     } while ((chunkBytes > 0) && (pool.used + bytesRead < pool.length));
  193.  
  194.     if (bytesRead > 0) {
  195.       chunk = pool.slice(0, bytesRead);
  196.       this.emit('data', chunk);
  197.     }
  198.   } while (bytesRead > 0);
  199.  
  200.   do {
  201.     pool = new Buffer(4096);
  202.     pool.used = 0;
  203.     bytesRead = 0;
  204.     chunkBytes = 0;
  205.     bytesWritten = 0;
  206.  
  207.     do {
  208.       try {
  209.         chunkBytes = this._ssl.encOut(pool,
  210.                                       pool.used + bytesRead,
  211.                                       pool.length - pool.used - bytesRead);
  212.       } catch (e) {
  213.         return this._error(e);
  214.       }
  215.       if (chunkBytes >= 0) {
  216.         debug('encOut read: '+ chunkBytes);
  217.         bytesRead += chunkBytes;
  218.       }
  219.     } while ((chunkBytes > 0) && (pool.used + bytesRead < pool.length));
  220.  
  221.     if (bytesRead > 0) {
  222.       chunk = pool.slice(0, bytesRead);
  223.       self._write_state = this._stream.write(chunk);
  224.     }
  225.   } while (bytesRead > 0 && this._write_state === true);
  226.  
  227.   if (!this._secureEstablished && this._ssl.isInitFinished()) {
  228.     this._secureEstablished = true;
  229.     debug('secure established');
  230.     this.emit('secure');
  231.     this._secureCycle();
  232.   }
  233. };
  234.  
  235. /**
  236.  * Attempt to pause the stream. Event can still be emitted.
  237.  */
  238. SecureStream.prototype.pause = function()
  239. {
  240.   this._stream.pause();
  241. };
  242.  
  243. /**
  244.  * Resume a stream that was previously paused.
  245.  */
  246. SecureStream.prototype.resume = function()
  247. {
  248.   this._stream.resume();
  249. };
  250.  
  251.  
  252. /* writable emit events: 'drain', 'error', 'close' */
  253. /* writable methods */
  254. SecureStream.prototype.destroy = function()
  255. {
  256.   this.writeable = false;
  257.   this.readable = false;
  258.   this._ssl.close();
  259.   this._stream.destroy();
  260. };
  261.  
  262. SecureStream.prototype.end = function(data, encoding)
  263. {
  264.   if (data) {
  265.     this.write(data, encoding);
  266.   }
  267.   this._ssl.shutdown();
  268.   this._cycle();
  269.   this._stream.end();
  270. };
  271.  
  272. SecureStream.prototype.write = function (chunk)
  273. {
  274.   this._clearIn_pending.push(chunk);
  275.   this._cycle();
  276.   return this._write_state;
  277. };
  278.  
  279. SecureStream.prototype._read = function (data)
  280. {
  281.   this._encIn_pending.push(data);
  282.   this._cycle();
  283. };
  284.  
  285. SecureStream.prototype._error = function (err)
  286. {
  287.   self.writeable = false;
  288.   self.readable = false;
  289.   self.emit('error', err);
  290. };
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement