| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 8f4ee7e commit 1864175
3 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -218,32 +218,18 @@ int SSLCertCallback(SSL* s, void* arg) { | |||
| 218 | 218 | // handshake will continue after certcb is done. | |
| 219 | 219 | return -1; | |
| 220 | 220 | ||
| 221 | - Environment* env = w->env(); | ||
| 222 | - HandleScope handle_scope(env->isolate()); | ||
| 223 | - Context::Scope context_scope(env->context()); | ||
| 224 | 221 | w->set_cert_cb_running(); | |
| 225 | 222 | ||
| 226 | - Local<Object> info = Object::New(env->isolate()); | ||
| 223 | + // The view points into SSL-owned memory, so copy it before deferring. | ||
| 224 | + std::string servername; | ||
| 225 | + if (auto name = SSLPointer::GetServerName(s)) servername = *name; | ||
| 227 | 226 | ||
| 228 | - auto servername = SSLPointer::GetServerName(s); | ||
| 229 | - Local<String> servername_str = | ||
| 230 | - !servername.has_value() | ||
| 231 | - ? String::Empty(env->isolate()) | ||
| 232 | - : OneByteString(env->isolate(), servername.value()); | ||
| 233 | - | ||
| 234 | - Local<Value> ocsp = Boolean::New( | ||
| 235 | - env->isolate(), SSL_get_tlsext_status_type(s) == TLSEXT_STATUSTYPE_ocsp); | ||
| 227 | + w->ScheduleCertCb(std::move(servername), | ||
| 228 | + SSL_get_tlsext_status_type(s) == TLSEXT_STATUSTYPE_ocsp); | ||
| 236 | 229 | ||
| 237 | - if (info->Set(env->context(), env->servername_string(), servername_str) | ||
| 238 | - .IsNothing() || | ||
| 239 | - info->Set(env->context(), env->ocsp_request_string(), ocsp).IsNothing()) { | ||
| 240 | - return 1; | ||
| 241 | - } | ||
| 242 | - | ||
| 243 | - Local<Value> argv[] = { info }; | ||
| 244 | - w->MakeCallback(env->oncertcb_string(), arraysize(argv), argv); | ||
| 245 | - | ||
| 246 | - return w->is_cert_cb_running() ? -1 : 1; | ||
| 230 | + // Suspend handshake with SSL_ERROR_WANT_X509_LOOKUP, and handshake will | ||
| 231 | + // continue after certcb is done. | ||
| 232 | + return -1; | ||
| 247 | 233 | } | |
| 248 | 234 | ||
| 249 | 235 | int SelectALPNCallback( | |
@@ -519,16 +505,48 @@ void TLSWrap::EmitClientHello(const std::vector<unsigned char>& session_id, | |||
| 519 | 505 | env->tls_ticket_string(), | |
| 520 | 506 | Boolean::New(env->isolate(), has_ticket)) | |
| 521 | 507 | .IsNothing()) { | |
| 522 | - // Continue the handshake unresumed rather than leaving it suspended. | ||
| 523 | - hello_answered_ = true; | ||
| 524 | - Cycle(); | ||
| 508 | + // An exception is pending, so don't re-enter SSL or JS to resume. | ||
| 525 | 509 | return; | |
| 526 | 510 | } | |
| 527 | 511 | ||
| 528 | 512 | Local<Value> argv[] = {hello_obj}; | |
| 529 | 513 | MakeCallback(env->onclienthello_string(), arraysize(argv), argv); | |
| 530 | 514 | } | |
| 531 | 515 | ||
| 516 | + // As with the ClientHello, JS must not run on the library's stack: 'oncertcb' | ||
| 517 | + // handlers synchronously call back into the handle to resume the handshake. | ||
| 518 | + void TLSWrap::ScheduleCertCb(std::string servername, bool ocsp) { | ||
| 519 | + Debug(this, "Scheduling oncertcb"); | ||
| 520 | + BaseObjectPtr<TLSWrap> strong_ref{this}; | ||
| 521 | + env()->SetImmediate( | ||
| 522 | + [this, strong_ref, servername = std::move(servername), ocsp]( | ||
| 523 | + Environment* env) { | ||
| 524 | + if (ssl_) EmitCertCb(servername, ocsp); | ||
| 525 | + }); | ||
| 526 | + } | ||
| 527 | + | ||
| 528 | + void TLSWrap::EmitCertCb(const std::string& servername, bool ocsp) { | ||
| 529 | + Debug(this, "Emitting oncertcb"); | ||
| 530 | + Environment* env = this->env(); | ||
| 531 | + HandleScope handle_scope(env->isolate()); | ||
| 532 | + Context::Scope context_scope(env->context()); | ||
| 533 | + | ||
| 534 | + Local<Object> info = Object::New(env->isolate()); | ||
| 535 | + if (info->Set(env->context(), | ||
| 536 | + env->servername_string(), | ||
| 537 | + OneByteString(env->isolate(), servername)) | ||
| 538 | + .IsNothing() || | ||
| 539 | + info->Set(env->context(), | ||
| 540 | + env->ocsp_request_string(), | ||
| 541 | + Boolean::New(env->isolate(), ocsp)) | ||
| 542 | + .IsNothing()) { | ||
| 543 | + return; | ||
| 544 | + } | ||
| 545 | + | ||
| 546 | + Local<Value> argv[] = {info}; | ||
| 547 | + MakeCallback(env->oncertcb_string(), arraysize(argv), argv); | ||
| 548 | + } | ||
| 549 | + | ||
| 532 | 550 | void TLSWrap::InitSSL() { | |
| 533 | 551 | // Initialize SSL – OpenSSL takes ownership of these. | |
| 534 | 552 | enc_in_ = NodeBIO::New(env()).release(); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -115,6 +115,9 @@ class TLSWrap : public AsyncWrap, | |||
| 115 | 115 | size_t session_id_len, | |
| 116 | 116 | bool has_ticket); | |
| 117 | 117 | ||
| 118 | + // Schedules 'oncertcb'. The handshake stays suspended until certCbDone(). | ||
| 119 | + void ScheduleCertCb(std::string servername, bool ocsp); | ||
| 120 | + | ||
| 118 | 121 | // Implement MemoryRetainer: | |
| 119 | 122 | void MemoryInfo(MemoryTracker* tracker) const override; | |
| 120 | 123 | SET_MEMORY_INFO_NAME(TLSWrap) | |
@@ -149,6 +152,7 @@ class TLSWrap : public AsyncWrap, | |||
| 149 | 152 | void WaitForCertCb(CertCb cb, void* arg); | |
| 150 | 153 | void EmitClientHello(const std::vector<unsigned char>& session_id, | |
| 151 | 154 | bool has_ticket); | |
| 155 | + void EmitCertCb(const std::string& servername, bool ocsp); | ||
| 152 | 156 | ||
| 153 | 157 | TLSWrap(Environment* env, | |
| 154 | 158 | v8::Local<v8::Object> obj, | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,49 @@ | |||
| 1 | + 'use strict'; | ||
| 2 | + | ||
| 3 | + // Writing to a server TLSSocket synchronously from inside an SNICallback, | ||
| 4 | + // while the handshake is still waiting on the certificate callback, must not | ||
| 5 | + // break the connection; the data must be delivered once the handshake ends. | ||
| 6 | + | ||
| 7 | + const common = require('../common'); | ||
| 8 | + | ||
| 9 | + if (!common.hasCrypto) | ||
| 10 | + common.skip('missing crypto'); | ||
| 11 | + | ||
| 12 | + const assert = require('assert'); | ||
| 13 | + const fixtures = require('../common/fixtures'); | ||
| 14 | + const net = require('net'); | ||
| 15 | + const tls = require('tls'); | ||
| 16 | + | ||
| 17 | + const secureContext = tls.createSecureContext({ | ||
| 18 | + key: fixtures.readKey('rsa_private.pem'), | ||
| 19 | + cert: fixtures.readKey('rsa_cert.crt'), | ||
| 20 | + }); | ||
| 21 | + | ||
| 22 | + let serverSocket; | ||
| 23 | + const server = net.createServer(common.mustCall((raw) => { | ||
| 24 | + serverSocket = new tls.TLSSocket(raw, { | ||
| 25 | + isServer: true, | ||
| 26 | + secureContext, | ||
| 27 | + SNICallback: common.mustCall((servername, callback) => { | ||
| 28 | + assert.strictEqual(servername, 'localhost'); | ||
| 29 | + serverSocket.write('from-mid-handshake'); | ||
| 30 | + callback(null, null); | ||
| 31 | + }), | ||
| 32 | + }); | ||
| 33 | + serverSocket.on('error', common.mustNotCall()); | ||
| 34 | + })); | ||
| 35 | + | ||
| 36 | + server.listen(0, common.mustCall(() => { | ||
| 37 | + const client = tls.connect({ | ||
| 38 | + port: server.address().port, | ||
| 39 | + servername: 'localhost', | ||
| 40 | + rejectUnauthorized: false, | ||
| 41 | + }, common.mustCall(() => { | ||
| 42 | + client.on('data', common.mustCall((data) => { | ||
| 43 | + assert.strictEqual(data.toString(), 'from-mid-handshake'); | ||
| 44 | + client.end(); | ||
| 45 | + server.close(); | ||
| 46 | + })); | ||
| 47 | + })); | ||
| 48 | + client.on('error', common.mustNotCall()); | ||
| 49 | + })); | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments