相互 TLS 是否应该仅在 TLS 握手期间执行?

Is Mutual TLS supposed to be performed during TLS handshake only?

最近我一直在为基于物联网的项目评估不同的 API 网关 (API GW) 选项。这样做的目的是找到一个足够好的解决方案来执行设备和 API GW 的相互 TLS (mTLS) 身份验证。

我尝试过的大多数解决方案似乎都在 TLS 握手期间执行 mTLS,如 nicely depicted here。所以这就是我理解的OSI Layer 4 (TCP/IP)认证方式。

然而,Kong API Gateway 似乎在 OSI 第 7 层(应用程序) 上执行此操作。基本上,在 TLS 握手阶段没有客户端身份验证,而是应用程序层验证对等证书。因此它能够发送具有 401 状态和一些负载的响应(如果 TLS 握手失败,这是不可能的)。例子

√ poc-mtls-local-env % make test-fail-wrong-cert                              master 
curl -v --cacert certs/gen/ca-chain.crt \
        --key certs/gen/device.key \
        --cert certs/gen/device.crt \
        https://mtls.auth.local.com/echo
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to mtls.auth.local.com (127.0.0.1) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: certs/gen/ca.crt
  CApath: none
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Request CERT (13):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Certificate (11):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS handshake, CERT verify (15):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
* ALPN, server accepted to use h2
* Server certificate:
*  subject: C=US; ST=NY; L=NYC; O=Sample; OU=UDS; CN=local.com
*  start date: Jul 29 12:10:25 2021 GMT
*  expire date: Jul 29 12:10:25 2022 GMT
*  subjectAltName: host "mtls.auth.local.com" matched cert's "mtls.auth.local.com"
*  issuer: C=US; ST=NY; O=Sample; OU=UDS; CN=Sample Intermediate CA; emailAddress=it@sample.com
*  SSL certificate verify ok.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x7fc0dd808200)
> GET /echo HTTP/2
> Host: mtls.auth.local.com
> User-Agent: curl/7.64.1
> Accept: */*
> 
* Connection state changed (MAX_CONCURRENT_STREAMS == 128)!
< HTTP/2 401 
< date: Tue, 10 Aug 2021 06:46:13 GMT
< content-type: application/json; charset=utf-8
< content-length: 49
< x-kong-response-latency: 4
< server: kong/2.4.1.1-enterprise-edition
< 
* Connection #0 to host mtls.auth.local.com left intact
{"message":"TLS certificate failed verification"}* Closing connection 0

我们可以清楚地看到请求成功通过了TLS握手,应用层形成401响应{"message": "TLS certificate failed verification"}

这让我想到了以下问题:

Most of the solutions I've tried out seem to perform mTLS during the TLS handshake as nicely depicted here. So this is what I understand OSI Layer 4 (TCP/IP) authentication method.

由于 TLS 在 OSI 第 4 层之上,因此身份验证也在第 4 层之上。但是 OSI 层放在一边(无论如何都不能充分匹配今天第 4 层之上的现实),您基本上会问相互身份验证发生在哪个阶段。

TLS 中的相互身份验证分两个阶段进行:请求客户端证书和验证证书是否符合要求。请求证书总是在 TLS 握手中完成,尽管它不需要是连接的初始 TLS 握手。

验证证书可以在 TLS 握手内部、外部或两者结合进行。通常,在握手中检查证书是由某个受信任的证书颁发机构颁发的,但进一步检查特定主题或可能是特定于应用程序的,因此将在应用程序内部的 TLS 握手之后完成。但也可能是在 TLS 握手内部或外部完成了完整验证。

接受 TLS 握手中的任何证书并验证证书,然后仅在握手之外验证证书,其优点是可以 return 向已建立的 TLS 连接内的客户端发送有用的错误消息。 TLS 握手中的验证错误反而会导致神秘错误,例如握手错误警报或只是关闭连接,这对调试问题没有帮助。