TLS 加密客户端你好
RFC 9849. TLS Encrypted Client Hello

原始链接: https://www.rfc-editor.org/rfc/rfc9849.html

## 加密客户端问候 (ECH) 处理摘要 当服务器收到客户端的初始连接尝试,其中包含加密的客户端问候 (ECH) 扩展时,它首先确定是否支持 ECH。它通过使用预配置的 ECHConfig 值列表尝试解密扩展,按配置 ID 匹配或尝试使用所有可用配置进行解密。 成功解密会显示一个新的客户端问候,用于处理。 服务器在解密有效负载之前,会验证兼容性(密码套件、ECH 版本),并使用与所选 ECHConfig 关联的私钥进行解密。 可选地,它可以验证 ECHConfig 中的公共名称是否与服务器名称指示 (SNI) 匹配。 如果解密成功,服务器会将解密的客户端问候转发到后端服务器。 如果后端请求重试(HelloRetryRequest),服务器将使用相同的 ECHConfig 解密客户端的第二次尝试。 如果*所有*解密尝试都失败,服务器将继续进行标准的 TLS 握手,并可能向客户端提供重试配置。 失败并不一定表示错误,因为它可能是 GREASE 扩展,并且如果需要 ECH,客户端应中止连接。 服务器会转发所有后续消息,不做修改。

## TLS 加密客户端问候 (ECH) 总结 一项新的标准,**TLS 加密客户端问候 (ECH)**,细节在 **RFC 9849** (以及相关的 **RFC 9848** 用于 DNS 引导) 中,正在获得关注。ECH 加密 TLS 握手的第一部分 – 特别是服务器名称指示 (SNI) – 通过隐藏用户连接的网站来增强隐私,使其免受网络观察者的窥探。 最近的 Hacker News 讨论强调了对负载均衡器的潜在影响。如果负载均衡器依赖 SNI 进行路由 *而不* 终止 TLS,则需要进行调整,可能倾向于类似于 gRPC 的客户端负载均衡方法。然而,执行第 3 层路由或直接终止 TLS 的负载均衡器不应受到重大影响。 对于不熟悉的人,ECH 的历史和功能的有用概述可以在这里找到:[https://www.feistyduck.com/newsletter/issue_127_encrypted_clienthello/](https://www.feistyduck.com/newsletter/issue_127_encrypted_clienthello/)。
相关文章

原文

7.1. Client-Facing Server

Upon receiving an "encrypted_client_hello" extension in an initial ClientHello, the client-facing server determines if it will accept ECH prior to negotiating any other TLS parameters. Note that successfully decrypting the extension will result in a new ClientHello to process, so even the client's TLS version preferences may have changed.

First, the server collects a set of candidate ECHConfig values. This list is determined by one of the two following methods:

  1. Compare ECHClientHello.config_id against identifiers of each known ECHConfig and select the ones that match, if any, as candidates.

  2. Collect all known ECHConfig values as candidates, with trial decryption below determining the final selection.

Some uses of ECH, such as local discovery mode, may randomize the ECHClientHello.config_id since it can be used as a tracking vector. In such cases, the second method SHOULD be used for matching the ECHClientHello to a known ECHConfig. See Section 10.4. Unless specified by the application profile or otherwise externally configured, implementations MUST use the first method.

The server then iterates over the candidate ECHConfig values, attempting to decrypt the "encrypted_client_hello" extension as follows.

The server verifies that the ECHConfig supports the cipher suite indicated by the ECHClientHello.cipher_suite and that the version of ECH indicated by the client matches the ECHConfig.version. If not, the server continues to the next candidate ECHConfig.

Next, the server decrypts ECHClientHello.payload, using the private key skR corresponding to ECHConfig, as follows:

    context = SetupBaseR(ECHClientHello.enc, skR,
                         "tls ech" || 0x00 || ECHConfig)
    EncodedClientHelloInner = context.Open(ClientHelloOuterAAD,
                                           ECHClientHello.payload)

ClientHelloOuterAAD is computed from ClientHelloOuter as described in Section 5.2. The info parameter to SetupBaseR is the concatenation "tls ech", a zero byte, and the serialized ECHConfig. If decryption fails, the server continues to the next candidate ECHConfig. Otherwise, the server reconstructs ClientHelloInner from EncodedClientHelloInner, as described in Section 5.1. It then stops iterating over the candidate ECHConfig values.

Once the server has chosen the correct ECHConfig, it MAY verify that the value in the ClientHelloOuter "server_name" extension matches the value of ECHConfig.contents.public_name and abort with an "illegal_parameter" alert if these do not match. This optional check allows the server to limit ECH connections to only use the public SNI values advertised in its ECHConfigs. The server MUST be careful not to unnecessarily reject connections if the same ECHConfig id or keypair is used in multiple ECHConfigs with distinct public names.

Upon determining the ClientHelloInner, the client-facing server checks that the message includes a well-formed "encrypted_client_hello" extension of type inner and that it does not offer TLS 1.2 or below. If either of these checks fails, the client-facing server MUST abort with an "illegal_parameter" alert.

If these checks succeed, the client-facing server then forwards the ClientHelloInner to the appropriate backend server, which proceeds as in Section 7.2. If the backend server responds with a HelloRetryRequest, the client-facing server forwards it, decrypts the client's second ClientHelloOuter using the procedure in Section 7.1.1, and forwards the resulting second ClientHelloInner. The client-facing server forwards all other TLS messages between the client and backend server unmodified.

Otherwise, if all candidate ECHConfig values fail to decrypt the extension, the client-facing server MUST ignore the extension and proceed with the connection using ClientHelloOuter with the following modifications:

  • If sending a HelloRetryRequest, the server MAY include an "encrypted_client_hello" extension with a payload of 8 random bytes; see Section 10.10.4 for details.

  • If the server is configured with any ECHConfigs, it MUST include the "encrypted_client_hello" extension in its EncryptedExtensions with the "retry_configs" field set to one or more ECHConfig structures with up-to-date keys. Servers MAY supply multiple ECHConfig values of different versions. This allows a server to support multiple versions at once.

Note that decryption failure could indicate a GREASE ECH extension (see Section 6.2), so it is necessary for servers to proceed with the connection and rely on the client to abort if ECH was required. In particular, the unrecognized value alone does not indicate a misconfigured ECH advertisement (Section 8.1.1). Instead, servers can measure occurrences of the "ech_required" alert to detect this case.

7.1.1. Processing ClientHello after HelloRetryRequest

After sending or forwarding a HelloRetryRequest, the client-facing server does not repeat the steps in Section 7.1 with the second ClientHelloOuter. Instead, it continues with the ECHConfig selection from the first ClientHelloOuter as follows:

If the client-facing server accepted ECH, it checks that the second ClientHelloOuter also contains the "encrypted_client_hello" extension. If not, it MUST abort the handshake with a "missing_extension" alert. Otherwise, it checks that ECHClientHello.cipher_suite and ECHClientHello.config_id are unchanged, and that ECHClientHello.enc is empty. If not, it MUST abort the handshake with an "illegal_parameter" alert.

Finally, it decrypts the new ECHClientHello.payload as a second message with the previous HPKE context:

    EncodedClientHelloInner = context.Open(ClientHelloOuterAAD,
                                           ECHClientHello.payload)

ClientHelloOuterAAD is computed as described in Section 5.2, but using the second ClientHelloOuter. If decryption fails, the client-facing server MUST abort the handshake with a "decrypt_error" alert. Otherwise, it reconstructs the second ClientHelloInner from the new EncodedClientHelloInner as described in Section 5.1, using the second ClientHelloOuter for any referenced extensions.

The client-facing server then forwards the resulting ClientHelloInner to the backend server. It forwards all subsequent TLS messages between the client and backend server unmodified.

If the client-facing server rejected ECH, or if the first ClientHello did not include an "encrypted_client_hello" extension, the client-facing server proceeds with the connection as usual. The server does not decrypt the second ClientHello's ECHClientHello.payload value, if there is one. Moreover, if the server is configured with any ECHConfigs, it MUST include the "encrypted_client_hello" extension in its EncryptedExtensions with the "retry_configs" field set to one or more ECHConfig structures with up-to-date keys, as described in Section 7.1.

Note that a client-facing server that forwards the first ClientHello cannot include its own "cookie" extension if the backend server sends a HelloRetryRequest. This means that the client-facing server either needs to maintain state for such a connection or it needs to coordinate with the backend server to include any information it requires to process the second ClientHello.

联系我们 contact @ memedata.com