
Libreswan软件的密钥协商协议IKEv1主模式实现分析
1 协商过程
IKEv1(互联网密钥交换协议第一版)是IPsec VPN隧道协商使用的标准密钥协商协议,其协商过程如下图所示。
总共来回交互6次消息。第一、第二消息用来双方协商在本次密钥交换过程中使用的保护策略,由发起方提供议案(Proposal),响应方从众多议案中选择其中一条作为本次协商使用;第三、第四条消息交换DH公钥以及使用对方公钥加密的各自的ID以及Nonce信息,通过这些信息建立共享密钥。其中HASH(1)代表对发起方用来加密使用的数字证书进行hash运算(hash函数由SA协商)产生的hash数据。第五、第六两条消息携带各自的加密后的认证内容验证共享密钥是否正确。该模式要求双方提前拥有对方的公钥信息。
2 主要函数
Libreswan是一款主流的IPsec VPN开源软件,其IKEv1主模式协商主要包含以下几个函数:
发起方
main_outI1
main_inR1_outI2
main_inR2_outI3
main_inR3
响应方
main_inI1_outR1
main_inI2_outR2
main_inI3_outR3
3 main_outI1发起方发送MI1消息
main_outI1生成发起方的state,构造HDR、SA、VID载荷,并发送出去。
关键函数:
生成state:new_state
初始化state并插入statetable中:initialize_new_state
构造HDR:out_struct
构造SA载荷:ikev1_out_sa
构造pluto VID载荷:ikev1_out_generic_raw
构造DPD/IKE分片/XAUTH VID载荷:out_vid
record_and_send_ike_msg()
4 main_inI1_outR1响应方处理MI1消息,发送MR1消息
main_inI1_outR1根据IP地址和端口号查找连接,生成响应方的state,解析MI1中的SA载荷,构造HDR、SA、VID载荷。
关键函数:
查找连接:find_host_connection
生成响应方的state :new_rstate
将生成的state插入statetable中:insert_state
构造HDR:out_struct
构造SA头部:out_struct
解析发起方SA并构造SA主体:parse_isakmp_sa_body
构造pluto VID载荷:ikev1_out_generic_raw
构造DPD/IKE分片/XAUTH/NAT-T VID载荷out_vid
5 main_inR1_outI2发起方处理MR1消息,发送MI2消息
main_inR1_outI2解析响应方SA,生成一个pluto_crypto_req_cont变量ke挂起state,调用build_ke_and_nonce构造ke和nonce。
build_ke_and_nonce生成一个pluto_crypto_req请求rd,调用send_crypto_helper_request计算ke和nonce值保存在rd请求中。
send_crypto_helper_request计算ke和nonce值保存在rd请求中,并调用ke中的回调函数main_inR1_outI2_continue。
main_inR1_outI2_continue恢复挂起的state,并调用main_inR1_outI2_tail和complete_v1_state_transition。
main_inR1_outI2_tail构造HDR、KE、Ni、NAT-D载荷,重新插入st到statetable中。
关键函数:
解析响应方:parse_isakmp_sa_body
构造ke_nonce请求:build_ke_and_nonce
执行ke_nonce计算:send_crypto_helper_request
返回HDR:ikev1_echo_hdr
构造KE载荷:ikev1_ship_KE
构造Ni载荷:ikev1_ship_nonce
完成状态转移并发送数据包:complete_v1_state_transition
6 main_inI2_outR2响应方处理MI2消息,发送MR2消息
main_inI2_outR2解析MI2消息中的KE和Ni载荷,生成pluto_crypto_req_cont变量ke挂起state,调用build_ke_and_nonce。
build_ke_and_nonce生成pluto_crypto_req请求rd,调用send_crypto_helper_request。
send_crypto_helper_request执行ke和nonce计算,完成后调用回调函数main_inI2_outR2_continue。
main_inI2_outR2_continue恢复挂起的st,调用main_inI2_outR2_tail和complete_v1_state_transition。
main_inI2_outR2_tail构造HDR、KE、Nr、CR证书请求、NAT-D载荷,生成pluto_crypto_req_cont变量dh,并调用start_dh_secrteiv执行dh计算。
start_dh_secrteiv生成pluto_crypto_req dh计算请求r,调用send_crypto_helper_request。
send_crypto_helper_request会计算4个skeyid,并保存在r中,计算结束后调用dh中的回调函数main_inI2_outR2_calcdone。
main_inI2_outR2_calcdone会检查st->st_suspended_md是否为NULL。
关键函数:
解析KE载荷:accept_KE
解析nonce载荷:accept_v1_nonce
构造ke_nonce请求build_ke_and_nonce
完成状态转移并发送数据包:complete_v1_state_transition
返回HDR:ikev1_echo_hdr
构造KE载荷:ikev1_ship_KE
构造Ni载荷:ikev1_ship_nonce
构造CR载荷:ikev1_build_and_ship_CR
构造DH计算请求:start_dh_secretiv
执行DH计算:send_crypto_helper_request
7 main_inR2_outI3发起方处理MR2消息,发送MI3消息(加密)
main_inR2_outI3解析MR2消息中的KE和Nr载荷,生成pluto_crypto_req_cont变量dh,并调用start_dh_secrteiv执行dh计算。
start_dh_secrteiv生成pluto_crypto_req dh计算请求r,调用send_crypto_helper_request。
send_crypto_helper_request会计算4个skeyid,并保存在r中,计算结束后调用dh中的回调函数main_inR2_outI3_cryptotail。
main_inR2_outI3_cryptotail恢复挂起的state,依次调用main_inR2_outI3_continue和complete_v1_state_transition。
main_inR2_outI3_continue解析证书请求,查找证书,构造ID、CERT、CR、HASH_I(或SIG_I)载荷,并加密以上载荷。由于smc->first_out_payload != ISAKMP_NEXT_NONE,HDR已经在process_v1_packet的process_packet_tail中构造。
关键函数:
解析KE载荷:accept_KE
解析nonce载荷:accept_v1_nonce
构造DH计算请求:start_dh_secretiv
解析证书请求:ikev1_decode_cr
查找证书:doi_log_cert_thinking
构造ID载荷:build_id_payload
构造CERT载荷:ikev1_ship_CERT
构造CR载荷:ikev1_build_and_ship_CR
计算载荷的hash值:main_mode_hash
对hash值进行RSA签名:RSA_sign_hash
加密载荷:encrypt_message
8 main_inI3_outR3响应方处理MI3消息,发送MR3消息(加密)
main_inI3_outR3验证MI3的签名,构造HDR、ID、CERT、HASH_R(或SIG_R)载荷,并加密以上载荷。生成Phase2的初始化向量IV。发起方à响应方的ISAKMP_SA建立完成。
关键函数:
验证签名:oakley_id_and_auth
查找证书:doi_log_cert_thinking
返回HDR:ikev1_echo_hdr
构造ID载荷:build_id_payload
构造证书载荷:ikev1_ship_CERT
计算载荷的hash值:main_mode_hash
对hash值进行RSA签名:RSA_sign_hash
加密载荷:encrypt_message
生成IV:set_ph1_iv_from_new
单方向ISAKMP_SA建立完成:ISAKMP_SA_established
9 main_inR3发起方处理MR3消息
main_inR3直接调用main_inR3_tail。
main_inR3_tail中验证MR3的签名,响应方à发起方的ISAKMP_SA建立完成。生成Phase2的初始化向量IV。
关键函数:
验证签名:oakley_id_and_auth
单方向ISAKMP_SA建立完成:ISAKMP_SA_established
生成IV:set_ph1_iv_from_new