本文档的Copyleft归yfydz所有,使用GPL发布,可以自由拷贝,转载,转载时请保持文档的完整性,严禁用于任何商业用途。
msn:
[email protected]
来源: http://yfydz.cublog.cn
13.4 发起方收到响应方第一回应包, 发送第2初始包
/* STATE_MAIN_I1: HDR, SA --> auth dependent
* PSK_AUTH, DS_AUTH: --> HDR, KE, Ni
*
* The following are not yet implemented:
* PKE_AUTH: --> HDR, KE, [ HASH(1), ] <IDi1_b>PubKey_r, <Ni_b>PubKey_r
* RPKE_AUTH: --> HDR, [ HASH(1), ] <Ni_b>Pubkey_r, <KE_b>Ke_i,
* <IDi1_b>Ke_i [,<<Cert-I_b>Ke_i]
*
* We must verify that the proposal received matches one we sent.
*/
// md中包含了所收到数据包的所有信息
stf_status
main_inR1_outI2(struct msg_digest *md)
{
// 相关状态结构
struct state *const st = md->st;
/* verify echoed SA */
{
struct payload_digest *const sapd = md->chain[ISAKMP_NEXT_SA];
// 解析数据包中的SA载荷,失败则返回
RETURN_STF_FAILURE(parse_isakmp_sa_body(&sapd->pbs
, &sapd->payload.sa
, NULL, TRUE, st));
}
#ifdef NAT_TRAVERSAL
DBG(DBG_CONTROLMORE, DBG_log("sender checking NAT-t: %d and %d"
, nat_traversal_enabled
, md->quirks.nat_traversal_vid))
if (nat_traversal_enabled && md->quirks.nat_traversal_vid) {
// 解析NAT穿越方法信息
st->hidden_variables.st_nat_traversal = nat_traversal_vid_to_method(md->quirks.nat_traversal_vid);
openswan_log("enabling possible NAT-traversal with method %s"
, bitnamesof(natt_type_bitnames, st->hidden_variables.st_nat_traversal>>1));
}
#endif
{
// ke: 密钥交换
struct ke_continuation *ke = alloc_thing(struct ke_continuation
, "outI2 KE");
ke->md = md;
// 状态是否已经使用加密处理
if (!st->st_sec_in_use) {
// 未用加密, 现在还是明文, 进行加密准备处理
// pluto密钥请求函数
ke->ke_pcrc.pcrc_func = main_inR1_outI2_continue;
// 相关的消息摘要
st->st_suspended_md = md;
// 密钥交换处理
return build_ke(&ke->ke_pcrc, st, st->st_oakley.group, st->st_import);
} else {
// 否则处理后续部分
return main_inR1_outI2_tail((struct pluto_crypto_req_cont *)ke
, NULL);
}
}
}
/* programs/pluto/crypto_ke.c */
stf_status build_ke(struct pluto_crypto_req_cont *cn
, struct state *st
, const struct oakley_group_desc *group
, enum crypto_importance importance)
{
// pluto加密请求结构
struct pluto_crypto_req *r;
err_t e;
bool toomuch = FALSE;
// 分配空间
r = alloc_thing(struct pluto_crypto_req, "build ke request");
// 结构长度
r->pcr_len = sizeof(struct pluto_crypto_req);
// 加密请求类型: 密钥交换的nonce
r->pcr_type = pcr_build_kenonce;
// 重要性
r->pcr_pcim = importance;
// 密钥交换的nonce结构参数
r->pcr_d.kn.thespace.start = 0;
r->pcr_d.kn.thespace.len = sizeof(r->pcr_d.kn.space);
r->pcr_d.kn.oakley_group = group->group;
cn->pcrc_serialno = st->st_serialno;
// 发送加密请求
e= send_crypto_helper_request(r, cn, &toomuch);
if(e != NULL) {
// 加密失败
loglog(RC_LOG_SERIOUS, "can not start crypto helper: %s", e);
if(toomuch) {
return STF_TOOMUCHCRYPTO;
} else {
return STF_FAIL;
}
} else if(!toomuch) {
// 加密任务处理繁忙,先挂起,等待重新调度
st->st_calculating = TRUE;
delete_event(st);
event_schedule(EVENT_CRYPTO_FAILED, EVENT_CRYPTO_FAILED_DELAY, st);
return STF_SUSPEND;
} else {
/* we must have run the continuation directly, so
* complete_state_transition already got called.
*/
// 成功, 而且内部已经进行了complete_state_transition()处理了
return STF_INLINE;
}
}
/* programs/pluto/pluto_crypt.c */
err_t send_crypto_helper_request(struct pluto_crypto_req *r
, struct pluto_crypto_req_cont *cn
, bool *toomuch)
{
struct pluto_crypto_worker *w;
int cnt;
/* do it all ourselves? */
if(pc_workers == NULL) {
// 一般情况下都会进入此处
reset_cur_state();
// 计算nonce
pluto_do_crypto_op(r);
/* call the continuation */
// 调用pluto密钥请求函数, 如main_inR1_outI2_continue()
(*cn->pcrc_func)(cn, r, NULL);
/* indicate that we did everything ourselves */
*toomuch = TRUE;
// 释放资源
pfree(cn);
pfree(r);
// NULL表示成功
return NULL;
}
// 以下代码忽略
......
}
// 继续
static void
main_inR1_outI2_continue(struct pluto_crypto_req_cont *pcrc
, struct pluto_crypto_req *r
, err_t ugh)
{
// ke结构实际就是pcrc和md的组合
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("main inR1_outI2: calculated ke+nonce, sending I2"));
/* 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;
// 完成接收R1发出I2处理
e = main_inR1_outI2_tail(pcrc, r);
// 这个条件基本应该都是真
if(ke->md != NULL) {
// 完成状态转移处理, 发送数据包
complete_state_transition(&ke->md, e);
// 释放消息摘要
release_md(ke->md);
}
reset_cur_state();
}
/* STATE_MAIN_I1: HDR, SA --> auth dependent
* PSK_AUTH, DS_AUTH: --> HDR, KE, Ni
*
* The following are not yet implemented:
* PKE_AUTH: --> HDR, KE, [ HASH(1), ] <IDi1_b>PubKey_r, <Ni_b>PubKey_r
* RPKE_AUTH: --> HDR, [ HASH(1), ] <Ni_b>Pubkey_r, <KE_b>Ke_i,
* <IDi1_b>Ke_i [,<<Cert-I_b>Ke_i]
*
* We must verify that the proposal received matches one we sent.
*/
// 结尾操作
static stf_status
main_inR1_outI2_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;
/**************** build output packet HDR;KE;Ni ****************/
// 初始化要发送的数据包包缓冲区
init_pbs(&md->reply, reply_buffer, sizeof(reply_buffer), "reply packet");
/* HDR out.
* We can't leave this to comm_handle() because the isa_np
* depends on the type of Auth (eventually).
*/
// 根据输入的数据包头的ISAKMP头结构复制到回应包, 下一载荷是KE
echo_hdr(md, FALSE, ISAKMP_NEXT_KE);
/* KE out */
// 输出KE载荷, st_gi是发起方的公共信息
if (!ship_KE(st, r , &st->st_gi
, &md->rbody, ISAKMP_NEXT_NONCE))
return STF_INTERNAL_ERROR;
#ifdef DEBUG
/* Ni out */
if (!ship_nonce(&st->st_ni, r, &md->rbody
, (cur_debugging & IMPAIR_BUST_MI2)? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE
, "Ni"))
return STF_INTERNAL_ERROR;
if (cur_debugging & IMPAIR_BUST_MI2)
{
/* generate a pointless large VID payload to push message over MTU */
pb_stream vid_pbs;
if (!out_generic(ISAKMP_NEXT_NONE, &isakmp_vendor_id_desc, &md->rbody
, &vid_pbs))
return STF_INTERNAL_ERROR;
if (!out_zero(1500 /*MTU?*/, &vid_pbs, "Filler VID"))
return STF_INTERNAL_ERROR;
close_output_pbs(&vid_pbs);
}
#else
/* Ni out */
// 输出NONCE载荷
if (!ship_nonce(&st->st_ni, r, &md->rbody, ISAKMP_NEXT_NONE, "Ni"))
return STF_INTERNAL_ERROR;
#endif
#ifdef NAT_TRAVERSAL
if (st->hidden_variables.st_nat_traversal & NAT_T_WITH_NATD) {
// NAT穿越信息
if (!nat_traversal_add_natd(ISAKMP_NEXT_NONE, &md->rbody, md))
return STF_INTERNAL_ERROR;
}
#endif
/* finish message */
// 封包结束
close_message(&md->rbody);
/* Reinsert the state, using the responder cookie we just received */
// 现在已经获取了对方的cookie, 将当前状态从状态哈希表中断开(原先是按空cookie哈希的),
// 保存对方cookie, 重新插入合适的哈希表
unhash_state(st);
memcpy(st->st_rcookie, md->hdr.isa_rcookie, COOKIE_SIZE);
insert_state(st); /* needs cookies, connection, and msgid (0) */
return STF_OK;
}
/*
* package up the calculate KE value, and emit it as a KE payload.
*/
// 输出密钥交换KE载荷
bool
ship_KE(struct state *st
, struct pluto_crypto_req *r
, chunk_t *g
, pb_stream *outs, u_int8_t np)
{
// KE的NONCE结构
struct pcr_kenonce *kn = &r->pcr_d.kn;
// 如果状态还没开始加密
if (!st->st_sec_in_use)
{
// 设置状态开始进行加密标志, 以后该状态所发出的数据包都将是加密的
st->st_sec_in_use = TRUE;
// 释放数据块链表g
freeanychunk(*g); /* happens in odd error cases */
// 复制NONCE
clonetochunk(*g, wire_chunk_ptr(kn, &(kn->gi))
, kn->gi.len, "saved gi value");
// st_sec: 本地密钥信息
// 对网络数据加密
n_to_mpz(&st->st_sec
, wire_chunk_ptr(kn, &(kn->secret))
, kn->secret.len);
// 加密后数据复制到st_sec_chunk
clonetochunk(st->st_sec_chunk
, wire_chunk_ptr(kn, &(kn->secret))
, kn->secret.len, "long term secret");
}
// 输出ISAKMP密钥交换载荷到缓冲区
return out_generic_chunk(np, &isakmp_keyex_desc, outs, *g, "keyex value");
}
// 输出NONCE载荷
bool
ship_nonce(chunk_t *n, struct pluto_crypto_req *r
, pb_stream *outs, u_int8_t np
, const char *name)
{
// KE的NONCE结构
struct pcr_kenonce *kn = &r->pcr_d.kn;
// 释放数据块链表
freeanychunk(*n);
// 复制初始NONCE数据块
clonetochunk(*n, wire_chunk_ptr(kn, &(kn->n))
, DEFAULT_NONCE_SIZE, "initiator nonce");
// 输出NONCE载荷到数据包缓冲区
return out_generic_chunk(np, &isakmp_nonce_desc, outs, *n, name);
}
13.5 响应方收到发送方第2初始化包, 发送第2响应包
处理和inR1_outI2类似, 如果状态没进行加密, 会进行加密请求然后continue和tail处理, 否则直接tail处理。
/* STATE_MAIN_R1:
* PSK_AUTH, DS_AUTH: HDR, KE, Ni --> HDR, KE, Nr
*
* The following are not yet implemented:
* PKE_AUTH: HDR, KE, [ HASH(1), ] <IDi1_b>PubKey_r, <Ni_b>PubKey_r
* --> HDR, KE, <IDr1_b>PubKey_i, <Nr_b>PubKey_i
* RPKE_AUTH:
* HDR, [ HASH(1), ] <Ni_b>Pubkey_r, <KE_b>Ke_i, <IDi1_b>Ke_i [,<<Cert-I_b>Ke_i]
* --> HDR, <Nr_b>PubKey_i, <KE_b>Ke_r, <IDr1_b>Ke_r
*/
stf_status
main_inI2_outR2(struct msg_digest *md)
{
// 状态
struct state *const st = md->st;
// I2数据包中的KE载荷
pb_stream *keyex_pbs = &md->chain[ISAKMP_NEXT_KE]->pbs;
/* 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"));
/* decode certificate requests */
// 解码证书
decode_cr(md, &st->st_connection->requested_ca);
// 状态是否已经获取证书
if(st->st_connection->requested_ca != NULL)
{
st->hidden_variables.st_got_certrequest = TRUE;
}
#ifdef NAT_TRAVERSAL
DBG(DBG_CONTROLMORE
, DBG_log("inI2: checking NAT-t: %d and %d"
, nat_traversal_enabled
, st->hidden_variables.st_nat_traversal));
// 检查NAT穿越信息
if (st->hidden_variables.st_nat_traversal & NAT_T_WITH_NATD) {
nat_traversal_natd_lookup(md);
}
if (st->hidden_variables.st_nat_traversal) {
// 显示NAT处理结果
nat_traversal_show_result(st->hidden_variables.st_nat_traversal
, md->sender_port);
}
if (st->hidden_variables.st_nat_traversal & NAT_T_WITH_KA) {
nat_traversal_new_ka_event();
}
#endif
{
// 分配KE结构
struct ke_continuation *ke = alloc_thing(struct ke_continuation
, "inI2_outR2 KE");
ke->md = md;
st->st_suspended_md = md;
// 如果状态还未加密
if (!st->st_sec_in_use) {
// 进行相关的加密初始化, 建立KE操作
ke->ke_pcrc.pcrc_func = main_inI2_outR2_continue;
return build_ke(&ke->ke_pcrc, st
, st->st_oakley.group, st->st_import);
} else {
// 否则状态已经处于加密状态, 执行tail操作
return main_inI2_outR2_tail((struct pluto_crypto_req_cont *)ke
, NULL);
}
}
}
// 继续操作
static void
main_inI2_outR2_continue(struct pluto_crypto_req_cont *pcrc
, struct pluto_crypto_req *r
, err_t ugh)
{
// KE结构
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("main inI2_outR2: calculated ke+nonce, sending R2"));
/* 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;
// 完成接收I1发出R2处理
e = main_inI2_outR2_tail(pcrc, r);
// 这个条件基本应该都是真
if(ke->md != NULL) {
// 完成状态转移操作, 发送数据包
complete_state_transition(&ke->md, e);
// 释放消息摘要结构
release_md(ke->md);
}
reset_cur_state();
}
// inI2_outR2结尾操作
stf_status
main_inI2_outR2_tail(struct pluto_crypto_req_cont *pcrc
, struct pluto_crypto_req *r)
{
// KE结构
struct ke_continuation *ke = (struct ke_continuation *)pcrc;
// 消息摘要
struct msg_digest *md = ke->md;
// 状态
struct state *st = md->st;
int next_payload;
/* send CR if auth is RSA and no preloaded RSA public key exists*/
// 是否发送证书标志
bool send_cr = FALSE;
/**************** build output packet HDR;KE;Nr ****************/
// 发送证书需要以下条件
// 配置中允许发送证书
send_cr = !no_cr_send
// 认证为RSA签名
&& (st->st_oakley.auth == OAKLEY_RSA_SIG)
// 没有预先加载的公钥
&& !has_preloaded_public_key(st)
// 连接配置中对方CA非空
&& st->st_connection->spd.that.ca.ptr != NULL;
/* HDR out done */
/* KE out */
// 输出KE载荷
if (!ship_KE(st, r, &st->st_gr
, &md->rbody, ISAKMP_NEXT_NONCE))
{
abort();
return STF_INTERNAL_ERROR;
}
#ifdef DEBUG
/* Nr out */
next_payload = ISAKMP_NEXT_NONE;
if(cur_debugging & IMPAIR_BUST_MR2)
{
next_payload = ISAKMP_NEXT_VID;
}
if(send_cr)
{
next_payload = ISAKMP_NEXT_CR;
}
if (!ship_nonce(&st->st_nr, r
, &md->rbody
, next_payload
, "Nr"))
return STF_INTERNAL_ERROR;
if (cur_debugging & IMPAIR_BUST_MR2)
{
/* generate a pointless large VID payload to push message over MTU */
pb_stream vid_pbs;
if (!out_generic((send_cr)? ISAKMP_NEXT_CR : ISAKMP_NEXT_NONE,
&isakmp_vendor_id_desc, &md->rbody, &vid_pbs))
return STF_INTERNAL_ERROR;
if (!out_zero(1500 /*MTU?*/, &vid_pbs, "Filler VID"))
return STF_INTERNAL_ERROR;
close_output_pbs(&vid_pbs);
}
#else
/* Nr out */
// 输出NONCE载荷
if (!ship_nonce(&st->st_nr
, &md->rbody, r
, (send_cr)? ISAKMP_NEXT_CR : ISAKMP_NEXT_NONE
, "Nr"))
return STF_INTERNAL_ERROR;
#endif
/* CR out */
// 是否发送证书
if (send_cr)
{
// 如果连接是永久性连接(双方地址固定)
if (st->st_connection->kind == CK_PERMANENT)
{
// 输出证书载荷
if (!build_and_ship_CR(CERT_X509_SIGNATURE
, st->st_connection->spd.that.ca
, &md->rbody, ISAKMP_NEXT_NONE))
return STF_INTERNAL_ERROR;
}
else
{
// 非永久连接, 如动态连接
generalName_t *ca = NULL;
// 查找所有可用的候选CA证书
if (collect_rw_ca_candidates(md, &ca))
{
generalName_t *gn;
// 遍历可用证书
for (gn = ca; gn != NULL; gn = gn->next)
{
// 输出单一证书载荷
if (!build_and_ship_CR(CERT_X509_SIGNATURE, gn->name
, &md->rbody
, gn->next == NULL ? ISAKMP_NEXT_NONE : ISAKMP_NEXT_CR))
return STF_INTERNAL_ERROR;
}
free_generalNames(ca, FALSE);
}
else
{
// 无可用证书, 输出空证书载荷
if (!build_and_ship_CR(CERT_X509_SIGNATURE, empty_chunk
, &md->rbody, ISAKMP_NEXT_NONE))
return STF_INTERNAL_ERROR;
}
}
}
#ifdef NAT_TRAVERSAL
// 输出NAT穿越信息
if (st->hidden_variables.st_nat_traversal & NAT_T_WITH_NATD) {
if (!nat_traversal_add_natd(ISAKMP_NEXT_NONE, &md->rbody, md))
return STF_INTERNAL_ERROR;
}
#endif
/* finish message */
// 结束信息
close_message(&md->rbody);
/*
* next message will be encrypted, so, we need to have
* the DH value calculated. We can do this in the background,
* sending the reply right away. We have to be careful on the next
* state, since the other end may reply faster than we can calculate
* things. If it is the case, then the packet is placed in the
* continuation, and we let the continuation process it. If there
* is a retransmit, we keep only the last packet.
*
* Also, note that this is not a suspended state, since we are
* actually just doing work in the background.
*
*/
{
/* Looks like we missed perform_dh() declared at
* programs/pluto/pluto_crypt.h as external and implemented nowhere.
* Following code regarding dh_continuation allocation seems useless
* as it's never used. At least, we should free it.
*/
// 以下进行DH交换的计算
// 分配DH结构
struct dh_continuation *dh = alloc_thing(struct dh_continuation
, "main_inI2_outR2_tail");
// DH结构相关状态和处理函数
dh->st = st;
dh->dh_pcrc.pcrc_func = main_inI2_outR2_calcdone;
passert(st->st_suspended_md == NULL);
// 奇怪的是以下操作和dh结构无关
// DH密钥初始化向量计算
(void)perform_dh_secretiv(st, RESPONDER, st->st_oakley.group->group);
update_iv(st);
// 释放dh结构
pfree(dh); dh = NULL;
}
return STF_OK;
}
/* accept_ke
*
* Check and accept DH public value (Gi or Gr) from peer's message.
* According to RFC2409 "The Internet key exchange (IKE)" 5:
* The Diffie-Hellman public value passed in a KE payload, in either
* a phase 1 or phase 2 exchange, MUST be the length of the negotiated
* Diffie-Hellman group enforced, if necessary, by pre-pending the
* value with zeros.
*/
// 获取密钥交换载荷
notification_t
accept_KE(chunk_t *dest, const char *val_name
, const struct oakley_group_desc *gr
, pb_stream *pbs)
{
// 检查数据长度是否正确
if (pbs_left(pbs) != gr->bytes)
{
loglog(RC_LOG_SERIOUS, "KE has %u byte DH public value; %u required"
, (unsigned) pbs_left(pbs), (unsigned) gr->bytes);
/* XXX Could send notification back */
return INVALID_KEY_INFORMATION;
}
// 拷贝KE载荷
clonereplacechunk(*dest, pbs->cur, pbs_left(pbs), val_name);
// 打印载荷具体数据
DBG_cond_dump_chunk(DBG_CRYPT, "DH public value received:\n", *dest);
return NOTHING_WRONG;
}
// 解析NONCE载荷
notification_t
accept_nonce(struct msg_digest *md, chunk_t *dest, const char *name)
{
// NONCE载荷链表
pb_stream *nonce_pbs = &md->chain[ISAKMP_NEXT_NONCE]->pbs;
// 数据长度
size_t len = pbs_left(nonce_pbs);
// 检查长度是否在合适范围内
if (len < MINIMUM_NONCE_SIZE || MAXIMUM_NONCE_SIZE < len)
{
loglog(RC_LOG_SERIOUS, "%s length not between %d and %d"
, name , MINIMUM_NONCE_SIZE, MAXIMUM_NONCE_SIZE);
return PAYLOAD_MALFORMED; /* ??? */
}
// 拷贝NONCE载荷数据
clonereplacechunk(*dest, nonce_pbs->cur, len, "nonce");
return NOTHING_WRONG;
}
...... 待续 ......