本文档的Copyleft归yfydz所有,使用GPL发布,可以自由拷贝,转载,转载时请保持文档的完整性,严禁用于任何商业用途。
msn:
[email protected]
来源: http://yfydz.cublog.cn
14. 野蛮模式协商
IKE野蛮协商处理函数基本都在programs/pluto目录下的ikev1_aggr.c和ipsec_doi.c中定义, 野蛮模式通常用在已经建好连接的断开后快速恢复连接, 数据交互较少, 只需三个数据包就可以完成第一阶段协商, 而主模式需要6个数据包才能完成协商。
14.1 过程
野蛮模式:
Initiator Responder
----------- -----------
HDR, SA, KE, Ni, IDii -->
aggr_outI1(发送初始化数据1)
<-- HDR, SA, KE, Nr, IDir,
[ CERT, ] SIG_R
aggr_inI1_outR1_psk(接收到初始化数据1, 发送响应数据1)
aggr_inI1_outR1_rsasig(根据认证方式分别用不同函数处理)
HDR, [ CERT, ] SIG_I -->
aggr_inR1_outI2(接收到响应数据1,发送初始化数据2)
aggr_inI2(接收到初始化数据2,完成野蛮模式协商, 建立ISAKMP SA)
连接发起函数为ipsecdoi_initiate()函数, 在其中调用了main_outI1(), aggr_outI1()和quick_outI1()函数分别发起主模式,野蛮模式和快速模式的协商。
14.2 发起方的第一个初始包
stf_status
aggr_outI1(int whack_sock,
struct connection *c,
struct state *predecessor,
lset_t policy,
unsigned long try
, enum crypto_importance importance)
{
struct state *st;
/* set up new state */
// 新分配状态结构, 准备建立新状态
cur_state = st = new_state();
// 状态所在连接
st->st_connection = c;
// 设置状态结构中的双方地址端口信息
set_state_ike_endpoints(st, c);
#ifdef DEBUG
extra_debugging(c);
#endif
// 状态相关参数: 策略
st->st_policy = policy & ~POLICY_IPSEC_MASK;
// 和whack的通信套接口
st->st_whack_sock = whack_sock;
// 重试次数
st->st_try = try;
// 状态类型: AGGR_I1
st->st_state = STATE_AGGR_I1;
// 获取发起方cookie
get_cookie(TRUE, st->st_icookie, COOKIE_SIZE, &c->spd.that.host_addr);
// 将状态结构插入系统的状态哈希表
insert_state(st); /* needs cookies, connection, and msgid (0) */
// 初始化状态结构中的st_oakley域,为一个struct oakley_trans_attrs结构
if(init_am_st_oakley(st, policy) == FALSE) {
loglog(RC_AGGRALGO, "can not initiate aggressive mode, at most one algorithm may be provided");
reset_globals();
return STF_FAIL;
}
if (HAS_IPSEC_POLICY(policy))
add_pending(dup_any(whack_sock), st, c, policy, 1
, predecessor == NULL? SOS_NOBODY : predecessor->st_serialno);
// 记录野蛮模式状态初始化信息, predecessor为该当前状态之前可能的状态
// (新状态是该状态的替换者)
if (predecessor == NULL) {
openswan_log("initiating Aggressive Mode #%lu, connection \"%s\""
, st->st_serialno, st->st_connection->name);
}
else {
openswan_log("initiating Aggressive Mode #%lu to replace #%lu, connection \"%s\""
, st->st_serialno, predecessor->st_serialno
, st->st_connection->name);
}
{
// 分配密钥交换结构
struct ke_continuation *ke = alloc_thing(struct ke_continuation
, "outI2 KE");
stf_status e;
// 分配消息摘要结构
ke->md = alloc_md();
ke->md->st = st;
st->st_suspended_md = ke->md;
if (!st->st_sec_in_use) {
// 如果数据还没加密, 准备密钥交换, 然后重新继续
ke->ke_pcrc.pcrc_func = aggr_outI1_continue;
// 密钥交换处理
e = build_ke(&ke->ke_pcrc, st, st->st_oakley.group, importance);
if(e != STF_SUSPEND) {
loglog(RC_CRYPTOFAILED, "system too busy");
delete_state(st);
}
} else {
// 已经加密了, 继续完成outI1过程
e = aggr_outI1_tail((struct pluto_crypto_req_cont *)ke
, NULL);
}
// 复位全局变量
reset_globals();
return e;
}
}
// 加密处理完成后的继续操作函数
static void
aggr_outI1_continue(struct pluto_crypto_req_cont *pcrc
, struct pluto_crypto_req *r
, err_t ugh)
{
// 密钥交换结构
struct ke_continuation *ke = (struct ke_continuation *)pcrc;
struct msg_digest *md = ke->md;
struct state *const st = md->st;
stf_status e;
DBG(DBG_CONTROLMORE
, DBG_log("aggr outI1: calculated ke+nonce, sending I1"));
/* XXX should check out ugh */
passert(ugh == NULL);
passert(cur_state == NULL);
passert(st != NULL);
passert(st->st_suspended_md == ke->md);
st->st_suspended_md = NULL; /* no longer connected or suspended */
// 设置当前状态
set_cur_state(st);
st->st_calculating = FALSE;
// 完成outI1过程
e = aggr_outI1_tail(pcrc, r);
if(ke->md != NULL) {
// 如果消息摘要非空(应该是likely的), 完成状态转移操作
complete_state_transition(&ke->md, e);
// 释放消息摘要结构
release_md(ke->md);
}
// 复位全局变量
reset_globals();
passert(GLOBALS_ARE_RESET());
}
// 结束处理, 构造发送包
static stf_status
aggr_outI1_tail(struct pluto_crypto_req_cont *pcrc
, struct pluto_crypto_req *r)
{
struct ke_continuation *ke = (struct ke_continuation *)pcrc;
struct msg_digest *md = ke->md;
struct state *const st = md->st;
struct connection *c = st->st_connection;
u_char space[8192]; /* NOTE: we assume 8192 is big enough to build the packet */
pb_stream reply; /* not actually a reply, but you know what I mean */
pb_stream rbody;
/* set up reply */
// 初始化回应包
init_pbs(&reply, space, sizeof(space), "reply packet");
/* HDR out */
{
struct isakmp_hdr hdr;
// 填充ISAKMP头结构
memset(&hdr, '\0', sizeof(hdr)); /* default to 0 */
// 版本
hdr.isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION;
// 下一载荷为SA载荷
hdr.isa_np = ISAKMP_NEXT_SA;
// 野蛮模式
hdr.isa_xchg = ISAKMP_XCHG_AGGR;
// 发起方cookie
memcpy(hdr.isa_icookie, st->st_icookie, COOKIE_SIZE);
/* R-cookie, flags and MessageID are left zero */
// 输出到缓冲区
if (!out_struct(&hdr, &isakmp_hdr_desc, &reply, &rbody))
{
cur_state = NULL;
return STF_INTERNAL_ERROR;
}
}
/* SA out */
{
// 填充SA载荷
u_char *sa_start = rbody.cur;
int policy_index = POLICY_ISAKMP(st->st_policy
, c->spd.this.xauth_server
, c->spd.this.xauth_client);
if (!out_sa(&rbody
, &oakley_am_sadb[policy_index], st
// 下一载荷是KE载荷
, TRUE, TRUE, ISAKMP_NEXT_KE))
{
return STF_INTERNAL_ERROR;
cur_state = NULL;
}
/* save initiator SA for later HASH */
passert(st->st_p1isa.ptr == NULL); /* no leak! */
clonetochunk(st->st_p1isa, sa_start, rbody.cur - sa_start,
"sa in aggr_outI1");
}
/* KE out */
// 填充密钥交换载荷
if (!ship_KE(st, r, &st->st_gi,
// 下一载荷是NONCE载荷
&rbody, ISAKMP_NEXT_NONCE))
return STF_INTERNAL_ERROR;
/* Ni out */
// 填充NONCE载荷, 下一载荷是ID载荷
if (!ship_nonce(&st->st_ni, r, &rbody, ISAKMP_NEXT_ID, "Ni"))
return STF_INTERNAL_ERROR;
/* IDii out */
{
struct isakmp_ipsec_id id_hd;
chunk_t id_b;
pb_stream id_pbs;
// 构造ID载荷
build_id_payload(&id_hd, &id_b, &st->st_connection->spd.this);
// 下一载荷是VID载荷
id_hd.isaiid_np = ISAKMP_NEXT_VID;
if (!out_struct(&id_hd, &isakmp_ipsec_identification_desc, &rbody, &id_pbs)
|| !out_chunk(id_b, &id_pbs, "my identity"))
return STF_INTERNAL_ERROR;
close_output_pbs(&id_pbs);
}
/* ALWAYS Announce our ability to do Dead Peer Detection to the peer */
{
// 没有NAT穿越时的下一载荷为空
int np = ISAKMP_NEXT_NONE;
#ifdef NAT_TRAVERSAL
if (nat_traversal_enabled
|| c->spd.this.xauth_client
|| c->spd.this.xauth_server) {
// 如果打开NAT穿越或使用XAUTH, 下一载荷是VID载荷
/* Add supported NAT-Traversal VID */
np = ISAKMP_NEXT_VID;
}
#endif
// 构造DPD VID载荷, 下一载荷是由np指定
if( !out_generic_raw(np, &isakmp_vendor_id_desc
, &rbody
, dpd_vendorid, dpd_vendorid_len
, "V_ID"))
return STF_INTERNAL_ERROR;
}
#ifdef NAT_TRAVERSAL
if (nat_traversal_enabled) {
/* Add supported NAT-Traversal VID */
int np = ISAKMP_NEXT_NONE;
#ifdef XAUTH
if(c->spd.this.xauth_client || c->spd.this.xauth_server) {
// 如果是使用XAUTH, 下一载荷还是VID载荷
np = ISAKMP_NEXT_VID;
}
#endif
// 添加NAT穿越VID载荷, 下一载荷如果有XAUTH的将是XAUTH的VID载荷
if (!nat_traversal_add_vid(np, &rbody)) {
reset_cur_state();
return STF_INTERNAL_ERROR;
}
}
#endif
#ifdef XAUTH
if(c->spd.this.xauth_client || c->spd.this.xauth_server)
{
// 填充XAUTH的VID载荷, 下一载荷是空
if(!out_vendorid(ISAKMP_NEXT_NONE, &rbody, VID_MISC_XAUTH))
{
return STF_INTERNAL_ERROR;
}
}
#endif
/* finish message */
// 结束数据包构造
close_message(&rbody);
close_output_pbs(&reply);
clonetochunk(st->st_tpacket, reply.start, pbs_offset(&reply),
"reply packet from aggr_outI1");
/* Transmit */
// 输出数据包具体原始信息
DBG_cond_dump(DBG_RAW, "sending:\n",
st->st_tpacket.ptr, st->st_tpacket.len);
// 发送数据包
send_packet(st, "aggr_outI1", TRUE);
/* Set up a retransmission event, half a minute henceforth */
// 删除状态的原始事件
delete_event(st);
// 重新挂接状态事件: 超时重发
event_schedule(EVENT_RETRANSMIT, EVENT_RETRANSMIT_DELAY_0, st);
whack_log(RC_NEW_STATE + STATE_AGGR_I1,
"%s: initiate", enum_name(&state_names, st->st_state));
cur_state = NULL;
return STF_IGNORE;
}
14.3 响应方收到发起方初始化包, 发送第一响应包
以下函数都在ipsec_doi.c中定义, 对于按预共享密钥认证还是RSA签名认证分别使用不同的函数进行处理:
stf_status
aggr_inI1_outR1_psk(struct msg_digest *md)
{
return aggr_inI1_outR1_common(md, OAKLEY_PRESHARED_KEY);
}
stf_status
aggr_inI1_outR1_rsasig(struct msg_digest *md)
{
return aggr_inI1_outR1_common(md, OAKLEY_RSA_SIG);
}
// 则两个函数都是aggr_inI1_outR1_common()函数的包裹函数
static stf_status
aggr_inI1_outR1_common(struct msg_digest *md
, int authtype)
{
/* With Aggressive Mode, we get an ID payload in this, the first
* message, so we can use it to index the preshared-secrets
* when the IP address would not be meaningful (i.e. Road
* Warrior). So our first task is to unravel the ID payload.
*/
struct state *st;
// SA载荷链表
struct payload_digest *const sa_pd = md->chain[ISAKMP_NEXT_SA];
// 密钥交换载荷链表
pb_stream *keyex_pbs = &md->chain[ISAKMP_NEXT_KE]->pbs;
// 根据地址端口查找连接
struct connection *c = find_host_connection(&md->iface->ip_addr
, md->iface->port
, &md->sender
, md->sender_port);
#if 0
#ifdef NAT_TRAVERSAL
if (c == NULL && md->iface->ike_float)
{
c = find_host_connection(&md->iface->addr, NAT_T_IKE_FLOAT_PORT
, &md->sender, md->sender_port);
}
#endif
#endif
if (c == NULL)
{
// 如果没找到连接, 可能是动态连接, 将对方地址置空后重新查找连接
/* see if a wildcarded connection can be found */
c = find_host_connection(&md->iface->ip_addr, pluto_port
, (ip_address*)NULL, md->sender_port);
if (c != NULL && c->policy & POLICY_AGGRESSIVE)
{
/* Create a temporary connection that is a copy of this one.
* His ID isn't declared yet.
*/
// 如果找到连接而且该根据支持野蛮模式, 将连接实例化
c = rw_instantiate(c, &md->sender,
NULL,
NULL);
}
else
{
// 否则失败返回
loglog(RC_LOG_SERIOUS, "initial Aggressive Mode message from %s"
" but no (wildcard) connection has been configured"
, ip_str(&md->sender));
/* XXX notification is in order! */
return STF_IGNORE;
}
}
/* Set up state */
// 分配新状态结构
cur_state = md->st = st = new_state(); /* (caller will reset cur_state) */
// 状态所处连接
st->st_connection = c;
// 远程对方的地址端口
st->st_remoteaddr = md->sender;
st->st_remoteport = md->sender_port;
// 网卡位置
st->st_interface = md->iface;
// 状态类型值为AGGR_R1
st->st_state = STATE_AGGR_R1;
/* until we have clue who this is, then be conservative about allocating
* them any crypto bandwidth */
// 重要性
st->st_import = pcim_stranger_crypto;
// 状态策略中带上野蛮模式标志
st->st_policy |= POLICY_AGGRESSIVE;
// 认证类型
st->st_oakley.auth = authtype;
// 解码对方ID信息
if (!decode_peer_id(md, FALSE, TRUE))
{
char buf[IDTOA_BUF];
// 如果解码失败, 错误返回
(void) idtoa(&st->st_connection->spd.that.id, buf, sizeof(buf));
loglog(RC_LOG_SERIOUS,
"initial Aggressive Mode packet claiming to be from %s"
" on %s but no connection has been authorized",
buf, ip_str(&md->sender));
/* XXX notification is in order! */
return STF_FAIL + INVALID_ID_INFORMATION;
}
c = st->st_connection;
#ifdef DEBUG
extra_debugging(c);
#endif
// 尝试次数
st->st_try = 0; /* Not our job to try again from start */
// 状态策略
st->st_policy = c->policy & ~POLICY_IPSEC_MASK; /* only as accurate as connection */
// 复制数据包中的发起方的cookie
memcpy(st->st_icookie, md->hdr.isa_icookie, COOKIE_SIZE);
// 构造响应方(本地)的cookie
get_cookie(FALSE, st->st_rcookie, COOKIE_SIZE, &md->sender);
// 将状态插入系统状态哈希链表
insert_state(st); /* needs cookies, connection, and msgid (0) */
st->st_doi = ISAKMP_DOI_IPSEC;
st->st_situation = SIT_IDENTITY_ONLY; /* We only support this */
// 日志记录信息
openswan_log("responding to Aggressive Mode, state #%lu, connection \"%s\""
" from %s"
, st->st_serialno, st->st_connection->name
, ip_str(&c->spd.that.host_addr));
#ifdef NAT_TRAVERSAL
// 如果对方支持NAT穿越, 本地也支持NAT穿越
if (md->quirks.nat_traversal_vid && nat_traversal_enabled) {
/* reply if NAT-Traversal draft is supported */
// 支持的NAT穿越策略
st->hidden_variables.st_nat_traversal = nat_traversal_vid_to_method(md->quirks.nat_traversal_vid);
}
#endif
/* save initiator SA for HASH */
// 保存发起方的SA和哈希载荷
clonereplacechunk(st->st_p1isa, sa_pd->pbs.start, pbs_room(&sa_pd->pbs),
"sa in aggr_inI1_outR1()");
/*
* parse_isakmp_sa picks the right group, which we need to know
* before we do any calculations. We will call it again to have it
* emit the winning SA into the output.
*/
/* SA body in */
{
pb_stream sabs = sa_pd->pbs;
// 读取输入数据包的SA载荷
RETURN_STF_FAILURE(parse_isakmp_sa_body(&sabs
, &sa_pd->payload.sa
, NULL, FALSE, st));
}
/* KE in */
// 读取KE载荷
RETURN_STF_FAILURE(accept_KE(&st->st_gi, "Gi", st->st_oakley.group, keyex_pbs));
/* Ni in */
// 读取NONCE载荷
RETURN_STF_FAILURE(accept_nonce(md, &st->st_ni, "Ni"));
{
// 分配密钥交换结构
struct ke_continuation *ke = alloc_thing(struct ke_continuation
, "outI2 KE");
ke->md = md;
st->st_suspended_md = md;
if (!st->st_sec_in_use) {
// 如果没有加密处理, 先进行加密准备处理
ke->ke_pcrc.pcrc_func = aggr_inI1_outR1_continue;
// 密钥交换处理
return build_ke(&ke->ke_pcrc, st, st->st_oakley.group
, st->st_import);
} else {
// 否则已经支持加密了, 完成inI1_outR1的后续操作
return aggr_inI1_outR1_tail((struct pluto_crypto_req_cont *)ke
, NULL);
}
}
}
// inI1_outR1结尾部分, 构造要发送的数据包
static stf_status
aggr_inI1_outR1_tail(struct pluto_crypto_req_cont *pcrc
, struct pluto_crypto_req *r)
{
// 密钥交换结构
struct ke_continuation *ke = (struct ke_continuation *)pcrc;
struct msg_digest *md = ke->md;
struct state *st = md->st;
// SA载荷链表
struct payload_digest *const sa_pd = md->chain[ISAKMP_NEXT_SA];
int auth_payload;
pb_stream r_sa_pbs;
pb_stream r_id_pbs; /* ID Payload; also used for hash calculation */
/* parse_isakmp_sa also spits out a winning SA into our reply,
* so we have to build our md->reply and emit HDR before calling it.
*/
// 初始化数据缓冲区
init_pbs(&md->reply, reply_buffer, sizeof(reply_buffer), "reply packet");
/* HDR out */
{
struct isakmp_hdr r_hdr = md->hdr;
// 填充ISAKMP头结构
memcpy(r_hdr.isa_rcookie, st->st_rcookie, COOKIE_SIZE);
// 下一载荷是SA载荷
r_hdr.isa_np = ISAKMP_NEXT_SA;
if (!out_struct(&r_hdr, &isakmp_hdr_desc, &md->reply, &md->rbody))
return STF_INTERNAL_ERROR;
}
/* start of SA out */
{
struct isakmp_sa r_sa = sa_pd->payload.sa;
notification_t r;
// 填充SA载荷, 下一载荷是KE载荷
r_sa.isasa_np = ISAKMP_NEXT_KE;
if (!out_struct(&r_sa, &isakmp_sa_desc, &md->rbody, &r_sa_pbs))
return STF_INTERNAL_ERROR;
/* SA body in and out */
// 解析输入包中的SA提议, 同时输出自己可用的SA提议
r = parse_isakmp_sa_body(&sa_pd->pbs, &sa_pd->payload.sa,
&r_sa_pbs, FALSE, st);
if (r != NOTHING_WRONG)
return STF_FAIL + r;
}
/* don't know until after SA body has been parsed */
// 根据认证类型确定下一载荷是哈希载荷还是RSA签名载荷
auth_payload = st->st_oakley.auth == OAKLEY_PRESHARED_KEY
? ISAKMP_NEXT_HASH : ISAKMP_NEXT_SIG;
/************** build rest of output: KE, Nr, IDir, HASH_R/SIG_R ********/
/* KE */
// 输出密钥交换载荷
if (!ship_KE(st, r, &st->st_gr,
&md->rbody, ISAKMP_NEXT_NONCE))
return STF_INTERNAL_ERROR;
/* Nr */
// 输出NONCE载荷
if (!ship_nonce(&st->st_nr, r
, &md->rbody, ISAKMP_NEXT_ID, "Nr"))
return STF_INTERNAL_ERROR;
/* IDir out */
{
struct isakmp_ipsec_id id_hd;
chunk_t id_b;
// 输出ID载荷
build_id_payload(&id_hd, &id_b, &st->st_connection->spd.this);
id_hd.isaiid_np = auth_payload;
if (!out_struct(&id_hd, &isakmp_ipsec_identification_desc, &md->rbody, &r_id_pbs)
|| !out_chunk(id_b, &r_id_pbs, "my identity"))
return STF_INTERNAL_ERROR;
close_output_pbs(&r_id_pbs);
}
// DH交换计算
(void)perform_dh_secretiv(st, RESPONDER, st->st_oakley.group->group);
// 更新初始化向量
update_iv(st);
/* HASH_R or SIG_R out */
{
u_char hash_val[MAX_DIGEST_LEN];
size_t hash_len = main_mode_hash(st, hash_val, FALSE, &r_id_pbs);
if (auth_payload == ISAKMP_NEXT_HASH)
{
// 如果是预共享密钥认证, 输出哈希载荷
/* HASH_R out */
if (!out_generic_raw(ISAKMP_NEXT_VID
, &isakmp_hash_desc
, &md->rbody
, hash_val
, hash_len
, "HASH_R"))
return STF_INTERNAL_ERROR;
}
else
{
// 是RSA签名认证
/* SIG_R out */
u_char sig_val[RSA_MAX_OCTETS];
size_t sig_len = RSA_sign_hash(st->st_connection
, sig_val, hash_val, hash_len);
if (sig_len == 0)
{
loglog(RC_LOG_SERIOUS, "unable to locate my private key for RSA Signature");
return STF_FAIL + AUTHENTICATION_FAILED;
}
// 输出RSA签名载荷
if (!out_generic_raw(ISAKMP_NEXT_VID, &isakmp_signature_desc
, &md->rbody, sig_val, sig_len, "SIG_R"))
return STF_INTERNAL_ERROR;
}
}
/*
* NOW SEND VENDOR ID payloads
*/
/* Announce our ability to do RFC 3706 Dead Peer Detection to the peer
if we have it enabled on this conn */
// 如果连接配置中设置了DPD尝试, 设置本地使用DPD标志
if(st->st_connection->dpd_delay && st->st_connection->dpd_timeout) {
/* Set local policy for DPD to be on */
st->hidden_variables.st_dpd_local = 1;
}
{
// 下一载荷缺省为空
int np = ISAKMP_NEXT_NONE;
#ifdef NAT_TRAVERSAL
if (st->hidden_variables.st_nat_traversal) {
// 如果使用NAT穿越, 下一载荷为VID载荷
np = ISAKMP_NEXT_VID;
}
#endif
// 输出DPD VID载荷
if( !out_generic_raw(np, &isakmp_vendor_id_desc
, &md->rbody, dpd_vendorid
, dpd_vendorid_len, "DPP Vendor ID")) {
return STF_INTERNAL_ERROR;
}
}
#ifdef NAT_TRAVERSAL
if (st->hidden_variables.st_nat_traversal) {
// 输出NAT穿越VID载荷
if (!out_vendorid(auth_payload
, &md->rbody
, md->quirks.nat_traversal_vid)) {
return STF_INTERNAL_ERROR;
}
}
if (st->hidden_variables.st_nat_traversal & NAT_T_WITH_NATD) {
// 填充NATD载荷, 会自动修改前一载荷中的下一载荷字段类型值
if (!nat_traversal_add_natd(auth_payload, &md->rbody, md))
return STF_INTERNAL_ERROR;
}
#endif
/* finish message */
// 数据构造结束
close_message(&md->rbody);
return STF_OK;
}
14.4 发起方收到响应方第一回应包, 发送第2初始包
stf_status
aggr_inR1_outI2(struct msg_digest *md)
{
/* With Aggressive Mode, we get an ID payload in this, the second
* message, so we can use it to index the preshared-secrets
* when the IP address would not be meaningful (i.e. Road
* Warrior). So our first task is to unravel the ID payload.
*/
// 所处状态
struct state *st = md->st;
// KE载荷链表
pb_stream *keyex_pbs = &md->chain[ISAKMP_NEXT_KE]->pbs;
// 状态策略带上野蛮协商标志
st->st_policy |= POLICY_AGGRESSIVE;
// 解码对方ID载荷
if (!decode_peer_id(md, FALSE, TRUE))
{
char buf[200];
// 失败的话记录日志返回错误
(void) idtoa(&st->st_connection->spd.that.id, buf, sizeof(buf));
loglog(RC_LOG_SERIOUS,
"initial Aggressive Mode packet claiming to be from %s"
" on %s but no connection has been authorized",
buf, ip_str(&md->sender));
/* XXX notification is in order! */
return STF_FAIL + INVALID_ID_INFORMATION;
}
/* verify echoed SA */
{
// 解析数据包中的SA载荷
struct payload_digest *const sapd = md->chain[ISAKMP_NEXT_SA];
notification_t r = \
parse_isakmp_sa_body(&sapd->pbs, &sapd->payload.sa,
NULL, TRUE, st);
// 出错返回
if (r != NOTHING_WRONG)
return STF_FAIL + r;
}
/* copy the quirks we might have accumulated */
copy_quirks(&st->quirks, &md->quirks);
#ifdef NAT_TRAVERSAL
// 检查是否要进行NAT穿越处理
if (nat_traversal_enabled && md->quirks.nat_traversal_vid) {
st->hidden_variables.st_nat_traversal = nat_traversal_vid_to_method(md->quirks.nat_traversal_vid);
}
#endif
/* KE in */
// 读取KE载荷
RETURN_STF_FAILURE(accept_KE(&st->st_gr, "Gr", st->st_oakley.group, keyex_pbs));
/* Ni in */
// 读取NONCE载荷
RETURN_STF_FAILURE(accept_nonce(md, &st->st_nr, "Nr"));
/* moved the following up as we need Rcookie for hash, skeyids */
/* Reinsert the state, using the responder cookie we just received */
// 将状态从系统哈希表中断开, 因为原来是按响应方cookie为空来查找哈希表的
unhash_state(st);
// 复制对方cookie
memcpy(st->st_rcookie, md->hdr.isa_rcookie, COOKIE_SIZE);
// 重新插入系统哈希表
insert_state(st); /* needs cookies, connection, and msgid (0) */
#ifdef NAT_TRAVERSAL
// 查找NATD信息
if (st->hidden_variables.st_nat_traversal & NAT_T_WITH_NATD) {
nat_traversal_natd_lookup(md);
}
// 输出NAT穿越信息
if (st->hidden_variables.st_nat_traversal) {
nat_traversal_show_result(st->hidden_variables.st_nat_traversal, md->sender_port);
}
// 如果是NAT穿越保活信息, 设置保活事件
if (st->hidden_variables.st_nat_traversal & NAT_T_WITH_KA) {
nat_traversal_new_ka_event();
}
#endif
{
stf_status stat;
// 进行DH交换计算密钥
stat = perform_dh_secretiv(st, INITIATOR, st->st_oakley.group->group);
if(stat != STF_OK) {
return stat;
}
}
// 继续完成数据包构造
return aggr_inR1_outI2_tail(md, NULL);
}
// 继续函数, 在使用OE情况下有效
static void
aggr_inR1_outI2_continue(struct adns_continuation *cr, err_t ugh)
{
key_continue(cr, ugh, aggr_inR1_outI2_tail);
}
static stf_status
aggr_inR1_outI2_tail(struct msg_digest *md
, struct key_continuation *kc)
{
struct state *const st = md->st;
struct connection *c = st->st_connection;
int auth_payload;
/* HASH_R or SIG_R in */
{
// 野蛮模式读取ID载荷和认证处理,如果需要使用OE来认证对方, 则启动OE认证后重新执行
// aggr_inR1_outI2_continue函数处理,一般情况下不需要
stf_status r = aggr_id_and_auth(md, TRUE
, aggr_inR1_outI2_continue, kc);
if (r != STF_OK)
return r;
}
// 根据认证类型确定下一载荷是哈希载荷还是RSA签名载荷
auth_payload = st->st_oakley.auth == OAKLEY_PRESHARED_KEY
? ISAKMP_NEXT_HASH : ISAKMP_NEXT_SIG;
/**************** build output packet: HDR, HASH_I/SIG_I **************/
/* HDR out */
{
// 构造ISAKMP头结构
struct isakmp_hdr r_hdr = md->hdr;
// 拷贝响应方的cookie
memcpy(r_hdr.isa_rcookie, st->st_rcookie, COOKIE_SIZE);
/* outputting should back-patch previous struct/hdr with payload type */
// 下一载荷
r_hdr.isa_np = auth_payload;
// 数据是加密
r_hdr.isa_flags |= ISAKMP_FLAG_ENCRYPTION; /* KLUDGE */
// 填充ISAKMP头
if (!out_struct(&r_hdr, &isakmp_hdr_desc, &md->reply, &md->rbody))
return STF_INTERNAL_ERROR;
}
#ifdef NAT_TRAVERSAL
if (st->hidden_variables.st_nat_traversal & NAT_T_WITH_NATD) {
// 填充NATD载荷, 会自动修改前一载荷中的下一载荷字段类型值
if (!nat_traversal_add_natd(auth_payload, &md->rbody, md))
return STF_INTERNAL_ERROR;
}
#endif
/* HASH_I or SIG_I out */
{
u_char buffer[1024];
struct isakmp_ipsec_id id_hd;
chunk_t id_b;
pb_stream id_pbs;
u_char hash_val[MAX_DIGEST_LEN];
size_t hash_len;
// 构造ID载荷
build_id_payload(&id_hd, &id_b, &st->st_connection->spd.this);
init_pbs(&id_pbs, buffer, sizeof(buffer), "identity payload");
id_hd.isaiid_np = ISAKMP_NEXT_NONE;
if (!out_struct(&id_hd, &isakmp_ipsec_identification_desc, &id_pbs, NULL)
|| !out_chunk(id_b, &id_pbs, "my identity"))
return STF_INTERNAL_ERROR;
hash_len = main_mode_hash(st, hash_val, TRUE, &id_pbs);
if (auth_payload == ISAKMP_NEXT_HASH)
{
// 填充哈希载荷
/* HASH_I out */
if (!out_generic_raw(ISAKMP_NEXT_NONE, &isakmp_hash_desc, &md->rbody
, hash_val, hash_len, "HASH_I"))
return STF_INTERNAL_ERROR;
}
else
{
// 填充RSA签名载荷
/* SIG_I out */
u_char sig_val[RSA_MAX_OCTETS];
size_t sig_len = RSA_sign_hash(st->st_connection
, sig_val, hash_val, hash_len);
if (sig_len == 0)
{
loglog(RC_LOG_SERIOUS, "unable to locate my private key for RSA Signature");
return STF_FAIL + AUTHENTICATION_FAILED;
}
if (!out_generic_raw(ISAKMP_NEXT_NONE, &isakmp_signature_desc
, &md->rbody, sig_val, sig_len, "SIG_I"))
return STF_INTERNAL_ERROR;
}
}
/* RFC2408 says we must encrypt at this point */
/* st_new_iv was computed by generate_skeyids_iv */
// 加密消息
if (!encrypt_message(&md->rbody, st))
return STF_INTERNAL_ERROR; /* ??? we may be partly committed */
// 最新的ISAKMP SA的序号
c->newest_isakmp_sa = st->st_serialno;
/* save last IV from phase 1 so it can be restored later so anything
* between the end of phase 1 and the start of phase 2 ie mode config
* payloads etc will not loose our IV
*/
// 保存初始化向量用于第2阶段
memcpy(st->st_ph1_iv, st->st_new_iv, st->st_new_iv_len);
st->st_ph1_iv_len = st->st_new_iv_len;
return STF_OK;
}
14.5 响应方接收到发起方的第2个数据包
// 就是aggr_inI2_tail()的包裹函数
stf_status
aggr_inI2(struct msg_digest *md)
{
return aggr_inI2_tail(md, NULL);
}
// 同样该函数在使用OE进行认证时才用
static void
aggr_inI2_continue(struct adns_continuation *cr, err_t ugh)
{
key_continue(cr, ugh, aggr_inI2_tail);
}
stf_status
aggr_inI2_tail(struct msg_digest *md
, struct key_continuation *kc)
{
struct state *const st = md->st;
struct connection *c = st->st_connection;
u_char buffer[1024];
struct payload_digest id_pd;
#ifdef NAT_TRAVERSAL
// NAT信息查找
if (st->hidden_variables.st_nat_traversal & NAT_T_WITH_NATD) {
nat_traversal_natd_lookup(md);
}
// 输出NAT穿越信息
if (st->hidden_variables.st_nat_traversal) {
nat_traversal_show_result(st->hidden_variables.st_nat_traversal, md->sender_port);
}
// 如果要支持NAT穿越保活, 调度发送保活信息
if (st->hidden_variables.st_nat_traversal & NAT_T_WITH_KA) {
nat_traversal_new_ka_event();
}
#endif
/* Reconstruct the peer ID so the peer hash can be authenticated */
{
// 重构对方的ID载荷来认证对方
struct isakmp_ipsec_id id_hd;
chunk_t id_b;
pb_stream pbs;
pb_stream id_pbs;
// 构造ID载荷
build_id_payload(&id_hd, &id_b, &st->st_connection->spd.that);
init_pbs(&pbs, buffer, sizeof(buffer), "identity payload");
id_hd.isaiid_np = ISAKMP_NEXT_NONE;
// 输出ID载荷
if (!out_struct(&id_hd, &isakmp_ipsec_identification_desc, &pbs, &id_pbs)
|| !out_chunk(id_b, &id_pbs, "my identity"))
return STF_INTERNAL_ERROR;
close_output_pbs(&id_pbs);
id_pbs.roof = pbs.cur;
id_pbs.cur = pbs.start;
// 读取自己构造的对方ID载荷信息
in_struct(&id_pd.payload, &isakmp_identification_desc, &id_pbs, &id_pd.pbs);
}
// ID载荷链表
md->chain[ISAKMP_NEXT_ID] = &id_pd;
/* HASH_I or SIG_I in */
{
// 野蛮模式读取ID载荷和认证处理,如果需要使用OE来认证对方, 则启动OE认证后重新执行
// aggr_inI2_continue函数处理,一般情况下不需要
stf_status r = aggr_id_and_auth(md, FALSE
, aggr_inI2_continue, kc);
// 失败则返回
if (r != STF_OK)
return r;
}
// 认证成功, 建立ISAKMP SA, 准备进入第2阶段
/* And reset the md to not leave stale pointers to our private id payload */
md->chain[ISAKMP_NEXT_ID] = NULL;
/**************** done input ****************/
// 连接当前的最新ISAKMP SA序号
c->newest_isakmp_sa = st->st_serialno;
// 更新初始化向量
update_iv(st); /* Finalize our Phase 1 IV */
/* save last IV from phase 1 so it can be restored later so anything
* between the end of phase 1 and the start of phase 2 ie mode config
* payloads etc will not loose our IV
*/
// 保存初始化向量用于第2阶段
memcpy(st->st_ph1_iv, st->st_new_iv, st->st_new_iv_len);
st->st_ph1_iv_len = st->st_new_iv_len;
DBG(DBG_CONTROL, DBG_log("phase 1 complete"));
return STF_OK;
}
...... 待续 ......