mirror of https://github.com/nodejs/node.git
TLS: simplify logic
parent
fc8afd45c7
commit
55bff5bab9
183
lib/tls.js
183
lib/tls.js
|
@ -51,7 +51,7 @@ function CryptoStream(pair) {
|
|||
|
||||
this.readable = this.writable = true;
|
||||
|
||||
this._writeState = true;
|
||||
this._paused = false;
|
||||
this._pending = [];
|
||||
this._pendingCallbacks = [];
|
||||
this._pendingBytes = 0;
|
||||
|
@ -90,11 +90,10 @@ CryptoStream.prototype.write = function(data /* , encoding, cb */) {
|
|||
|
||||
this._pending.push(data);
|
||||
this._pendingCallbacks.push(cb);
|
||||
|
||||
this._pendingBytes += data.length;
|
||||
|
||||
this.pair._writeCalled = true;
|
||||
this.pair._cycle();
|
||||
this.pair.cycle();
|
||||
|
||||
return this._pendingBytes < 128 * 1024;
|
||||
};
|
||||
|
@ -102,14 +101,14 @@ CryptoStream.prototype.write = function(data /* , encoding, cb */) {
|
|||
|
||||
CryptoStream.prototype.pause = function() {
|
||||
debug('paused ' + (this == this.pair.cleartext ? 'cleartext' : 'encrypted'));
|
||||
this._writeState = false;
|
||||
this._paused = true;
|
||||
};
|
||||
|
||||
|
||||
CryptoStream.prototype.resume = function() {
|
||||
debug('resume ' + (this == this.pair.cleartext ? 'cleartext' : 'encrypted'));
|
||||
this._writeState = true;
|
||||
this.pair._cycle();
|
||||
this._paused = false;
|
||||
this.pair.cycle();
|
||||
};
|
||||
|
||||
|
||||
|
@ -147,8 +146,8 @@ function parseCertString(s) {
|
|||
|
||||
|
||||
CryptoStream.prototype.getPeerCertificate = function() {
|
||||
if (this.pair._ssl) {
|
||||
var c = this.pair._ssl.getPeerCertificate();
|
||||
if (this.pair.ssl) {
|
||||
var c = this.pair.ssl.getPeerCertificate();
|
||||
|
||||
if (c) {
|
||||
if (c.issuer) c.issuer = parseCertString(c.issuer);
|
||||
|
@ -162,8 +161,8 @@ CryptoStream.prototype.getPeerCertificate = function() {
|
|||
|
||||
|
||||
CryptoStream.prototype.getCipher = function(err) {
|
||||
if (this.pair._ssl) {
|
||||
return this.pair._ssl.getCurrentCipher();
|
||||
if (this.pair.ssl) {
|
||||
return this.pair.ssl.getCurrentCipher();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
@ -171,23 +170,22 @@ CryptoStream.prototype.getCipher = function(err) {
|
|||
|
||||
|
||||
CryptoStream.prototype.end = function(d) {
|
||||
if (this.writable) {
|
||||
if (this.pair._done) return;
|
||||
if (this.pair._doneFlag) return;
|
||||
if (!this.writable) return;
|
||||
|
||||
if (d) {
|
||||
this.write(d);
|
||||
}
|
||||
|
||||
this._pending.push(END_OF_FILE);
|
||||
this._pendingCallbacks.push(null);
|
||||
|
||||
// If this is an encrypted stream then we need to disable further 'data'
|
||||
// events.
|
||||
|
||||
this.writable = false;
|
||||
|
||||
this.pair._cycle();
|
||||
if (d) {
|
||||
this.write(d);
|
||||
}
|
||||
|
||||
this._pending.push(END_OF_FILE);
|
||||
this._pendingCallbacks.push(null);
|
||||
|
||||
// If this is an encrypted stream then we need to disable further 'data'
|
||||
// events.
|
||||
|
||||
this.writable = false;
|
||||
|
||||
this.pair.cycle();
|
||||
};
|
||||
|
||||
|
||||
|
@ -201,8 +199,8 @@ CryptoStream.prototype.destroySoon = function(err) {
|
|||
|
||||
|
||||
CryptoStream.prototype.destroy = function(err) {
|
||||
if (this.pair._done) return;
|
||||
this.pair._destroy();
|
||||
if (this.pair._doneFlag) return;
|
||||
this.pair.destroy();
|
||||
};
|
||||
|
||||
|
||||
|
@ -211,9 +209,9 @@ CryptoStream.prototype._done = function() {
|
|||
|
||||
if (this.pair.cleartext._doneFlag &&
|
||||
this.pair.encrypted._doneFlag &&
|
||||
!this.pair._done) {
|
||||
!this.pair._doneFlag) {
|
||||
// If both streams are done:
|
||||
this.pair._destroy();
|
||||
this.pair.destroy();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -241,7 +239,7 @@ CryptoStream.prototype._push = function() {
|
|||
return;
|
||||
}
|
||||
|
||||
while (this._writeState == true) {
|
||||
while (!this._paused) {
|
||||
var bytesRead = 0;
|
||||
var chunkBytes = 0;
|
||||
var pool = new Buffer(16 * 4096); // alloc every time?
|
||||
|
@ -249,18 +247,18 @@ CryptoStream.prototype._push = function() {
|
|||
do {
|
||||
chunkBytes = this._pusher(pool, bytesRead, pool.length - bytesRead);
|
||||
|
||||
if (this.pair._ssl && this.pair._ssl.error) {
|
||||
this.pair._error();
|
||||
if (this.pair.ssl && this.pair.ssl.error) {
|
||||
this.pair.error();
|
||||
return;
|
||||
}
|
||||
|
||||
this.pair._maybeInitFinished();
|
||||
this.pair.maybeInitFinished();
|
||||
|
||||
if (chunkBytes >= 0) {
|
||||
bytesRead += chunkBytes;
|
||||
}
|
||||
|
||||
} while ((chunkBytes > 0) && (bytesRead < pool.length));
|
||||
} while (chunkBytes > 0 && bytesRead < pool.length);
|
||||
|
||||
assert(bytesRead >= 0);
|
||||
|
||||
|
@ -313,7 +311,7 @@ CryptoStream.prototype._pull = function() {
|
|||
assert(havePending || this._pendingBytes == 0);
|
||||
|
||||
while (this._pending.length > 0) {
|
||||
if (!this.pair._ssl) break;
|
||||
if (!this.pair.ssl) break;
|
||||
|
||||
var tmp = this._pending.shift();
|
||||
var cb = this._pendingCallbacks.shift();
|
||||
|
@ -330,7 +328,7 @@ CryptoStream.prototype._pull = function() {
|
|||
assert(this === this.pair.cleartext);
|
||||
debug('end cleartext');
|
||||
|
||||
this.pair._ssl.shutdown();
|
||||
this.pair.ssl.shutdown();
|
||||
|
||||
// TODO check if we get EAGAIN From shutdown, would have to do it
|
||||
// again. should unshift END_OF_FILE back onto pending and wait for
|
||||
|
@ -338,7 +336,7 @@ CryptoStream.prototype._pull = function() {
|
|||
|
||||
this.pair.encrypted._destroyAfterPush = true;
|
||||
}
|
||||
this.pair._cycle();
|
||||
this.pair.cycle();
|
||||
this._done()
|
||||
return;
|
||||
}
|
||||
|
@ -347,12 +345,12 @@ CryptoStream.prototype._pull = function() {
|
|||
|
||||
var rv = this._puller(tmp);
|
||||
|
||||
if (this.pair._ssl && this.pair._ssl.error) {
|
||||
this.pair._error();
|
||||
if (this.pair.ssl && this.pair.ssl.error) {
|
||||
this.pair.error();
|
||||
return;
|
||||
}
|
||||
|
||||
this.pair._maybeInitFinished();
|
||||
this.pair.maybeInitFinished();
|
||||
|
||||
if (rv === 0 || rv < 0) {
|
||||
this._pending.unshift(tmp);
|
||||
|
@ -384,8 +382,8 @@ util.inherits(CleartextStream, CryptoStream);
|
|||
|
||||
|
||||
CleartextStream.prototype._internallyPendingBytes = function() {
|
||||
if (this.pair._ssl) {
|
||||
return this.pair._ssl.clearPending();
|
||||
if (this.pair.ssl) {
|
||||
return this.pair.ssl.clearPending();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
@ -394,14 +392,14 @@ CleartextStream.prototype._internallyPendingBytes = function() {
|
|||
|
||||
CleartextStream.prototype._puller = function(b) {
|
||||
debug('clearIn ' + b.length + ' bytes');
|
||||
return this.pair._ssl.clearIn(b, 0, b.length);
|
||||
return this.pair.ssl.clearIn(b, 0, b.length);
|
||||
};
|
||||
|
||||
|
||||
CleartextStream.prototype._pusher = function(pool, offset, length) {
|
||||
debug('reading from clearOut');
|
||||
if (!this.pair._ssl) return -1;
|
||||
return this.pair._ssl.clearOut(pool, offset, length);
|
||||
if (!this.pair.ssl) return -1;
|
||||
return this.pair.ssl.clearOut(pool, offset, length);
|
||||
};
|
||||
|
||||
|
||||
|
@ -412,8 +410,8 @@ util.inherits(EncryptedStream, CryptoStream);
|
|||
|
||||
|
||||
EncryptedStream.prototype._internallyPendingBytes = function() {
|
||||
if (this.pair._ssl) {
|
||||
return this.pair._ssl.encPending();
|
||||
if (this.pair.ssl) {
|
||||
return this.pair.ssl.encPending();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
@ -422,14 +420,14 @@ EncryptedStream.prototype._internallyPendingBytes = function() {
|
|||
|
||||
EncryptedStream.prototype._puller = function(b) {
|
||||
debug('writing from encIn');
|
||||
return this.pair._ssl.encIn(b, 0, b.length);
|
||||
return this.pair.ssl.encIn(b, 0, b.length);
|
||||
};
|
||||
|
||||
|
||||
EncryptedStream.prototype._pusher = function(pool, offset, length) {
|
||||
debug('reading from encOut');
|
||||
if (!this.pair._ssl) return -1;
|
||||
return this.pair._ssl.encOut(pool, offset, length);
|
||||
if (!this.pair.ssl) return -1;
|
||||
return this.pair.ssl.encOut(pool, offset, length);
|
||||
};
|
||||
|
||||
|
||||
|
@ -453,9 +451,7 @@ function SecurePair(credentials, isServer, requestCert, rejectUnauthorized) {
|
|||
this._isServer = isServer ? true : false;
|
||||
this._encWriteState = true;
|
||||
this._clearWriteState = true;
|
||||
this._done = false;
|
||||
|
||||
var crypto = require('crypto');
|
||||
this._doneFlag = false;
|
||||
|
||||
if (!credentials) {
|
||||
this.credentials = crypto.createCredentials();
|
||||
|
@ -473,7 +469,7 @@ function SecurePair(credentials, isServer, requestCert, rejectUnauthorized) {
|
|||
this._rejectUnauthorized = rejectUnauthorized ? true : false;
|
||||
this._requestCert = requestCert ? true : false;
|
||||
|
||||
this._ssl = new Connection(this.credentials.context,
|
||||
this.ssl = new Connection(this.credentials.context,
|
||||
this._isServer ? true : false,
|
||||
this._requestCert,
|
||||
this._rejectUnauthorized);
|
||||
|
@ -486,8 +482,8 @@ function SecurePair(credentials, isServer, requestCert, rejectUnauthorized) {
|
|||
this.encrypted = new EncryptedStream(this);
|
||||
|
||||
process.nextTick(function() {
|
||||
self._ssl.start();
|
||||
self._cycle();
|
||||
self.ssl.start();
|
||||
self.cycle();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -535,59 +531,54 @@ exports.createSecurePair = function(credentials,
|
|||
* Because it is also called everywhere, we also check if the connection has
|
||||
* completed negotiation and emit 'secure' from here if it has.
|
||||
*/
|
||||
SecurePair.prototype._cycle = function(depth) {
|
||||
depth = depth ? depth : 0;
|
||||
if (this._done) {
|
||||
return;
|
||||
}
|
||||
SecurePair.prototype.cycle = function(depth) {
|
||||
if (this._doneFlag) return;
|
||||
|
||||
if(depth == 0) this._writeCalled = false;
|
||||
depth = depth ? depth : 0;
|
||||
|
||||
if (depth == 0) this._writeCalled = false;
|
||||
|
||||
var established = this._secureEstablished;
|
||||
|
||||
if (!this._cycleEncryptedPullLock) {
|
||||
this._cycleEncryptedPullLock = true;
|
||||
if (!this.cycleEncryptedPullLock) {
|
||||
this.cycleEncryptedPullLock = true;
|
||||
debug("encrypted._pull");
|
||||
this.encrypted._pull();
|
||||
this._cycleEncryptedPullLock = false;
|
||||
this.cycleEncryptedPullLock = false;
|
||||
}
|
||||
|
||||
if (!this._cycleCleartextPullLock) {
|
||||
this._cycleCleartextPullLock = true;
|
||||
if (!this.cycleCleartextPullLock) {
|
||||
this.cycleCleartextPullLock = true;
|
||||
debug("cleartext._pull");
|
||||
this.cleartext._pull();
|
||||
this._cycleCleartextPullLock = false;
|
||||
this.cycleCleartextPullLock = false;
|
||||
}
|
||||
|
||||
if (!this._cycleCleartextPushLock) {
|
||||
this._cycleCleartextPushLock = true;
|
||||
if (!this.cycleCleartextPushLock) {
|
||||
this.cycleCleartextPushLock = true;
|
||||
debug("cleartext._push");
|
||||
this.cleartext._push();
|
||||
this._cycleCleartextPushLock = false;
|
||||
this.cycleCleartextPushLock = false;
|
||||
}
|
||||
|
||||
if (!this._cycleEncryptedPushLock) {
|
||||
this._cycleEncryptedPushLock = true;
|
||||
if (!this.cycleEncryptedPushLock) {
|
||||
this.cycleEncryptedPushLock = true;
|
||||
debug("encrypted._push");
|
||||
this.encrypted._push();
|
||||
this._cycleEncryptedPushLock = false;
|
||||
}
|
||||
|
||||
if (this._done) {
|
||||
return;
|
||||
this.cycleEncryptedPushLock = false;
|
||||
}
|
||||
|
||||
if ((!established && this._secureEstablished) ||
|
||||
(depth == 0 && this._writeCalled)) {
|
||||
// If we were not established but now we are, let's cycle again.
|
||||
// Or if there is some data to write...
|
||||
this._cycle(depth + 1);
|
||||
this.cycle(depth + 1);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
SecurePair.prototype._maybeInitFinished = function() {
|
||||
if (this._ssl && !this._secureEstablished && this._ssl.isInitFinished()) {
|
||||
SecurePair.prototype.maybeInitFinished = function() {
|
||||
if (this.ssl && !this._secureEstablished && this.ssl.isInitFinished()) {
|
||||
this._secureEstablished = true;
|
||||
debug('secure established');
|
||||
this.emit('secure');
|
||||
|
@ -595,14 +586,14 @@ SecurePair.prototype._maybeInitFinished = function() {
|
|||
};
|
||||
|
||||
|
||||
SecurePair.prototype._destroy = function() {
|
||||
SecurePair.prototype.destroy = function() {
|
||||
var self = this;
|
||||
|
||||
if (!this._done) {
|
||||
this._done = true;
|
||||
this._ssl.error = null;
|
||||
this._ssl.close();
|
||||
this._ssl = null;
|
||||
if (!this._doneFlag) {
|
||||
this._doneFlag = true;
|
||||
this.ssl.error = null;
|
||||
this.ssl.close();
|
||||
this.ssl = null;
|
||||
|
||||
self.encrypted.writable = self.encrypted.readable = false;
|
||||
self.cleartext.writable = self.cleartext.readable = false;
|
||||
|
@ -612,23 +603,21 @@ SecurePair.prototype._destroy = function() {
|
|||
self.cleartext.emit('close');
|
||||
});
|
||||
}
|
||||
|
||||
this._cycle();
|
||||
};
|
||||
|
||||
|
||||
SecurePair.prototype._error = function() {
|
||||
SecurePair.prototype.error = function() {
|
||||
if (!this._secureEstablished) {
|
||||
this._destroy();
|
||||
this.destroy();
|
||||
} else {
|
||||
var err = this._ssl.error;
|
||||
this._ssl.error = null;
|
||||
var err = this.ssl.error;
|
||||
this.ssl.error = null;
|
||||
|
||||
if (this._isServer &&
|
||||
this._rejectUnauthorized &&
|
||||
/peer did not return a certificate/.test(err.message)) {
|
||||
// Not really an error.
|
||||
this._destroy();
|
||||
this.destroy();
|
||||
} else {
|
||||
this.cleartext.emit('error', err);
|
||||
}
|
||||
|
@ -749,13 +738,13 @@ function Server(/* [options], listener */) {
|
|||
cleartext._controlReleased = true;
|
||||
self.emit('secureConnection', pair.cleartext, pair.encrypted);
|
||||
} else {
|
||||
var verifyError = pair._ssl.verifyError();
|
||||
var verifyError = pair.ssl.verifyError();
|
||||
if (verifyError) {
|
||||
pair.cleartext.authorizationError = verifyError;
|
||||
|
||||
if (self.rejectUnauthorized) {
|
||||
socket.destroy();
|
||||
pair._destroy();
|
||||
pair.destroy();
|
||||
} else {
|
||||
cleartext._controlReleased = true;
|
||||
self.emit('secureConnection', pair.cleartext, pair.encrypted);
|
||||
|
@ -851,7 +840,7 @@ exports.connect = function(port /* host, options, cb */) {
|
|||
socket.connect(port, host);
|
||||
|
||||
pair.on('secure', function() {
|
||||
var verifyError = pair._ssl.verifyError();
|
||||
var verifyError = pair.ssl.verifyError();
|
||||
|
||||
if (verifyError) {
|
||||
cleartext.authorized = false;
|
||||
|
|
Loading…
Reference in New Issue