You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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
The cert hook pauses, and ssl_cert_callback() returns -1.
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.
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.
In HANDSHAKE_HOOKS_CLIENT_CERT, calledHooks(TS_EVENT_SSL_CERT) returns false, so selectCertificate() runs a second time.
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.
When a
TS_SSL_CERT_HOOKplugin pauses the handshake and later reenables it, the TLS library callsssl_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
ssl_cert_callback()returns -1.SSLNetVConnection::reenable()callsresume_tls_event()(CERT_INVOKE→CERT), theninvoke_tls_event(), which finds no further cert hook and moves the state toHANDSHAKE_HOOKS_CLIENT_CERT.cert_cbfromtls_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.HANDSHAKE_HOOKS_CLIENT_CERT,calledHooks(TS_EVENT_SSL_CERT)returns false, soselectCertificate()runs a second time.callHooks(TS_EVENT_SSL_CERT)inHANDSHAKE_HOOKS_CLIENT_CERTstarts theTS_SSL_VERIFY_CLIENT_HOOKlist and invokes it withTS_EVENT_SSL_CERT.Effect
TS_EVENT_SSL_CERTinstead ofTS_EVENT_SSL_VERIFY_CLIENT.selectCertificate()may replace anSSL_CTXthat 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), skipselectCertificate()andcallHooks(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.