Skip to content

Commit e83a41a

Browse files
indutnyrvagg
authored andcommitted
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: #2304 PR-URL: #2312 Reviewed-By: Shigeki Ohtsu <[email protected]>
1 parent 0ee4df9 commit e83a41a

File tree

3 files changed

+121
-0
lines changed

3 files changed

+121
-0
lines changed

src/env.h

+1
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@ namespace node {
198198
V(syscall_string, "syscall") \
199199
V(tick_callback_string, "_tickCallback") \
200200
V(tick_domain_cb_string, "_tickDomainCallback") \
201+
V(ticketkeycallback_string, "onticketkeycallback") \
201202
V(timeout_string, "timeout") \
202203
V(times_string, "times") \
203204
V(timestamp_string, "timestamp") \

src/node_crypto.cc

+104
Original file line numberDiff line numberDiff line change
@@ -300,9 +300,23 @@ void SecureContext::Initialize(Environment* env, Handle<Object> target) {
300300
env->SetProtoMethod(t, "getTicketKeys", SecureContext::GetTicketKeys);
301301
env->SetProtoMethod(t, "setTicketKeys", SecureContext::SetTicketKeys);
302302
env->SetProtoMethod(t, "setFreeListLength", SecureContext::SetFreeListLength);
303+
env->SetProtoMethod(t,
304+
"enableTicketKeyCallback",
305+
SecureContext::EnableTicketKeyCallback);
303306
env->SetProtoMethod(t, "getCertificate", SecureContext::GetCertificate<true>);
304307
env->SetProtoMethod(t, "getIssuer", SecureContext::GetCertificate<false>);
305308

309+
t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kTicketKeyReturnIndex"),
310+
Integer::NewFromUnsigned(env->isolate(), kTicketKeyReturnIndex));
311+
t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kTicketKeyHMACIndex"),
312+
Integer::NewFromUnsigned(env->isolate(), kTicketKeyHMACIndex));
313+
t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kTicketKeyAESIndex"),
314+
Integer::NewFromUnsigned(env->isolate(), kTicketKeyAESIndex));
315+
t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kTicketKeyNameIndex"),
316+
Integer::NewFromUnsigned(env->isolate(), kTicketKeyNameIndex));
317+
t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kTicketKeyIVIndex"),
318+
Integer::NewFromUnsigned(env->isolate(), kTicketKeyIVIndex));
319+
306320
t->PrototypeTemplate()->SetAccessor(
307321
FIXED_ONE_BYTE_STRING(env->isolate(), "_external"),
308322
CtxGetter,
@@ -378,6 +392,7 @@ void SecureContext::Init(const FunctionCallbackInfo<Value>& args) {
378392
}
379393

380394
sc->ctx_ = SSL_CTX_new(method);
395+
SSL_CTX_set_app_data(sc->ctx_, sc);
381396

382397
// Disable SSLv2 in the case when method == SSLv23_method() and the
383398
// cipher list contains SSLv2 ciphers (not the default, should be rare.)
@@ -982,6 +997,95 @@ void SecureContext::SetFreeListLength(const FunctionCallbackInfo<Value>& args) {
982997
}
983998

984999

1000+
void SecureContext::EnableTicketKeyCallback(
1001+
const FunctionCallbackInfo<Value>& args) {
1002+
SecureContext* wrap = Unwrap<SecureContext>(args.Holder());
1003+
1004+
SSL_CTX_set_tlsext_ticket_key_cb(wrap->ctx_, TicketKeyCallback);
1005+
}
1006+
1007+
1008+
int SecureContext::TicketKeyCallback(SSL* ssl,
1009+
unsigned char* name,
1010+
unsigned char* iv,
1011+
EVP_CIPHER_CTX* ectx,
1012+
HMAC_CTX* hctx,
1013+
int enc) {
1014+
static const int kTicketPartSize = 16;
1015+
1016+
SecureContext* sc = static_cast<SecureContext*>(
1017+
SSL_CTX_get_app_data(ssl->ctx));
1018+
1019+
Environment* env = sc->env();
1020+
HandleScope handle_scope(env->isolate());
1021+
Context::Scope context_scope(env->context());
1022+
1023+
Local<Value> argv[] = {
1024+
Buffer::New(env,
1025+
reinterpret_cast<char*>(name),
1026+
kTicketPartSize).ToLocalChecked(),
1027+
Buffer::New(env,
1028+
reinterpret_cast<char*>(iv),
1029+
kTicketPartSize).ToLocalChecked(),
1030+
Boolean::New(env->isolate(), enc != 0)
1031+
};
1032+
Local<Value> ret = node::MakeCallback(env,
1033+
sc->object(),
1034+
env->ticketkeycallback_string(),
1035+
ARRAY_SIZE(argv),
1036+
argv);
1037+
Local<Array> arr = ret.As<Array>();
1038+
1039+
int r = arr->Get(kTicketKeyReturnIndex)->Int32Value();
1040+
if (r < 0)
1041+
return r;
1042+
1043+
Local<Value> hmac = arr->Get(kTicketKeyHMACIndex);
1044+
Local<Value> aes = arr->Get(kTicketKeyAESIndex);
1045+
if (Buffer::Length(aes) != kTicketPartSize)
1046+
return -1;
1047+
1048+
if (enc) {
1049+
Local<Value> name_val = arr->Get(kTicketKeyNameIndex);
1050+
Local<Value> iv_val = arr->Get(kTicketKeyIVIndex);
1051+
1052+
if (Buffer::Length(name_val) != kTicketPartSize ||
1053+
Buffer::Length(iv_val) != kTicketPartSize) {
1054+
return -1;
1055+
}
1056+
1057+
memcpy(name, Buffer::Data(name_val), kTicketPartSize);
1058+
memcpy(iv, Buffer::Data(iv_val), kTicketPartSize);
1059+
}
1060+
1061+
HMAC_Init_ex(hctx,
1062+
Buffer::Data(hmac),
1063+
Buffer::Length(hmac),
1064+
EVP_sha256(),
1065+
nullptr);
1066+
1067+
const unsigned char* aes_key =
1068+
reinterpret_cast<unsigned char*>(Buffer::Data(aes));
1069+
if (enc) {
1070+
EVP_EncryptInit_ex(ectx,
1071+
EVP_aes_128_cbc(),
1072+
nullptr,
1073+
aes_key,
1074+
iv);
1075+
} else {
1076+
EVP_DecryptInit_ex(ectx,
1077+
EVP_aes_128_cbc(),
1078+
nullptr,
1079+
aes_key,
1080+
iv);
1081+
}
1082+
1083+
return r;
1084+
}
1085+
1086+
1087+
1088+
9851089
void SecureContext::CtxGetter(Local<String> property,
9861090
const PropertyCallbackInfo<Value>& info) {
9871091
HandleScope scope(info.GetIsolate());

src/node_crypto.h

+16
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,13 @@ class SecureContext : public BaseObject {
6868

6969
static const int kMaxSessionSize = 10 * 1024;
7070

71+
// See TicketKeyCallback
72+
static const int kTicketKeyReturnIndex = 0;
73+
static const int kTicketKeyHMACIndex = 1;
74+
static const int kTicketKeyAESIndex = 2;
75+
static const int kTicketKeyNameIndex = 3;
76+
static const int kTicketKeyIVIndex = 4;
77+
7178
protected:
7279
static const int64_t kExternalSize = sizeof(SSL_CTX);
7380

@@ -92,12 +99,21 @@ class SecureContext : public BaseObject {
9299
static void SetTicketKeys(const v8::FunctionCallbackInfo<v8::Value>& args);
93100
static void SetFreeListLength(
94101
const v8::FunctionCallbackInfo<v8::Value>& args);
102+
static void EnableTicketKeyCallback(
103+
const v8::FunctionCallbackInfo<v8::Value>& args);
95104
static void CtxGetter(v8::Local<v8::String> property,
96105
const v8::PropertyCallbackInfo<v8::Value>& info);
97106

98107
template <bool primary>
99108
static void GetCertificate(const v8::FunctionCallbackInfo<v8::Value>& args);
100109

110+
static int TicketKeyCallback(SSL* ssl,
111+
unsigned char* name,
112+
unsigned char* iv,
113+
EVP_CIPHER_CTX* ectx,
114+
HMAC_CTX* hctx,
115+
int enc);
116+
101117
SecureContext(Environment* env, v8::Local<v8::Object> wrap)
102118
: BaseObject(env, wrap),
103119
ca_store_(nullptr),

0 commit comments

Comments
 (0)