源码地图
主线位置:三条主线的地图。握手主线走
client/、server/、tls13/;记录主线走msgs/、record_layer.rs、conn.rs、common_state.rs、vecbuf.rs;校验主线从webpki/出去,进入单独的 rustls-webpki 仓库。本页先用cargo tree看 rustls 依赖谁,再看rustls/src里每个目录管什么、互相怎么引用,最后说明工作区里其他 crate 的用途。
flowchart TB app[应用] --> conn["conn 与 common_state"] conn --> sm["client 与 server 状态机"] conn --> rl["record_layer"] sm --> ks["tls13 密钥日程"] sm --> msgs["msgs 线上格式"] rl --> msgs sm --> ver["webpki 适配层"] ver --> wp["rustls-webpki"] ks --> cr["crypto 接口"] rl --> cr cr --> prov["ring 或 aws-lc-rs"] wp --> prov
依赖图:cargo tree 核实
一个只开 ring、std、tls12(default-features = false)的小程序,cargo tree -e normal 的原样输出:
intro-size-ring v0.1.0 (~/exp-rustls/intro-size-ring)
`-- rustls v0.23.46
|-- once_cell v1.21.4
|-- ring v0.17.14
| |-- cfg-if v1.0.5
| |-- getrandom v0.2.17
| | |-- cfg-if v1.0.5
| | `-- libc v0.2.191
| |-- libc v0.2.191
| `-- untrusted v0.9.0
|-- rustls-pki-types v1.15.1
| `-- zeroize v1.9.1
|-- rustls-webpki v0.103.16
| |-- ring v0.17.14 (*)
| |-- rustls-pki-types v1.15.1 (*)
| `-- untrusted v0.9.0
|-- subtle v2.6.1
`-- zeroize v1.9.1
把 ring 换成 aws_lc_rs,ring 那一支变成 aws-lc-rs v1.19.0 → aws-lc-sys v0.47.0,rustls-webpki 下面也跟着换成 aws-lc-rs。这棵树说明三件事:
- rustls 自己的直接依赖只有六个:两个兄弟 crate(webpki、pki-types),一个密码学后端,加上
subtle(常数时间比较)、zeroize(清零秘密)、once_cell(进程级默认 provider 的存放处)。开logging时再加log。 - rustls-webpki 也依赖同一个密码学后端。 rustls 的 feature
ring写的是["dep:ring", "webpki/ring"]:证书链上的签名由 webpki 用 ring(或 aws-lc-rs)验证,rustls 的 provider 只是把 webpki 提供的算法表交给校验器。 - 没有 tokio,没有
std::net。连接对象不知道套接字是什么,见 sans-IO。
rustls/src 下的目录
按 tag 统计 rustls/src 的 .rs 行数(含文件内的 #[cfg(test)] 单元测试,不含 client/test.rs 这类独立测试文件和 verifybench.rs,这些一共 2898 行),合计 46310 行:
| 目录或文件 | 行数 | 管什么 | 讲它的页 |
|---|---|---|---|
crypto/ | 9461 | CryptoProvider 结构和一组 trait(cipher.rs、hash.rs、hmac.rs、tls13.rs、signer.rs、hpke.rs);两个内置实现 ring/(2967 行)和 aws_lc_rs/(4263 行,多出后量子 pq/ 和 HPKE) | 05 密码学提供者 |
msgs/ | 7919 | 线上格式:codec.rs(Codec、Reader)、handshake.rs(3266 行,所有握手消息和扩展)、deframer/(输入缓冲与去帧)、fragmenter.rs、message/、persist.rs(会话票据里存什么) | 02 记录层 |
client/ | 7619 | 客户端:client_conn.rs(ClientConfig、ClientConnection)、hs.rs(ClientHello 与 ServerHello)、tls13.rs、tls12.rs、ech.rs(1365 行)、handy.rs(会话缓存)、builder.rs | 03 握手 |
server/ | 5228 | 服务端:server_conn.rs(ServerConfig、ServerConnection、Acceptor)、hs.rs(ExpectClientHello)、tls13.rs、tls12.rs、handy.rs、builder.rs | 03 握手 |
webpki/ | 1863 | 和 rustls-webpki 的适配层:RootCertStore、WebPkiServerVerifier、WebPkiClientVerifier、verify.rs | 04 证书校验 |
tls13/ | 1436 | key_schedule.rs(1311 行,KeySchedule* 类型链)、Tls13CipherSuite | 密钥日程 |
conn.rs + conn/ | 1335 + 892 | ConnectionCommon、ConnectionCore、Reader / Writer;conn/unbuffered.rs(不缓冲的接口)、conn/kernel.rs(kTLS) | sans-IO |
common_state.rs | 1136 | CommonState:两个方向的记录层、发送缓冲、wants_read / wants_write、告警 | 发送路径 |
error.rs | 1390 | Error 和它的子枚举(CertificateError、PeerMisbehaved 等) | — |
quic.rs | 1056 | QUIC:只导出密钥和握手消息,不碰记录层 | TLS 1.2 与其他 |
compress.rs | 725 | RFC 8879 证书压缩 | — |
manual/ | 671 | 编进 rustdoc 的设计说明(全是文档注释) | 怎么读这一卷 |
record_layer.rs | 358 | RecordLayer:加解密器、序列号 | 加密与序列号 |
hash_hs.rs | 347 | 握手转录哈希 | 密钥日程 |
vecbuf.rs | 377 | ChunkVecBuffer:发送缓冲和明文接收缓冲 | 发送路径 |
stream.rs | 306 | Stream / StreamOwned | sans-IO |
| 其余 | 约 4200 | lib.rs(718 行,大半是文档)、builder.rs、enums.rs、tls12/、ticketer.rs、verify.rs、suites.rs、key_log*.rs、limited_cache.rs 等 | — |
卷目录里的规模估计和实测有出入:crypto/ 约 9.5k 而不是 8k,两个 provider 也不是各一半(aws-lc-rs 多出后量子和 HPKE);client/ 约 7.6k,server/ 约 5.2k,都比估计大。
lib.rs 顶上有两行全 crate 的约束:#![forbid(unsafe_code, unused_must_use)] 和 #![no_std]。rustls 本身没有一行 unsafe,需要 unsafe 的地方都在密码学后端里;no_std 加上 extern crate alloc,让 std 成为可选 feature,注释说这样「forces one to explicitly import」std 才有的东西,防止不知不觉依赖 std。
模块之间的依赖方向
按 use crate::... 统计,方向大体是单向的:
msgs/是最底层,几乎只引用msgs自己、error、enums。例外是msgs/persist.rs引用了client::ResolvesClientCert。record_layer.rs只引用crypto、msgs、error;conn.rs引用common_state、msgs、record_layer、vecbuf,不引用client或server:连接对象对两侧是泛型的,ConnectionCommon<Data>里的Data是ClientConnectionData或ServerConnectionData。client/和server/在最上面,引用msgs(各 53 处和 34 处)、crypto、conn、common_state、tls13、hash_hs、verify。两者互不引用。crypto/定义 trait,tls13/用它们派生密钥;例外是两个 provider 的ticketer.rs实现server::ProducesTickets,crypto/signer.rs引用两侧的证书解析 trait。webpki/是到 rustls-webpki 的唯一出口。握手状态机只经由verify.rs里的ServerCertVerifier/ClientCertVerifiertrait 调证书校验;直接引用webpki/的只有几处:client/builder.rs建默认的WebPkiServerVerifier,两个 provider 的mod.rs拿WebPkiSupportedAlgorithms(签名算法表),server/handy.rs按 SNI 选证书时检查名字。
工作区里的其他 crate
根目录 Cargo.toml 的 members 有十二个,default-members 只有 examples 和 rustls。除了 rustls 和 rustls-post-quantum(0.2.2),都写了 publish = false:
| 成员 | 行数 | 用途 |
|---|---|---|
rustls | 见上 | 本卷的主体 |
examples | 3079 | 12 个可执行例子:simpleclient、simpleserver(用 Stream)、tlsclient-mio、tlsserver-mio(mio 事件循环)、unbuffered-client / -server / -async-client、server_acceptor、ech-client、limitedclient、0-RTT 的一对 |
rustls-test | 1900 | 测试共用的代码(证书、握手辅助函数) |
bogo | 2447 | 让 BoringSSL 的 BoGo 测试套件驱动 rustls 的适配层 |
openssl-tests | 1064 | 需要 OpenSSL 才能跑的互通测试 |
connect-tests | 407 | 连真实网站的测试 |
ci-bench / rustls-bench | 1905 / 1536 | CI 里的基准测试和本地基准工具 |
provider-example | 1067 | 用 RustCrypto 写的一个最小自定义 provider |
rustls-provider-test | 123 | provider 的集成测试 |
rustls-fuzzing-provider | 652 | 给模糊测试用的 provider |
rustls-post-quantum | 262 | 早期的后量子实验 crate,0.23.x 里 X25519MLKEM768 已并入 aws-lc-rs provider |
fuzz/ 在 exclude 里(要 nightly)。另有 test-ca/(测试用的证书)、website/、audit/、admin/ 目录。
两个兄弟仓库
| crate | 版本 | 规模 | 管什么 | 从哪读起 |
|---|---|---|---|---|
| rustls-webpki | 0.103.16 | src/ 10244 行 | X.509 证书解析与路径校验:verify_cert.rs(1523 行,路径构建与预算)、subject_name/(DNS 名和 IP 地址匹配)、crl/(吊销列表)、der.rs;ring_algs.rs / aws_lc_rs_algs.rs 是两个后端的签名算法表 | EndEntityCert::verify_for_usage,见 路径构建 |
| rustls-pki-types | 1.15.1 | src/ 约 4100 行 | 只有类型,不做密码学:CertificateDer、PrivateKeyDer、ServerName(server_name.rs)、UnixTime、PEM 解析(pem.rs)、算法标识(alg_id.rs) | lib.rs;rustls::pki_types 原样转导出它 |
卷目录估计 webpki「约 9k」,按 tag 实数是 10244 行(含 648 行的 alg_tests.rs)。
小结
- rustls 的直接依赖只有 webpki、pki-types、一个密码学后端和
subtle/zeroize/once_cell;webpki 用同一个后端验签名。 rustls/src合计 46310 行:crypto/、msgs/、client/、server/四大块占四分之三。- 依赖方向:
msgs在底,record_layer/conn/common_state居中,client/server在顶且互不引用;证书校验只从webpki/出去。 - 全 crate
forbid(unsafe_code)并且是no_std加alloc,std是 feature。 - 工作区十二个成员,只有
rustls和rustls-post-quantum发布;examples/的simpleclient和tlsclient-mio是读接口用法的起点。