diff --git a/doc/api/tls.markdown b/doc/api/tls.markdown
index cf7a87fa2a7..2a4c312b503 100644
--- a/doc/api/tls.markdown
+++ b/doc/api/tls.markdown
@@ -205,6 +205,12 @@ automatically set as a listener for the [secureConnection][] event. The
session identifiers and TLS session tickets created by the server are
timed out. See [SSL_CTX_set_timeout] for more details.
+ - `ticketKeys`: A 48-byte `Buffer` instance consisting of 16-byte prefix,
+ 16-byte hmac key, 16-byte AES key. You could use it to accept tls session
+ tickets on multiple instances of tls server.
+
+ NOTE: Automatically shared between `cluster` module workers.
+
- `sessionIdContext`: A string containing a opaque identifier for session
resumption. If `requestCert` is `true`, the default is MD5 hash value
generated from command-line. Otherwise, the default is not provided.
@@ -314,6 +320,8 @@ Creates a new client connection to the given `port` and `host` (old API) or
SSL version 3. The possible values depend on your installation of
OpenSSL and are defined in the constant [SSL_METHODS][].
+ - `session`: A `Buffer` instance, containing TLS session.
+
The `callback` parameter will be added as a listener for the
['secureConnect'][] event.
@@ -398,6 +406,8 @@ Construct a new TLSSocket object from existing TCP socket.
- `SNICallback`: Optional, see [tls.createServer][]
+ - `session`: Optional, a `Buffer` instance, containing TLS session
+
## tls.createSecurePair([credentials], [isServer], [requestCert], [rejectUnauthorized])
Stability: 0 - Deprecated. Use tls.TLSSocket instead.
@@ -646,6 +656,18 @@ and their processing can be delayed due to packet loss or reordering. However,
smaller fragments add extra TLS framing bytes and CPU overhead, which may
decrease overall server throughput.
+### tlsSocket.getSession()
+
+Return ASN.1 encoded TLS session or `undefined` if none was negotiated. Could
+be used to speed up handshake establishment when reconnecting to the server.
+
+### tlsSocket.getTLSTicket()
+
+NOTE: Works only with client TLS sockets. Useful only for debugging, for
+session reuse provide `session` option to `tls.connect`.
+
+Return TLS session ticket or `undefined` if none was negotiated.
+
### tlsSocket.address()
Returns the bound address, the address family name and port of the
diff --git a/lib/_tls_wrap.js b/lib/_tls_wrap.js
index 9324130574f..ff762107d2b 100644
--- a/lib/_tls_wrap.js
+++ b/lib/_tls_wrap.js
@@ -232,6 +232,9 @@ TLSSocket.prototype._init = function(socket) {
} else {
this.ssl.onhandshakestart = function() {};
this.ssl.onhandshakedone = this._finishInit.bind(this);
+
+ if (options.session)
+ this.ssl.setSession(options.session);
}
this.ssl.onerror = function(err) {
@@ -321,6 +324,10 @@ TLSSocket.prototype.setMaxSendFragment = function setMaxSendFragment(size) {
return this.ssl.setMaxSendFragment(size) == 1;
};
+TLSSocket.prototype.getTLSTicket = function getTLSTicket() {
+ return this.ssl.getTLSTicket();
+};
+
TLSSocket.prototype._handleTimeout = function() {
this._tlsError(new Error('TLS handshake timeout'));
};
@@ -620,6 +627,7 @@ Server.prototype.setOptions = function(options) {
if (!util.isUndefined(options.ecdhCurve))
this.ecdhCurve = options.ecdhCurve;
if (options.sessionTimeout) this.sessionTimeout = options.sessionTimeout;
+ if (options.ticketKeys) this.ticketKeys = options.ticketKeys;
var secureOptions = options.secureOptions || 0;
if (options.honorCipherOrder) {
secureOptions |= constants.SSL_OP_CIPHER_SERVER_PREFERENCE;
@@ -747,6 +755,7 @@ exports.connect = function(/* [port, host], options, cb */) {
isServer: false,
requestCert: true,
rejectUnauthorized: options.rejectUnauthorized,
+ session: options.session,
NPNProtocols: NPN.NPNProtocols
});
result = socket;
diff --git a/src/node_crypto.cc b/src/node_crypto.cc
index 987e2cfa49f..9952b2c0aaa 100644
--- a/src/node_crypto.cc
+++ b/src/node_crypto.cc
@@ -856,6 +856,7 @@ void SSLWrap::AddMethods(Handle t) {
NODE_SET_PROTOTYPE_METHOD(t, "endParser", EndParser);
NODE_SET_PROTOTYPE_METHOD(t, "renegotiate", Renegotiate);
NODE_SET_PROTOTYPE_METHOD(t, "shutdown", Shutdown);
+ NODE_SET_PROTOTYPE_METHOD(t, "getTLSTicket", GetTLSTicket);
#ifdef SSL_set_max_send_fragment
NODE_SET_PROTOTYPE_METHOD(t, "setMaxSendFragment", SetMaxSendFragment);
@@ -1129,7 +1130,7 @@ void SSLWrap::GetSession(const FunctionCallbackInfo& args) {
unsigned char* sbuf = new unsigned char[slen];
unsigned char* p = sbuf;
i2d_SSL_SESSION(sess, &p);
- args.GetReturnValue().Set(Encode(sbuf, slen, BINARY));
+ args.GetReturnValue().Set(Encode(sbuf, slen, BUFFER));
delete[] sbuf;
}
@@ -1247,6 +1248,25 @@ void SSLWrap::Shutdown(const FunctionCallbackInfo& args) {
}
+template
+void SSLWrap::GetTLSTicket(const FunctionCallbackInfo& args) {
+ HandleScope scope(args.GetIsolate());
+
+ Base* w = Unwrap(args.This());
+ Environment* env = w->ssl_env();
+
+ SSL_SESSION* sess = SSL_get_session(w->ssl_);
+ if (sess == NULL || sess->tlsext_tick == NULL)
+ return;
+
+ Local