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,
}
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.)
}
+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());
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);
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),