From 4e551aea7b54a2443b3f2e7e6f9144645ebb3459 Mon Sep 17 00:00:00 2001 From: Ian Haken Date: Mon, 12 Mar 2018 22:11:33 -0700 Subject: [PATCH] Add checkServerIdentity callback. --- .../ext/channel_credentials.cc | 74 ++++++++++++++++++- 1 file changed, 73 insertions(+), 1 deletion(-) diff --git a/packages/grpc-native-core/ext/channel_credentials.cc b/packages/grpc-native-core/ext/channel_credentials.cc index c334d5d0..d56780cf 100644 --- a/packages/grpc-native-core/ext/channel_credentials.cc +++ b/packages/grpc-native-core/ext/channel_credentials.cc @@ -38,6 +38,8 @@ using Nan::ObjectWrap; using Nan::Persistent; using Nan::Utf8String; +using v8::Array; +using v8::Context; using v8::Exception; using v8::External; using v8::Function; @@ -58,6 +60,43 @@ ChannelCredentials::~ChannelCredentials() { grpc_channel_credentials_release(wrapped_credentials); } +struct callback_md { + Nan::Callback *callback; +}; + +static int verify_peer_callback_wrapper(const char* servername, const char* cert, void* userdata) { + Nan::HandleScope scope; + Nan::TryCatch try_catch; + struct callback_md* md = (struct callback_md*)userdata; + + const unsigned argc = 2; + Local argv[argc]; + if (servername == NULL) { + argv[0] = Nan::Null(); + } else { + argv[0] = Nan::New(servername).ToLocalChecked(); + } + if (cert == NULL) { + argv[1] = Nan::Null(); + } else { + argv[1] = Nan::New(cert).ToLocalChecked(); + } + + md->callback->Call(argc, argv); + + if (try_catch.HasCaught()) { + return 1; + } + + return 0; +} + +static void verify_peer_callback_destruct(void *userdata) { + callback_md *md = (callback_md*)userdata; + delete md->callback; + delete md; +} + void ChannelCredentials::Init(Local exports) { HandleScope scope; Local tpl = Nan::New(New); @@ -148,9 +187,42 @@ NAN_METHOD(ChannelCredentials::CreateSsl) { "createSsl's second and third arguments must be" " provided or omitted together"); } + + verify_peer_options verify_options = {NULL, NULL, NULL}; + if (info.Length() >= 4 && info[3]->IsObject()) { + Local context = Nan::New(); + Local object = info[3]->ToObject(); + MaybeLocal maybe_props = object->GetOwnPropertyNames(context); + if (!maybe_props.IsEmpty()) { + Local props = maybe_props.ToLocalChecked(); + for(uint32_t i=0; i < props->Length(); i++) { + Local key = props->Get(i); + Local value = object->Get(key); + + if (key->IsString()) { + Nan::Utf8String keyStr(key->ToString()); + + if (strcmp("checkServerIdentity", (const char*)(*keyStr)) == 0) { + + if (!value->IsFunction()) { + return Nan::ThrowError("Value of checkServerIdentity must be a function."); + } + struct callback_md *md = new struct callback_md; + md->callback = new Callback(Local::Cast(value)); + verify_options.verify_peer_callback = verify_peer_callback_wrapper; + verify_options.verify_peer_callback_userdata = (void*)md; + verify_options.verify_peer_destruct = verify_peer_callback_destruct; + + } + } + // do stuff with key / value + } + } + } + grpc_channel_credentials *creds = grpc_ssl_credentials_create( root_certs.get(), private_key.isAssigned() ? &key_cert_pair : NULL, - NULL, NULL); + &verify_options, NULL); if (creds == NULL) { info.GetReturnValue().SetNull(); } else {