diff options
author | James M Snell <jasnell@gmail.com> | 2020-07-23 22:11:12 +0300 |
---|---|---|
committer | James M Snell <jasnell@gmail.com> | 2020-07-27 23:33:14 +0300 |
commit | 1f94b89309bcd56a2883cd1b0eb2db610251095e (patch) | |
tree | f26a6929226f6ff4039c0ea58584821147b26ce4 /lib/internal/quic | |
parent | 06664298fa07442b5be6dbc891ea999f6c9e7d28 (diff) |
quic: refactor ocsp to use async function rather than event/callback
PR-URL: https://github.com/nodejs/node/pull/34498
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Diffstat (limited to 'lib/internal/quic')
-rw-r--r-- | lib/internal/quic/core.js | 117 | ||||
-rw-r--r-- | lib/internal/quic/util.js | 33 |
2 files changed, 77 insertions, 73 deletions
diff --git a/lib/internal/quic/core.js b/lib/internal/quic/core.js index 6a227d3d4ae..821b2839fe9 100644 --- a/lib/internal/quic/core.js +++ b/lib/internal/quic/core.js @@ -209,11 +209,11 @@ const kAddSession = Symbol('kAddSession'); const kAddStream = Symbol('kAddStream'); const kBind = Symbol('kBind'); const kClose = Symbol('kClose'); -const kCert = Symbol('kCert'); const kClientHello = Symbol('kClientHello'); const kDestroy = Symbol('kDestroy'); const kEndpointBound = Symbol('kEndpointBound'); const kEndpointClose = Symbol('kEndpointClose'); +const kHandleOcsp = Symbol('kHandleOcsp'); const kHandshake = Symbol('kHandshake'); const kHandshakeComplete = Symbol('kHandshakeComplete'); const kHandshakePost = Symbol('kHandshakePost'); @@ -323,52 +323,37 @@ function onSessionClientHello(alpn, servername, ciphers) { clientHelloCallback.bind(this)); } -// Used only within the onSessionCert function. Invoked -// to complete the session cert process. -function sessionCertCallback(err, context, ocspResponse) { - if (err) { - this[owner_symbol].destroy(err); - return; - } - if (context != null && !context.context) { - this[owner_symbol].destroy( - new ERR_INVALID_ARG_TYPE( - 'context', - 'SecureContext', - context)); - } - if (ocspResponse != null) { - if (typeof ocspResponse === 'string') - ocspResponse = Buffer.from(ocspResponse); - if (!isArrayBufferView(ocspResponse)) { - this[owner_symbol].destroy( - new ERR_INVALID_ARG_TYPE( - 'ocspResponse', - ['string', 'Buffer', 'TypedArray', 'DataView'], - ocspResponse)); - } - } - try { - this.onCertDone(context ? context.context : undefined, ocspResponse); - } catch (err) { - this[owner_symbol].destroy(err); - } -} - // This callback is only ever invoked for QuicServerSession instances, // and is used to trigger OCSP request processing when needed. The // user callback must invoke .onCertDone() in order for the // TLS handshake to continue. function onSessionCert(servername) { - this[owner_symbol][kCert](servername, sessionCertCallback.bind(this)); + this[owner_symbol][kHandleOcsp](servername) + .then(({ context, data }) => { + if (context !== undefined && !context?.context) + throw new ERR_INVALID_ARG_TYPE('context', 'SecureContext', context); + if (data !== undefined) { + if (typeof data === 'string') + data = Buffer.from(data); + if (!isArrayBufferView(data)) { + throw new ERR_INVALID_ARG_TYPE( + 'data', + ['string', 'Buffer', 'TypedArray', 'DataView'], + data); + } + } + this.onCertDone(context?.context, data); + }) + .catch((error) => this[owner_symbol].destroy(error)); } // This callback is only ever invoked for QuicClientSession instances, // and is used to deliver the OCSP response as provided by the server. // If the requestOCSP configuration option is false, this will never // be called. -function onSessionStatus(response) { - this[owner_symbol][kCert](response); +function onSessionStatus(data) { + this[owner_symbol][kHandleOcsp](data) + .catch((error) => this[owner_symbol].destroy(error)); } // Called by the C++ internals when the TLS handshake is completed. @@ -524,12 +509,12 @@ setCallbacks({ onSocketServerBusy, onSessionReady, onSessionCert, + onSessionStatus, onSessionClientHello, onSessionClose, onSessionHandshake, onSessionKeylog, onSessionQlog, - onSessionStatus, onSessionTicket, onSessionVersionNegotiation, onStreamReady, @@ -933,6 +918,7 @@ class QuicSocket extends EventEmitter { listenPending: false, listenPromise: undefined, lookup: undefined, + ocspHandler: undefined, server: undefined, serverSecureContext: undefined, sessions: new Set(), @@ -1032,6 +1018,7 @@ class QuicSocket extends EventEmitter { return { highWaterMark: state.highWaterMark, defaultEncoding: state.defaultEncoding, + ocspHandler: state.ocspHandler, }; } @@ -1224,6 +1211,7 @@ class QuicSocket extends EventEmitter { lookup = state.lookup, defaultEncoding, highWaterMark, + ocspHandler, transportParams, } = validateQuicSocketListenOptions(options); @@ -1239,6 +1227,7 @@ class QuicSocket extends EventEmitter { state.defaultEncoding = defaultEncoding; state.alpn = alpn; state.listenPending = true; + state.ocspHandler = ocspHandler; await this[kMaybeBind](); @@ -1663,6 +1652,7 @@ class QuicSession extends EventEmitter { handshakeCompletePromiseReject: undefined, idleTimeout: false, maxPacketLength: NGTCP2_DEFAULT_MAX_PKTLEN, + ocspHandler: undefined, servername: undefined, socket: undefined, silentClose: false, @@ -1685,6 +1675,7 @@ class QuicSession extends EventEmitter { servername, highWaterMark, defaultEncoding, + ocspHandler, } = options; super({ captureRejections: true }); this.on('newListener', onNewListener); @@ -1695,6 +1686,7 @@ class QuicSession extends EventEmitter { state.alpn = alpn; state.highWaterMark = highWaterMark; state.defaultEncoding = defaultEncoding; + state.ocspHandler = ocspHandler; socket[kAddSession](this); } @@ -1758,6 +1750,7 @@ class QuicSession extends EventEmitter { state.state = new QuicSessionSharedState(handle.state); state.handshakeAckHistogram = new Histogram(handle.ack); state.handshakeContinuationHistogram = new Histogram(handle.rate); + state.state.ocspEnabled = state.ocspHandler !== undefined; if (handle.qlogStream !== undefined) { this[kSetQLogStream](handle.qlogStream); handle.qlogStream = undefined; @@ -2284,8 +2277,9 @@ class QuicServerSession extends QuicSession { const { highWaterMark, defaultEncoding, + ocspHandler, } = options; - super(socket, { highWaterMark, defaultEncoding }); + super(socket, { highWaterMark, defaultEncoding, ocspHandler }); this[kSetHandle](handle); } @@ -2301,26 +2295,18 @@ class QuicServerSession extends QuicSession { callback.bind(this[kHandle])); } - // Called only when an OCSPRequest event handler is registered. - // Allows user code the ability to answer the OCSP query. - [kCert](servername, callback) { + async [kHandleOcsp](servername) { + const internalState = this[kInternalState]; const state = this[kInternalServerState]; - const { serverSecureContext } = this.socket; - let { context } = serverSecureContext; - - for (var i = 0; i < state.contexts.length; i++) { - const elem = state.contexts[i]; - if (elem[0].test(servername)) { - context = elem[1]; - break; - } - } - - this.emit( - 'OCSPRequest', - servername, - context, - callback.bind(this[kHandle])); + const { context } = this.socket.serverSecureContext; + + return internalState.ocspHandler?.( + 'request', + { + servername, + context, + contexts: Array.from(state.contexts) + }); } get allowEarlyData() { return false; } @@ -2358,10 +2344,10 @@ class QuicClientSession extends QuicSession { alpn, dcid, minDHSize, + ocspHandler, port, preferredAddressPolicy, remoteTransportParams, - requestOCSP, servername, sessionTicket, verifyHostnameIdentity, @@ -2379,7 +2365,13 @@ class QuicClientSession extends QuicSession { ); } - super(socket, { servername, alpn, highWaterMark, defaultEncoding }); + super(socket, { + servername, + alpn, + highWaterMark, + defaultEncoding, + ocspHandler + }); const state = this[kInternalClientState]; state.handshakeStarted = autoStart; state.minDHSize = minDHSize; @@ -2412,7 +2404,7 @@ class QuicClientSession extends QuicSession { this.alpnProtocol, (verifyHostnameIdentity ? QUICCLIENTSESSION_OPTION_VERIFY_HOSTNAME_IDENTITY : 0) | - (requestOCSP ? + (ocspHandler !== undefined ? QUICCLIENTSESSION_OPTION_REQUEST_OCSP : 0), qlog, autoStart); @@ -2444,8 +2436,9 @@ class QuicClientSession extends QuicSession { return true; } - [kCert](response) { - this.emit('OCSPResponse', response); + async [kHandleOcsp](data) { + const internalState = this[kInternalState]; + return internalState.ocspHandler?.('response', { data }); } get allowEarlyData() { diff --git a/lib/internal/quic/util.js b/lib/internal/quic/util.js index f46a8714e00..3d0ebb0884a 100644 --- a/lib/internal/quic/util.js +++ b/lib/internal/quic/util.js @@ -72,7 +72,7 @@ const { IDX_QUICSESSION_STATE_KEYLOG_ENABLED, IDX_QUICSESSION_STATE_CLIENT_HELLO_ENABLED, - IDX_QUICSESSION_STATE_CERT_ENABLED, + IDX_QUICSESSION_STATE_OCSP_ENABLED, IDX_QUICSESSION_STATE_PATH_VALIDATED_ENABLED, IDX_QUICSESSION_STATE_USE_PREFERRED_ADDRESS_ENABLED, IDX_QUICSESSION_STATE_HANDSHAKE_CONFIRMED, @@ -368,10 +368,10 @@ function validateQuicClientSessionOptions(options = {}) { alpn = '', dcid: dcid_value, minDHSize = 1024, + ocspHandler, port = 0, preferredAddressPolicy = 'ignore', remoteTransportParams, - requestOCSP = false, servername = (isIP(address) ? '' : address), sessionTicket, verifyHostnameIdentity = true, @@ -434,23 +434,29 @@ function validateQuicClientSessionOptions(options = {}) { if (preferredAddressPolicy !== undefined) validateString(preferredAddressPolicy, 'options.preferredAddressPolicy'); - validateBoolean(requestOCSP, 'options.requestOCSP'); validateBoolean(verifyHostnameIdentity, 'options.verifyHostnameIdentity'); validateBoolean(qlog, 'options.qlog'); + if (ocspHandler !== undefined && typeof ocspHandler !== 'function') { + throw new ERR_INVALID_ARG_TYPE( + 'options.ocspHandler', + 'functon', + ocspHandler); + } + return { autoStart, address, alpn, dcid, minDHSize, + ocspHandler, port, preferredAddressPolicy: preferredAddressPolicy === 'accept' ? QUIC_PREFERRED_ADDRESS_USE : QUIC_PREFERRED_ADDRESS_IGNORE, remoteTransportParams, - requestOCSP, servername, sessionTicket, verifyHostnameIdentity, @@ -605,6 +611,7 @@ function validateQuicSocketListenOptions(options = {}) { alpn = NGHTTP3_ALPN_H3, defaultEncoding, highWaterMark, + ocspHandler, requestCert, rejectUnauthorized, lookup, @@ -616,6 +623,12 @@ function validateQuicSocketListenOptions(options = {}) { validateBoolean(requestCert, 'options.requestCert'); if (lookup !== undefined) validateLookup(lookup); + if (ocspHandler !== undefined && typeof ocspHandler !== 'function') { + throw new ERR_INVALID_ARG_TYPE( + 'options.ocspHandler', + 'functon', + ocspHandler); + } const transportParams = validateTransportParams( options, @@ -625,6 +638,7 @@ function validateQuicSocketListenOptions(options = {}) { return { alpn, lookup, + ocspHandler, rejectUnauthorized, requestCert, transportParams, @@ -804,9 +818,6 @@ function toggleListeners(state, event, on) { case 'pathValidation': state.pathValidatedEnabled = on; break; - case 'OCSPRequest': - state.certEnabled = on; - break; case 'usePreferredAddress': state.usePreferredAddressEnabled = on; break; @@ -915,14 +926,14 @@ class QuicSessionSharedState { .writeUInt8(on ? 1 : 0, IDX_QUICSESSION_STATE_CLIENT_HELLO_ENABLED); } - get certEnabled() { + get ocspEnabled() { return Boolean(this[kHandle] - .readUInt8(IDX_QUICSESSION_STATE_CERT_ENABLED)); + .readUInt8(IDX_QUICSESSION_STATE_OCSP_ENABLED)); } - set certEnabled(on) { + set ocspEnabled(on) { this[kHandle] - .writeUInt8(on ? 1 : 0, IDX_QUICSESSION_STATE_CERT_ENABLED); + .writeUInt8(on ? 1 : 0, IDX_QUICSESSION_STATE_OCSP_ENABLED); } get pathValidatedEnabled() { |