上一篇简述TLCP抓包的情况,很多在细节在抓包的层面并没有很好的体现出来。所以本文将简述通过对gmssl的tlcp部分代码进行分析,以及结合《GB∕T 38636-2020 信息安全技术 传输层密码协议(TLCP)》这个国家标准,对TLCP一些遗漏的细节进行补充,特别是双证书机制的部分。
sequenceDiagram
client->>server: 1、Client Hello
server->>client: 2、Server Hello
server->>client: 3、Certificate
server->>client: 4、Server Key Exchange
server->>client: 5、Server Hello Done
client->>server: 6、Client Key Exchange
client->>server: 7、Change Cipher Spec, Encrypted Handshake Message
server->>client: 8、Change Cipher Spec
server->>client: 9、Encrypted Handshake Message
gmssl tlcp_server -port 4433 -cert double_certs.pem -key signkey.pem -pass 1234 -ex_key enckey.pem -ex_pass 1234
gmssl tlcp_client -host 127.0.0.1 -port 4433
tlcp server的启动
tlcp上下文的初始化,将传入的证书整合进TCLP_CTX这个struct中
typedef struct {
int protocol;
int is_client;
int cipher_suites[TLS_MAX_CIPHER_SUITES_COUNT];
size_t cipher_suites_cnt;
uint8_t *cacerts;
size_t cacertslen;
uint8_t *certs;
size_t certslen;
SM2_KEY signkey;
SM2_KEY kenckey;
int verify_depth;
} TLS_CTX;
......
if (tls_ctx_init(&ctx, TLS_protocol_tlcp, TLS_server_mode) != 1
|| tls_ctx_set_cipher_suites(&ctx, server_ciphers, sizeof(server_ciphers)/sizeof(int)) != 1
|| tls_ctx_set_tlcp_server_certificate_and_keys(&ctx, certfile, signkeyfile, signpass, enckeyfile, encpass) != 1) {
error_print();
return -1;
}
这里详细看一下TLS_CTX这个结构体
- int protocol
这里协议就是指Record Layer的Version字段为(0x0101)
- int cipher_suites[TLS_MAX_CIPHER_SUITES_COUNT];size_t cipher_suites_cnt;
支持的套件列表,后续进行加密套件协商的时候需要用到
- uint8_t *cacerts;size_t cacertslen;int verify_depth;
CA证书,启用双向认证后用来对客户端的证书进行校验
- uint8_t *certs;size_t certslen;
从double_certs.pem中读取到的证书。
- SM2_KEY signkey;
从signkey.pem结合密码获取sm2私钥,用来对通信端的身份进行验证。
- SM2_KEY kenckey;
从enckey.pem结合密码获取sm2私钥,该私钥为tlcp协议独有,用于密钥交换。
tlcp_server建立tcp连接后
接收到客户端的tcp请求后,将accept后的socket与tlcp关联,这里就主要考虑到TLS_CONNECT这个struct。
typedef struct {
int protocol;
int is_client;
int cipher_suites[TLS_MAX_CIPHER_SUITES_COUNT];
size_t cipher_suites_cnt;
int sock;
uint8_t enced_record[TLS_MAX_RECORD_SIZE];
size_t enced_record_len;
uint8_t record[TLS_MAX_RECORD_SIZE];
uint8_t databuf[TLS_MAX_PLAINTEXT_SIZE];
uint8_t *data;
size_t datalen;
int cipher_suite;
uint8_t session_id[32];
size_t session_id_len;
uint8_t server_certs[TLS_MAX_CERTIFICATES_SIZE];
size_t server_certs_len;
uint8_t client_certs[TLS_MAX_CERTIFICATES_SIZE];
size_t client_certs_len;
uint8_t ca_certs[2048];
size_t ca_certs_len;
SM2_KEY sign_key;
SM2_KEY kenc_key;
int verify_result;
uint8_t master_secret[48];
uint8_t key_block[96];
SM3_HMAC_CTX client_write_mac_ctx;
SM3_HMAC_CTX server_write_mac_ctx;
SM4_KEY client_write_enc_key;
SM4_KEY server_write_enc_key;
uint8_t client_seq_num[8];
uint8_t server_seq_num[8];
uint8_t client_write_iv[12]; // tls13
uint8_t server_write_iv[12]; // tls13
BLOCK_CIPHER_KEY client_write_key;
BLOCK_CIPHER_KEY server_write_key;
} TLS_CONNECT;、
......
if (tls_init(&conn, &ctx) != 1
|| tls_set_socket(&conn, conn_sock) != 1) {
error_print();
return -1;
}
if (tls_do_handshake(&conn) != 1) {
error_print();
return -1;
}
conn整合ctx的成员。接下来就是重点tlcp的握手部分,主要在int tlcp_do_accept(TLS_CONNECT *conn)和int tlcp_do_connect(TLS_CONNECT *conn)这两个函数。
TLCP握手分析
记录层定义
记录层接受从高层来的任意来的任意大小的非空连续数据,将数据分段、压缩、计算校验码、加密,然后传输。接收到的数据经过解密、验证、解压缩、重新封装然后传送给高层应用。
GB/T 38636-2020(接下来简称GB)中规定记录层结构:
struct {
Content Type;
ProtocoVersion version;
uint16 length;
opaque fragment[TLSPlainttext,length];
} TLSPlaintext;
Type是片段的记录层协议类型,定义为
enum {
change_cipher_spec(20),
alert(21),
handshake(22),
application_data(23),(255)
}
Version所用协议的版本号。这里的版本号为1.1,定义为
struct{
uint8 major=0x01,
uint8 minor=0x01;
} ProtocolVersion;
length以字节为单位的片段长度,小于或等于2^14
fragment是将传输的数据,记录层协议版不关心具体数据内容。
握手协议定义
GB中对于握手协议的结构定义 握手协议是在记录协议之上的协议,用于协商安全参数。握手协议的消息通过记录层协议传输。 握手消息结构定义:
struct {
HandshakeType msg_type;
uint24 length;
select (msg_type){
case client_hello: ClientHello;
case server_hello: ServerHello;
case certifivate: Certificate;
case server_key_exchange: ServerKeyExchange;
case certificate_request: CertificateRequest;
case server_hello_done: ServerHelloDone;
case certificate_verify: CertificateVerify;
case client_key_exchange: ClientKeyExchange;
case finished: Finished;
} body;
}Handshake;
握手消息类型定义如下:
enum{
client_hello(1),
server_hello(2),
certificate(11),
server_key_exchange(12),
certificate_request(13),
server_hello_done(14),
certificate_verify(15),
client_key_exchange(16)
}
- client:send Client Hello
GB规定的Client Hello消息
struct {
Protocol Version client_version ;
Randomrandom;
SessionID session_id ;
CipherSuite cipher_suites 〈 2..2^16-1 〉;
CompressionMethod compression_methods 〈 1..2^8-1 〉;
} ClientHello ;
tls_random_generate(client_random);
if (tls_record_set_handshake_client_hello(record, &recordlen,
TLS_protocol_tlcp, client_random, NULL, 0,
tlcp_ciphers, tlcp_ciphers_count, NULL, 0) != 1) {
error_print();
goto end;
}
if (tls_record_send(record, recordlen, conn->sock) != 1) {
error_print();
goto end;
}
生成随机数后通过tls_record_set_handshake_client_hello函数组成握手信息,将client_hello 信息封装成记录层。封装完成后,将携带client_hello的握手消息的记录层发送给服务端。
对比抓包情况一致。
- server: receive Client Hello;send Server Hello;
接收client hello进行处理
// 接收记录层消息
if (tls_record_recv(record, &recordlen, conn->sock) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_unexpected_message);
goto end;
}
// 校验记录层协议
if (tls_record_protocol(record) != TLS_protocol_tlcp) {
error_print();
tls_send_alert(conn, TLS_alert_protocol_version);
goto end;
}
// 从记录层解码出Client Hello握手消息
if (tls_record_get_handshake_client_hello(record,
&protocol, &random, &session_id, &session_id_len,
&client_ciphers, &client_ciphers_len,
&exts, &exts_len) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_unexpected_message);
goto end;
}
//校验握手协议TLCP版本
if (protocol != TLS_protocol_tlcp) {
error_print();
tls_send_alert(conn, TLS_alert_protocol_version);
goto end;
}
memcpy(client_random, random, 32);
// 协商密码套件
if (tls_cipher_suites_select(client_ciphers, client_ciphers_len,
server_ciphers, sizeof(server_ciphers)/sizeof(server_ciphers[0]),
&conn->cipher_suite) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_insufficient_security);
goto end;
}
主要逻辑在于消息解码(tls_record_get_handshake_client_hello函数)和套件协商(tls_cipher_suites_select)
发送Server Hello
GB规定的Server Hello消息应当协商出密码套件,服务端发送这个消息作为客户端hello消息的回复。
struct {
ProtocolVersionserver _ version ;
Randomrandom;
SessionID session_id ;
CipherSuite cipher_suite ;
CompressionMethod compression_method ;
} ServerHello ;
代码实现
tls_random_generate(server_random);
if (tls_record_set_handshake_server_hello(record, &recordlen,
TLS_protocol_tlcp, server_random, NULL, 0,
conn->cipher_suite, NULL, 0) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_internal_error);
goto end;
}
if (tls_record_send(record, recordlen, conn->sock) != 1) {
error_print();
goto end;
}
生成随机数,将随机数和协商出的密码套件封装成握手消息,放在记录层发送给客户端。
3.client: receive Client Hello
if (tls_record_recv(record, &recordlen, conn->sock) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_unexpected_message);
goto end;
}
if (tls_record_get_handshake_server_hello(record,
&protocol, &random, &session_id, &session_id_len, &cipher_suite,
&exts, &exts_len) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_unexpected_message);
goto end;
}
if (tls_cipher_suite_in_list(cipher_suite, tlcp_ciphers, tlcp_ciphers_count) != 1) {
tls_send_alert(conn, TLS_alert_handshake_failure);
error_print();
goto end;
}
conn->cipher_suite = cipher_suite;
解码消息,获取服务端的随机数以及加密套件。
- server:Certificate
服务端证书消息
服务端应发送一个服务端证书消息给客户端,该消息总是紧跟在服务端hello消息之后。当选中的密码套件使用RSA或ECC或ECDHE算法时,本消息的内容为服务端签名证书和加密证书;当选中的密码套件使用IBC或IBSDH算法时,本消息的内容为服务端标识和IBC公共参数,用于客户端与服务端协商IBC公开参数。
证书消息结构
opaqueASN.1Cert 〈 1..2^24-1 〉;
struct {
ASN.1Certcertificate 〈 0..2^24-1 〉;
}Certificate;
其中签名证书在前,加密证书在后。
代码实现
if (tls_record_set_handshake_certificate(record, &recordlen,
conn->server_certs, conn->server_certs_len) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_internal_error);
goto end;
}
if (tls_record_send(record, recordlen, conn->sock) != 1) {
error_print();
goto end;
}
int tls_record_set_handshake_certificate(uint8_t *record, size_t *recordlen,const uint8_t *certs, size_t certslen){
......
while (certslen) {
const uint8_t *cert;
size_t certlen;
if (x509_cert_from_der(&cert, &certlen, &certs, &certslen) != 1) {
error_print();
return -1;
}
tls_uint24array_to_bytes(cert, certlen, NULL, &datalen);
if (datalen > TLS_MAX_HANDSHAKE_DATA_SIZE) {
error_print();
return -1;
}
tls_uint24array_to_bytes(cert, certlen, &p, &len);
}
......
}
从certs中抽取所有证书放入记录层,所以从抓包来看有三张证书
- client: receive Certificate
if (tls_record_recv(record, &recordlen, conn->sock) != 1
|| tls_record_protocol(record) != TLS_protocol_tlcp) {
error_print();
tls_send_alert(conn, TLS_alert_unexpected_message);
goto end;
}
if (tls_record_get_handshake_certificate(record,
conn->server_certs, &conn->server_certs_len) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_unexpected_message);
goto end;
}
tls_record_get_handshake_certificate函数直接解析了证书链。
- server: Server Key Exchange
服务端密钥交换消息。本消息传送的信息用于客户端计算产生48字节的预主密钥。
服务端密钥交换消息的结构
enum { ECDHE , ECC , IBSDH, IBC , RSA } KeyExchangeAlgorithm;
struct {
select( KeyExchangeAlgorithm ){
......
case ECC :
digitally-signed struct {
opaqueclient_random [ 32 ];
opaqueserver_random[ 32 ];
opaqueASN.1Cert 〈 1..2^24-1 〉;
} signed_params
......
}
这里使用的是ECC,我们就只看ECC部分。当密钥交换方式为ECC和RSA时,signed_params是服务端对双方随机数和服务端加密证书的签名。
代码实现
if (x509_certs_get_cert_by_index(conn->server_certs, conn->server_certs_len, 1,
&server_enc_cert, &server_enc_cert_len) != 1) {
error_print();
goto end;
}
p = server_enc_cert_lenbuf; len = 0;
tls_uint24_to_bytes(server_enc_cert_len, &p, &len);
if (sm2_sign_init(&sign_ctx, &conn->sign_key, SM2_DEFAULT_ID, SM2_DEFAULT_ID_LENGTH) != 1
|| sm2_sign_update(&sign_ctx, client_random, 32) != 1
|| sm2_sign_update(&sign_ctx, server_random, 32) != 1
|| sm2_sign_update(&sign_ctx, server_enc_cert_lenbuf, 3) != 1
|| sm2_sign_update(&sign_ctx, server_enc_cert, server_enc_cert_len) != 1
|| sm2_sign_finish(&sign_ctx, sigbuf, &siglen) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_internal_error);
goto end;
}
if (tlcp_record_set_handshake_server_key_exchange_pke(record, &recordlen, sigbuf, siglen) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_internal_error);
goto end;
}
tlcp_record_trace(stderr, record, recordlen, 0, 0);
if (tls_record_send(record, recordlen, conn->sock) != 1) {
error_print();
goto end;
}
通过sm2_sign_update将client_random,server_random,server_enc_cert_lenbuf,server_enc_cert等做sm3处理,将最后得出的密钥使用sign_cert中的私钥进行sm2进行加密。将加密后的预主密钥发送到客户端。
- client: receive Server Key Exchange
// 接收加密后预主密钥
if (tlcp_record_get_handshake_server_key_exchange_pke(record, &sig, &siglen) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_unexpected_message);
goto end;
}
//获取公钥
if (x509_certs_get_cert_by_index(conn->server_certs, conn->server_certs_len, 0, &cp, &len) != 1
|| x509_cert_get_subject_public_key(cp, len, &server_sign_key) != 1
|| x509_certs_get_cert_by_index(conn->server_certs, conn->server_certs_len, 1, &server_enc_cert, &server_enc_cert_len) != 1
|| x509_cert_get_subject_public_key(server_enc_cert, server_enc_cert_len, &server_enc_key) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_bad_certificate);
goto end;
}
p = server_enc_cert_lenbuf; len = 0;
tls_uint24_to_bytes(server_enc_cert_len, &p, &len);
// 校验预主密钥
if (sm2_verify_init(&verify_ctx, &server_sign_key, SM2_DEFAULT_ID, SM2_DEFAULT_ID_LENGTH) != 1
|| sm2_verify_update(&verify_ctx, client_random, 32) != 1
|| sm2_verify_update(&verify_ctx, server_random, 32) != 1
|| sm2_verify_update(&verify_ctx, server_enc_cert_lenbuf, 3) != 1
|| sm2_verify_update(&verify_ctx, server_enc_cert, server_enc_cert_len) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_internal_error);
goto end;
}
if (sm2_verify_finish(&verify_ctx, sig, siglen) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_decrypt_error);
goto end;
}
从之前下发的证书链中解析出身份验证证书中,并获取解密公钥;也解析出sign证书,并获取公钥。 和服务端一样将四个参数进行sm3处理。将接收加密的预主密钥进行解密,并与sm3获取的值进行对比。本质上就是一个验签过程。
- server: Server Hello Done
表示握手过程的hello消息阶段完成。发送完该消息后服务端会等待客户端的响应消息。
- client: receive Server Hello Done;Client Key Exchange;
客户端接收到服务端的服务端的hello完成消息之后,主要就是校验服务端的hello消息参数是否可以接受。正常将继续接下来的握手协议,Client Key Exchange步骤。
如果密钥算法使用RSA算法、ECC算法和IBC算法,本消息中包含预主密钥,该预主密钥由客户端产生,采用服务端的加密公钥进行加密。
客户端密钥交换消息结构定义如下:
struct {
select( KeyExchangeAlgorithm ){
......
caseECC :
opaqueECCEncryptedPreMasterSecret 〈 0..2^16-1 〉;
......
}
}
预主密钥的数据结构
struct {
ProtocolVersion client_version ;
opaque random[ 46 ];
} PreMasterSecret ;
代码实现
//生成主密钥
if (tls_pre_master_secret_generate(pre_master_secret, TLS_protocol_tlcp) != 1
|| tls_prf(pre_master_secret, 48, "master secret",
client_random, 32, server_random, 32,
48, conn->master_secret) != 1
|| tls_prf(conn->master_secret, 48, "key expansion",
server_random, 32, client_random, 32,
96, conn->key_block) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_internal_error);
goto end;
}
sm3_hmac_init(&conn->client_write_mac_ctx, conn->key_block, 32);
sm3_hmac_init(&conn->server_write_mac_ctx, conn->key_block + 32, 32);
sm4_set_encrypt_key(&conn->client_write_enc_key, conn->key_block + 64);
sm4_set_decrypt_key(&conn->server_write_enc_key, conn->key_block + 80);
if (sm2_encrypt(&server_enc_key, pre_master_secret, 48,
enced_pre_master_secret, &enced_pre_master_secret_len) != 1
|| tls_record_set_handshake_client_key_exchange_pke(record, &recordlen,
enced_pre_master_secret, enced_pre_master_secret_len) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_internal_error);
goto end;
}
if (tls_record_send(record, recordlen, conn->sock) != 1) {
error_print();
goto end;
}
通过随机生成随机生成的pre_master_secret,将server_random和client_random作为随机种子去生成主密钥。将预主密钥用密钥交换算法的公钥加密发送给服务端。这里就是与普通TLS最大的不同,会有另外一个公钥将客户端的预主密钥进行加密。
- server: receive Client Key Exchange
if (tls_record_get_handshake_client_key_exchange_pke(record, &enced_pms, &enced_pms_len) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_unexpected_message);
goto end;
}
if (sm2_decrypt(&conn->kenc_key, enced_pms, enced_pms_len,
pre_master_secret, &pre_master_secret_len) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_decrypt_error);
goto end;
}
if (pre_master_secret_len != 48) {
error_print();
tls_send_alert(conn, TLS_alert_decrypt_error);
goto end;
}
读取被客户端加密后的预主密钥,并进行解密获取。
- client: Change Cipher Spec, Encrypted Handshake Message
// Change Cipher Spec
if (tls_record_set_change_cipher_spec(record, &recordlen) !=1) {
error_print();
tls_send_alert(conn, TLS_alert_internal_error);
goto end;
}
if (tls_record_send(record, recordlen, conn->sock) != 1) {
error_print();
goto end;
}
//
if (tls_prf(conn->master_secret, 48, "client finished",sm3_hash, 32, NULL, 0, sizeof(local_verify_data), local_verify_data) != 1
|| tls_record_set_handshake_finished(finished_record, &finished_record_len,
local_verify_data, sizeof(local_verify_data)) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_internal_error);
goto end;
}
if (tls_record_encrypt(&conn->client_write_mac_ctx, &conn->client_write_enc_key,
conn->client_seq_num, finished_record, finished_record_len, record, &recordlen) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_internal_error);
goto end;
}
tls_seq_num_incr(conn->client_seq_num);
if (tls_record_send(record, recordlen, conn->sock) != 1) {
error_print();
goto end;
}
发送Change Cipher Spec,并发送一个加密后的消息,加密消息为client finished。
- server: receive Change Cipher Spec, Encrypted Handshake Message;Change Cipher Spec
if (tls_prf(pre_master_secret, 48, "master secret",
client_random, 32, server_random, 32,
48, conn->master_secret) != 1
|| tls_prf(conn->master_secret, 48, "key expansion",
server_random, 32, client_random, 32,
96, conn->key_block) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_internal_error);
goto end;
}
sm3_hmac_init(&conn->client_write_mac_ctx, conn->key_block, 32);
sm3_hmac_init(&conn->server_write_mac_ctx, conn->key_block + 32, 32);
sm4_set_decrypt_key(&conn->client_write_enc_key, conn->key_block + 64);
sm4_set_encrypt_key(&conn->server_write_enc_key, conn->key_block + 80);
//接收 ChangeCipherSpec消息
if (tls_record_recv(record, &recordlen, conn->sock) != 1
|| tls_record_protocol(record) != TLS_protocol_tlcp) {
error_print();
tls_send_alert(conn, TLS_alert_unexpected_message);
goto end;
}
if (tls_record_get_change_cipher_spec(record) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_unexpected_message);
goto end;
}
//解码
if (tls_record_decrypt(&conn->client_write_mac_ctx, &conn->client_write_enc_key,
conn->client_seq_num, record, recordlen, finished_record, &finished_record_len) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_bad_record_mac);
goto end;
}
tls_seq_num_incr(conn->client_seq_num);
if (tls_record_get_handshake_finished(finished_record, &verify_data, &verify_data_len) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_bad_record_mac);
goto end;
}
if (verify_data_len != sizeof(local_verify_data)) {
error_print();
tls_send_alert(conn, TLS_alert_bad_record_mac);
goto end;
}
memcpy(&tmp_sm3_ctx, &sm3_ctx, sizeof(SM3_CTX));
sm3_update(&sm3_ctx, finished_record + 5, finished_record_len - 5);
sm3_finish(&tmp_sm3_ctx, sm3_hash);
if (tls_prf(conn->master_secret, 48, "client finished", sm3_hash, 32, NULL, 0,
sizeof(local_verify_data), local_verify_data) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_internal_error);
goto end;
}
if (memcmp(verify_data, local_verify_data, sizeof(local_verify_data)) != 0) {
error_puts("client_finished.verify_data verification failure");
tls_send_alert(conn, TLS_alert_decrypt_error);
goto end;
}
if (tls_record_set_change_cipher_spec(record, &recordlen) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_internal_error);
goto end;
}
if (tls_record_send(record, recordlen, conn->sock) != 1) {
error_print();
goto end;
}
通过与客户端相同的方式生成主密钥
对接收到加密包进行验证。
发送服务端的Change Cipher Spec
- client: receive Change Cipher Spec
同服务端处理差不多,不赘述。
- server: Encrypted Handshake Message
sm3_finish(&sm3_ctx, sm3_hash);
if (tls_prf(conn->master_secret, 48, "server finished", sm3_hash, 32, NULL, 0,
sizeof(local_verify_data), local_verify_data) != 1
|| tls_record_set_handshake_finished(finished_record, &finished_record_len,
local_verify_data, sizeof(local_verify_data)) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_internal_error);
goto end;
}
if (tls_record_encrypt(&conn->server_write_mac_ctx, &conn->server_write_enc_key,
conn->server_seq_num, finished_record, finished_record_len, record, &recordlen) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_internal_error);
goto end;
}
tls_seq_num_incr(conn->server_seq_num);
if (tls_record_send(record, recordlen, conn->sock) != 1) {
error_print();
goto end;
}
服务端同客户端类似,对server finished进行加密传输。
- client: receive Encrypted Handshake Message
同服务端处理差不多,不赘述。
- client:开始进行加密数据传输
if (tls_record_set_type(record, TLS_record_application_data) != 1
|| tls_record_set_protocol(record, conn->protocol) != 1
|| tls_record_set_length(record, inlen) != 1) {
error_print();
return -1;
}
if (tls_cbc_encrypt(hmac_ctx, enc_key, seq_num, tls_record_header(record),
in, inlen, tls_record_data(record), &datalen) != 1) {
error_print();
return -1;
}
if (tls_record_set_length(record, datalen) != 1) {
error_print();
return -1;
}
tls_seq_num_incr(seq_num);
if (tls_record_send(record, tls_record_length(record), conn->sock) != 1) {
error_print();
return -1;
}
做好记录层的准备,将要传输的数据sm4和cbc进行处理加密
- server:接收加密数据并进行解密。
if ((ret = tls_record_recv(record, &recordlen, conn->sock)) != 1) {
if (ret < 0) error_print();
return ret;
}
if (tls_cbc_decrypt(hmac_ctx, dec_key, seq_num, record,
tls_record_data(record), tls_record_data_length(record),
conn->databuf, &conn->datalen) != 1) {
error_print();
return -1;
}
conn->data = conn->databuf;
tls_seq_num_incr(seq_num);
tls_record_set_data(record, conn->data, conn->datalen);
接收记录层,从记录层解析出加密数据,并进行解密。
至此,整个流程解析完毕。