|
@ -24,7 +24,10 @@ var SecureStream = null; |
|
|
|
|
|
|
|
|
function SecurePair(credentials, isServer, requestCert, rejectUnauthorized) { |
|
|
function SecurePair(credentials, isServer, requestCert, rejectUnauthorized) { |
|
|
if (!(this instanceof SecurePair)) { |
|
|
if (!(this instanceof SecurePair)) { |
|
|
return new SecurePair(credentials, isServer, requestCert, rejectUnauthorized); |
|
|
return new SecurePair(credentials, |
|
|
|
|
|
isServer, |
|
|
|
|
|
requestCert, |
|
|
|
|
|
rejectUnauthorized); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
var self = this; |
|
|
var self = this; |
|
@ -183,6 +186,39 @@ exports.createSecurePair = function(credentials, |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
SecurePair.prototype._mover = function(reader, writer, checker) { |
|
|
|
|
|
var bytesRead; |
|
|
|
|
|
var pool; |
|
|
|
|
|
var chunkBytes; |
|
|
|
|
|
var chunk; |
|
|
|
|
|
|
|
|
|
|
|
do { |
|
|
|
|
|
bytesRead = 0; |
|
|
|
|
|
chunkBytes = 0; |
|
|
|
|
|
pool = new Buffer(4096); // alloc every time?
|
|
|
|
|
|
pool.used = 0; |
|
|
|
|
|
|
|
|
|
|
|
do { |
|
|
|
|
|
try { |
|
|
|
|
|
chunkBytes = reader(pool, |
|
|
|
|
|
pool.used + bytesRead, |
|
|
|
|
|
pool.length - pool.used - bytesRead); |
|
|
|
|
|
} catch (e) { |
|
|
|
|
|
return this._error(e); |
|
|
|
|
|
} |
|
|
|
|
|
if (chunkBytes >= 0) { |
|
|
|
|
|
bytesRead += chunkBytes; |
|
|
|
|
|
} |
|
|
|
|
|
} while ((chunkBytes > 0) && (pool.used + bytesRead < pool.length)); |
|
|
|
|
|
|
|
|
|
|
|
if (bytesRead > 0) { |
|
|
|
|
|
chunk = pool.slice(0, bytesRead); |
|
|
|
|
|
writer(chunk); |
|
|
|
|
|
} |
|
|
|
|
|
} while (bytesRead > 0 && checker()); |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* Attempt to cycle OpenSSLs buffers in various directions. |
|
|
* Attempt to cycle OpenSSLs buffers in various directions. |
|
|
* |
|
|
* |
|
@ -221,7 +257,6 @@ SecurePair.prototype._cycle = function() { |
|
|
var tmp; |
|
|
var tmp; |
|
|
var bytesRead; |
|
|
var bytesRead; |
|
|
var bytesWritten; |
|
|
var bytesWritten; |
|
|
var chunkBytes; |
|
|
|
|
|
var chunk = null; |
|
|
var chunk = null; |
|
|
var pool = null; |
|
|
var pool = null; |
|
|
|
|
|
|
|
@ -272,40 +307,10 @@ SecurePair.prototype._cycle = function() { |
|
|
assert(rv === tmp.length); |
|
|
assert(rv === tmp.length); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function mover(reader, writer, checker) { |
|
|
// Move decrypted, clear data out into the application.
|
|
|
var bytesRead; |
|
|
|
|
|
var pool; |
|
|
|
|
|
var chunkBytes; |
|
|
|
|
|
do { |
|
|
|
|
|
bytesRead = 0; |
|
|
|
|
|
chunkBytes = 0; |
|
|
|
|
|
pool = new Buffer(4096); |
|
|
|
|
|
pool.used = 0; |
|
|
|
|
|
|
|
|
|
|
|
do { |
|
|
|
|
|
try { |
|
|
|
|
|
chunkBytes = reader(pool, |
|
|
|
|
|
pool.used + bytesRead, |
|
|
|
|
|
pool.length - pool.used - bytesRead); |
|
|
|
|
|
} catch (e) { |
|
|
|
|
|
return self._error(e); |
|
|
|
|
|
} |
|
|
|
|
|
if (chunkBytes >= 0) { |
|
|
|
|
|
bytesRead += chunkBytes; |
|
|
|
|
|
} |
|
|
|
|
|
} while ((chunkBytes > 0) && (pool.used + bytesRead < pool.length)); |
|
|
|
|
|
|
|
|
|
|
|
if (bytesRead > 0) { |
|
|
|
|
|
chunk = pool.slice(0, bytesRead); |
|
|
|
|
|
writer(chunk); |
|
|
|
|
|
} |
|
|
|
|
|
} while (checker(bytesRead)); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Move decryptoed, clear data out into the application.
|
|
|
|
|
|
// From the user's perspective this occurs as a 'data' event
|
|
|
// From the user's perspective this occurs as a 'data' event
|
|
|
// on the pair.cleartext.
|
|
|
// on the pair.cleartext.
|
|
|
mover( |
|
|
this._mover( |
|
|
function(pool, offset, length) { |
|
|
function(pool, offset, length) { |
|
|
debug('reading from clearOut'); |
|
|
debug('reading from clearOut'); |
|
|
return self._ssl.clearOut(pool, offset, length); |
|
|
return self._ssl.clearOut(pool, offset, length); |
|
@ -313,8 +318,8 @@ SecurePair.prototype._cycle = function() { |
|
|
function(chunk) { |
|
|
function(chunk) { |
|
|
self.cleartext.emit('data', chunk); |
|
|
self.cleartext.emit('data', chunk); |
|
|
}, |
|
|
}, |
|
|
function(bytesRead) { |
|
|
function() { |
|
|
return bytesRead > 0 && self._cleartextWriteState === true; |
|
|
return self._cleartextWriteState === true; |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
// Move encrypted data to the stream. From the user's perspective this
|
|
|
// Move encrypted data to the stream. From the user's perspective this
|
|
@ -325,7 +330,7 @@ SecurePair.prototype._cycle = function() { |
|
|
// socket.write(d);
|
|
|
// socket.write(d);
|
|
|
// });
|
|
|
// });
|
|
|
//
|
|
|
//
|
|
|
mover( |
|
|
this._mover( |
|
|
function(pool, offset, length) { |
|
|
function(pool, offset, length) { |
|
|
debug('reading from encOut'); |
|
|
debug('reading from encOut'); |
|
|
if (!self._ssl) return -1; |
|
|
if (!self._ssl) return -1; |
|
@ -334,13 +339,12 @@ SecurePair.prototype._cycle = function() { |
|
|
function(chunk) { |
|
|
function(chunk) { |
|
|
self.encrypted.emit('data', chunk); |
|
|
self.encrypted.emit('data', chunk); |
|
|
}, |
|
|
}, |
|
|
function(bytesRead) { |
|
|
function() { |
|
|
if (!self._ssl) return false; |
|
|
if (!self._ssl) return false; |
|
|
return bytesRead > 0 && self._encryptedWriteState === true; |
|
|
return self._encryptedWriteState === true; |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (this._ssl && !this._secureEstablished && this._ssl.isInitFinished()) { |
|
|
if (this._ssl && !this._secureEstablished && this._ssl.isInitFinished()) { |
|
|
this._secureEstablished = true; |
|
|
this._secureEstablished = true; |
|
|
debug('secure established'); |
|
|
debug('secure established'); |
|
@ -359,6 +363,7 @@ SecurePair.prototype._destroy = function(err) { |
|
|
this.cleartext.emit('close'); |
|
|
this.cleartext.emit('close'); |
|
|
this.emit('end', err); |
|
|
this.emit('end', err); |
|
|
} |
|
|
} |
|
|
|
|
|
this._cycle(); |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -498,7 +503,12 @@ function Server(/* [options], listener */) { |
|
|
} else { |
|
|
} else { |
|
|
var verifyError = pair._ssl.verifyError(); |
|
|
var verifyError = pair._ssl.verifyError(); |
|
|
if (verifyError) { |
|
|
if (verifyError) { |
|
|
self.emit('unauthorized', pair.cleartext, verifyError); |
|
|
if (self.rejectUnauthorized) { |
|
|
|
|
|
socket.destroy(); |
|
|
|
|
|
pair._destroy(); |
|
|
|
|
|
} else { |
|
|
|
|
|
self.emit('unauthorized', pair.cleartext, verifyError); |
|
|
|
|
|
} |
|
|
} else { |
|
|
} else { |
|
|
self.emit('authorized', pair.cleartext); |
|
|
self.emit('authorized', pair.cleartext); |
|
|
} |
|
|
} |
|
@ -506,12 +516,12 @@ function Server(/* [options], listener */) { |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
pair.on('error', function(e) { |
|
|
pair.on('error', function(e) { |
|
|
console.log('pair got error: ' + e); |
|
|
console.error('pair got error: ' + e); |
|
|
self.emit('error', e); |
|
|
self.emit('error', e); |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
pair.cleartext.on('error', function(err) { |
|
|
pair.cleartext.on('error', function(err) { |
|
|
console.log('cleartext got error: ' + err); |
|
|
console.error('cleartext got error: ' + err); |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
pair.encrypted.on('error', function(err) { |
|
|
pair.encrypted.on('error', function(err) { |
|
|