Skip to content

Commit

Permalink
tls: introduce internal onticketkeycallback
Browse files Browse the repository at this point in the history
`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: #2304
PR-URL: #2312
Reviewed-By: Shigeki Ohtsu <ohtsu@iij.ad.jp>
  • Loading branch information
indutny authored and rvagg committed Aug 17, 2015
1 parent 0ee4df9 commit e83a41a
Show file tree
Hide file tree
Showing 3 changed files with 121 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/env.h
Original file line number Diff line number Diff line change
Expand Up @@ -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") \
Expand Down
104 changes: 104 additions & 0 deletions src/node_crypto.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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.)
Expand Down Expand Up @@ -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());
Expand Down
16 changes: 16 additions & 0 deletions src/node_crypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -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),
Expand Down

0 comments on commit e83a41a

Please sign in to comment.