Requirement: Verify client certificate at the route level if configured, and do not fail in early SSL handshake.
Issue: The original implementation will fail the SSL handshake if the client certificate is required but fails to be verified. It has no chance to check if the route is in the whitelist, i.e. Bypass the MTLS. Solution: OpenSSL enables us to skip the verification error so that we could handle the error after the route gets known. Change the verify callback, then we could implement route-level MTLS. Timing diagram: user->apisix ssl phase: Client Hello apisix ssl phase->apisix ssl phase: if SNI is MTLS apisix ssl phase-->user: Server Hello, Certificate Request user->apisix ssl phase: Send Certificate apisix ssl phase->apisix ssl phase: if the SNI has route whitelist, verify the Client Cert, log and ignore errors apisix ssl phase->apisix ssl phase: Otherwise, respond failure user->apisix ssl phase: If do not send Certificate apisix ssl phase->apisix ssl phase: if the SNI has route whitelist, log and ignore the absence apisix ssl phase->apisix ssl phase: Otherwise, respond failure user->apisix other phases: Request routes in the whitelist apisix other phases-->user: Response user->apisix other phases: Request routes *NOT* in the whitelist apisix other phases-->user: if verification failed in ssl phase (Client Cert not sent or invalid), respond 400 Response example: < HTTP/2 400 < date: Mon, 27 Mar 2023 15:47:54 GMT < content-type: text/html; charset=utf-8 < content-length: 229 < server: APISIX/3.2.0 < <html><head><title>400 No required SSL certificate was sent</title></head><body><center><h1>400 Bad Request</h1></center><center>No required SSL certificate was sent</center><hr><center>openresty</center><p><em>Powered by <a href="https://apisix.apache.org/">APISIX</a>.</em></p></body></html>