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>

Reply via email to