一、概述
在设备认证过程中,pake协议用于认证会话密钥协商,基于该会话密钥,双方可以安全地交换各自的身份公钥。从本文开始,将对pake协议的详细过程进行介绍,本博客主要介绍客户端发起start请求的过程,协议状态从PROTOCOL_INIT转换为START_REQUEST。
二、源码分析
这一模块的源码位于:/base/security/deviceauth。
1. start_pake函数,启动pake模块。
scss
/*
函数功能:启动pake模块
函数参数:
handle:hichain实例
params:操作参数
函数返回值:
成功:0
失败:error
*/
DLL_API_PUBLIC int32_t start_pake(hc_handle handle, const struct operation_parameter *params)
{
LOGI("Begin start pake");
check_ptr_return_val(handle, HC_INPUT_ERROR);//检查参数有效性
check_ptr_return_val(params, HC_INPUT_ERROR);
struct hichain *hichain = (struct hichain *)handle;//获取hichain实例
int32_t ret = build_object(hichain, PAKE_MODULAR, true, params);//构建PAKE_MODULAR client子对象
if (ret != HC_OK) {
LOGE("Build pake client sub object failed, error code is %d", ret);
return ret;
}
ret = triggered_pake_client(hichain, BIND);//触发pake client子对象,发起设备绑定
LOGI("Triggered pake client error code is %d", ret);
LOGI("End start pake");
return ret;
}
2. 首先调用build_object函数构建pake客户端对象。
c
/*
函数功能:构建HiChain子对象
函数参数:
hichain:HiChain实例
modular:消息模块类型
is_client:是否是client
params:构建参数
函数返回值:
成功:返回0 HC_OK
失败:返回错误码
详细:
*/
int32_t build_object(struct hichain *hichain, int32_t modular, bool is_client, const void *params)
{
//初始化HC对象表map
const struct object_map map[] = { { PAKE_MODULAR, true, (void **)&hichain->pake_client },//pake客户端
{ PAKE_MODULAR, false, (void **)&hichain->pake_server },//pake服务端
{ STS_MODULAR, true, (void **)&hichain->sts_client },//sts客户端
{ STS_MODULAR, false, (void **)&hichain->sts_server },//sts服务端
{ ADD_MODULAR, true, (void **)&hichain->auth_info },//认证信息
{ REMOVE_MODULAR, true, (void **)&hichain->auth_info },//认证信息
{ SEC_CLONE_MODULAR, false, (void **)&hichain->sec_clone_server } };//安全克隆服务端
void **object = get_object(map, sizeof(map) / sizeof(map[0]), modular, is_client);//根据消息模块类型获取HC对象
if ((object == NULL) || (*object != NULL)) {//获取失败
DBG_OUT("No sub-objects need to be applied for");
return HC_OK;
}
if (check_mutex_object_is_null(map, sizeof(map) / sizeof(map[0]), modular, is_client) == false) {//检查互斥对象是否为空
LOGE("The mutex sub-object have been created, create %d:%d sub-object failed", modular, is_client);
return HC_REPEATED_REFERENCE;
}
if (check_depend_object_is_not_null(map, sizeof(map) / sizeof(map[0]), modular, is_client) == false) {//检查依赖对象是否为非空
LOGE("The depend sub-object is not created, create %d:%d sub-object failed", modular, is_client);
return HC_NEED_DEPEND;
}
*object = build_object_by_modular(hichain, modular, is_client, params);//根据消息模块协议类型构建子对象
if (*object == NULL) {
LOGE("Create %d:%d sub-object failed", modular, is_client);
return HC_BUILD_OBJECT_FAILED;//构建失败
}
DBG_OUT("Create %d:%d sub-object success", modular, is_client);
return HC_OK;
}
3. 实际上最终是执行build_pake_client_object函数构建客户端对象。
c
/*
函数功能:构建pake协议客户端对象
函数参数:
hichain:hichain实例
params:参数
函数返回值:
成功:子对象首地址
失败:NULL
*/
static void *build_pake_client_object(struct hichain *hichain, const void *params)
{
(void)params;//未使用参数
struct hc_pin pin = { 0, {0} };
struct operation_parameter para;//操作参数
(void)memset_s(¶, sizeof(para), 0, sizeof(para));//清空操作参数空间
hichain->cb.get_protocol_params(&hichain->identity, hichain->operation_code, &pin, ¶);//获取协议参数
if (check_param_is_valid(¶) == false) {//检查参数是否有效
LOGE("Param invalid");
return NULL;
}
if (pin.length > HC_PIN_BUFF_LEN) {//检查PIN是否有效
LOGE("PIN invalid");
return NULL;
}
return build_pake_client(&hichain->identity, &pin, para.key_length, ¶.self_auth_id, ¶.peer_auth_id);//构建pake客户端对象
}
/*
函数功能:构建pake客户端
函数参数:
identity:hichain会话标识
pin:PIN码
key_length:密钥长度
client:客户端认证id
server:服务端认证id
函数返回值:
成功:struct pake_client地址
失败:NULL
*/
struct pake_client *build_pake_client(const struct session_identity *identity, const struct hc_pin *pin,
uint32_t key_length, const struct hc_auth_id *client, const struct hc_auth_id *server)
{
struct pake_client *pake_client = (struct pake_client *)MALLOC(sizeof(struct pake_client));//为pake客户端对象申请空间
if (pake_client == NULL) {
LOGE("Build pake client object failed");
return NULL;
}
(void)memset_s(pake_client, sizeof(*pake_client), 0, sizeof(*pake_client));//清空该空间
struct client_virtual_func_group funcs = { build_start_request_data, parse_start_response_data,
build_end_request_data, parse_end_response_data };//初始化客户端虚函数组
init_client(&pake_client->client_info, &funcs);//初始化协议基础信息和协议客户端打包函数为funcs
pake_client->pin = *pin;//赋值PIN
pake_client->key_length = key_length;//赋值密钥长度
pake_client->self_id = *client;//赋值客户端认证id为本端id
pake_client->peer_id = *server;//赋值服务端认证id为对端id
pake_client->identity = identity;//赋值会话标识
pake_client->prime_type = NUM_LEN_384;//最大质数类型
LOGI("Build pake client object %u success", pake_client_sn(pake_client));
return pake_client;
}
4. build_start_request_data函数,构造start请求数据。
ini
//构造pake_client start请求数据,data参数:数据地址
static int32_t build_start_request_data(void *handle, void *data)
{
struct pake_client *pake_client = (struct pake_client *)handle;//接收pake_client对象
struct pake_start_request_data *send_data = (struct pake_start_request_data *)data;//接收数据地址
send_data->peer_version.first = 1;//初始化对端版本号
send_data->peer_version.second = 0;
send_data->peer_version.third = 0;
send_data->peer_support_version.first = 1;//初始化对端可支持的版本号
send_data->peer_support_version.second = 0;
send_data->peer_support_version.third = 0;
send_data->operation_code = pake_client->operation_code;//赋值操作码
send_data->epk_len = HC_BIG_PRIME_MAX_LEN;//企业级公钥长度为最大质数长度
return HC_OK;
}
5. 回到start_pake 函数中,继续执行triggered_pake_client函数,触发pake client子对象,发起设备绑定。
ini
/*
函数功能:触发pake_client子对象
函数参数:
hichain:hichain实例
operation_code:操作码
函数返回值:
成功:0
失败:error
*/
static int32_t triggered_pake_client(struct hichain *hichain, int32_t operation_code)
#if !(defined(_CUT_PAKE_) || defined(_CUT_PAKE_CLIENT_))
{
hichain->operation_code = operation_code;//赋值操作码
hichain->pake_client->operation_code = operation_code;
struct message send = {//"发送消息"
.msg_code = PAKE_REQUEST,
.rsv = 0,
.payload = NULL
};
int32_t ret = send_pake_start_request(hichain->pake_client, &send);//发送pake协议start请求
if (ret != HC_OK) {
LOGE("Object %u build sts start request failed, error code is %d", pake_client_sn(hichain->pake_client), ret);
return HC_BUILD_SEND_DATA_FAILED;
}
void *send_data = NULL;
uint32_t send_data_len = 0;
ret = build_send_data_by_struct(&send, &send_data, &send_data_len);//构造格式化的客户端请求数据,此处为json格式的字符串
if (ret != HC_OK) {
LOGW("build send data failed, error code is %d", ret);
} else {
DBG_OUT("send_data:%s", (uint8_t *)send_data);
hichain->cb.transmit(&hichain->identity, send_data, send_data_len);//调用软总线模块传输数据,消息起始地址为send_data,长度为send_data_len
FREE(send_data);
}
set_result(hichain, INVALID_MESSAGE, PAKE_REQUEST, ret);//根据接收消息码和发送消息码设置hichain结果和状态
destroy_send_data(&send);//销毁发送缓冲区
return ret;
}
6. 在triggered_pake_client函数中,首先执行send_pake_start_request函数初始化待发送消息。
scss
/*
函数功能:发送"pake start request"消息
函数参数:
pake_client:pake客户端对象
send:待发送消息
函数返回值:
成功:0
失败:error
*/
int32_t send_pake_start_request(struct pake_client *pake_client, struct message *send)
{
check_ptr_return_val(pake_client, HC_INPUT_ERROR);//检查参数有效性
check_ptr_return_val(send, HC_INPUT_ERROR);
struct pake_start_request_data *send_data =
(struct pake_start_request_data *)MALLOC(sizeof(struct pake_start_request_data));//为待发送的请求消息申请内存空间
if (send_data == NULL) {
LOGE("Malloc struct PAKE_START_REQUEST_DATA failed");
return HC_MALLOC_FAILED;
}
(void)memset_s(send_data, sizeof(*send_data), 0, sizeof(*send_data));//清空该内存空间
int32_t ret = send_start_request(pake_client, send_data);//发送start请求
if (ret != HC_OK) {
LOGE("Called send_start_request failed, error code is %d", ret);
FREE(send_data);
send->msg_code = INFORM_MESSAGE;
} else {
DBG_OUT("Called send_start_request success");
send->msg_code = PAKE_REQUEST;
send->payload = send_data;
}
return ret;
}
/*
函数功能:发送start请求
函数参数:
handle:句柄
send_data:待发送数据地址
函数返回值:
成功:0
失败:error
*/
int32_t send_start_request(void *handle, void *send_data)
{
check_ptr_return_val(handle, HC_INPUT_ERROR);//检查参数有效性
check_ptr_return_val(send_data, HC_INPUT_ERROR);
struct key_agreement_client *client = (struct key_agreement_client *)handle;//密钥协商客户端
struct key_agreement_protocol *base = &client->protocol_base_info;//基础密钥协议信息
DBG_OUT("Object %u begin send start request data", base->sn);
if (is_state_error(client, SEND_START_REQUEST)) {//判断协议动作和协议状态是否对应错误
LOGE("Object %u state error", base->sn);
return PROTOCOL_STATE_ERROR;
}
struct client_virtual_func_group *funcs = &client->package_funcs;//赋值虚拟函数群为客户端打包函数
int32_t ret = funcs->build_start_request_data(handle, send_data);//执行打包函数
if (ret != HC_OK) {
set_state(base, PROTOCOL_ERROR);
LOGE("Object %u build start request data failed, error code is %d", base->sn, ret);
return ret;
}
set_state(base, START_REQUEST);//设置协议新状态为START_REQUEST
set_last_time_sec(base);//设置上一次的时间
DBG_OUT("Object %u send start request data success", base->sn);
return HC_OK;
}
/*
函数功能:设置协议状态
函数参数:
handle:密钥协商协议句柄
new_state:新协议状态
函数返回值:无
*/
void set_state(struct key_agreement_protocol *handle, enum protocol_state new_state)
{
check_ptr_return(handle);//检查参数有效性
enum protocol_state ori_state = handle->state;//定义原始状态
DBG_OUT("Object %u state is %u, new state is %u", handle->sn, ori_state, new_state);
if ((ori_state == PROTOCOL_TIMEOUT) || (ori_state == PROTOCOL_ERROR) || (ori_state == PROTOCOL_FINISH)) {//如果原始状态为"超时"、"错误"、"结束",就直接返回,因为没有下一状态
LOGE("Object %u state cannot change", handle->sn);
return; /* not allowed to modify these end status */
}
if (new_state < ori_state) {//不允许协议状态回滚
LOGE("Object %u state cannot rollback", handle->sn);
return;
}
if (handle->state != new_state) {//如果新状态与当前状态不等
handle->last_state = ori_state;//将原始状态赋给last_state(上一个状态)
handle->state = new_state;//赋值新状态
}
}
7. 然后执行build_send_data_by_struct函数,构造格式化的客户端请求数据,此处为json格式的字符串。
c
/*
函数功能:构造结构化的发送消息
函数参数:
message:输出参数,消息地址
send_data:输出参数,消息有效载荷地址
send_data_len:输出参数,消息有效载荷长度
函数返回值:
成功:返回0
失败:返回错误码
*/
static int32_t build_send_data_by_struct(const struct message *message, void **send_data, uint32_t *send_data_len)
{
//消息构造表
const struct make_message_map map[] = { { PAKE_REQUEST, make_pake_request },//构造pake请求消息
{ PAKE_RESPONSE, make_pake_response },//构造pake响应消息
{ PAKE_CLIENT_CONFIRM, make_pake_client_confirm },//构造pake协议客户端认证消息
{ PAKE_SERVER_CONFIRM_RESPONSE, make_pake_server_confirm },//构造pake协议服务端认证消息
{ AUTH_START_REQUEST, make_auth_start_request },//构造认证开始请求消息
{ AUTH_START_RESPONSE, make_auth_start_response },//构造认证开始响应消息
{ AUTH_ACK_REQUEST, make_auth_ack_request },//构造认证确认请求消息
{ AUTH_ACK_RESPONSE, make_auth_ack_response },//构造认证确认响应消息
{ ADD_AUTHINFO_REQUEST, make_add_auth_info_request },//构造添加认证信息请求消息
{ REMOVE_AUTHINFO_REQUEST, make_rmv_auth_info_request },//构造移除认证信息请求消息
{ ADD_AUTHINFO_RESPONSE, make_add_auth_info_response },//构造添加认证信息响应消息
{ REMOVE_AUTHINFO_RESPONSE, make_rmv_auth_info_response },//构造移除认证信息响应消息
{ EXCHANGE_REQUEST, make_exchange_request },//构造交换信息请求消息
{ EXCHANGE_RESPONSE, make_exchange_response },//构造交换信息响应消息
{ SEC_CLONE_START_RESPONSE, sec_clone_make_srv_proof },
{ SEC_CLONE_ACK_RESPONSE, sec_clone_make_clone_ret },
{ INFORM_MESSAGE, make_inform_message } };//构造通知消息
if (message->msg_code == INVALID_MESSAGE) {//如果消息码为无效,则返回"无消息发送"
return HC_NO_MESSAGE_TO_SEND;
}
if (message->payload == NULL) {//如果发送负载为空,则返回错误码
LOGE("Message payload is null");
return HC_BUILD_SEND_DATA_FAILED;
}
for (uint32_t i = 0; i < sizeof(map) / sizeof(struct make_message_map); i++) {//遍历消息构造表
if (map[i].msg_code != message->msg_code) {
continue;
}
*send_data = map[i].make_message(message->payload);//调用构造消息回调函数!!!
if (*send_data == NULL) {//构造消息失败
return HC_BUILD_SEND_DATA_FAILED;
}
*send_data_len = strlen(*send_data);//构造消息成功,获取长度
return HC_OK;
}
LOGE("Unsupport encape 0x%04x message", message->msg_code);
return HC_INNER_ERROR;
}
DD一下: 欢迎大家关注公众号<程序猿百晓生>,可以了解到以下知识点。
erlang
`欢迎大家关注公众号<程序猿百晓生>,可以了解到以下知识点。`
1.OpenHarmony开发基础
2.OpenHarmony北向开发环境搭建
3.鸿蒙南向开发环境的搭建
4.鸿蒙生态应用开发白皮书V2.0 & V3.0
5.鸿蒙开发面试真题(含参考答案)
6.TypeScript入门学习手册
7.OpenHarmony 经典面试题(含参考答案)
8.OpenHarmony设备开发入门【最新版】
9.沉浸式剖析OpenHarmony源代码
10.系统定制指南
11.【OpenHarmony】Uboot 驱动加载流程
12.OpenHarmony构建系统--GN与子系统、部件、模块详解
13.ohos开机init启动流程
14.鸿蒙版性能优化指南
.......
8. 实际上是执行make_pake_request回调函数构造pake请求消息。
swift
/*
函数功能:构造pake请求消息
函数参数:
data:数据首地址
函数返回值:返回json格式的字符串
详细:
消息字符串实际为:{"message":1,"payload":{"version":{"currentVersion":"1.0.0","minVersion":"1.0.0"},"support256mod":true,"operationCode":1}}
*/
char *make_pake_request(void *data)
{
struct pake_start_request_data *pake_request = data;//接收pake_start_request_data结构的数据
char *ret_str = (char *)MALLOC(RET_STR_LENGTH);//为回复消息申请空间
if (ret_str == NULL) {
return NULL;
}
(void)memset_s(ret_str, RET_STR_LENGTH, 0, RET_STR_LENGTH);//清空该空间
if (snprintf_s(ret_str, RET_STR_LENGTH, RET_STR_LENGTH - 1,
"{\"%s\":%d,\"%s\":{\"%s\":{\"%s\":\"%u.%u.%u\",\"%s\":\"%u.%u.%u\"},\"%s\":true,\"%s\":%d}}",
FIELD_MESSAGE, PAKE_REQUEST, FIELD_PAYLOAD, FIELD_VERSION, FIELD_CURRENT_VERSION,
pake_request->peer_version.first, pake_request->peer_version.second,
pake_request->peer_version.third, FIELD_MIN_VERSION,
pake_request->peer_support_version.first, pake_request->peer_support_version.second,
pake_request->peer_support_version.third, FIELD_SUPPORT_256_MOD,
FIELD_OPERATION_CODE, pake_request->operation_code) < 0) {//生成json格式的字符串作为消息数据
LOGE("String generate failed");
FREE(ret_str);
ret_str = NULL;
}
return ret_str;//返回json格式的字符串
}
9. 最后执行set_result函数设置hichain状态和结果。
c
/*
函数功能:设置最终结果信息,即HiChain状态
函数参数:
hichain:hichain实例对象
rcv_msg_code:接收消息码
snd_msg_code:发送消息码
error_code:错误码
函数返回值:无
*/
static void set_result(struct hichain *hichain, uint16_t rcv_msg_code, uint16_t snd_msg_code, int32_t error_code)
{
if (error_code != HC_OK) {//如果错误码不是0,则直接跳转到error,按对应错误码设置结果
LOGE("Error code is not ok, and set end failed");
goto error;
}
if (snd_msg_code == INFORM_MESSAGE) {//如果发送消息码为通知消息,则直接跳转到error
LOGE("Send an inform message, and set end failed");
goto error;
}
//消息结果表
const struct msg_result_map map[] = { { PAKE_REQUEST, KEY_AGREEMENT_PROCESSING, KEY_AGREEMENT_STATE },//密钥协商过程中
{ PAKE_RESPONSE, KEY_AGREEMENT_PROCESSING, KEY_AGREEMENT_STATE },//密钥协商过程中
{ PAKE_CLIENT_CONFIRM, KEY_AGREEMENT_END, OPERATION_STATE },//密钥协商结束
{ PAKE_SERVER_CONFIRM_RESPONSE, KEY_AGREEMENT_END, OPERATION_STATE },//密钥协商结束
{ EXCHANGE_REQUEST, END_SUCCESS, OVER_STATE },
{ EXCHANGE_RESPONSE, END_SUCCESS, OVER_STATE },
{ AUTH_START_REQUEST, KEY_AGREEMENT_PROCESSING, KEY_AGREEMENT_STATE },
{ AUTH_START_RESPONSE, KEY_AGREEMENT_PROCESSING, KEY_AGREEMENT_STATE },
{ AUTH_ACK_REQUEST, KEY_AGREEMENT_END, OPERATION_STATE },
{ AUTH_ACK_RESPONSE, KEY_AGREEMENT_END, OPERATION_STATE },
{ ADD_AUTHINFO_REQUEST, END_SUCCESS, OVER_STATE },
{ ADD_AUTHINFO_RESPONSE, END_SUCCESS, OVER_STATE },
{ REMOVE_AUTHINFO_REQUEST, END_SUCCESS, OVER_STATE },
{ REMOVE_AUTHINFO_RESPONSE, END_SUCCESS, OVER_STATE },
{ SEC_CLONE_START_REQUEST, OPERATION_PROCESSING, OPERATION_STATE },
{ SEC_CLONE_ACK_REQUEST, END_SUCCESS, OVER_STATE },
{ INFORM_MESSAGE, END_FAILED, OVER_STATE },
{ INVALID_MESSAGE, KEY_AGREEMENT_PROCESSING, KEY_AGREEMENT_STATE } };
const struct msg_result_map *map_ptr = select_result_map(rcv_msg_code, map,
sizeof(map) / sizeof(struct msg_result_map));//根据接收消息码查找结果表
set_result_by_map(hichain, map_ptr);//根据结果表内容设置最终结果
return;
error:
hichain->last_state = hichain->state;//将hc当前状态赋给last_state
hichain->state = OVER_STATE;//设置hc当前状态为OVER_STATE
hichain->cb.set_service_result(&hichain->identity, END_FAILED);//调用软总线模块回调函数设置服务结果为END_FAILED!!!
}
三、小结
经过分析,可以得到pake协议的start请求的消息格式为:
json
{
"message":1,//消息码为PAKE_REQUEST
"payload":
{
"version":
{
"currentVersion":"1.0.0",//当前版本号
"minVersion":"1.0.0"//最低版本号
},
"support256mod":true,//是否支持256mod
"operationCode":1//操作码为BIND
}
}
根据消息内容可以知道,客户端发起start请求的目的在于将本端的协议版本号、是否支持256mod、操作码等信息发送给服务端,向服务端发起认证会话密钥协商请求。