- 作者:anhkgg
- 日期:2017-11-16
rustls已经支持tls1.3,但是测试分析中使用的tls1.2,所以后面分析主要集中在tls1.2。
主要分析的源码内容:
- client和server的握手协议流程
- rustls是如何进行数据传输的
- 数据传输是如何加密解密的
源码结构
分为client和server两部分
公共接口
session.rs定义了SessionCommon,包括了数据传输、数据加密、包处理相关接口。
主要字段
1 | pub struct SessionCommon { |
主要接口
函数名 | 说明 |
---|---|
read_tls |
接收底层连接数据 |
write_tls |
通过底层连接发送数据 |
process_new_packets |
每次调用read_tls之后都需要调用该函数主动触发消息处理 |
wants_read/wants_write |
是否有数据需要接收发送 |
encrypt_outgoing |
加密要发送的数据,在握手完成之后需要 |
decrypt_incoming |
解密要接收的数据,在握手完成之后需要 |
send_msg_encrypt |
发送加密数据 |
send_appdata_encrypt |
发送握手之后的数据,加密 |
send_some_plaintext |
发送明文数据,握手之后会被加密发送 |
start_traffic |
握手完成之后调用,设置传输标志,发送缓存的数据明文 |
send_msg |
发送TLS消息,根据是否加密走不通发送方式 |
take_received_plaintext |
握手完成之后,收到数据会被调用,参数已经是明文Message |
set_message_encrypter |
设置消息加密接口,start_encryption_tls12 中调用 |
set_message_decrypter |
设置消息解密接口,start_encryption_tls12 中调用 |
start_encryption_tls12 |
TLS1.2设置加解密接口,在ExpectTLS12ServerDone::handle/ExpectTLS12ClientKX::handle调用 |
ciper.rs定义了加密解密的接口。
MessageEncrypter
,MessageDecrypter
,具体使用加解密方法在握手过程中ExpectTLS12ServerDone::handle/ExpectTLS12ClientKX::handle设置。
1 | //client端 |
client详解
1 | src/client/mod.rs 导出ClientSession接口,外部使用 |
ClientSession
内部由ClientSessionImpl
实现。
1 | pub struct ClientSessionImpl { |
握手,准备第一个数据包。
ClientSessionImpl::new
内部就会准备握手要发送的第一个数据包。
1 | cs.state = Some(hs::start_handshake(&mut cs, hostname)); |
然后,收到返回数据之后,会在ClientSessionImpl::process_main_protocol
调用state.handle
来处理收到的数据,然后返回新的state,用于下次处理,如此循环,知道握手完成。
1 | fn process_main_protocol(&mut self, msg: Message) -> Result<(), TLSError> { |
消息处理调用流程如下:
1 | //ClientSessionImpl |
下面直接列出client端握手处理流程:
1 | ExpectServerHelloOrHelloRetryRequest:handle |
在ExpectTLS12Finished::handle
中,会保存session
,开始传输数据,以及返回下次的state
,此时握手协议已经完成。
1 | save_session(&mut st.handshake, |
后面数据传输的所有流程都会进入ExpectTLS12Traffic::handle
,也就是开始传输协议。
1 | impl State for ExpectTLS12Traffic { |
传输数据的处理。
接收数据
调用take_received_plaintext
将获取到的明文Message传给内部处理,存入SessionCommon
的received_plaintext
,等待用户的提取。
那明文Message是怎么来的呢?是在前面说到的消息处理流程中,到handle之前。
1 | process_new_packets->process_msg->process_main_protocol->state.handle |
在process_msg
中会判断peer_encrypting
状态为真则将数据解密,而该状态是在握手中ExpectTLS12CCS::handle
被设置为true的。
1 | pub fn process_msg(&mut self, mut msg: Message) -> Result<(), TLSError> { |
发送数据
握手过程中,发送数据包使用sess.common.send_msg(ch, false)
。send_msg
内部根据是否加密状态(must_encrypt
)进行不同处理,直接缓存或者调用send_msg_encrypt
加密之后缓存。
1 | send_msg_encrypt->send_single_fragment->encrypt_outgoing(加密) |
最后都是通过queue_tls_message
将数据先缓存,然后在调用write_tls
之后将数据发送。
1 | pub fn write_tls(&mut self, wr: &mut Write) -> io::Result<usize> { |
握手完成后,通过ClientSession
实现的io::write
(或者write_all
)接口发送明文数据。
1 | impl io::Write for ClientSession { |
send_some_plaintext
在根据是否握手完成有不同的操作,握手未完成时,先缓存明文到sendable_plaintext
,握手完成后,直接调用send_appdata_encrypt
缓存密文(进入send_single_fragment
过程加密)。
1 | pub fn send_some_plaintext(&mut self, data: &[u8]) -> io::Result<usize> { |
握手完成时,之前缓存的明文数据通过start_traffic
实际将数据加密缓存到sendable_tls,最后也是通过write_tls发送出去。
1 | pub fn start_traffic(&mut self) { |
握手完成之后调用的send_some_plaintext
是直接将数据加密缓存,在write_tls后发送出去。
server详解
1 | src/server/mod.rs 导出ServerSession接口,外部使用 |
公开外部使用的借口ServerSession,内部由ServerSessionImpl实现。
1 | pub struct ServerSessionImpl { |
接口基本和ClientSession类似,不再详述
握手流程
server和client处理握手的方式都一样,每个握手包处理对象都会实现State接口。
1 | pub trait State { |
然后在收到client消息之后,在process_main_protocol
中调用对应握手包对象的handle函数,并且会返回握手期望处理的下次数据包对象给state,以便下次收到消息继续处理。
1 | //process_main_protocol |
握手流程:
1 | -----ExpectClientHello::handle |
消息传输
同样,握手完成后,server在ExpectTLS12Traffic::handle
中处理后续的传输协议中的消息。
1 | impl State for ExpectTLS12Traffic { |
数据加密和解密流程基本和client类似,不再详述。
另外,client和server握手中需要发送的数据包构造都在hs.rs::emit_xxx函数中
消息相关
该部分存在单独的msgs目录下,包含了握手过程中各种消息类型的定义,消息传输具体设计的fragment/deframe
等。
所有消息统一的结构Message
,Message
也定义了一下方便获取字段和数据的借口,这里不再详述。
1 | pub struct Message { |
1 | //msgs/message.rs |
其他
文件 | 说明 |
---|---|
key.rs | 密钥、证书结构定义 |
pemfile.rs | PEM文件解析生成密钥相关接口 |
verify.rs | 证书验证相关 |
suites.rs | 加密套件、密钥交换相关 |
sign.rs | 签名相关 |
vecbuf.rs | 所有消息数据最底层存储结构,vec构成 |
webpki | 三方库,完成证书验证 |
ring | 三方库,完成加密算法相关能力 |
下篇在根据示例代码分析一下rustls库具体的使用
转载请注明出处:https://anhkgg.github.io/rustls-source-code-analyze/