tls: introduce internal onticketkeycallback
`enableTicketKeyCallback` and `onticketkeycallback` could be potentially used to renew the TLS Session Tickets before they expire. However this commit will introduce it only for private use yet, because we are not sure about the API, and already need this feature for testing. See: https://github.com/nodejs/io.js/issues/2304 PR-URL: https://github.com/nodejs/io.js/pull/2312 Reviewed-By: Shigeki Ohtsu <ohtsu@iij.ad.jp>
This commit is contained in:
parent
03d2bd3819
commit
c399d176b2
@ -198,6 +198,7 @@ namespace node {
|
||||
V(syscall_string, "syscall") \
|
||||
V(tick_callback_string, "_tickCallback") \
|
||||
V(tick_domain_cb_string, "_tickDomainCallback") \
|
||||
V(ticketkeycallback_string, "onticketkeycallback") \
|
||||
V(timeout_string, "timeout") \
|
||||
V(times_string, "times") \
|
||||
V(timestamp_string, "timestamp") \
|
||||
|
@ -300,9 +300,23 @@ void SecureContext::Initialize(Environment* env, Handle<Object> target) {
|
||||
env->SetProtoMethod(t, "getTicketKeys", SecureContext::GetTicketKeys);
|
||||
env->SetProtoMethod(t, "setTicketKeys", SecureContext::SetTicketKeys);
|
||||
env->SetProtoMethod(t, "setFreeListLength", SecureContext::SetFreeListLength);
|
||||
env->SetProtoMethod(t,
|
||||
"enableTicketKeyCallback",
|
||||
SecureContext::EnableTicketKeyCallback);
|
||||
env->SetProtoMethod(t, "getCertificate", SecureContext::GetCertificate<true>);
|
||||
env->SetProtoMethod(t, "getIssuer", SecureContext::GetCertificate<false>);
|
||||
|
||||
t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kTicketKeyReturnIndex"),
|
||||
Integer::NewFromUnsigned(env->isolate(), kTicketKeyReturnIndex));
|
||||
t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kTicketKeyHMACIndex"),
|
||||
Integer::NewFromUnsigned(env->isolate(), kTicketKeyHMACIndex));
|
||||
t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kTicketKeyAESIndex"),
|
||||
Integer::NewFromUnsigned(env->isolate(), kTicketKeyAESIndex));
|
||||
t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kTicketKeyNameIndex"),
|
||||
Integer::NewFromUnsigned(env->isolate(), kTicketKeyNameIndex));
|
||||
t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kTicketKeyIVIndex"),
|
||||
Integer::NewFromUnsigned(env->isolate(), kTicketKeyIVIndex));
|
||||
|
||||
t->PrototypeTemplate()->SetAccessor(
|
||||
FIXED_ONE_BYTE_STRING(env->isolate(), "_external"),
|
||||
CtxGetter,
|
||||
@ -378,6 +392,7 @@ void SecureContext::Init(const FunctionCallbackInfo<Value>& args) {
|
||||
}
|
||||
|
||||
sc->ctx_ = SSL_CTX_new(method);
|
||||
SSL_CTX_set_app_data(sc->ctx_, sc);
|
||||
|
||||
// Disable SSLv2 in the case when method == SSLv23_method() and the
|
||||
// cipher list contains SSLv2 ciphers (not the default, should be rare.)
|
||||
@ -982,6 +997,95 @@ void SecureContext::SetFreeListLength(const FunctionCallbackInfo<Value>& args) {
|
||||
}
|
||||
|
||||
|
||||
void SecureContext::EnableTicketKeyCallback(
|
||||
const FunctionCallbackInfo<Value>& args) {
|
||||
SecureContext* wrap = Unwrap<SecureContext>(args.Holder());
|
||||
|
||||
SSL_CTX_set_tlsext_ticket_key_cb(wrap->ctx_, TicketKeyCallback);
|
||||
}
|
||||
|
||||
|
||||
int SecureContext::TicketKeyCallback(SSL* ssl,
|
||||
unsigned char* name,
|
||||
unsigned char* iv,
|
||||
EVP_CIPHER_CTX* ectx,
|
||||
HMAC_CTX* hctx,
|
||||
int enc) {
|
||||
static const int kTicketPartSize = 16;
|
||||
|
||||
SecureContext* sc = static_cast<SecureContext*>(
|
||||
SSL_CTX_get_app_data(ssl->ctx));
|
||||
|
||||
Environment* env = sc->env();
|
||||
HandleScope handle_scope(env->isolate());
|
||||
Context::Scope context_scope(env->context());
|
||||
|
||||
Local<Value> argv[] = {
|
||||
Buffer::New(env,
|
||||
reinterpret_cast<char*>(name),
|
||||
kTicketPartSize).ToLocalChecked(),
|
||||
Buffer::New(env,
|
||||
reinterpret_cast<char*>(iv),
|
||||
kTicketPartSize).ToLocalChecked(),
|
||||
Boolean::New(env->isolate(), enc != 0)
|
||||
};
|
||||
Local<Value> ret = node::MakeCallback(env,
|
||||
sc->object(),
|
||||
env->ticketkeycallback_string(),
|
||||
ARRAY_SIZE(argv),
|
||||
argv);
|
||||
Local<Array> arr = ret.As<Array>();
|
||||
|
||||
int r = arr->Get(kTicketKeyReturnIndex)->Int32Value();
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
Local<Value> hmac = arr->Get(kTicketKeyHMACIndex);
|
||||
Local<Value> aes = arr->Get(kTicketKeyAESIndex);
|
||||
if (Buffer::Length(aes) != kTicketPartSize)
|
||||
return -1;
|
||||
|
||||
if (enc) {
|
||||
Local<Value> name_val = arr->Get(kTicketKeyNameIndex);
|
||||
Local<Value> iv_val = arr->Get(kTicketKeyIVIndex);
|
||||
|
||||
if (Buffer::Length(name_val) != kTicketPartSize ||
|
||||
Buffer::Length(iv_val) != kTicketPartSize) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(name, Buffer::Data(name_val), kTicketPartSize);
|
||||
memcpy(iv, Buffer::Data(iv_val), kTicketPartSize);
|
||||
}
|
||||
|
||||
HMAC_Init_ex(hctx,
|
||||
Buffer::Data(hmac),
|
||||
Buffer::Length(hmac),
|
||||
EVP_sha256(),
|
||||
nullptr);
|
||||
|
||||
const unsigned char* aes_key =
|
||||
reinterpret_cast<unsigned char*>(Buffer::Data(aes));
|
||||
if (enc) {
|
||||
EVP_EncryptInit_ex(ectx,
|
||||
EVP_aes_128_cbc(),
|
||||
nullptr,
|
||||
aes_key,
|
||||
iv);
|
||||
} else {
|
||||
EVP_DecryptInit_ex(ectx,
|
||||
EVP_aes_128_cbc(),
|
||||
nullptr,
|
||||
aes_key,
|
||||
iv);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void SecureContext::CtxGetter(Local<String> property,
|
||||
const PropertyCallbackInfo<Value>& info) {
|
||||
HandleScope scope(info.GetIsolate());
|
||||
|
@ -68,6 +68,13 @@ class SecureContext : public BaseObject {
|
||||
|
||||
static const int kMaxSessionSize = 10 * 1024;
|
||||
|
||||
// See TicketKeyCallback
|
||||
static const int kTicketKeyReturnIndex = 0;
|
||||
static const int kTicketKeyHMACIndex = 1;
|
||||
static const int kTicketKeyAESIndex = 2;
|
||||
static const int kTicketKeyNameIndex = 3;
|
||||
static const int kTicketKeyIVIndex = 4;
|
||||
|
||||
protected:
|
||||
static const int64_t kExternalSize = sizeof(SSL_CTX);
|
||||
|
||||
@ -92,12 +99,21 @@ class SecureContext : public BaseObject {
|
||||
static void SetTicketKeys(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
static void SetFreeListLength(
|
||||
const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
static void EnableTicketKeyCallback(
|
||||
const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
static void CtxGetter(v8::Local<v8::String> property,
|
||||
const v8::PropertyCallbackInfo<v8::Value>& info);
|
||||
|
||||
template <bool primary>
|
||||
static void GetCertificate(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
|
||||
static int TicketKeyCallback(SSL* ssl,
|
||||
unsigned char* name,
|
||||
unsigned char* iv,
|
||||
EVP_CIPHER_CTX* ectx,
|
||||
HMAC_CTX* hctx,
|
||||
int enc);
|
||||
|
||||
SecureContext(Environment* env, v8::Local<v8::Object> wrap)
|
||||
: BaseObject(env, wrap),
|
||||
ca_store_(nullptr),
|
||||
|
Loading…
x
Reference in New Issue
Block a user