0.23.x: buffered writes still return Ok(len) after TLS 1.2 confidentiality limit is reached (backport of #3332 error behavior?)

未关闭
#3,366 2 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

维护者通常 1 天内回复

还没有人认领这个 Issue。

评估

难度
4/5
预计耗时
3-5 天
新手友好度
45/100
Issue 类型
缺陷
描述清晰度
基本清楚
活跃度
活跃
技术栈
cryptography, networking, rust

调研方向

Start by reading CommonState::send_appdata_encrypt, Writer::write, and send_close_notify to understand how the confidentiality-limit error is currently discarded. Examine tls12_connection_fails_after_alert_at_confidentiality_limit in the rel-0.23 tests and add coverage showing the failed and subsequent writes return errors rather than Ok(len). Done means the chosen write-error behavior is implemented consistently, while preserving the distinction required for async callers.

由索引模型根据 Issue 内容生成。

描述

Checklist

  • I've searched the issue tracker for similar bugs.

Describe the bug

This is a follow-up to #3301 / #3332, asking about the 0.23.x line.

On main, #3332 makes a buffered write that hits the TLS 1.2 confidentiality limit return Err(Error::EncryptError), and later writes fail too. The 0.23.46 backport (ab3ca337cc, 9363630547) stops partial writes and stops encrypting with the exhausted key, but Writer::write still returns Ok(len) for data that is never encrypted or sent:

  • CommonState::send_appdata_encrypt does return len; when check_pre_encrypt_action(last) fails.
  • send_close_notify() does not set core.state, so check_error() lets later writes through. Each one logs traffic keys exhausted again and also returns Ok(len).
  • The rel-0.23 tests treat this as expected: tls12_connection_fails_after_alert_at_confidentiality_limit does client.writer().write_all(b"later").unwrap().

The caller cannot tell the bytes were dropped. It also cannot tell the connection is now write-dead, until the peer closes it.

Real-world impact

This shows up in GreptimeDB's Kafka remote WAL (GreptimeTeam/greptimedb#9681), using rskafka + tokio-rustls over TLS 1.2 to AWS MSK. MSK offers neither TLS 1.3 nor ChaCha20-Poly1305, so AES-GCM and its 2^24-record limit are unavoidable there.

  1. The client hits the limit. rustls queues close_notify, and every request written after that "succeeds" (Ok(len)) without being sent.
  2. The Kafka broker defers closing when close_notify arrives in the same read as preceding application data (a separate Kafka issue). Because the client sends nothing more, the broker never closes the socket.
  3. rskafka waits for responses that will never come, so every in-flight request hangs until the request timeout instead of failing fast and reconnecting.

If the write returned an error, rskafka would poison the connection right away and retry on a new one.

To Reproduce

The existing rel-0.23 tests show it: in tls12_connection_fails_after_alert_at_confidentiality_limit, the write_all(b"later") after exhaustion returns Ok. #9681 has an end-to-end repro with Kafka 3.9 limited to TLSv1.2 and a lowered confidentiality_limit.

Applicable Version(s)

rustls 0.23.46 (also 0.23.45 and earlier), tokio-rustls 0.26, Linux x86_64.

Expected behavior

Same as main after #3332: the write that cannot be encrypted, and every later write, returns an error. For example, an io::Error wrapping Error::EncryptError, like check_error() already does for other fatal errors.

Questions

  1. Was keeping Ok(..) in 0.23 a deliberate compatibility decision, or would a backport of the error-returning behavior to rel-0.23 be accepted?
  2. If a backport is welcome, which do you prefer: storing the error in core.state (simplest, but it also fails the read side), or a write-only flag so already-received responses stay readable after close_notify?

I'm happy to send a PR against rel-0.23 once the direction is clear.

Note for async users: the fix needs to be an Err, not Ok(0). tokio-rustls's poll_write would spin on Ok(0) when wants_write() is false.

主要语言
Rust
星标
7.7k
派生
947
平均合并
3 天 11 小时
30 天内合并 PR
46

环境准备

  • 没有 Dockerfile 或 Docker Compose 文件
  • 没有 Pull Request 模板
  • 阅读贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

rustls/rustls 的其他 Issue

查看 rustls/rustls 的全部 Issue

相似的 Issue

更多 Rust Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。