> 文档中心 > OpenHarmony解读之设备认证:pake协议-客户端发起start请求

OpenHarmony解读之设备认证:pake协议-客户端发起start请求


一、概述

在设备认证过程中,pake协议用于认证会话密钥协商,基于该会话密钥,双方可以安全地交换各自的身份公钥。从本文开始,将对pake协议的详细过程进行介绍,本博客主要介绍客户端发起start请求的过程,协议状态从PROTOCOL_INIT转换为START_REQUEST。

二、源码分析

这一模块的源码位于:/base/security/deviceauth。

1. start_pake函数,启动pake模块。
/*函数功能:启动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客户端对象。
/*函数功能:构建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函数构建客户端对象。
/*函数功能:构建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(&para, sizeof(para), 0, sizeof(para));//清空操作参数空间    hichain->cb.get_protocol_params(&hichain->identity, hichain->operation_code, &pin, &para);//获取协议参数    if (check_param_is_valid(&para) == 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, &para.self_auth_id, &para.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请求数据。
//构造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子对象,发起设备绑定。
/*函数功能:触发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函数初始化待发送消息。
/*函数功能:发送“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格式的字符串。
/*函数功能:构造结构化的发送消息函数参数:    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;}
8. 实际上是执行make_pake_request回调函数构造pake请求消息。
/*函数功能:构造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状态和结果。
/*函数功能:设置最终结果信息,即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请求的消息格式为:

{    "message":1,//消息码为PAKE_REQUEST    "payload":    { "version": {     "currentVersion":"1.0.0",//当前版本号     "minVersion":"1.0.0"//最低版本号 }, "support256mod":true,//是否支持256mod "operationCode":1//操作码为BIND    }}

根据消息内容可以知道,客户端发起start请求的目的在于将本端的协议版本号、是否支持256mod、操作码等信息发送给服务端,向服务端发起认证会话密钥协商请求