mirror of https://github.com/nodejs/node.git
parent
509cfbc2b7
commit
d62c2d975a
|
@ -352,6 +352,7 @@ function Server(/* [options], listener */) {
|
|||
crl: self.crl,
|
||||
sessionIdContext: self.sessionIdContext
|
||||
});
|
||||
this._sharedCreds = sharedCreds;
|
||||
|
||||
var timeout = options.handshakeTimeout || (120 * 1000);
|
||||
|
||||
|
@ -363,6 +364,10 @@ function Server(/* [options], listener */) {
|
|||
sharedCreds.context.setSessionTimeout(self.sessionTimeout);
|
||||
}
|
||||
|
||||
if (self.ticketKeys) {
|
||||
sharedCreds.context.setTicketKeys(self.ticketKeys);
|
||||
}
|
||||
|
||||
// constructor call
|
||||
net.Server.call(this, function(raw_socket) {
|
||||
var socket = new TLSSocket(raw_socket, {
|
||||
|
@ -422,6 +427,18 @@ exports.createServer = function(options, listener) {
|
|||
};
|
||||
|
||||
|
||||
Server.prototype._getServerData = function() {
|
||||
return {
|
||||
ticketKeys: this._sharedCreds.context.getTicketKeys().toString('hex')
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
Server.prototype._setServerData = function(data) {
|
||||
this._sharedCreds.context.setTicketKeys(new Buffer(data.ticketKeys, 'hex'));
|
||||
};
|
||||
|
||||
|
||||
Server.prototype.setOptions = function(options) {
|
||||
if (IS_BOOLEAN(options.requestCert)) {
|
||||
this.requestCert = options.requestCert;
|
||||
|
|
|
@ -193,6 +193,8 @@ void SecureContext::Initialize(Handle<Object> target) {
|
|||
SecureContext::SetSessionTimeout);
|
||||
NODE_SET_PROTOTYPE_METHOD(t, "close", SecureContext::Close);
|
||||
NODE_SET_PROTOTYPE_METHOD(t, "loadPKCS12", SecureContext::LoadPKCS12);
|
||||
NODE_SET_PROTOTYPE_METHOD(t, "getTicketKeys", SecureContext::GetTicketKeys);
|
||||
NODE_SET_PROTOTYPE_METHOD(t, "setTicketKeys", SecureContext::SetTicketKeys);
|
||||
|
||||
target->Set(String::NewSymbol("SecureContext"), t->GetFunction());
|
||||
}
|
||||
|
@ -750,6 +752,47 @@ void SecureContext::LoadPKCS12(const FunctionCallbackInfo<Value>& args) {
|
|||
}
|
||||
|
||||
|
||||
void SecureContext::GetTicketKeys(const FunctionCallbackInfo<Value>& args) {
|
||||
#if !defined(OPENSSL_NO_TLSEXT) && defined(SSL_CTX_get_tlsext_ticket_keys)
|
||||
HandleScope scope(node_isolate);
|
||||
|
||||
UNWRAP(SecureContext);
|
||||
|
||||
Local<Object> buff = Buffer::New(48);
|
||||
if (SSL_CTX_get_tlsext_ticket_keys(wrap->ctx_,
|
||||
Buffer::Data(buff),
|
||||
Buffer::Length(buff)) != 1) {
|
||||
return ThrowError("Failed to fetch tls ticket keys");
|
||||
}
|
||||
|
||||
args.GetReturnValue().Set(buff);
|
||||
#endif // !def(OPENSSL_NO_TLSEXT) && def(SSL_CTX_get_tlsext_ticket_keys)
|
||||
}
|
||||
|
||||
|
||||
void SecureContext::SetTicketKeys(const FunctionCallbackInfo<Value>& args) {
|
||||
#if !defined(OPENSSL_NO_TLSEXT) && defined(SSL_CTX_get_tlsext_ticket_keys)
|
||||
HandleScope scope(node_isolate);
|
||||
|
||||
if (args.Length() < 1 ||
|
||||
!Buffer::HasInstance(args[0]) ||
|
||||
Buffer::Length(args[0]) != 48) {
|
||||
return ThrowTypeError("Bad argument");
|
||||
}
|
||||
|
||||
UNWRAP(SecureContext);
|
||||
|
||||
if (SSL_CTX_set_tlsext_ticket_keys(wrap->ctx_,
|
||||
Buffer::Data(args[0]),
|
||||
Buffer::Length(args[0])) != 1) {
|
||||
return ThrowError("Failed to fetch tls ticket keys");
|
||||
}
|
||||
|
||||
args.GetReturnValue().Set(true);
|
||||
#endif // !def(OPENSSL_NO_TLSEXT) && def(SSL_CTX_get_tlsext_ticket_keys)
|
||||
}
|
||||
|
||||
|
||||
size_t ClientHelloParser::Write(const uint8_t* data, size_t len) {
|
||||
HandleScope scope(node_isolate);
|
||||
|
||||
|
|
|
@ -79,6 +79,8 @@ class SecureContext : ObjectWrap {
|
|||
const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
static void Close(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
static void LoadPKCS12(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
static void GetTicketKeys(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
static void SetTicketKeys(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
|
||||
static SSL_SESSION* GetSessionCallback(SSL* s,
|
||||
unsigned char* key,
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
// Copyright Joyent, Inc. and other Node contributors.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
||||
// persons to whom the Software is furnished to do so, subject to the
|
||||
// following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
if (!process.versions.openssl) {
|
||||
console.error('Skipping because node compiled without OpenSSL.');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
var common = require('../common');
|
||||
var assert = require('assert');
|
||||
var cluster = require('cluster');
|
||||
var tls = require('tls');
|
||||
var fs = require('fs');
|
||||
var join = require('path').join;
|
||||
|
||||
var workerCount = 4;
|
||||
var expectedReqCount = 16;
|
||||
|
||||
if (cluster.isMaster) {
|
||||
var reusedCount = 0;
|
||||
var reqCount = 0;
|
||||
var lastSession = null;
|
||||
var shootOnce = false;
|
||||
|
||||
function shoot() {
|
||||
console.error('[master] connecting');
|
||||
var c = tls.connect(common.PORT, {
|
||||
session: lastSession,
|
||||
rejectUnauthorized: false
|
||||
}, function() {
|
||||
lastSession = c.getSession();
|
||||
c.end();
|
||||
|
||||
if (++reqCount === expectedReqCount) {
|
||||
Object.keys(cluster.workers).forEach(function(id) {
|
||||
cluster.workers[id].send('die');
|
||||
});
|
||||
} else {
|
||||
shoot();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function fork() {
|
||||
var worker = cluster.fork();
|
||||
var workerReqCount = 0;
|
||||
worker.on('message', function(msg) {
|
||||
console.error('[master] got %j', msg);
|
||||
if (msg === 'reused') {
|
||||
++reusedCount;
|
||||
} else if (msg === 'listening' && !shootOnce) {
|
||||
shootOnce = true;
|
||||
shoot();
|
||||
}
|
||||
});
|
||||
|
||||
worker.on('exit', function() {
|
||||
console.error('[master] worker died');
|
||||
});
|
||||
}
|
||||
for (var i = 0; i < workerCount; i++) {
|
||||
fork();
|
||||
}
|
||||
|
||||
process.on('exit', function() {
|
||||
assert.equal(reqCount, expectedReqCount);
|
||||
assert.equal(reusedCount + 1, reqCount);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
var keyFile = join(common.fixturesDir, 'agent.key');
|
||||
var certFile = join(common.fixturesDir, 'agent.crt');
|
||||
var key = fs.readFileSync(keyFile);
|
||||
var cert = fs.readFileSync(certFile);
|
||||
var options = {
|
||||
key: key,
|
||||
cert: cert
|
||||
};
|
||||
|
||||
var server = tls.createServer(options, function(c) {
|
||||
if (c.isSessionReused()) {
|
||||
process.send('reused');
|
||||
} else {
|
||||
process.send('not-reused');
|
||||
}
|
||||
c.end();
|
||||
});
|
||||
|
||||
server.listen(common.PORT, function() {
|
||||
process.send('listening');
|
||||
});
|
||||
|
||||
process.on('message', function listener(msg) {
|
||||
console.error('[worker] got %j', msg);
|
||||
if (msg === 'die') {
|
||||
server.close(function() {
|
||||
console.error('[worker] server close');
|
||||
|
||||
process.exit();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
process.on('exit', function() {
|
||||
console.error('[worker] exit');
|
||||
});
|
Loading…
Reference in New Issue