@@ -226,6 +226,46 @@ int SelectALPNCallback(
226
226
unsigned int inlen,
227
227
void * arg) {
228
228
TLSWrap* w = static_cast <TLSWrap*>(arg);
229
+ if (w->alpn_callback_enabled_ ) {
230
+ Environment* env = w->env ();
231
+
232
+ Local<Value> callback_arg = Buffer::Copy (
233
+ env,
234
+ reinterpret_cast <const char *>(in),
235
+ inlen).ToLocalChecked ();
236
+
237
+ MaybeLocal<Value> maybe_callback_result = w->MakeCallback (
238
+ env->alpn_callback_string (),
239
+ 1 ,
240
+ &callback_arg);
241
+
242
+ if (UNLIKELY (maybe_callback_result.IsEmpty ())) {
243
+ // Implies the callback didn't return, because some exception was thrown
244
+ // during processing, e.g. if callback returned an invalid ALPN value.
245
+ return SSL_TLSEXT_ERR_ALERT_FATAL;
246
+ }
247
+
248
+ Local<Value> callback_result = maybe_callback_result.ToLocalChecked ();
249
+
250
+ if (callback_result->IsUndefined ()) {
251
+ // If you set an ALPN callback, but you return undefined for an ALPN
252
+ // request, you're rejecting all proposed ALPN protocols, and so we send
253
+ // a fatal alert:
254
+ return SSL_TLSEXT_ERR_ALERT_FATAL;
255
+ }
256
+
257
+ CHECK (callback_result->IsNumber ());
258
+ unsigned int result_int = callback_result.As <v8::Number>()->Value ();
259
+
260
+ // The callback returns an offset into the given buffer, for the selected
261
+ // protocol that should be returned. We then set outlen & out to point
262
+ // to the selected input length & value directly:
263
+ *outlen = *(in + result_int);
264
+ *out = (in + result_int + 1 );
265
+
266
+ return SSL_TLSEXT_ERR_OK;
267
+ }
268
+
229
269
const std::vector<unsigned char >& alpn_protos = w->alpn_protos_ ;
230
270
231
271
if (alpn_protos.empty ()) return SSL_TLSEXT_ERR_NOACK;
@@ -1233,6 +1273,15 @@ void TLSWrap::OnClientHelloParseEnd(void* arg) {
1233
1273
c->Cycle ();
1234
1274
}
1235
1275
1276
+ void TLSWrap::EnableALPNCb (const FunctionCallbackInfo<Value>& args) {
1277
+ TLSWrap* wrap;
1278
+ ASSIGN_OR_RETURN_UNWRAP (&wrap, args.Holder ());
1279
+ wrap->alpn_callback_enabled_ = true ;
1280
+
1281
+ SSL* ssl = wrap->ssl_ .get ();
1282
+ SSL_CTX_set_alpn_select_cb (SSL_get_SSL_CTX (ssl), SelectALPNCallback, wrap);
1283
+ }
1284
+
1236
1285
void TLSWrap::GetServername (const FunctionCallbackInfo<Value>& args) {
1237
1286
Environment* env = Environment::GetCurrent (args);
1238
1287
@@ -2044,6 +2093,7 @@ void TLSWrap::Initialize(
2044
2093
SetProtoMethod (isolate, t, " certCbDone" , CertCbDone);
2045
2094
SetProtoMethod (isolate, t, " destroySSL" , DestroySSL);
2046
2095
SetProtoMethod (isolate, t, " enableCertCb" , EnableCertCb);
2096
+ SetProtoMethod (isolate, t, " enableALPNCb" , EnableALPNCb);
2047
2097
SetProtoMethod (isolate, t, " endParser" , EndParser);
2048
2098
SetProtoMethod (isolate, t, " enableKeylogCallback" , EnableKeylogCallback);
2049
2099
SetProtoMethod (isolate, t, " enableSessionCallbacks" , EnableSessionCallbacks);
@@ -2109,6 +2159,7 @@ void TLSWrap::RegisterExternalReferences(ExternalReferenceRegistry* registry) {
2109
2159
registry->Register (CertCbDone);
2110
2160
registry->Register (DestroySSL);
2111
2161
registry->Register (EnableCertCb);
2162
+ registry->Register (EnableALPNCb);
2112
2163
registry->Register (EndParser);
2113
2164
registry->Register (EnableKeylogCallback);
2114
2165
registry->Register (EnableSessionCallbacks);
0 commit comments