IKEv2协议协商流程: (IKE-SA-INIT 交换)第二包

1. IKEv2 协商总体框架

IKEv1协议建立一对IPSec SA,使用主动模式需要9个报文,使用野蛮模式需要使用6个报文方能协商成功。IKEv2对IKEv1协议进行了优化,IKEv2只需要进行两次交互,使用 4 条消息就可以完成一个 IKEv2 SA 和一对 IPsec SA 的协商建立。IKEv2 定义了三种交互:

  • 初始交换

  • 创建子 SA 交换

  • 通知交换

    下图简单介绍一下 IKEv2 协商过程中的初始交换过程,之后我们将对ikev2_parent_inI1outR1()接口相关的处理流程做一个简单说明。

初始化交换通过两次交换共4个报文便可以完成一对IKE SA和IPSec SA的协商。上图主要用来描述协商报文的内容和对应的处理函数入口。下图则是用来说明各接口对应的协商状态。协商过程中是根据该状态来确定当前的协商阶段。

RFC文档中的报文格式:

  1. Initiator Responder
  2. -------------------------------------------------------------------
  3. HDR, SAi1, KEi, Ni -->
  4. <-- HDR, SAr1, KEr, Nr, [CERTREQ]
  5. HDR, SK {IDi, [CERT,] [CERTREQ,]
  6. [IDr,] AUTH, SAi2,
  7. TSi, TSr} -->
  8. <-- HDR, SK {IDr, [CERT,] AUTH,
  9. SAr2, TSi, TSr}

其中:

报文字段 说明
HDR 报文头部
SAi1、SAr1 IKE SA建议
SAi2、SAr2 IPSEC SA建议载荷
KEi、KEr DH算法公共值
Ni、Nr Nonce随机数
CERT、CERTREQ 证书载荷、证书请求载荷
IDi、IDr ID载荷
TSi、TSr 流量选择器,使用此载荷完成保护子网的协商
AUTH 认证数据载荷

这里面需要说明的是:报文中的SK并不是一个载荷。而是:SK {…}表示里面的内容被加密和认证保护。

下面对响应端对发起端第一包的处理流程做一个详细说明。入口函数为:ikev2_parent_inI1outR1()

2. 第二包流程图

3. openswan源码学习

3.1 ikev2parent_inI1outR1()

此函数是IKEv2协议 响应端开始协商的入口函数。主要功能包括:

  • 根据收到报文四元组(IP和端口)查找连接:c
  • 新建一个协商状态结构:state
  • 根据发起端的地址等信息生成Cookie值
  • 将连接上的参数信息、配置信息初始化state结构上参数
    • 隧道本端IP和端口
    • 隧道对端IP和端口
    • 隧道的出接口
    • 配置策略
    • … …
  • 抗重放检测(Cookie challenge)
    • 根据发起端IP、SPI、Nonce计算用于抗重放的cookie
    • 如果报文中包含KE和Cookie类型的通知载荷
      • 比较两端的cookie是否一致
    • 如果报文中不包含Cookie类型的通知载荷
      • 发送携带cookie的通知报文,使发起端重新开始协商
  • 解析报文中的KE载荷,获取到DH组信息
    • DH组猜测成功,则计算DH算法的公共值,用于构建响应报文的KE载荷
  1. static stf_status
  2. ikev2_parent_inI1outR1_tail(struct pluto_crypto_req_cont *pcrc
  3. , struct pluto_crypto_req *r);
  4. stf_status ikev2parent_inI1outR1(struct msg_digest *md)
  5. {
  6. struct state *st = md->st;
  7. lset_t policy = POLICY_IKEV2_ALLOW;
  8. lset_t policy_hint = LEMPTY;
  9. /*
  10. * 根据隧道两端协商地址和端口来查找连接
  11. */
  12. struct connection *c = find_host_connection(ANY_MATCH, &md->iface->ip_addr
  13. , md->iface->port
  14. , KH_IPADDR
  15. , &md->sender
  16. , md->sender_port
  17. , POLICY_IKEV2_ALLOW, LEMPTY, &policy_hint);
  18. if(c==NULL) {/*连接查找失败则提示相应的错误信息*/
  19. if(policy_hint & POLICY_IKEV2_ALLOW) {
  20. /* connection not found, because IKEv2 was not allowed */
  21. /* send back AUTHENTICATION_FAILED per WG mailing list discussion */
  22. openswan_log("connection refused, IKEv2 not authorized");
  23. return STF_FAIL + v2N_AUTHENTICATION_FAILED;
  24. }
  25. /*
  26. * be careful about responding, or logging, since it may be that we
  27. * are under DOS
  28. */
  29. DBG_log("no connection with matching policy found\n");
  30. return STF_FAIL + v2N_AUTHENTICATION_FAILED;
  31. }
  32. loglog(RC_COMMENT, "tentatively considering connection: %s\n", c ? c->name : "<none>");
  33. if(!st) {/*如果没有对应的状态,则新建一个state*/
  34. st = new_state();
  35. /* set up new state */
  36. memcpy(st->st_icookie, md->hdr.isa_icookie, COOKIE_SIZE);
  37. /* initialize_new_state expects valid icookie/rcookie values, so create it now */
  38. /*相应方根据发起方的地址信息、当前时间生成一个cookie*/
  39. get_cookie(FALSE, st->st_rcookie, COOKIE_SIZE, &md->sender);
  40. initialize_new_state(st, c, policy, 0, NULL_FD, pcim_stranger_crypto);
  41. st->st_ikev2 = TRUE;
  42. st->st_localaddr = md->iface->ip_addr;
  43. st->st_localport = md->iface->port;
  44. st->st_remoteaddr = md->sender;
  45. st->st_remoteport = md->sender_port;
  46. st->st_ike_maj = md->maj;
  47. st->st_ike_min = md->min;
  48. change_state(st, STATE_PARENT_R1);
  49. md->st = st;
  50. md->from_state = STATE_IKEv2_BASE;
  51. md->transition_state = st;
  52. }
  53. /* check,as a responder, are we under dos attack or not
  54. * if yes go to 6 message exchange mode. it is a config option for now.
  55. * TBD set force_busy dynamically
  56. * Paul: Can we check for STF_TOOMUCHCRYPTO ?
  57. */
  58. if(force_busy == TRUE)/*开启抗重放!!!!!!!!*/
  59. {
  60. u_char dcookie[SHA1_DIGEST_SIZE];
  61. chunk_t dc;
  62. /*计算用于cookie challenge的cookie值*/
  63. ikev2_get_dcookie( dcookie, st->st_ni, &md->sender, st->st_icookie);
  64. dc.ptr = dcookie;
  65. dc.len = SHA1_DIGEST_SIZE;/*20bytes*/
  66. /* check if I1 packet contian KE and a v2N payload with type COOKIE */
  67. /*报文格式??? : HDR + NOTIF + KE*/
  68. if ( md->chain[ISAKMP_NEXT_v2KE] && md->chain[ISAKMP_NEXT_v2N] &&
  69. (md->chain[ISAKMP_NEXT_v2N]->payload.v2n.isan_type == v2N_COOKIE))
  70. {/*对方的协商报文中包含了cookie*/
  71. /*
  72. * ISAKMP_NEXT_v2N : IKEv2 通知载荷
  73. * ISAKMP_NEXT_v2Ni : 发起端Nonce载荷
  74. * ISAKMP_NEXT_v2Nr : 接收端Nonce载荷
  75. */
  76. u_int8_t spisize;
  77. const pb_stream *dc_pbs;
  78. chunk_t blob;
  79. DBG(DBG_CONTROLMORE
  80. , DBG_log("received a DOS cookie in I1 verify it"));
  81. /* we received dcookie we send earlier verify it */
  82. spisize = md->chain[ISAKMP_NEXT_v2N]->payload.v2n.isan_spisize;
  83. dc_pbs = &md->chain[ISAKMP_NEXT_v2N]->pbs;
  84. blob.ptr = dc_pbs->cur + spisize;
  85. blob.len = pbs_left(dc_pbs) - spisize;
  86. DBG(DBG_CONTROLMORE
  87. ,DBG_dump_chunk("dcookie received in I1 Packet", blob);
  88. DBG_dump("dcookie computed", dcookie, SHA1_DIGEST_SIZE));
  89. /*检查收到的cookie和本端发送的cookie是否一致!!!*/
  90. if(memcmp(blob.ptr, dcookie, SHA1_DIGEST_SIZE)!=0) {
  91. openswan_log("mismatch in DOS v2N_COOKIE,send a new one");
  92. SEND_V2_NOTIFICATION_DATA(md, st, v2N_COOKIE, &dc);
  93. return STF_FAIL + v2N_INVALID_IKE_SPI;
  94. }
  95. DBG(DBG_CONTROLMORE
  96. ,DBG_log("dcookie received match with computed one"));
  97. }
  98. else/*收到的报文中并不包含COOKIE载荷,因此需要发起cookie challenge*/
  99. {/*COOKIE challenge通知载荷发送*/
  100. /* we are under DOS attack I1 contains no DOS COOKIE */
  101. DBG(DBG_CONTROLMORE
  102. ,DBG_log("busy mode on. receieved I1 without a valid dcookie");
  103. DBG_log("send a dcookie and forget this state"));
  104. SEND_V2_NOTIFICATION_DATA(md, st, v2N_COOKIE, &dc);
  105. return STF_FAIL;
  106. }
  107. }
  108. else {
  109. DBG(DBG_CONTROLMORE ,DBG_log("will not send/process a dcookie"));
  110. }
  111. /*
  112. * If we did not get a KE payload, we cannot continue. There should be
  113. * a Notify telling us why. We inform the user, but continue to try this
  114. * connection via regular retransmit intervals.
  115. */
  116. if(md->chain[ISAKMP_NEXT_v2N] && (md->chain[ISAKMP_NEXT_v2KE] == NULL))
  117. {
  118. const char *from_state_name = enum_name(&state_names, st->st_state);
  119. const u_int16_t isan_type = md->chain[ISAKMP_NEXT_v2N]->payload.v2n.isan_type;
  120. openswan_log("%s: received %s"
  121. , from_state_name
  122. , enum_name(&ikev2_notify_names, isan_type));
  123. return STF_FAIL + isan_type;
  124. } else if( md->chain[ISAKMP_NEXT_v2N]) {
  125. /* XXX/SML: KE payload came with a notification-- is there a problem? */
  126. DBG(DBG_CONTROL,DBG_log("received a notify.."));
  127. }
  128. /*
  129. * We have to agree to the DH group before we actually know who
  130. * we are talking to. If we support the group, we use it.
  131. *
  132. * It is really too hard here to go through all the possible policies
  133. * that might permit this group. If we think we are being DOS'ed
  134. * then we should demand a cookie.
  135. */
  136. {
  137. struct ikev2_ke *ke;
  138. if (md->chain[ISAKMP_NEXT_v2KE] == NULL)
  139. return STF_FAIL;
  140. ke = &md->chain[ISAKMP_NEXT_v2KE]->payload.v2ke;
  141. /*KE载荷中包含DH GROUP信息*/
  142. st->st_oakley.group=lookup_group(ke->isak_group);/*查找DH GROUP,并存储在st->st_oakley上*/
  143. if(st->st_oakley.group==NULL) {
  144. char fromname[ADDRTOT_BUF];
  145. addrtot(&md->sender, 0, fromname, ADDRTOT_BUF);
  146. openswan_log("rejecting I1 from %s:%u, invalid DH group=%u"
  147. ,fromname, md->sender_port, ke->isak_group);
  148. return v2N_INVALID_KE_PAYLOAD;
  149. }
  150. }
  151. /* now. we need to go calculate the nonce, and the KE */
  152. {
  153. struct ke_continuation *ke = alloc_thing(struct ke_continuation
  154. , "ikev2_inI1outR1 KE");
  155. stf_status e;
  156. ke->md = md;
  157. set_suspended(st, ke->md);
  158. if (!st->st_sec_in_use) {
  159. pcrc_init(&ke->ke_pcrc);
  160. ke->ke_pcrc.pcrc_func = ikev2_parent_inI1outR1_continue;
  161. e = build_ke(&ke->ke_pcrc, st, st->st_oakley.group, pcim_stranger_crypto);
  162. if(e != STF_SUSPEND && e != STF_INLINE) {
  163. loglog(RC_CRYPTOFAILED, "system too busy");
  164. delete_state(st);
  165. }
  166. } else {
  167. e = ikev2_parent_inI1outR1_tail((struct pluto_crypto_req_cont *)ke
  168. , NULL);
  169. }
  170. reset_globals();
  171. return e;
  172. }
  173. }

3.2 ikev2parent_inI1outR1_tail()

此函数最主要的功能就是构建应答报文。具体的步骤包括如下几个方面:

  • 保存对端发送的协商报文,用于后续认证操作
  • 解析协商报文中的通知载荷
    • NAT-D
    • error information
    • … …
  • 构建IKEv2报文头部
  • 构建SA建议载荷
    • 将本地配置策略生成并转换为ikev2 SADB
    • 解析对端的SA载荷中所有的建议载荷
    • 使用排列组合匹配本地的SADB算法信息
  • 解析对端KE载荷
  • 解析对端Nonce载荷。
  • 构建KE载荷
  • 构建Nonce载荷
  • 构建NAT-D载荷
  • 保存当前报文供后续的认证等操作
  • 发送报文
  1. static stf_status
  2. ikev2_parent_inI1outR1_tail(struct pluto_crypto_req_cont *pcrc
  3. , struct pluto_crypto_req *r)
  4. {
  5. struct ke_continuation *ke = (struct ke_continuation *)pcrc;
  6. struct msg_digest *md = ke->md;
  7. struct payload_digest *const sa_pd = md->chain[ISAKMP_NEXT_v2SA];
  8. struct state *const st = md->st;
  9. stf_status notok;
  10. int numvidtosend=0;
  11. #ifdef PLUTO_SENDS_VENDORID
  12. numvidtosend++; /* we send Openswan VID */
  13. #endif
  14. if (sa_pd == NULL) {
  15. return STF_FAIL;
  16. }
  17. /* note that we don't update the state here yet */
  18. /* record first packet for later checking of signature */
  19. clonetochunk(st->st_firstpacket_him, md->message_pbs.start
  20. , pbs_offset(&md->message_pbs), "saved first received packet");
  21. /*
  22. * verify the NAT DETECTION notify messages before answering.
  23. * on the responder side, this allows us to detect when *we* are behind
  24. * at NAPT (probably with a port-forward).
  25. *
  26. * If we are, then we set a bit saying so, which later on will make us pick the
  27. * UDP encapsulation for packets. It is up to the initiator to switch ports
  28. * from 500 to 4500. Could be they have already done so, we do not care here.
  29. */
  30. if(md->chain[ISAKMP_NEXT_v2N]) {/*处理通知载荷,其中包括NAT-D探测*/
  31. ikev2_process_notifies(st, md);
  32. }
  33. /* make sure HDR is at start of a clean buffer */
  34. zero(reply_buffer);
  35. init_pbs(&reply_stream, reply_buffer, sizeof(reply_buffer), "reply packet");
  36. /* HDR out */
  37. {
  38. struct isakmp_hdr r_hdr = md->hdr;
  39. memcpy(r_hdr.isa_rcookie, st->st_rcookie, COOKIE_SIZE);
  40. r_hdr.isa_version = IKEv2_MAJOR_VERSION << ISA_MAJ_SHIFT | IKEv2_MINOR_VERSION;
  41. r_hdr.isa_np = ISAKMP_NEXT_v2SA;
  42. r_hdr.isa_flags = ISAKMP_FLAGS_R|IKEv2_ORIG_INITIATOR_FLAG(st);
  43. r_hdr.isa_msgid = st->st_msgid;
  44. if (!out_struct(&r_hdr, &isakmp_hdr_desc, &reply_stream, &md->rbody))
  45. return STF_INTERNAL_ERROR;
  46. }
  47. /* start of SA out */
  48. {
  49. struct ikev2_sa r_sa = sa_pd->payload.v2sa;/*收到的报文中的SA头部信息*/
  50. v2_notification_t rn;
  51. pb_stream r_sa_pbs;
  52. r_sa.isasa_np = ISAKMP_NEXT_v2KE; /* XXX */
  53. if (!out_struct(&r_sa, &ikev2_sa_desc, &md->rbody, &r_sa_pbs))
  54. return STF_INTERNAL_ERROR;
  55. /* SA body in and out *//*解析对方的SA建议载荷,并将选择的建议载荷填充到r_sa_pbs中*/
  56. rn = ikev2_parse_parent_sa_body(&sa_pd->pbs, &sa_pd->payload.v2sa,
  57. &r_sa_pbs, st, FALSE);
  58. if (rn != v2N_NOTHING_WRONG)
  59. return STF_FAIL + rn;
  60. }
  61. /*解析对端的KE载荷,存储在st_gi中*/
  62. if((notok = accept_v2_KE(md, st, &st->st_gi, "Gi"))!=STF_OK) {
  63. return notok;
  64. }
  65. /* Ni in *//*解析对端的Nonce载荷,存储在st_ni中*/
  66. RETURN_STF_FAILURE(accept_v2_nonce(md, &st->st_ni, "Ni"));
  67. /* send KE *//*填充KE*/
  68. if(!ship_v2KE(st, r, &st->st_gr, &md->rbody, ISAKMP_NEXT_v2Nr))
  69. return STF_INTERNAL_ERROR;
  70. /* send NONCE *//*填充Nonce*/
  71. unpack_nonce(&st->st_nr, r);
  72. if(!justship_v2Nonce(st, &md->rbody, &st->st_nr, 0)) {
  73. return STF_INTERNAL_ERROR;
  74. }
  75. if(!justship_v2nat(st, &md->rbody)) {/*填充NAT-D*/
  76. return STF_INTERNAL_ERROR;
  77. }
  78. /* Send VendrID if needed VID */
  79. {
  80. pbs_set_np(&md->rbody, ISAKMP_NEXT_v2V);
  81. if (!out_generic_raw(0, &isakmp_vendor_id_desc, &md->rbody
  82. , pluto_vendorid, strlen(pluto_vendorid), "Vendor ID"))
  83. return STF_INTERNAL_ERROR;
  84. }
  85. close_message(&md->rbody);
  86. close_output_pbs(&reply_stream);
  87. /* let TCL hack it before we mark the length. */
  88. TCLCALLOUT("v2_avoidEmitting", st, st->st_connection, md);
  89. /* keep it for a retransmit if necessary */
  90. freeanychunk(st->st_tpacket);
  91. clonetochunk(st->st_tpacket, reply_stream.start, pbs_offset(&reply_stream)
  92. , "reply packet for ikev2_parent_inI1outR1_tail")
  93. /* save packet for later signing */
  94. freeanychunk(st->st_firstpacket_me);
  95. clonetochunk(st->st_firstpacket_me, reply_stream.start
  96. , pbs_offset(&reply_stream), "saved first packet");
  97. /* while waiting for initiator to continue, arrange to die if nothing happens */
  98. delete_event(st);
  99. event_schedule(EVENT_SO_DISCARD, 300, st);
  100. return STF_OK;
  101. }

3.3 ikev2_parse_parent_sa_body()

该函数主要的作用是解析协商报文中的SA建议载荷,并从中选择本地支持的算法进行协商。

主要流程如下

  • 根据配置的SA建议载荷转换为SADB结构
  • 将SADB结构转换为IKEv2的SA结构
  • 解析报文中的SA载荷
  • 将报文SA中的算法进行排列组合, 并与本地SADB中的算法进行匹配
    • 加密算法
    • 完整性哈希算法
    • PRF哈希算法
    • DH算法
  • 根据算法标识获取算法详细参数,并将其存储在state上
  • 如果为响应端
    • 将选中的算法填充到报文SA载荷中
  1. v2_notification_t
  2. ikev2_parse_parent_sa_body(
  3. pb_stream *sa_pbs, /* body of input SA Payload */
  4. const struct ikev2_sa *sa_prop UNUSED, /* header of input SA Payload */
  5. pb_stream *r_sa_pbs, /* if non-NULL, where to emit winning SA */
  6. struct state *st, /* current state object */
  7. bool selection UNUSED /* if this SA is a selection, only one
  8. * tranform can appear. */
  9. )
  10. {
  11. pb_stream proposal_pbs;
  12. struct ikev2_prop proposal;
  13. unsigned int np = ISAKMP_NEXT_P;
  14. /* we need to parse proposal structures until there are none */
  15. unsigned int lastpropnum=-1;
  16. bool conjunction, gotmatch;
  17. struct ikev2_prop winning_prop;
  18. struct db_sa *sadb;
  19. struct trans_attrs ta;
  20. struct connection *c = st->st_connection;
  21. /*根据配置确定选用的SADB模板*/
  22. int policy_index = POLICY_ISAKMP(c->policy
  23. , c->spd.this.xauth_server
  24. , c->spd.this.xauth_client);
  25. struct ikev2_transform_list itl0, *itl;
  26. memset(&itl0, 0, sizeof(struct ikev2_transform_list));
  27. itl = &itl0;
  28. /* find the policy structures */
  29. /*根据策略配置生成SADB信息*/
  30. sadb = st->st_sadb;
  31. if(!sadb) {
  32. st->st_sadb = &oakley_sadb[policy_index];
  33. sadb = oakley_alg_makedb(st->st_connection->alg_info_ike
  34. , st->st_sadb, 0);
  35. if(sadb != NULL) {
  36. st->st_sadb = sadb;
  37. }
  38. sadb = st->st_sadb;
  39. }
  40. /*将SA结构由IKEv1转换为IKEv2*/
  41. sadb = st->st_sadb = sa_v2_convert(sadb);
  42. gotmatch = FALSE;
  43. conjunction = FALSE;
  44. zero(&ta);
  45. while(np == ISAKMP_NEXT_P) {/*一般情况下只有一个建议载荷*/
  46. /*
  47. * note: we don't support ESN,
  48. * so ignore any proposal that insists on it
  49. */
  50. if(!in_struct(&proposal, &ikev2_prop_desc, sa_pbs, &proposal_pbs))
  51. return PAYLOAD_MALFORMED;
  52. if(proposal.isap_protoid != PROTO_ISAKMP) {
  53. loglog(RC_LOG_SERIOUS, "unexpected PARENT_SA, expected child");
  54. return PAYLOAD_MALFORMED;
  55. }
  56. ... ...
  57. gotmatch = FALSE;
  58. {/*将报文中的建议载荷转换为struct ikev2_transform_list*/
  59. stf_status ret = ikev2_process_transforms(&proposal
  60. , &proposal_pbs, itl);
  61. if(ret != STF_OK) return ret;
  62. }
  63. np = proposal.isap_np;/*下一个建议载荷 或者为空*/
  64. if(ikev2_match_transform_list_parent(sadb
  65. , proposal.isap_propnum
  66. , itl)) {/*匹配成功的算法组合存储在itl中*/
  67. winning_prop = proposal;
  68. gotmatch = TRUE;
  69. /* gotmatch is true, so will never go inside if*/
  70. }
  71. }
  72. /*
  73. * we are out of the loop. There are two situations in which we break
  74. * out: gotmatch == FALSE, means nothing selected.
  75. */
  76. if(!gotmatch) {
  77. return NO_PROPOSAL_CHOSEN;
  78. }
  79. /*
  80. * since we found something that matched, we might need to emit the
  81. * winning value.
  82. *
  83. * 从对方的建议载荷中找到了合适的算法信息;
  84. */
  85. /*加密算法*/
  86. ta.encrypt = itl->encr_transforms[itl->encr_i];
  87. ta.enckeylen = itl->encr_keylens[itl->encr_i] > 0 ?
  88. itl->encr_keylens[itl->encr_i] : 0;
  89. ta.encrypter = (struct encrypt_desc *)ike_alg_ikev2_find(IKE_ALG_ENCRYPT
  90. , ta.encrypt
  91. , ta.enckeylen);
  92. passert(ta.encrypter != NULL);
  93. if (ta.enckeylen <= 0)
  94. ta.enckeylen = ta.encrypter->keydeflen;
  95. /*完整性哈希算法*/
  96. ta.integ_hash = itl->integ_transforms[itl->integ_i];
  97. ta.integ_hasher= (struct hash_desc *)ike_alg_ikev2_find(IKE_ALG_INTEG,ta.integ_hash, 0);
  98. passert(ta.integ_hasher != NULL);
  99. /*PRF 哈希算法*/
  100. ta.prf_hash = itl->prf_transforms[itl->prf_i];
  101. ta.prf_hasher = (struct hash_desc *)ike_alg_ikev2_find(IKE_ALG_HASH, ta.prf_hash, 0);
  102. passert(ta.prf_hasher != NULL);
  103. /*DH 算法*/
  104. ta.groupnum = itl->dh_transforms[itl->dh_i];
  105. ta.group = lookup_group(ta.groupnum);
  106. st->st_oakley = ta;/*将算法信息存储到state上*/
  107. if (r_sa_pbs != NULL)/*将选中的算法填充到应答报文的SA载荷上*/
  108. {
  109. return ikev2_emit_winning_sa(st, r_sa_pbs
  110. , ta
  111. , /*parentSA*/TRUE
  112. , winning_prop);
  113. }
  114. return NOTHING_WRONG;
  115. }

4. 小结

4.1 SA载荷中加密套件算法选择

  • IKEv2加密套件的转换详细说明见下表
用途 名称 编号
IKE转换类型Ⅰ(加密) ENCR_3DES 3
ENCR_NULL 11
ENCR_AES_CBC 12
ENCR_AES_CTR 13
IKE转换类型Ⅱ(PRF) PRF_HMAC_MD5 1
PEF_HMAC_SHA1 2
PRF_AES128_CBC 4
IKE转换类型Ⅲ(完整性) AUTH_HMAC_MD5_96 1
AUTH_HMAC_SHA1_96 2
AUTH_AES_XCBC_96 5
IKE转换类型Ⅳ(DH组) 1024 MODP (Group 2) 2
2048 MODP (Group 14) 14

安全关联(SA)负载包含了一个SPI数值和一套建议(通常是一个)。这些建议是通过一些复杂的建议结构关联起来的。每一个建议结构都会被编号(参见上表)并且包含一个IPsec协议标识符,此标识符用来支持采用的协议,如IKE, ESP, AH。

每一个建议载荷包含一个或者多个变换载荷用来描述指定协议的算法。通常情况下,AH协议仅有一个变换载荷(与完整性检验算法有关),ESP协议有两个变换载荷(与完整性检验算法和加密算法相对应),DH算法有四个转换结构(DH组编号、PRF算法、完整性检验算法、加密算法)。而第二个报文中的SA加密套件中的建议载荷便属于DH转换结构。

4.2 密钥交换KE和随机负载Nonce

IKE_SA_INIT交换报文中处理SA载荷外,还包括KE载荷和Nonce载荷。

  • KE载荷包括DH组编号和密钥交换数据(DH算法公共值)
  • Nonce载荷则是随机生成的随机数,用于生成密钥材料。

DH一旦交换完成,双方便可以计算出自己的SKEYSEED,该值用来生成所有与IKE_SA相关的子密钥,包括:SK_d, SK_ai, SK_ar, SK_ei, SK_er, SK_pi, SK_pr

SKEYSEED的计算方式如下:

S

K

E

Y

S

E

E

D

=

p

r

f

(

N

i

N

r

,

g

i

r

)

SKEYSEED = prf(Ni | Nr, g^{ir} )

SKEYSEED=prf(Ni∣Nr,gir)

密钥 用途
SK_ai, SK_ar 用于认证
SK_ei, SK_er 用于加密
SK_d 用于派生CHILD_SA密钥
SK_p 用于在IKE_AUTH交换中生成AUTH载荷

版本所有,谢绝转载!!!

IKEv2协议协商流程: (IKE-SA-INIT 交换)第二包的更多相关文章

  1. IKEv2协议协商流程: (IKE-SA-INIT 交换)第一包

    文章目录 1. IKEv2 协商总体框架 2. 第一包流程图 3. openswan源码学习 3.1 ikev2parent_outI1() 3.2 ikev2parent_outI1_withsta ...

  2. IKEv2协议关键知识点总结整理

    文章目录 @[toc] 1. IKEv2基本原理 2. IKEv2协议重点注意事项 2.1 情景一:==IKEv2协商密钥逻辑== ①密钥协商流程 ②函数调用关系 ③流程简述 2.2 情景二:==使用 ...

  3. [ipsec][crypto] IKEv2的协商交互分析

    一: 无论协商了什么样的加密算法.DH都交换一块长度为32byte的内存,作为key. IKE和esp的key,分别基于这块内存生成. 二: 当esp的算法协商没有指定dh group时,rekey将 ...

  4. openswan协商流程之(二):main_inI1_outR1()

    主模式第二包:main_inI1_outR1() 文章目录 主模式第二包:main_inI1_outR1() 1. 序言 2. `main_inI1_outR1()`处理流程图 3. `main_in ...

  5. openswan协商流程之(一):main_outI1()

    主模式第一包:main_outI1() 1. 序言 main_outI1()作为主模式主动发起连接请求的核心处理函数,我们可以通过学习该函数的处理流程来探究openswan中报文封装的基本思想.如果之 ...

  6. PPTP协议握手流程分析

    一  PPTP概述 PPTP(Point to Point Tunneling Protocol),即点对点隧道协议.该协议是在PPP协议的基础上开发的一种新的增强型安全协议,支持多协议虚拟专用网,可 ...

  7. PPTP协议握手流程分析--转载

    一  PPTP概述   PPTP(Point to Point Tunneling Protocol),即点对点隧道协议.该协议是在PPP协议的基础上开发的一种新的增强型安全协议,支持多协议虚拟专用网 ...

  8. openswan协商流程之(七):main_inR3

    主模式第六包(收包):main_inR3 1. 序言 main_inR3()函数是ISAKMP协商过程中第一阶段的最后一个报文的接收处理函数,它的作用同main_inI3_outR3()部分功能相同: ...

  9. 数据包接收系列 — IP协议处理流程(二)

    本文主要内容:在接收数据包时,IP协议的处理流程. 内核版本:2.6.37 Author:zhangskd @ csdn blog 我们接着来看数据包如何发往本地的四层协议. ip_local_del ...

随机推荐

  1. 配置多个git用的ssh key

    参考 http://www.sail.name/2018/12/16/ssh-config-of-mac/ 有一点注意 Host 的名字和 HostName改为一致. 因为从git仓库复制的地址是全程 ...

  2. 全网最硬核Handler面试题深度解析

    1.简述Handler的实现原理 Android 应用是通过消息驱动运行的,在 Android 中一切皆消息,包括触摸事件,视图的绘制.显示和刷新等等都是消息.Handler 是消息机制的上层接口,平 ...

  3. 关于TreeSet集合的理解

    TreeSet 集合主要是实现了Collection集合的实现类,主要框架为: 1. Set接口的框架: |----Collection接口:单例集合,用来存储一个一个的对象 |----Set接口: ...

  4. Kurento实战之三:知识点小导游

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  5. Sqli-Labs less26-28a

    less-26 从第26关开始,我的sqli-labs就在docker上运行了,因为windows中阿帕奇对空格的转义有问题 通过源码可以看到有很多过滤,包括空格 or和and. 方法: or可以用| ...

  6. Sqli-Labs less11-12

    less-11 11关以后已经和前几关不同.页面由get方式变成了类似form表单的post方式的登陆界面,我们不能直接看到数据,所以要用到burp抓包. 抓包方式前面已经说过,这里直接使用,我们先输 ...

  7. 旅游景点 Tourist Attractions 题解

    题面在这里 再次破了纪录,连做了3天... 让我们从头来一点一点分析 1.预处理 先看题面,乍一看貌似是个图论题,有n个点m条边,给定一些必须经过的点和强制经过顺序,求一条最短路 我们发现n和m都比较 ...

  8. [ES6深度解析]12:Classes

    我们将讨论一个老问题:在JavaScript中创建对象的构造函数. 存在的问题 假设我们想要创建最典型的面向对象设计的示例:Circle类.假设我们正在为一个简单的Canvas库编写一个Circle. ...

  9. ASP.NET Core教程:ASP.NET Core使用AutoMapper

    一.前言 在实际的项目开发过程中,我们使用各种ORM框架可以使我们快捷的获取到数据,并且可以将获取到的数据绑定到对应的List<T>中,然后页面或者接口直接显示List<T>中 ...

  10. xxx.pch(No such file or directory)

    今天在写一个组件的Demo,发现把一个现象. 我把stdafx.h和stdafx.cpp从工程删除了(本地也被我删除了).后来又想把它加回去,就用新的工程生成这两个文件.然后拷贝过来,增加到工程. 但 ...