18 个版本 (10 个重大更改)

0.11.0 2021 年 9 月 20 日
0.10.0 2021 年 1 月 13 日
0.9.4 2021 年 1 月 11 日
0.9.3 2020 年 6 月 8 日
0.3.0 2016 年 11 月 29 日

#221 in 网络编程

Download history • Rust 包仓库 3713/week @ 2024-03-14 • Rust 包仓库 3604/week @ 2024-03-21 • Rust 包仓库 3353/week @ 2024-03-28 • Rust 包仓库 3259/week @ 2024-04-04 • Rust 包仓库 5651/week @ 2024-04-11 • Rust 包仓库 5299/week @ 2024-04-18 • Rust 包仓库 6452/week @ 2024-04-25 • Rust 包仓库 3651/week @ 2024-05-02 • Rust 包仓库 3976/week @ 2024-05-09 • Rust 包仓库 4749/week @ 2024-05-16 • Rust 包仓库 4779/week @ 2024-05-23 • Rust 包仓库 6038/week @ 2024-05-30 • Rust 包仓库 4410/week @ 2024-06-06 • Rust 包仓库 3884/week @ 2024-06-13 • Rust 包仓库 4465/week @ 2024-06-20 • Rust 包仓库 4363/week @ 2024-06-27 • Rust 包仓库

18,162 每月下载量
12 crates 中使用

MIT/Apache

145KB
3K SLoC

tls-parser

License: MIT Apache License 2.0 Crates.io Version Github CI Minimum rustc version

TLS 解析器

使用 nom 解析器组合框架实现的 TLS 解析器。

该解析器的目的是实现 TLS 消息分析,例如使用来自网络 IDS 的规则,例如在 TLS 握手过程中。

它实现了记录和消息的结构和解析函数,但需要额外的代码来处理分片,或完全检查消息。解析某些 TLS 消息需要知道之前选择的参数。请参阅 rusticata TLS 解析器 以获取完整示例。

它是用纯 Rust 编写的,速度快,并且大量使用零拷贝。对安全性、安全性和该 crate 的设计(递归限制、防御性编程)、测试和模糊测试进行了大量关注。它还旨在无 panic。

代码可在 Github 上找到,并属于 Rusticata 项目。

解析记录

主要解析函数位于 tls.rs 文件中。入口函数是

  • parse_tls_plaintext:解析为纯文本的记录
  • parse_tls_encrypted:读取加密记录。解析器没有加密或解密功能,因此内容将保留为不可见数据。

示例

use tls_parser::parse_tls_plaintext;
use tls_parser::nom::{Err, IResult};

let bytes : &[u8]= include_bytes!("../assets/client_hello_dhe.bin");
// [ 0x16, 0x03, 0x01 ... ];
let res = parse_tls_plaintext(&bytes);
match res {
    Ok((rem,record)) => {
        // rem is the remaining data (not parsed)
        // record is an object of type TlsRecord
    },
    Err(Err::Incomplete(needed)) => {
        eprintln!("Defragmentation required (TLS record)");
    },
    Err(e) => { eprintln!("parse_tls_record_with_header failed: {:?}",e); }
}

请注意,确定记录是否为纯文本是调用者的责任。

由于读取 TLS 记录可能涉及记录的分片,因此提供了一些函数,只读取记录作为不可见数据(确保记录完整并给出记录头),然后从数据中读取消息。

以下是两步解析的示例


// [ 0x16, 0x03, 0x01 ... ];
match parse_tls_raw_record(bytes) {
    Ok((rem, ref r)) => {
        match parse_tls_record_with_header(r.data, &r.hdr) {
            Ok((rem2,ref msg_list)) => {
                for msg in msg_list {
                    // msg has type TlsMessage
                }
            }
            Err(Err::Incomplete(needed)) => { eprintln!("incomplete record") }
            Err(_) => { eprintln!("error while parsing record") }
        }
    }
    Err(Err::Incomplete(needed)) => { eprintln!("incomplete record header") }
    Err(_) => { eprintln!("error while parsing record header") }
}

如果从网络读取数据包,则需要进行一些额外的工作,以支持 TCP 段的重新组合和 TLS 记录的重新组合。

有关支持解碎片化和状态的TLS解析器的完整示例,请参阅rusticata/src/tls.rs文件,该文件位于rusticata软件包中。

状态机

tls_states.rs中提供了TLS状态机。状态机与解析函数分离,几乎是独立的。它作为转换表的实现,主要用于握手阶段。

使用前面的函数读取TLS消息后,可以使用tls_state_transition函数更新TLS状态。如果转换成功,它返回Ok(new_state),否则返回Err(error_state)


struct ParseContext {
    state: TlsState,
}

match tls_state_transition(ctx.state, msg, to_server) {
    Ok(s)  => { ctx.state = s; Ok(()) }
    Err(_) => {
        ctx.state = TlsState::Invalid;
        Err("Invalid state")
    }
}

实现说明

在解析消息时,如果一个字段是一个对应于已知值的枚举整数值,则不会将其解析为枚举类型,而是作为整数解析。虽然这会使访问复杂化,但它允许读取无效值并继续解析(对于IDS,读取值比获得通用解析错误更好)。

更改

0.11.0

  • 升级到nom 7
  • 添加ClientHello特质以支持常见的CH属性
  • 获取DTLS ClientHello中的扩展
  • 添加示例/辅助程序以列出/查询密码套件信息
  • 添加伪条目TLS_EMPTY_RENEGOTIATION_INFO_SCSVTLS_FALLBACK_SCSV (#16)
  • 更新密码套件文件
  • 添加了对SignedCertificateTimestamp列表的解析
  • 重新导出nom
  • 添加对no_std的支持

感谢:@JackLiar,@xonatius

0.10.0

  • 升级到nom 6
  • 移除所有基于宏的解析器(尽可能使用函数和nom-derive)
  • 添加对DTLS(握手)的支持
  • 添加解析客户端/服务器问候语中期望的扩展的函数

0.9.4

  • 在服务器问候语中,可以发送空SNI扩展(RFC 6066)

0.9.3

  • 修复状态机中的错误(错误的客户端证书方向)

0.9.2

  • 升级到phf 0.8
  • 升级cookie-factory到0.3.0

0.9.1

  • 将cookie-factory标记为可选(仅用于序列化)

0.9.0

  • 升级到nom 5
  • Rustfmt

0.8.1

  • 设置版本为2018
  • 检查心跳消息长度(减法可能下溢)
  • 添加更多记录长度的检查(RFC合规性,不用于解析器安全性)

0.8.0

  • 添加对记录大小限制扩展的支持
  • 添加对加密服务器名称(eSNI)扩展的支持
  • 状态机:使用方向并支持TLS 1.3 0-RTT
  • 状态机:添加新状态以指示连接已关闭(在致命警报之后)
  • 使用TlsVersion类型用于SSL记录版本
  • 更新文档,并使用cargo sync-readme

0.7.1

  • 改进状态机,处理恢复失败和非致命警报
  • 改进签名/散列算法的处理和显示
  • 更新密码套件到2019-03-19

0.7.0

  • 将大多数枚举转换为新类型
    • 警告:这是一个破坏性更改
  • 更新依赖关系并删除未使用的软件包
  • 更新密码套件到2019-01-23

0.6.0

  • 升级到nom 4.0
    • 警告:这是一个破坏性更改
  • 修复填充和签名时间戳错误的扩展ID
  • 重写parse_cipher_suites和parse_compressions_algs以使其更快
  • 更新密码套件到2018-08-13

标准

以下是非详尽列表,列出了此解析器基于的RFC

  • RFC 2246:TLS协议版本1.0
  • RFC 4346:传输层安全性(TLS)协议版本1.1
  • RFC 4366:传输层安全性(TLS)扩展
  • RFC 4492:传输层安全性(TLS)中的椭圆曲线密码套件
  • RFC 4507:无需服务器端状态的传输层安全性(TLS)会话恢复
  • RFC 5077:无需服务器端状态的传输层安全性(TLS)会话恢复
  • RFC 5246:传输层安全性(TLS)协议版本 1.2
  • RFC 5430:传输层安全性(TLS)套件B配置文件
  • RFC 5746:传输层安全性(TLS)重协商指示扩展
  • RFC 6066:传输层安全性(TLS)扩展:扩展定义
  • RFC 6520:传输层安全性(TLS)和数据报传输层安全性(DTLS)心跳扩展
  • RFC 6961:传输层安全性(TLS)多个证书状态请求扩展
  • RFC 7027:传输层安全性(TLS)的椭圆曲线密码学(ECC)Brainpool曲线
  • RFC 7301:传输层安全性(TLS)应用层协议协商扩展
  • RFC 7366:传输层安全性(TLS)和数据报传输层安全性(DTLS)的加密后-MAC
  • RFC 7627:传输层安全性(TLS)会话哈希和扩展主密钥扩展
  • RFC 7919:传输层安全性(TLS)协商的有限域Diffie-Hellman临时参数
  • RFC 8422:传输层安全性(TLS)版本 1.2及更早版本的椭圆曲线密码学(ECC)加密套件
  • RFC 8446:传输层安全性(TLS)协议版本 1.3
  • draft-agl-tls-nextprotoneg-03:传输层安全性(TLS)下一个协议协商扩展

常见问题及限制

如果提供主密钥,解析器能否解密TLS会话?

不,尚未实现

解析器支持TLS压缩吗?

不支持。注意,大多数TLS实现都在FREAK攻击之后禁用了它,所以虽然tls-parser中检测到ServerHello中的压缩是可能的,但可能应该将其解释为警报。

TLS加密套件在哪里?

它们在运行cargo build时构建。

为了简化从IANA TLS参数更新列表,提供了一个脚本(scripts/extract-iana-ciphers.py)。此脚本将从IANA下载并预解析列表,并生成包含所有加密套件名称和参数的文件。

在构建过程中,build.rs将解析此文件并生成包含所有已知加密和它们的属性的静态、只读哈希表。

许可证

根据您的选择,许可如下

贡献

除非您明确表示,否则任何有意提交以包含在您的工作中的贡献,如Apache-2.0许可证中定义的,应按上述方式双重许可,不附加任何额外条款或条件。

依赖关系

~3MB
~63K SLoC