Copilot commented on code in PR #13729:
URL: https://github.com/apache/trafficserver/pull/13729#discussion_r4095451623


##########
src/iocore/net/SSLUtils.cc:
##########
@@ -1063,24 +1063,29 @@ 
SSLMultiCertConfigLoader::_set_handshake_callbacks(SSL_CTX *ctx)
 #elif HAVE_SSL_CTX_SET_SELECT_CERTIFICATE_CB
   SSL_CTX_set_select_certificate_cb(ctx, [](const SSL_CLIENT_HELLO 
*client_hello) -> ssl_select_cert_result_t {
     ssl_select_cert_result_t res;
-    res = ssl_client_hello_callback(client_hello);
-    if (res == ssl_select_cert_error) {
-      return res;
-    }
+    TLSEventSupport         *es = 
TLSEventSupport::getInstance(client_hello->ssl);
+
+    // BoringSSL runs this whole callback again once a paused hook reenables, 
whereas OpenSSL calls
+    // only the callback that paused. After a pause in the cert hook, the 
client hello and
+    // servername work is already done and must not run twice.
+    if (es == nullptr || !es->reached_cert_hooks()) {
+      res = ssl_client_hello_callback(client_hello);
+      if (res != ssl_select_cert_success) {
+        return res;
+      }

Review Comment:
   When a cert hook pauses, `SSLNetVConnection::reenable()` advances the hook 
state past the final cert hook to `HANDSHAKE_HOOKS_CLIENT_CERT` before 
BoringSSL re-enters this callback (`TLSEventSupport.cc:519-522`). 
`reached_cert_hooks()` then makes this branch skip ClientHello/SNI, but 
`ssl_cert_callback()` sees `calledHooks(TS_EVENT_SSL_CERT)` as false in 
`HANDSHAKE_HOOKS_CLIENT_CERT`, so it selects the certificate a second time and 
`callHooks(TS_EVENT_SSL_CERT)` can start the verify-client hook list with the 
wrong event. Preserve an explicit cert-processing/retry state (or otherwise 
make `ssl_cert_callback()` recognize this resumed state) so the retry does not 
re-run certificate selection or enter client-cert hooks as `TS_EVENT_SSL_CERT`.
   
   This issue also appears on line 1071 of the same file.



##########
src/iocore/net/TLSEventSupport.cc:
##########
@@ -375,6 +375,20 @@ TLSEventSupport::calledHooks(TSEvent eventId) const
   return retval;
 }
 
+bool
+TLSEventSupport::reached_cert_hooks() const
+{
+  switch (this->sslHandshakeHookState) {
+  case SSLHandshakeHookState::HANDSHAKE_HOOKS_CERT:
+  case SSLHandshakeHookState::HANDSHAKE_HOOKS_CERT_INVOKE:
+  case SSLHandshakeHookState::HANDSHAKE_HOOKS_CLIENT_CERT:
+  case SSLHandshakeHookState::HANDSHAKE_HOOKS_CLIENT_CERT_INVOKE:

Review Comment:
   `HANDSHAKE_HOOKS_CLIENT_CERT` is reached after the last `TS_EVENT_SSL_CERT` 
hook has already completed. On the retry callback, this predicate skips 
client-hello/servername but still calls `ssl_cert_callback`; 
`ssl_cert_callback`'s `calledHooks(TS_EVENT_SSL_CERT)` check is false in 
`CLIENT_CERT`, so it reselects the certificate and enters the client-cert hook 
list with `TS_EVENT_SSL_CERT` instead of finishing the handshake normally. The 
retry path needs to distinguish an unfinished `CERT`/`CERT_INVOKE` phase from 
the already-completed `CLIENT_CERT` phase.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to