parent
a4436bab7b
commit
75ea11fc08
@ -484,10 +484,11 @@ established - it will be forwarded here.
|
|||||||
|
|
||||||
### Event: 'newSession'
|
### Event: 'newSession'
|
||||||
|
|
||||||
`function (sessionId, sessionData) { }`
|
`function (sessionId, sessionData, callback) { }`
|
||||||
|
|
||||||
Emitted on creation of TLS session. May be used to store sessions in external
|
Emitted on creation of TLS session. May be used to store sessions in external
|
||||||
storage.
|
storage. `callback` must be invoked eventually, otherwise no data will be
|
||||||
|
sent or received from secure connection.
|
||||||
|
|
||||||
NOTE: adding this event listener will have an effect only on connections
|
NOTE: adding this event listener will have an effect only on connections
|
||||||
established after addition of event listener.
|
established after addition of event listener.
|
||||||
|
@ -653,7 +653,27 @@ function onclienthello(hello) {
|
|||||||
|
|
||||||
function onnewsession(key, session) {
|
function onnewsession(key, session) {
|
||||||
if (!this.server) return;
|
if (!this.server) return;
|
||||||
this.server.emit('newSession', key, session);
|
|
||||||
|
var self = this;
|
||||||
|
var once = false;
|
||||||
|
|
||||||
|
self.server.emit('newSession', key, session, function() {
|
||||||
|
if (once)
|
||||||
|
return;
|
||||||
|
once = true;
|
||||||
|
|
||||||
|
if (self.ssl)
|
||||||
|
self.ssl.newSessionDone();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function onnewsessiondone() {
|
||||||
|
if (!this.server) return;
|
||||||
|
|
||||||
|
// Cycle through data
|
||||||
|
this.cleartext.read(0);
|
||||||
|
this.encrypted.read(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -138,8 +138,25 @@ function onclienthello(hello) {
|
|||||||
|
|
||||||
|
|
||||||
function onnewsession(key, session) {
|
function onnewsession(key, session) {
|
||||||
if (this.server)
|
if (!this.server)
|
||||||
this.server.emit('newSession', key, session);
|
return;
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
var once = false;
|
||||||
|
|
||||||
|
this._newSessionPending = true;
|
||||||
|
this.server.emit('newSession', key, session, function() {
|
||||||
|
if (once)
|
||||||
|
return;
|
||||||
|
once = true;
|
||||||
|
|
||||||
|
self.ssl.newSessionDone();
|
||||||
|
|
||||||
|
self._newSessionPending = false;
|
||||||
|
if (self._securePending)
|
||||||
|
self._finishInit();
|
||||||
|
self._securePending = false;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -164,6 +181,8 @@ function TLSSocket(socket, options) {
|
|||||||
|
|
||||||
this._tlsOptions = options;
|
this._tlsOptions = options;
|
||||||
this._secureEstablished = false;
|
this._secureEstablished = false;
|
||||||
|
this._securePending = false;
|
||||||
|
this._newSessionPending = false;
|
||||||
this._controlReleased = false;
|
this._controlReleased = false;
|
||||||
this._SNICallback = null;
|
this._SNICallback = null;
|
||||||
this.ssl = null;
|
this.ssl = null;
|
||||||
@ -347,6 +366,12 @@ TLSSocket.prototype._releaseControl = function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
TLSSocket.prototype._finishInit = function() {
|
TLSSocket.prototype._finishInit = function() {
|
||||||
|
// `newSession` callback wasn't called yet
|
||||||
|
if (this._newSessionPending) {
|
||||||
|
this._securePending = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (process.features.tls_npn) {
|
if (process.features.tls_npn) {
|
||||||
this.npnProtocol = this.ssl.getNegotiatedProtocol();
|
this.npnProtocol = this.ssl.getNegotiatedProtocol();
|
||||||
}
|
}
|
||||||
|
@ -121,6 +121,7 @@ namespace node {
|
|||||||
V(onhandshakestart_string, "onhandshakestart") \
|
V(onhandshakestart_string, "onhandshakestart") \
|
||||||
V(onmessage_string, "onmessage") \
|
V(onmessage_string, "onmessage") \
|
||||||
V(onnewsession_string, "onnewsession") \
|
V(onnewsession_string, "onnewsession") \
|
||||||
|
V(onnewsessiondone_string, "onnewsessiondone") \
|
||||||
V(onread_string, "onread") \
|
V(onread_string, "onread") \
|
||||||
V(onselect_string, "onselect") \
|
V(onselect_string, "onselect") \
|
||||||
V(onsignal_string, "onsignal") \
|
V(onsignal_string, "onsignal") \
|
||||||
|
@ -857,6 +857,7 @@ void SSLWrap<Base>::AddMethods(Handle<FunctionTemplate> t) {
|
|||||||
NODE_SET_PROTOTYPE_METHOD(t, "renegotiate", Renegotiate);
|
NODE_SET_PROTOTYPE_METHOD(t, "renegotiate", Renegotiate);
|
||||||
NODE_SET_PROTOTYPE_METHOD(t, "shutdown", Shutdown);
|
NODE_SET_PROTOTYPE_METHOD(t, "shutdown", Shutdown);
|
||||||
NODE_SET_PROTOTYPE_METHOD(t, "getTLSTicket", GetTLSTicket);
|
NODE_SET_PROTOTYPE_METHOD(t, "getTLSTicket", GetTLSTicket);
|
||||||
|
NODE_SET_PROTOTYPE_METHOD(t, "newSessionDone", NewSessionDone);
|
||||||
|
|
||||||
#ifdef SSL_set_max_send_fragment
|
#ifdef SSL_set_max_send_fragment
|
||||||
NODE_SET_PROTOTYPE_METHOD(t, "setMaxSendFragment", SetMaxSendFragment);
|
NODE_SET_PROTOTYPE_METHOD(t, "setMaxSendFragment", SetMaxSendFragment);
|
||||||
@ -929,6 +930,7 @@ int SSLWrap<Base>::NewSessionCallback(SSL* s, SSL_SESSION* sess) {
|
|||||||
reinterpret_cast<char*>(sess->session_id),
|
reinterpret_cast<char*>(sess->session_id),
|
||||||
sess->session_id_length);
|
sess->session_id_length);
|
||||||
Local<Value> argv[] = { session, buff };
|
Local<Value> argv[] = { session, buff };
|
||||||
|
w->new_session_wait_ = true;
|
||||||
w->MakeCallback(env->onnewsession_string(), ARRAY_SIZE(argv), argv);
|
w->MakeCallback(env->onnewsession_string(), ARRAY_SIZE(argv), argv);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -1267,6 +1269,16 @@ void SSLWrap<Base>::GetTLSTicket(const FunctionCallbackInfo<Value>& args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <class Base>
|
||||||
|
void SSLWrap<Base>::NewSessionDone(const FunctionCallbackInfo<Value>& args) {
|
||||||
|
HandleScope scope(args.GetIsolate());
|
||||||
|
|
||||||
|
Base* w = Unwrap<Base>(args.This());
|
||||||
|
w->new_session_wait_ = false;
|
||||||
|
w->NewSessionDoneCb();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef SSL_set_max_send_fragment
|
#ifdef SSL_set_max_send_fragment
|
||||||
template <class Base>
|
template <class Base>
|
||||||
void SSLWrap<Base>::SetMaxSendFragment(
|
void SSLWrap<Base>::SetMaxSendFragment(
|
||||||
@ -1651,6 +1663,13 @@ void Connection::SetShutdownFlags() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Connection::NewSessionDoneCb() {
|
||||||
|
HandleScope scope(env()->isolate());
|
||||||
|
|
||||||
|
MakeCallback(env()->onnewsessiondone_string(), 0, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Connection::Initialize(Environment* env, Handle<Object> target) {
|
void Connection::Initialize(Environment* env, Handle<Object> target) {
|
||||||
Local<FunctionTemplate> t = FunctionTemplate::New(Connection::New);
|
Local<FunctionTemplate> t = FunctionTemplate::New(Connection::New);
|
||||||
t->InstanceTemplate()->SetInternalFieldCount(1);
|
t->InstanceTemplate()->SetInternalFieldCount(1);
|
||||||
|
@ -137,7 +137,8 @@ class SSLWrap {
|
|||||||
: env_(env),
|
: env_(env),
|
||||||
kind_(kind),
|
kind_(kind),
|
||||||
next_sess_(NULL),
|
next_sess_(NULL),
|
||||||
session_callbacks_(false) {
|
session_callbacks_(false),
|
||||||
|
new_session_wait_(false) {
|
||||||
ssl_ = SSL_new(sc->ctx_);
|
ssl_ = SSL_new(sc->ctx_);
|
||||||
assert(ssl_ != NULL);
|
assert(ssl_ != NULL);
|
||||||
}
|
}
|
||||||
@ -162,6 +163,7 @@ class SSLWrap {
|
|||||||
inline void enable_session_callbacks() { session_callbacks_ = true; }
|
inline void enable_session_callbacks() { session_callbacks_ = true; }
|
||||||
inline bool is_server() const { return kind_ == kServer; }
|
inline bool is_server() const { return kind_ == kServer; }
|
||||||
inline bool is_client() const { return kind_ == kClient; }
|
inline bool is_client() const { return kind_ == kClient; }
|
||||||
|
inline bool is_waiting_new_session() const { return new_session_wait_; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static void InitNPN(SecureContext* sc, Base* base);
|
static void InitNPN(SecureContext* sc, Base* base);
|
||||||
@ -188,6 +190,7 @@ class SSLWrap {
|
|||||||
static void Renegotiate(const v8::FunctionCallbackInfo<v8::Value>& args);
|
static void Renegotiate(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||||
static void Shutdown(const v8::FunctionCallbackInfo<v8::Value>& args);
|
static void Shutdown(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||||
static void GetTLSTicket(const v8::FunctionCallbackInfo<v8::Value>& args);
|
static void GetTLSTicket(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||||
|
static void NewSessionDone(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||||
|
|
||||||
#ifdef SSL_set_max_send_fragment
|
#ifdef SSL_set_max_send_fragment
|
||||||
static void SetMaxSendFragment(
|
static void SetMaxSendFragment(
|
||||||
@ -219,6 +222,7 @@ class SSLWrap {
|
|||||||
SSL_SESSION* next_sess_;
|
SSL_SESSION* next_sess_;
|
||||||
SSL* ssl_;
|
SSL* ssl_;
|
||||||
bool session_callbacks_;
|
bool session_callbacks_;
|
||||||
|
bool new_session_wait_;
|
||||||
ClientHelloParser hello_parser_;
|
ClientHelloParser hello_parser_;
|
||||||
|
|
||||||
#ifdef OPENSSL_NPN_NEGOTIATED
|
#ifdef OPENSSL_NPN_NEGOTIATED
|
||||||
@ -291,6 +295,7 @@ class Connection : public SSLWrap<Connection>, public AsyncWrap {
|
|||||||
|
|
||||||
void ClearError();
|
void ClearError();
|
||||||
void SetShutdownFlags();
|
void SetShutdownFlags();
|
||||||
|
void NewSessionDoneCb();
|
||||||
|
|
||||||
Connection(Environment* env,
|
Connection(Environment* env,
|
||||||
v8::Local<v8::Object> wrap,
|
v8::Local<v8::Object> wrap,
|
||||||
@ -319,6 +324,7 @@ class Connection : public SSLWrap<Connection>, public AsyncWrap {
|
|||||||
|
|
||||||
friend class ClientHelloParser;
|
friend class ClientHelloParser;
|
||||||
friend class SecureContext;
|
friend class SecureContext;
|
||||||
|
friend class SSLWrap<Connection>;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CipherBase : public BaseObject {
|
class CipherBase : public BaseObject {
|
||||||
|
@ -81,6 +81,7 @@ TLSCallbacks::TLSCallbacks(Environment* env,
|
|||||||
established_(false),
|
established_(false),
|
||||||
shutdown_(false),
|
shutdown_(false),
|
||||||
error_(NULL),
|
error_(NULL),
|
||||||
|
cycle_depth_(0),
|
||||||
eof_(false) {
|
eof_(false) {
|
||||||
node::Wrap<TLSCallbacks>(object(), this);
|
node::Wrap<TLSCallbacks>(object(), this);
|
||||||
|
|
||||||
@ -158,6 +159,11 @@ bool TLSCallbacks::InvokeQueued(int status) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void TLSCallbacks::NewSessionDoneCb() {
|
||||||
|
Cycle();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void TLSCallbacks::InitSSL() {
|
void TLSCallbacks::InitSSL() {
|
||||||
// Initialize SSL
|
// Initialize SSL
|
||||||
enc_in_ = NodeBIO::New();
|
enc_in_ = NodeBIO::New();
|
||||||
@ -309,6 +315,10 @@ void TLSCallbacks::EncOut() {
|
|||||||
if (write_size_ != 0)
|
if (write_size_ != 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// Wait for `newSession` callback to be invoked
|
||||||
|
if (is_waiting_new_session())
|
||||||
|
return;
|
||||||
|
|
||||||
// Split-off queue
|
// Split-off queue
|
||||||
if (established_ && !QUEUE_EMPTY(&write_item_queue_))
|
if (established_ && !QUEUE_EMPTY(&write_item_queue_))
|
||||||
MakePending();
|
MakePending();
|
||||||
|
@ -102,11 +102,18 @@ class TLSCallbacks : public crypto::SSLWrap<TLSCallbacks>,
|
|||||||
void ClearOut();
|
void ClearOut();
|
||||||
void MakePending();
|
void MakePending();
|
||||||
bool InvokeQueued(int status);
|
bool InvokeQueued(int status);
|
||||||
|
void NewSessionDoneCb();
|
||||||
|
|
||||||
inline void Cycle() {
|
inline void Cycle() {
|
||||||
ClearIn();
|
// Prevent recursion
|
||||||
ClearOut();
|
if (++cycle_depth_ > 1)
|
||||||
EncOut();
|
return;
|
||||||
|
|
||||||
|
for (; cycle_depth_ > 0; cycle_depth_--) {
|
||||||
|
ClearIn();
|
||||||
|
ClearOut();
|
||||||
|
EncOut();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
v8::Local<v8::Value> GetSSLError(int status, int* err, const char** msg);
|
v8::Local<v8::Value> GetSSLError(int status, int* err, const char** msg);
|
||||||
@ -144,6 +151,7 @@ class TLSCallbacks : public crypto::SSLWrap<TLSCallbacks>,
|
|||||||
bool established_;
|
bool established_;
|
||||||
bool shutdown_;
|
bool shutdown_;
|
||||||
const char* error_;
|
const char* error_;
|
||||||
|
int cycle_depth_;
|
||||||
|
|
||||||
// If true - delivered EOF to the js-land, either after `close_notify`, or
|
// If true - delivered EOF to the js-land, either after `close_notify`, or
|
||||||
// after the `UV_EOF` on socket.
|
// after the `UV_EOF` on socket.
|
||||||
@ -155,6 +163,8 @@ class TLSCallbacks : public crypto::SSLWrap<TLSCallbacks>,
|
|||||||
|
|
||||||
static size_t error_off_;
|
static size_t error_off_;
|
||||||
static char error_buf_[1024];
|
static char error_buf_[1024];
|
||||||
|
|
||||||
|
friend class SSLWrap<TLSCallbacks>;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace node
|
} // namespace node
|
||||||
|
@ -64,12 +64,16 @@ function doTest(testOptions, callback) {
|
|||||||
++requestCount;
|
++requestCount;
|
||||||
cleartext.end();
|
cleartext.end();
|
||||||
});
|
});
|
||||||
server.on('newSession', function(id, data) {
|
server.on('newSession', function(id, data, cb) {
|
||||||
assert.ok(!session);
|
// Emulate asynchronous store
|
||||||
session = {
|
setTimeout(function() {
|
||||||
id: id,
|
assert.ok(!session);
|
||||||
data: data
|
session = {
|
||||||
};
|
id: id,
|
||||||
|
data: data
|
||||||
|
};
|
||||||
|
cb();
|
||||||
|
}, 1000);
|
||||||
});
|
});
|
||||||
server.on('resumeSession', function(id, callback) {
|
server.on('resumeSession', function(id, callback) {
|
||||||
++resumeCount;
|
++resumeCount;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user