openswan协商流程之(六):main_inI3_outR3()
主模式第六包:main_inI3_outR3
1. 序言
main_inI3_outR3()
函数是ISAKMP协商过程中第六包的核心处理函数的入口,第五六包主要用来验证对方的身份信息,同时此报文也是加密后的报文。这里我们主要说明main_inI3_outR3
的函数调用关系、处理流程以及对源码的注释分析,关于main_inI3_outR3
的上下文环境暂不叙述,留给后面的文章进行更新。
ISAKMP协商报文的处理流程都比较复杂,此函数在协商的报文处理函数中比较复杂的,因此个人学习期间难免有遗漏和理解错误的地方,请大家多多批评指正。
目前主要是整理源码中的处理里流程和实现逻辑,尚未深入比较细节的处理;后续在我整理完毕使用主模式协商的9个报文后,我再次结合代码整理每一个报文的详细流程,到时把每一个报文的注意事项、作用,处理方式做一个整体上的把握。同时结合书本上的描述来解释代码层的实现。
第五六个报文的载荷内容如下:
在这里插入图片描述:
2.函数调用关系
略。
3. 第六个报文流程图
第六个报文的处理流程可以分为三类:
- 解析对方的身份标识(ID)和证书载荷,匹配对方的身份标识
- 身份验证
- 预共享秘钥
- 数字证书
- 构建应答报文
- 身份标识
- 证书载荷
- 对数据包进行签名
- 加密
流程图下图:
4. main_inI3_outR3_tail源码学习
因为main_inI3_outR3
中直接调用了main_inI3_outR3_tail
, 故而直接将main_inI3_outR3_tail
的源代码进行说明,而不再介绍main_inI3_outR3
。
该函数的是第六包的核心处理函数,它中调用了main_id_and_auth()
完成了对方的ID载荷、证书载荷等的解析和认证工作。
在认证成功的前提下,在继续构建自已的应答报文,将自己的身份标识、证书、签名值等载荷封装然后对报文进行加密,最后发送给隧道的发起者。
static stf_status
main_inI3_outR3_tail(struct msg_digest *md
, struct key_continuation *kc)
{
struct state *const st = md->st;
u_int8_t auth_payload;
pb_stream r_id_pbs; /* ID Payload; also used for hash calculation */
cert_t mycert;
bool send_cert;
unsigned int np;
/* ID and HASH_I or SIG_I in
* Note: this may switch the connection being used!
*/
{
stf_status r = main_id_and_auth(md, FALSE
, main_inI3_outR3_continue
, kc);
if (r != STF_OK)
return r;
}
/* send certificate if we have one and auth is RSA */
mycert = st->st_connection->spd.this.cert;
send_cert = st->st_oakley.auth == OAKLEY_RSA_SIG
&& mycert.type != CERT_NONE
&& ((st->st_connection->spd.this.sendcert == cert_sendifasked
&& st->hidden_variables.st_got_certrequest)
|| st->st_connection->spd.this.sendcert==cert_alwayssend);
doi_log_cert_thinking(md
, st->st_oakley.auth
, mycert.type
, st->st_connection->spd.this.sendcert
, st->hidden_variables.st_got_certrequest
, send_cert);
/*************** build output packet HDR*;IDir;HASH/SIG_R ***************/
/* proccess_packet() would automatically generate the HDR*
* payload if smc->first_out_payload is not ISAKMP_NEXT_NONE.
* We don't do this because we wish there to be no partially
* built output packet if we need to suspend for asynch DNS.
*/
/* ??? NOTE: this is almost the same as main_inR2_outI3's code */
/* HDR* out
* If auth were PKE_AUTH or RPKE_AUTH, ISAKMP_NEXT_HASH would
* be first payload.
*/
echo_hdr(md, TRUE, ISAKMP_NEXT_ID);/*回转数据包头;*/
auth_payload = st->st_oakley.auth == OAKLEY_PRESHARED_KEY
? ISAKMP_NEXT_HASH : ISAKMP_NEXT_SIG;
/* IDir out *//*添加ID载荷*/
{
/* id_hd should be struct isakmp_id, but struct isakmp_ipsec_id
* allows build_id_payload() to work for both phases.
*/
struct isakmp_ipsec_id id_hd;
chunk_t id_b;
build_id_payload(&id_hd, &id_b, &st->st_connection->spd.this);
id_hd.isaiid_np = (send_cert)? ISAKMP_NEXT_CERT : 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"))/*添加ID内容*/
return STF_INTERNAL_ERROR;
close_output_pbs(&r_id_pbs);
}
/* CERT out, if we have one */
if (send_cert)/*添加证书载荷*/
{
pb_stream cert_pbs;
struct isakmp_cert cert_hd;
cert_hd.isacert_np = ISAKMP_NEXT_SIG;
cert_hd.isacert_type = mycert.type;
openswan_log("I am sending my cert");
/*添加证书头部描述*/
if (!out_struct(&cert_hd, &isakmp_ipsec_certificate_desc, &md->rbody, &cert_pbs))
return STF_INTERNAL_ERROR;
/*添加证书主体内容*/
if (!out_chunk(get_mycert(mycert), &cert_pbs, "CERT"))
return STF_INTERNAL_ERROR;
close_output_pbs(&cert_pbs);
}
#ifdef TPM
{
pb_stream *pbs = &md->rbody;
size_t enc_len = pbs_offset(pbs) - sizeof(struct isakmp_hdr);
TCLCALLOUT_crypt("preHash", st,pbs,sizeof(struct isakmp_hdr),enc_len);
/* find location of ID PBS */
tpm_findID(pbs, &r_id_pbs);
}
#endif
/* IKEv2 NOTIFY payload */
np = ISAKMP_NEXT_NONE;
if(st->st_connection->policy & POLICY_IKEV2_ALLOW) {
np = ISAKMP_NEXT_VID;
}
/* HASH_R or SIG_R out */
{
u_char hash_val[MAX_DIGEST_LEN];/*计算ID载荷的hash值*/
size_t hash_len = main_mode_hash(st, hash_val, FALSE, &r_id_pbs);
if (auth_payload == ISAKMP_NEXT_HASH)/*如果采用hash进制认证*/
{
/* HASH_R out *//*填充哈希值*/
if (!out_generic_raw(np, &isakmp_hash_desc, &md->rbody
, hash_val, hash_len, "HASH_R"))
return STF_INTERNAL_ERROR;
}
else/*在哈希的基础上再进行一个签名采用签名进制认证*/
{
/* 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;
}
if (!out_generic_raw(np, &isakmp_signature_desc/*填充签名签名信息*/
, &md->rbody, sig_val, sig_len, "SIG_R"))
return STF_INTERNAL_ERROR;
}
}
if(st->st_connection->policy & POLICY_IKEV2_ALLOW) {
if(!out_vid(ISAKMP_NEXT_NONE, &md->rbody, VID_MISC_IKEv2))
return STF_INTERNAL_ERROR;
}
/* encrypt message, sans fixed part of header */
if (!encrypt_message(&md->rbody, st))
return STF_INTERNAL_ERROR; /* ??? we may be partly committed */
/* Last block of Phase 1 (R3), kept for Phase 2 IV generation */
DBG_cond_dump(DBG_CRYPT, "last encrypted block of Phase 1:"
, st->st_new_iv, st->st_new_iv_len);
/*保存第一阶段的IV信息*/
st->st_ph1_iv_len = st->st_new_iv_len;
set_ph1_iv(st, st->st_new_iv);/*设置初始化向量*/
/* It seems as per Cisco implementation, XAUTH and MODECFG
* are not supposed to be performed again during rekey */
if( st->st_connection->remotepeertype == CISCO &&
st->st_connection->newest_isakmp_sa != SOS_NOBODY &&
st->st_connection->spd.this.xauth_client) {
DBG(DBG_CONTROL, DBG_log("Skipping XAUTH for rekey for Cisco Peer compatibility."));
st->hidden_variables.st_xauth_client_done = TRUE;
st->st_oakley.xauth = 0;
if(st->st_connection->spd.this.modecfg_client) {
DBG(DBG_CONTROL, DBG_log("Skipping ModeCFG for rekey for Cisco Peer compatibility."));
st->hidden_variables.st_modecfg_vars_set = TRUE;
st->hidden_variables.st_modecfg_started = TRUE;
}
}
ISAKMP_SA_established(st->st_connection, st->st_serialno);
/* ??? If st->st_connectionc->gw_info != NULL,
* we should keep the public key -- it tested out.
*/
return STF_OK;
}
5. oakley_id_and_auth源码学习
oakley_id_and_auth()
函数的作用是对第五包中的身份标识、证书载荷、证书请求载荷等进行解析,并根据配置的认证方式(预共享秘钥、数字证书)完成对对端的认证。
stf_status
oakley_id_and_auth(struct msg_digest *md
, bool initiator /* are we the Initiator? */
, bool aggrmode /* aggressive mode? */
, cont_fn_t cont_fn /* continuation function */
, const struct key_continuation *kc /* current state, can be NULL */
){
struct state *st = md->st;
u_char hash_val[MAX_DIGEST_LEN];
size_t hash_len;
stf_status r = STF_OK;
/* if we are already processing a packet on this st, we will be unable
* to start another crypto operation below */
if (is_suspended(st)) {/*当前有数据包正在处理*/
openswan_log("%s: already processing a suspended cyrpto operation "
"on this SA, duplicate will be dropped.", __func__);
return STF_TOOMUCHCRYPTO;
}
//1 HDR*, IDii, [ CERT, ] SIG_I
/* ID Payload in.
* Note: this may switch the connection being used!
*//*主动模式时,需要解析对端标识信息;*/
if (!aggrmode && !decode_peer_id(md, initiator, FALSE))
return STF_FAIL + INVALID_ID_INFORMATION;
/*对报文进行验签:
1.计算对端ID的哈希值
2. 如果使用的共享秘钥,则报文中使用hash算法进行签名,因此直接比较哈希值是否一致即可
3. 如果使用证书的方式,则需要使用RSA....等进行验签
*/
/* Hash the ID Payload.
* main_mode_hash requires idpl->cur to be at end of payload
* so we temporarily set if so.
*/
{
pb_stream *idpl = &md->chain[ISAKMP_NEXT_ID]->pbs;
u_int8_t *old_cur = idpl->cur;
idpl->cur = idpl->roof;
hash_len = main_mode_hash(st, hash_val, !initiator, idpl);
idpl->cur = old_cur;
}
switch (st->st_oakley.auth)
{
case OAKLEY_PRESHARED_KEY:/*共享秘钥认证*/
{
pb_stream *const hash_pbs = &md->chain[ISAKMP_NEXT_HASH]->pbs;/*获取哈希载荷的数据部分(即哈希值)*/
if (pbs_left(hash_pbs) != hash_len
|| memcmp(hash_pbs->cur, hash_val, hash_len) != 0)
{
DBG_cond_dump(DBG_CRYPT, "received HASH:"
, hash_pbs->cur, pbs_left(hash_pbs));
loglog(RC_LOG_SERIOUS, "received Hash Payload does not match computed value");
/* XXX Could send notification back */
r = STF_FAIL + INVALID_HASH_INFORMATION;
}
}
break;
case OAKLEY_RSA_SIG:/*数字证书认证*/
r = RSA_check_signature(st, hash_val, hash_len
, &md->chain[ISAKMP_NEXT_SIG]->pbs
#ifdef USE_KEYRR
, kc == NULL? NULL : kc->ac.keys_from_dns
#endif /* USE_KEYRR */
, kc == NULL? NULL : kc->ac.gateways_from_dns
);
if (r == STF_SUSPEND)
{
/* initiate/resume asynchronous DNS lookup for key */
struct key_continuation *nkc
= alloc_thing(struct key_continuation, "key continuation");
enum key_oppo_step step_done = kc == NULL? kos_null : kc->step;
err_t ugh;
/* Record that state is used by a suspended md */
passert(st->st_suspended_md == NULL);
set_suspended(st,md);
nkc->failure_ok = FALSE;
nkc->md = md;
switch (step_done)
{
case kos_null:
/* first try: look for the TXT records */
nkc->step = kos_his_txt;
#ifdef USE_KEYRR
nkc->failure_ok = TRUE;
#endif
ugh = start_adns_query(&st->st_connection->spd.that.id
, &st->st_connection->spd.that.id /* SG itself */
, ns_t_txt
, cont_fn
, &nkc->ac);
break;
#ifdef USE_KEYRR
case kos_his_txt:
/* second try: look for the KEY records */
nkc->step = kos_his_key;
ugh = start_adns_query(&st->st_connection->spd.that.id
, NULL /* no sgw for KEY */
, ns_t_key
, cont_fn
, &nkc->ac);
break;
#endif /* USE_KEYRR */
default:
bad_case(step_done);
}
if (ugh != NULL)
{
report_key_dns_failure(&st->st_connection->spd.that.id, ugh);
set_suspended(st, NULL);
r = STF_FAIL + INVALID_KEY_INFORMATION;
} else {
/*
* since this state is waiting for a DNS query, delete
* any events that might kill it.
*/
delete_event(st);
}
}
break;
default:
bad_case(st->st_oakley.auth);
}
if (r == STF_OK)
DBG(DBG_CRYPT, DBG_log("authentication succeeded"));
return r;
}
openswan协商流程之(六):main_inI3_outR3()的更多相关文章
- openswan协商流程之(七):main_inR3
主模式第六包(收包):main_inR3 1. 序言 main_inR3()函数是ISAKMP协商过程中第一阶段的最后一个报文的接收处理函数,它的作用同main_inI3_outR3()部分功能相同: ...
- openswan协商流程之(一):main_outI1()
主模式第一包:main_outI1() 1. 序言 main_outI1()作为主模式主动发起连接请求的核心处理函数,我们可以通过学习该函数的处理流程来探究openswan中报文封装的基本思想.如果之 ...
- openswan协商流程之(五):main_inR2_outI3()
主模式第五包:main_inR2_outI3 文章目录 主模式第五包:main_inR2_outI3 1. 序言 2.函数调用关系 3. 第五个报文流程图 4. main_inR2_outI3()源码 ...
- openswan协商流程之(四):main_inI2_outR2()
主模式第四包:main_inI2_outR2 1. 序言 main_inI2_outR2()函数是ISAKMP协商过程中第四包的核心处理函数的入口,同时在此处理流程中已经获取到足够的隧道信息,可以生成 ...
- openswan协商流程之(三):main_inR1_outI2
主模式第三包:main_inR1_outI2 1. 序言 main_inR1_outI2()函数是ISAKMP协商过程中第三包的核心处理函数的入口.这里我们主要说明main_inR1_outI2的函数 ...
- openswan协商流程之(二):main_inI1_outR1()
主模式第二包:main_inI1_outR1() 文章目录 主模式第二包:main_inI1_outR1() 1. 序言 2. `main_inI1_outR1()`处理流程图 3. `main_in ...
- IKEv2协议协商流程: (IKE-SA-INIT 交换)第二包
IKEv2协议协商流程: (IKE-SA-INIT 交换)第二包 文章目录 IKEv2协议协商流程: (IKE-SA-INIT 交换)第二包 1. IKEv2 协商总体框架 2. 第二包流程图 3. ...
- IKEv2协议协商流程: (IKE-SA-INIT 交换)第一包
文章目录 1. IKEv2 协商总体框架 2. 第一包流程图 3. openswan源码学习 3.1 ikev2parent_outI1() 3.2 ikev2parent_outI1_withsta ...
- Android 4.4 Kitkat Phone工作流程浅析(六)__InCallActivity显示更新流程
本文来自http://blog.csdn.net/yihongyuelan 转载请务必注明出处 本文代码以MTK平台Android 4.4为分析对象,与Google原生AOSP有些许差异,请读者知悉. ...
随机推荐
- 开机时自动启动的AutoHotkey脚本 2019年10月09日
;;; 开机时自动启动的AutoHotkey脚本 2019年10月09日;; http://www.autoahk.com/archives/16600; https://www.cnblogs.co ...
- 【UGUI源码分析】Unity遮罩之Mask详细解读
遮罩,顾名思义是一种可以掩盖其它元素的控件.常用于修改其它元素的外观,或限制元素的形状.比如ScrollView或者圆头像效果都有用到遮罩功能.本系列文章希望通过阅读UGUI源码的方式,来探究遮罩的实 ...
- 双非本科Android开发,如何逆袭拿到大厂 Offer?
从2020年3月18日投出第一份暑期实习简历至今,已经过去400多天.我也尘埃落定,即将去CVTE做Android开发. 休息了很长时间,如今已经能够很平静地回首这段历程,写下这篇文,致敬曾经走过的漫 ...
- 字节跳动上传了一份“面试官版Android面试小册”,不讲一句废话,全是精华
前言 金三银四马上就到了,很多粉丝朋友私信希望我出一篇面试专题或者分享面试相关的笔记来学习,这不今天就给大家安排上了?(都是干货,错过就是亏.) 下面的面试笔记都是精心整理好免费分享给大家的,希望新朋 ...
- Python之replace()方法失效
1.背景 Titanic存活率预测案例: # 读取数据 df_train = pd.read_csv("./data/train.csv") df_train.head() OUT ...
- 易语言效率与C++究竟差多少(质数和计算)
文本首发bIlibili,cnblogs为作者补发,如在其他平台看见本文,均为经允许的盗窃 易语言作为款主打 中文 易用 编程的开发软件.但是很多人都在批评易语言的效率. 我们今天通过 质数和计算 来 ...
- Linux命令(七)之上传/共享/挂载文件至Linux系统中
.personSunflowerP { background: rgba(51, 153, 0, 0.66); border-bottom: 1px solid rgba(0, 102, 0, 1); ...
- 把对象交给spring管理的3种方法及经典应用
背景 先说一说什么叫把对象交给spring管理.它区别于把类交给spring管理.在spring里采用注解方式@Service.@Component这些,实际上管理的是类,把这些类交给spring来负 ...
- Python 应用爬虫下载QQ音乐
Python应用爬虫下载QQ音乐 目录: 1.简介怎样实现下载QQ音乐的过程: 2.代码 1.下载QQ音乐的过程 首先我们先来到QQ音乐的官网: https://y.qq.com/,在搜索栏上输入一首 ...
- 基于RT1052 Aworks 内存扩容记录(一)
本文主要是通过迁移的思维,记录本人初次使用周立功的Aworks框架进行BSP开发 1. 首先阅读原理图 内存容量由32M扩容至64M. 2. 再则比较两颗芯片的参数 通过比较32M和64M SDRAM ...