Skip to content

Resuming after a TLS cert hook pause re-runs certificate selection and misdispatches verify-client hooks #13730

Description

@maskit

When a TS_SSL_CERT_HOOK plugin pauses the handshake and later reenables it, the TLS library calls ssl_cert_callback() again (src/iocore/net/SSLUtils.cc). By then the cert hooks have already finished, but the callback does not recognize that state.

Sequence

  1. The cert hook pauses, and ssl_cert_callback() returns -1.
  2. The plugin reenables. SSLNetVConnection::reenable() calls resume_tls_event() (CERT_INVOKE → CERT), then invoke_tls_event(), which finds no further cert hook and moves the state to HANDSHAKE_HOOKS_CLIENT_CERT.
  3. The library calls the callback again. OpenSSL re-invokes cert_cb from tls_post_process_client_hello() after a negative return. BoringSSL re-runs the select certificate callback once Honor TLS handshake hook pauses on BoringSSL #13729 returns a retry for the pause.
  4. In HANDSHAKE_HOOKS_CLIENT_CERT, calledHooks(TS_EVENT_SSL_CERT) returns false, so selectCertificate() runs a second time.
  5. callHooks(TS_EVENT_SSL_CERT) in HANDSHAKE_HOOKS_CLIENT_CERT starts the TS_SSL_VERIFY_CLIENT_HOOK list and invokes it with TS_EVENT_SSL_CERT.

Effect

  • Verify-client hooks are called early and with TS_EVENT_SSL_CERT instead of TS_EVENT_SSL_VERIFY_CLIENT.
  • The second selectCertificate() may replace an SSL_CTX that the cert hook plugin set while it held the pause. Not yet confirmed; it depends on whether the name or IP lookup finds a match.

With no verify-client hooks registered, callHooks() returns success and the handshake completes, which may be why this has gone unnoticed.

Possible fix

In ssl_cert_callback(), when the hook state shows the cert hooks have completed (HANDSHAKE_HOOKS_CLIENT_CERT / HANDSHAKE_HOOKS_CLIENT_CERT_INVOKE), skip selectCertificate() and callHooks(TS_EVENT_SSL_CERT) and continue as success. The CA cert and session ticket steps at the end of the callback still need to run on that call, since the paused call skipped them.

Testing

A test that pauses the cert hook with a verify-client hook registered, and checks that the verify-client hook only receives TS_EVENT_SSL_VERIFY_CLIENT, should cover both backends.

Found while reviewing #13729. The sequence above is from reading the code; it has not been reproduced yet.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions