据公开值Gi/Gr和随机数Ni/Nr生成的一个公有秘密值; 调用函数gernerate_skeyid(),生成下列各值:
SKEYID(密钥材料,用于生成后几个密钥值), SKEYID_D(用于产生IPsec SA的密钥),
SKEYID_A(用于认证(后继的)ISAKMP消息的密钥), SKEYID_E(用于加密ISAKMP交换的密钥), 新的IV值;
将state中的iv值更新为刚刚生成的iv值,更新state的状态为STATE_MAIN_R2,返回STF_REPLY。
3.3.4.2.1.5 消息5:发起方的身份标识IDi、散列函数值HASH-I及对HASH-I的签名(加密)结果
stf_status main_inR2_outI3(struct msg_digest *md)
目的:收到响应方的D-H公开值和随机数,计算D-H值和其它密钥材料材料。 参数:md ―― 消息摘要,接收到的消息
返回值:STF_REPLY ―― 成功, 其它 ―― 有错误 算法:
检查并接受对方消息中的DH公开值Gr,调用函数accept_KE(); 检查并接受对方消息中的随机数NONCE-Nr,调用函数accept_nonce();
计算dh值,调用函数compute_dh_shared(),得到state->st_shared,该值为双方根据公开值Gi/Gr和随机数Ni/Nr生成的一个公有秘密值; 调用函数gernerate_skeyid(),生成下列各值:
SKEYID(密钥材料,用于生成后几个密钥值), SKEYID_D(用于产生IPsec SA的密钥),
SKEYID_A(用于认证(后继的)ISAKMP消息的密钥), SKEYID_E(用于加密ISAKMP交换的密钥), 新的IV值;
构造外出包的IDii(发起方的身份标识):
调用函数build_id_payload()构造身份载荷,调用函数out_struct(); 构造外出包的HASH_I或SIG_I; 加密ISAKMP包,除了ISAKMP包头部分;
更新state的状态为STATE_MAIN_I3,返回STF_REPLY。
3.3.4.2.1.6 消息6:响应方的身份标识IDr、散列函数值HASH-R及对HASH-R的签名(加密)结果
stf_status main_inI3_outR3(struct msg_digest *md)
目的:响应方的第三个协商消息,验证发起方的身份,发送自己的身份消息。 参数:md ―― 消息摘要,接收到的消息
返回值:STF_REPLY ―― 成功, 其它 ―― 有错误 算法:
根据收到的消息的认证方式判断,它是使用的HASH载荷还是签名载荷; 解析对方的身份(ID),调用函数decode_peer_id();
检验HASH载荷或签名载荷,返回一个notification_t类型的结果; 计算外出的IDir(响应方的身份标识):
调用函数build_id_payload()构造身份载荷,调用函数out_struct(); 构造外出包的HASH_R或SIG_R; 加密ISAKMP包,除了ISAKMP包头部分;
5.更新state的状态为STATE_MAIN_I3,返回STF_REPLY。 3.3.4.2.1.7 发起方的结束工作
目的:接收到响应方的最后一个消息后,做相应的处理工作。 参数:md ―― 消息摘要,接收到的消息
返回值:STF_REPLY ―― 成功, 其它 ―― 有错误 算法:
根据收到的消息的认证方式判断,它是使用的HASH载荷还是签名载荷; 解析对方的身份(ID),调用函数decode_peer_id();
检验HASH载荷或签名载荷,返回一个notification_t类型的结果,使用函数check_main_authenticator();
更新state状态为STATE_MAIN_I4,将这个state的序列号通知给这个connection; 返回STF_UPEND_QUICH,这表示第一阶段已经成功完成,可以初始化第二阶段。
3.3.4.2.2 IPsec SA的建立(快速模式)
3.3.4.2.2.1 消息1:发起方为协商IPSEC SA发出的第一个消息
stf_status quick_outI1(int whack_sock, struct state *isakmp_sa, struct connection *c, unsigned long try)
目的:发起方开始协商IPsec SA的第一个消息,在此消息中,发送散列值HASH-1、一个或
多个供响应方选择的安全联盟方案(每个安全联盟方案包括随机生成的安全参数索引SPI、提案—安全协议AH或ESP、变换—具体的加密算法/散列算法及其SA属性)、发送方的nounce Nii、发送方的D-H公开值gi、发送方的IDii 。其中,gi、IDii及IDir可选(用于提供PFS服务)。 参数:
whack_sock ―― whack套接口
isakmp_sa ―― 已经协商好的ISAKMP SA c
―― 拥有这个IPSEC SA的连接(connection) ―― 安全策略
―― 协商时的最大重试次数
x
x
policy try
返回值:STF_NO_REPLY ―― 成功 , 其它 ―― 有错误 算法:
调用函数duplicate_state(isakmp_sa),复制一个协商好的ISAKMP 的state; 填充state的部分成员变量值,调用函数insert_state()将这个st插入hash表中; 调用函数init_pbs(),开始构造外出的协商消息,初始化; 构造HDR头;
构造SA载荷,调用函数out_sa();
构造NONCE载荷,调用函数build_and_ship_nonce();
7.如果选择了pfs(完美向前保密),则构造密钥交换载荷(KE),调用 函build_and_ship_KE(); 构造IDci和IDcr;
调用函数close_output_pbs(),完成消息的构造;
调用函数quick_mode_hashI2(),计算HSAH(1),放到output中;
调用函数init_phase2_iv(),生成iv值,调用函数encrypt_message(),加密信息; 保存该包,并调用函数send_packet(),发送此消息包,返回STF_NO_REPLY。 3.3.4.2.2.2 消息2:响应方为协商IPSEC SA发出的第一个消息 stf_status quick_inI1_outR1(struct msg_digest *md)
目的:散列值HASH-2、响应方选择的安全联盟方案(其中的SPI可与消息1中同一提案的SPI不同)、响应方的nounce Nir、响应方的D-H公开值gi、响应方的IDir 。 参数:md ―― 接收到的对方发送的协商消息 返回值:STF_REPLY ―― 成功 , 其它 ―― 有错误 算法:
取出并赋值ISAKMP的state,使用函数duplicate_state(); 填充state的部分成员变量值;
y
数
检测收到的HASH(1)是否正确,调用宏CHECK_QUICK_HASH(); 构造SA载荷,选择接受的策略;
调用函数accept_nonce(),检查发起方的随机数; 调用函数accept_PFS_KE(),检查发起方D-H公开值; 确认对方身份,使用函数decode_net_id();
调用函数find_client_connection(),查找相应的connection;
构造响应消息,包括NONCE、KE、IDci、IDcr等等,过程与上个消息中的构造过程基本相同;
调用函数compute_keymats,计算密钥材料;
调用函数install_inbound_ipsec_sa(),安装进入的SA; 调用函数encrypt_message(),将构造好的协商消息加密; 更新st的状态,返回STF_REPLY。
3.3.4.2.2.3 消息3:发起方为协商IPSEC SA发出的第二个消息 stf_status quick_inR1_outI2(struct msg_digest *md) 目的:
参数:md ―― 接收到的对方发送的协商消息 返回值:STF_REPLY ―― 成功 , 其它 ―― 有错误 算法:
验证响应方的身份,与2.2中的3~6步基本相同; 构造响应消息,包括HDR、HASH(3)等等; 调用函数compute_keymats(),计算密钥材料; 调用函数install_ipsec_sa(),安装SA;
调用函数encrypt_message()加密响应消息,更新st的状态,返回STF_REPLY。 3.3.4.2.2.4 响应方的结束工作
stf_status quick_inI2(struct msg_digest *md) 目的:协商结束,安装IPSEC SA。
参数:md ―― 接收到的对方发送的协商消息
返回值:STF_NO_REPLY ―― 成功 , 其它 ―― 有错误 算法:
调用函数install_ipsec_sa(),安装IPSEC SA; 更新st的状态,返回STF_NO_REPLY。