Destroying the TLS session implies destroying the underlying socket but
before this commit, that was done with net.Socket#destroy() rather than
net.Socket#destroySoon(). The former closes the connection right away,
even when there is still data to write. In other words, sometimes the
final TLS record got truncated.
Fixes#6107.
Otherwise the data ends up "on the wire" twice, and
switching between consuming the stream using `ondata`
vs. `read()` would yield duplicate data, which was bad.
The NPN protocols was set on `require('tls')` or `global` object instead
of being a local property. This fact lead to strange persistence of NPN
protocols, and sometimes incorrect protocol selection (when no NPN
protocols were passed in client options).
fix#6168
`maybeInitFinished()` can emit the 'secure' event which
in turn destroys the connection in case of authentication
failure and sets `this.pair.ssl` to `null`.
If such condition appeared after non-empty read - loop will continue
and `clearOut` will be called on `null` object instead of
`crypto::Connection` instance. Resulting in the following assertion:
ERROR: Error: Hostname/IP doesn't match certificate's altnames
Assertion failed: handle->InternalFieldCount() > 0
fix#5756
A pooled https agent may get a Connection: close, but never finish
destroying the socket as the prior request had already emitted finish
likely from a pipe.
Since the socket is not marked as destroyed it may get reused by the
agent pool and result in an ECONNRESET.
re: #5712#5739
Split `tls.js` into `_tls_legacy.js`, containing legacy
`createSecurePair` API, and `_tls_wrap.js` containing new code based on
`tls_wrap` binding.
Remove tests that are no longer useful/valid.
1. Emit `sslOutEnd` only when `_internallyPendingBytes() === 0`.
2. Read before checking `._halfRead`, otherwise we'll see only previous
value, and will invoke `._write` callback improperly.
3. Wait for both `end` and `finish` events in `.destroySoon`.
4. Unpipe encrypted stream from socket to prevent write after destroy.
Stream's `._write()` callback should be invoked only after it's opposite
stream has finished processing incoming data, otherwise `finish` event
fires too early and connection might be closed while there's some data
to send to the client.
see #5544
Quote from SSL_shutdown man page:
The output of SSL_get_error(3) may be misleading,
as an erroneous SSL_ERROR_SYSCALL may be flagged even though
no error occurred.
Also, handle all other errors to prevent assertion in `ClearError()`.
When writing bad data to EncryptedStream it'll first get to the
ClientHello parser, and, only after it will refuse it, to the OpenSSL.
But ClientHello parser has limited buffer and therefore write could
return `bytes_written` < `incoming_bytes`, which is not the case when
working with OpenSSL.
After such errors ClientHello parser disables itself and will
pass-through all data to the OpenSSL. So just trying to write data one
more time will throw the rest into OpenSSL and let it handle it.
This saves a few calls to gettimeofday which can be expensive, and
potentially subject to clock drift. Instead use the loop time which
uses hrtime internally.
fixes#5497
Add localAddress and localPort properties to tls.CleartextStream.
Like remoteAddress and localPort, delegate to the backing net.Socket
object.
Refs #5502.
RFC 6125 explicitly states that a client "MUST NOT seek a match
for a reference identifier of CN-ID if the presented identifiers
include a DNS-ID, SRV-ID, URI-ID, or any application-specific
identifier types supported by the client", but it MAY do so if
none of the mentioned identifier types (but others) are present.
The v0.8 Stream.pipe() method automatically destroyed the destination
stream whenever the src stream closed. However, this caused a lot of
problems, and was removed by popular demand. (Many userland modules
still have a no-op destroy() method just because of this.) It was also
very hazardous because this would be done even if { end: false } was
passed in the pipe options.
In v0.10, we decided that the 'close' event and destroy() method are
application-specific, and pipe() doesn't automatically call destroy().
However, TLS actually depended (silently) on this behavior. So, in this
case, we should just go ahead and destroy the thing when close happens.
Closes#5145
Calling `this.pair.encrypted._internallyPendingBytes()` before
handling/resetting error will result in assertion failure:
../src/node_crypto.cc:962: void node::crypto::Connection::ClearError():
Assertion `handle_->Get(String::New("error"))->BooleanValue() == false'
failed.
see #5058
Add the `sessionTimeout` integral value to the list of options
recognized by `tls.createServer`.
This option will be useful for applications which need frequently
establish short-lived TLS connections to the same endpoint. The TLS
tickets RFC is an ideal option to reduce the socket setup overhead
for such scenarios, but the default ticket timeout value (5
minutes) is too low to be useful.
Commit f53441a added crypto.getCiphers() as a function that returns the
names of SSL ciphers.
Commit 14a6c4e then added crypto.getHashes(), which returns the names of
digest algorithms, but that creates a subtle inconsistency: the return
values of crypto.getHashes() are valid arguments to crypto.createHash()
but that is not true for crypto.getCiphers() - the returned values are
only valid for SSL/TLS functions.
Rectify that by adding tls.getCiphers() and making crypto.getCiphers()
return proper cipher names.
This is not a great fix, and it's a bug that's very tricky to reproduce.
Occasionally, while downloading a file, especially on Linux for some
reason, the pause/resume timing will be just right such that the
CryptoStream is in a 'reading' state, but actually has no data, so it
ought to pull more in. Because there's no reads happening, it just sits
there, and the process will exit
This is, fundamentally, a factor of how the HTTP implementation sits
atop CryptoStreams and TCP Socket objects, which is utterly horrible,
and needs to be rewritten. However, in the meantime, npm downloads are
prematurely exiting, causing hard-to-debug "cb() never called!" errors.
1. Get rid of unnecessary 'finishing' flag
2. Dont check both ending and ended. Extraneous.
Also: Remove extraneous 'finishing' flag, and don't check both 'ending'
and 'ended', since checking just 'ending' is sufficient.
This makes it so that `stream.push(chunk)` is the only way to signal the
end of reading, removing the confusing disparity between the
callback-style _read method, and the fact that most real-world streams
do not have a 1:1 corollation between the "please give me data" event,
and the actual arrival of a chunk of data.
It is still possible, of course, to implement a `CallbackReadable` on
top of this. Simply provide a method like this as the callback:
function readCallback(er, chunk) {
if (er)
stream.emit('error', er);
else
stream.push(chunk);
}
However, *only* fs streams actually would behave in this way, so it
makes not a lot of sense to make TCP, TLS, HTTP, and all the rest have
to bend into this uncomfortable paradigm.
lib/http.js is using stream._handle.readStart/readStop to control
data-flow coming out from underlying stream. If this methods are not
present - data might be buffered regardless of whether it'll be read.
see #4657
This adds a proxy for bytesWritten to the tls.CryptoStream. This
change makes the connection object more similar between HTTP and
HTTPS requests in an effort to avoid confusion.
See issue #4650 for more background information.
Don't allow connections to stall indefinitely if the SSL/TLS handshake does
not complete.
Adds a new tls.Server and https.Server configuration option, handshakeTimeout.
Fixes#4355.