本文档的Copyleft归yfydz所有,使用GPL发布,可以自由拷贝,转载,转载时请保持文档的完整性,严禁用于任何商业用途。
msn: yfydz_no1@hotmail.com
来源: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;
}

...... 待续 ......