Skip to content

Commit cbdcaea

Browse files
committed
src: in-source comments and minor TLS cleanups
Renamed some internal C++ methods and properties for consistency, and commented SSL I/O. - Rename waiting_new_session_ after is_waiting_new_session(), instead of using reverse naming (new_session_wait_), and change "waiting" to "awaiting". - Make TLSWrap::ClearIn() return void, the value is never used. - Fix a getTicketKeys() cut-n-paste error. Since it doesn't use the arguments, remove them from the js wrapper. - Remove call of setTicketKeys(getTicketKeys()), its a no-op.
1 parent 4814987 commit cbdcaea

8 files changed

+84
-39
lines changed

lib/_tls_wrap.js

+2-4
Original file line numberDiff line numberDiff line change
@@ -1003,8 +1003,6 @@ Server.prototype.setSecureContext = function(options) {
10031003
if (options.ticketKeys) {
10041004
this.ticketKeys = options.ticketKeys;
10051005
this.setTicketKeys(this.ticketKeys);
1006-
} else {
1007-
this.setTicketKeys(this.getTicketKeys());
10081006
}
10091007
};
10101008

@@ -1021,8 +1019,8 @@ Server.prototype._setServerData = function(data) {
10211019
};
10221020

10231021

1024-
Server.prototype.getTicketKeys = function getTicketKeys(keys) {
1025-
return this._sharedCreds.context.getTicketKeys(keys);
1022+
Server.prototype.getTicketKeys = function getTicketKeys() {
1023+
return this._sharedCreds.context.getTicketKeys();
10261024
};
10271025

10281026

src/node_crypto.cc

+3-2
Original file line numberDiff line numberDiff line change
@@ -1532,7 +1532,7 @@ int SSLWrap<Base>::NewSessionCallback(SSL* s, SSL_SESSION* sess) {
15321532
reinterpret_cast<const char*>(session_id_data),
15331533
session_id_length).ToLocalChecked();
15341534
Local<Value> argv[] = { session_id, session };
1535-
w->new_session_wait_ = true;
1535+
w->awaiting_new_session_ = true;
15361536
w->MakeCallback(env->onnewsession_string(), arraysize(argv), argv);
15371537

15381538
return 0;
@@ -2128,6 +2128,7 @@ void SSLWrap<Base>::Renegotiate(const FunctionCallbackInfo<Value>& args) {
21282128

21292129
ClearErrorOnReturn clear_error_on_return;
21302130

2131+
// XXX(sam) Return/throw an error, don't discard the SSL error reason.
21312132
bool yes = SSL_renegotiate(w->ssl_.get()) == 1;
21322133
args.GetReturnValue().Set(yes);
21332134
}
@@ -2161,7 +2162,7 @@ template <class Base>
21612162
void SSLWrap<Base>::NewSessionDone(const FunctionCallbackInfo<Value>& args) {
21622163
Base* w;
21632164
ASSIGN_OR_RETURN_UNWRAP(&w, args.Holder());
2164-
w->new_session_wait_ = false;
2165+
w->awaiting_new_session_ = false;
21652166
w->NewSessionDoneCb();
21662167
}
21672168

src/node_crypto.h

+3-3
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ class SSLWrap {
218218
kind_(kind),
219219
next_sess_(nullptr),
220220
session_callbacks_(false),
221-
new_session_wait_(false),
221+
awaiting_new_session_(false),
222222
cert_cb_(nullptr),
223223
cert_cb_arg_(nullptr),
224224
cert_cb_running_(false) {
@@ -234,7 +234,7 @@ class SSLWrap {
234234
inline void enable_session_callbacks() { session_callbacks_ = true; }
235235
inline bool is_server() const { return kind_ == kServer; }
236236
inline bool is_client() const { return kind_ == kClient; }
237-
inline bool is_waiting_new_session() const { return new_session_wait_; }
237+
inline bool is_awaiting_new_session() const { return awaiting_new_session_; }
238238
inline bool is_waiting_cert_cb() const { return cert_cb_ != nullptr; }
239239

240240
protected:
@@ -325,7 +325,7 @@ class SSLWrap {
325325
SSLSessionPointer next_sess_;
326326
SSLPointer ssl_;
327327
bool session_callbacks_;
328-
bool new_session_wait_;
328+
bool awaiting_new_session_;
329329

330330
// SSL_set_cert_cb
331331
CertCb cert_cb_;

src/node_crypto_bio.h

+6-5
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ namespace node {
3434
namespace crypto {
3535

3636
// This class represents buffers for OpenSSL I/O, implemented as a singly-linked
37-
// list of chunks. It can be used both for writing data from Node to OpenSSL
38-
// and back, but only one direction per instance.
37+
// list of chunks. It can be used either for writing data from Node to OpenSSL,
38+
// or for reading data back, but not both.
3939
// The structure is only accessed, and owned by, the OpenSSL BIOPointer
4040
// (a.k.a. std::unique_ptr<BIO>).
4141
class NodeBIO : public MemoryRetainer {
@@ -80,11 +80,12 @@ class NodeBIO : public MemoryRetainer {
8080
// Put `len` bytes from `data` into buffer
8181
void Write(const char* data, size_t size);
8282

83-
// Return pointer to internal data and amount of
84-
// contiguous data available for future writes
83+
// Return pointer to contiguous block of reserved data and the size available
84+
// for future writes. Call Commit() once the write is complete.
8585
char* PeekWritable(size_t* size);
8686

87-
// Commit reserved data
87+
// Specify how much data was written into the block returned by
88+
// PeekWritable().
8889
void Commit(size_t size);
8990

9091

src/node_crypto_clienthello.h

+3
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@
3030
namespace node {
3131
namespace crypto {
3232

33+
// Parse the client hello so we can do async session resumption. OpenSSL's
34+
// session resumption uses synchronous callbacks, see SSL_CTX_sess_set_get_cb
35+
// and get_session_cb.
3336
class ClientHelloParser {
3437
public:
3538
inline ClientHelloParser();

src/stream_wrap.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ void LibuvStreamWrap::OnUvRead(ssize_t nread, const uv_buf_t* buf) {
232232
type = uv_pipe_pending_type(reinterpret_cast<uv_pipe_t*>(stream()));
233233
}
234234

235-
// We should not be getting this callback if someone as already called
235+
// We should not be getting this callback if someone has already called
236236
// uv_close() on the handle.
237237
CHECK_EQ(persistent().IsEmpty(), false);
238238

src/tls_wrap.cc

+43-17
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,11 @@ void TLSWrap::InitSSL() {
116116
#endif // SSL_MODE_RELEASE_BUFFERS
117117

118118
SSL_set_app_data(ssl_.get(), this);
119+
// Using InfoCallback isn't how we are supposed to check handshake progress:
120+
// https://github.com/openssl/openssl/issues/7199#issuecomment-420915993
121+
//
122+
// Note on when this gets called on various openssl versions:
123+
// https://github.com/openssl/openssl/issues/7199#issuecomment-420670544
119124
SSL_set_info_callback(ssl_.get(), SSLInfoCallback);
120125

121126
if (is_server()) {
@@ -194,6 +199,9 @@ void TLSWrap::Start(const FunctionCallbackInfo<Value>& args) {
194199

195200
// Send ClientHello handshake
196201
CHECK(wrap->is_client());
202+
// Seems odd to read when when we want to send, but SSL_read() triggers a
203+
// handshake if a session isn't established, and handshake will cause
204+
// encrypted data to become available for output.
197205
wrap->ClearOut();
198206
wrap->EncOut();
199207
}
@@ -248,7 +256,7 @@ void TLSWrap::EncOut() {
248256
return;
249257

250258
// Wait for `newSession` callback to be invoked
251-
if (is_waiting_new_session())
259+
if (is_awaiting_new_session())
252260
return;
253261

254262
// Split-off queue
@@ -258,7 +266,7 @@ void TLSWrap::EncOut() {
258266
if (ssl_ == nullptr)
259267
return;
260268

261-
// No data to write
269+
// No encrypted output ready to write to the underlying stream.
262270
if (BIO_pending(enc_out_) == 0) {
263271
if (pending_cleartext_input_.empty())
264272
InvokeQueued(0);
@@ -480,13 +488,13 @@ void TLSWrap::ClearOut() {
480488
}
481489

482490

483-
bool TLSWrap::ClearIn() {
491+
void TLSWrap::ClearIn() {
484492
// Ignore cycling data if ClientHello wasn't yet parsed
485493
if (!hello_parser_.IsEnded())
486-
return false;
494+
return;
487495

488496
if (ssl_ == nullptr)
489-
return false;
497+
return;
490498

491499
std::vector<uv_buf_t> buffers;
492500
buffers.swap(pending_cleartext_input_);
@@ -506,8 +514,9 @@ bool TLSWrap::ClearIn() {
506514

507515
// All written
508516
if (i == buffers.size()) {
517+
// We wrote all the buffers, so no writes failed (written < 0 on failure).
509518
CHECK_GE(written, 0);
510-
return true;
519+
return;
511520
}
512521

513522
// Error or partial write
@@ -519,6 +528,8 @@ bool TLSWrap::ClearIn() {
519528
Local<Value> arg = GetSSLError(written, &err, &error_str);
520529
if (!arg.IsEmpty()) {
521530
write_callback_scheduled_ = true;
531+
// XXX(sam) Should forward an error object with .code/.function/.etc, if
532+
// possible.
522533
InvokeQueued(UV_EPROTO, error_str.c_str());
523534
} else {
524535
// Push back the not-yet-written pending buffers into their queue.
@@ -529,7 +540,7 @@ bool TLSWrap::ClearIn() {
529540
buffers.end());
530541
}
531542

532-
return false;
543+
return;
533544
}
534545

535546

@@ -585,6 +596,7 @@ void TLSWrap::ClearError() {
585596
}
586597

587598

599+
// Called by StreamBase::Write() to request async write of clear text into SSL.
588600
int TLSWrap::DoWrite(WriteWrap* w,
589601
uv_buf_t* bufs,
590602
size_t count,
@@ -598,18 +610,26 @@ int TLSWrap::DoWrite(WriteWrap* w,
598610
}
599611

600612
bool empty = true;
601-
602-
// Empty writes should not go through encryption process
603613
size_t i;
604-
for (i = 0; i < count; i++)
614+
for (i = 0; i < count; i++) {
605615
if (bufs[i].len > 0) {
606616
empty = false;
607617
break;
608618
}
619+
}
620+
621+
// We want to trigger a Write() on the underlying stream to drive the stream
622+
// system, but don't want to encrypt empty buffers into a TLS frame, so see
623+
// if we can find something to Write().
624+
// First, call ClearOut(). It does an SSL_read(), which might cause handshake
625+
// or other internal messages to be encrypted. If it does, write them later
626+
// with EncOut().
627+
// If there is still no encrypted output, call Write(bufs) on the underlying
628+
// stream. Since the bufs are empty, it won't actually write non-TLS data
629+
// onto the socket, we just want the side-effects. After, make sure the
630+
// WriteWrap was accepted by the stream, or that we call Done() on it.
609631
if (empty) {
610632
ClearOut();
611-
// However, if there is any data that should be written to the socket,
612-
// the callback should not be invoked immediately
613633
if (BIO_pending(enc_out_) == 0) {
614634
CHECK_NULL(current_empty_write_);
615635
current_empty_write_ = w;
@@ -629,7 +649,7 @@ int TLSWrap::DoWrite(WriteWrap* w,
629649
CHECK_NULL(current_write_);
630650
current_write_ = w;
631651

632-
// Write queued data
652+
// Write encrypted data to underlying stream and call Done().
633653
if (empty) {
634654
EncOut();
635655
return 0;
@@ -648,17 +668,20 @@ int TLSWrap::DoWrite(WriteWrap* w,
648668
if (i != count) {
649669
int err;
650670
Local<Value> arg = GetSSLError(written, &err, &error_);
671+
672+
// If we stopped writing because of an error, it's fatal, discard the data.
651673
if (!arg.IsEmpty()) {
652674
current_write_ = nullptr;
653675
return UV_EPROTO;
654676
}
655677

678+
// Otherwise, save unwritten data so it can be written later by ClearIn().
656679
pending_cleartext_input_.insert(pending_cleartext_input_.end(),
657680
&bufs[i],
658681
&bufs[count]);
659682
}
660683

661-
// Try writing data immediately
684+
// Write any encrypted/handshake output that may be ready.
662685
EncOut();
663686

664687
return 0;
@@ -690,17 +713,20 @@ void TLSWrap::OnStreamRead(ssize_t nread, const uv_buf_t& buf) {
690713
return;
691714
}
692715

693-
// Only client connections can receive data
694716
if (ssl_ == nullptr) {
695717
EmitRead(UV_EPROTO);
696718
return;
697719
}
698720

699-
// Commit read data
721+
// Commit the amount of data actually read into the peeked/allocated buffer
722+
// from the underlying stream.
700723
crypto::NodeBIO* enc_in = crypto::NodeBIO::FromBIO(enc_in_);
701724
enc_in->Commit(nread);
702725

703-
// Parse ClientHello first
726+
// Parse ClientHello first, if we need to. It's only parsed if session event
727+
// listeners are used on the server side. "ended" is the initial state, so
728+
// can mean parsing was never started, or that parsing is finished. Either
729+
// way, ended means we can give the buffered data to SSL.
704730
if (!hello_parser_.IsEnded()) {
705731
size_t avail = 0;
706732
uint8_t* data = reinterpret_cast<uint8_t*>(enc_in->Peek(&avail));

src/tls_wrap.h

+23-7
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,9 @@ class TLSWrap : public AsyncWrap,
7272
uv_buf_t* bufs,
7373
size_t count,
7474
uv_stream_t* send_handle) override;
75+
// Return error_ string or nullptr if it's empty.
7576
const char* Error() const override;
77+
// Reset error_ string to empty. Not related to "clear text".
7678
void ClearError() override;
7779

7880
void NewSessionDoneCb();
@@ -105,11 +107,22 @@ class TLSWrap : public AsyncWrap,
105107

106108
static void SSLInfoCallback(const SSL* ssl_, int where, int ret);
107109
void InitSSL();
108-
void EncOut();
109-
bool ClearIn();
110-
void ClearOut();
110+
// SSL has a "clear" text (unencrypted) side (to/from the node API) and
111+
// encrypted ("enc") text side (to/from the underlying socket/stream).
112+
// On each side data flows "in" or "out" of SSL context.
113+
//
114+
// EncIn() doesn't exist. Encrypted data is pushed from underlying stream into
115+
// enc_in_ via the stream listener's OnStreamAlloc()/OnStreamRead() interface.
116+
void EncOut(); // Write encrypted data from enc_out_ to underlying stream.
117+
void ClearIn(); // SSL_write() clear data "in" to SSL.
118+
void ClearOut(); // SSL_read() clear text "out" from SSL.
119+
120+
// Call Done() on outstanding WriteWrap request.
111121
bool InvokeQueued(int status, const char* error_str = nullptr);
112122

123+
// Drive the SSL state machine by attempting to SSL_read() and SSL_write() to
124+
// it. Transparent handshakes mean SSL_read() might trigger I/O on the
125+
// underlying stream even if there is no clear text to read or write.
113126
inline void Cycle() {
114127
// Prevent recursion
115128
if (++cycle_depth_ > 1)
@@ -118,6 +131,7 @@ class TLSWrap : public AsyncWrap,
118131
for (; cycle_depth_ > 0; cycle_depth_--) {
119132
ClearIn();
120133
ClearOut();
134+
// EncIn() doesn't exist, it happens via stream listener callbacks.
121135
EncOut();
122136
}
123137
}
@@ -139,16 +153,18 @@ class TLSWrap : public AsyncWrap,
139153
static void SetVerifyMode(const v8::FunctionCallbackInfo<v8::Value>& args);
140154
static void EnableSessionCallbacks(
141155
const v8::FunctionCallbackInfo<v8::Value>& args);
142-
static void EnableCertCb(
143-
const v8::FunctionCallbackInfo<v8::Value>& args);
156+
static void EnableTrace(const v8::FunctionCallbackInfo<v8::Value>& args);
157+
static void EnableCertCb(const v8::FunctionCallbackInfo<v8::Value>& args);
144158
static void DestroySSL(const v8::FunctionCallbackInfo<v8::Value>& args);
145159
static void GetServername(const v8::FunctionCallbackInfo<v8::Value>& args);
146160
static void SetServername(const v8::FunctionCallbackInfo<v8::Value>& args);
147161
static int SelectSNIContextCallback(SSL* s, int* ad, void* arg);
148162

149163
crypto::SecureContext* sc_;
150-
BIO* enc_in_ = nullptr;
151-
BIO* enc_out_ = nullptr;
164+
// BIO buffers hold encrypted data.
165+
BIO* enc_in_ = nullptr; // StreamListener fills this for SSL_read().
166+
BIO* enc_out_ = nullptr; // SSL_write()/handshake fills this for EncOut().
167+
// Waiting for ClearIn() to pass to SSL_write().
152168
std::vector<uv_buf_t> pending_cleartext_input_;
153169
size_t write_size_ = 0;
154170
WriteWrap* current_write_ = nullptr;

0 commit comments

Comments
 (0)