> 文档中心 > OpenHarmony解读之设备认证:sts协议-服务端响应sts end请求

OpenHarmony解读之设备认证:sts协议-服务端响应sts end请求


一、概述

在上文中说到,客户端根据服务端的start响应消息发起了end请求,本文将重点介绍服务端是如何处理和响应end请求的。

二、源码分析

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

1. 首先解析认证ack请求消息,parse_auth_ack_request函数,获取该消息中的关键字段,保存在相应结构体中。
/*函数功能:解析认证ack请求消息函数参数:    payload:消息负载    data_type:数据类型函数返回值:    成功:返回解析完成的消息负载地址    失败:返回NULL*/void *parse_auth_ack_request(const char *payload, enum json_object_data_type data_type){    struct sts_end_request_data *auth_ack_request = (struct sts_end_request_data *)MALLOC(sizeof(struct sts_end_request_data));//申请sts_end_request_data结构体空间保存解析的数据    if (auth_ack_request == NULL) { return NULL;    }    (void)memset_s(auth_ack_request, sizeof(*auth_ack_request), 0, sizeof(*auth_ack_request));//清空该空间    json_handle obj = parse_payload(payload, data_type);//如果消息负载为json格式的字符串,则将json格式的数据解析成cjson结构体对象    if (obj == NULL) { LOGE("Parse Auth ACK Request parse payload failed"); goto error;    }    /* authData */    int32_t result = byte_convert(obj, FIELD_AUTH_DATA, auth_ack_request->auth_data.auth_data,      (uint32_t *)&auth_ack_request->auth_data.length, HC_AUTH_DATA_BUFF_LEN);//获取authData,将原来的十六进制字符串格式转换为byte数组格式    if (result != HC_OK) { LOGE("Parse Auth ACK Request Data failed, field is null in addId"); goto error;    }    free_payload(obj, data_type);    return (void *)auth_ack_request;//返回解析完成的结构体error:    free_payload(obj, data_type);    FREE(auth_ack_request);    return NULL;}
2. 然后调用proc_sts_request_message函数处理请求消息,再这个函数里面,根据消息类型选择对应的处理方式,此处应是send_sts_end_response函数。
/*函数功能:构造sts协议end响应数据函数参数:    handle:sts服务端对象    receive:接收到的消息    send:待发送的数据缓冲区地址函数返回值:    成功:0    失败:error num*/int32_t send_sts_end_response(struct sts_server *handle, struct message *receive, struct message *send){    DBG_OUT("Called send sts end response");    check_ptr_return_val(handle, HC_INPUT_ERROR);//检查参数有效性    check_ptr_return_val(receive, HC_INPUT_ERROR);    check_ptr_return_val(send, HC_INPUT_ERROR);    int32_t ret = HC_OK;    struct sts_end_response_data *send_data = (struct sts_end_response_data *)MALLOC(sizeof(struct sts_end_response_data));//申请sts_end_response_data结构体空间send_data    if (send_data == NULL) { LOGE("Malloc struct sts_end_response_data failed"); send->msg_code = INFORM_MESSAGE; return HC_MALLOC_FAILED;    }    (void)memset_s(send_data, sizeof(*send_data), 0, sizeof(*send_data));//清空该空间    if (handle->ack_request == 0) { struct sts_end_request_data *receive_data = receive->payload;//用sts_end_request_data结构接收消息负载 ret = send_end_response(handle, receive_data, send_data);//构造end响应消息 if (ret != HC_OK) {//执行失败     LOGE("Called send_end_response failed, error code is %d", ret);     FREE(send_data);     send_data = NULL;     send->msg_code = INFORM_MESSAGE; } else {//执行成功     DBG_OUT("Called send_end_response success");     send->msg_code = AUTH_ACK_RESPONSE;//设置消息码为AUTH_ACK_RESPONSE     send->payload = send_data;//赋值待发送的数据     handle->ack_request = 1;//将start_request标志置1     (void)memcpy_s(&handle->end_response_data, sizeof(struct sts_end_response_data),      send_data, sizeof(struct sts_end_response_data)); }    } else {//如果start_request不为0,则再次调用send_start_response DBG_OUT("Called send sts end response again"); send->msg_code = AUTH_ACK_RESPONSE;//置响应消息码为AUTH_ACK_RESPONSE (void)memcpy_s(send_data, sizeof(struct sts_end_response_data),  &handle->end_response_data, sizeof(struct sts_end_response_data)); send->payload = send_data;//赋值消息负载    }    return ret;}/*函数功能:发送end响应消息,首先解析end请求数据,然后构造end响应消息函数参数:    handle:句柄,可用相关结构体获取    receive_data:接收的数据    send_data:待发送数据地址函数返回值:    成功:0    失败:error*/int32_t send_end_response(void *handle, void *receive_data, void *send_data){    check_ptr_return_val(handle, HC_INPUT_ERROR);//检查参数有效性    check_ptr_return_val(receive_data, HC_INPUT_ERROR);    check_ptr_return_val(send_data, HC_INPUT_ERROR);    struct key_agreement_server *server = handle;//以密钥协商服务端对象接收该对象    struct key_agreement_protocol *base = &server->protocol_base_info;//赋值协议基础信息    DBG_OUT("Object %u begin receive end request data and send end response data", base->sn);    if (is_state_error(server, SEND_END_RESPONSE)) {//判断协议状态是否错误 LOGE("Object %u state error", base->sn); return PROTOCOL_STATE_ERROR;    }    const struct server_virtual_func_group *funcs = &server->package_funcs;//赋值服务端打包函数    int32_t ret = funcs->parse_end_request_data(handle, receive_data);//执行解析函数解析end请求数据    if (ret != HC_OK) {//解析失败 set_state(base, PROTOCOL_ERROR); LOGE("Object %u parse end request data failed, error code is %d", base->sn, ret); return ret;    }    ret = funcs->build_end_response_data(handle, send_data);//调用回调函数构造end响应消息    if (ret != HC_OK) { set_state(base, PROTOCOL_ERROR); LOGE("Object %u build end response data failed, error code is %d", base->sn, ret); return ret;    }    set_state(base, PROTOCOL_FINISH);//设置协议状态为:PROTOCOL_FINISH    set_last_time_sec(base);//设置上一次的时间    DBG_OUT("Object %u receive end request data send end response data succcess", base->sn);    return HC_OK;}
3. 紧接着在上述函数中执行回调函数parse_end_request_data,解析end请求数据。这个函数的功能主要对客户端发来的认证数据进行解密,然后再根据ED25519算法进行签名验证。
/*函数功能:解析end请求数据函数参数:    handle:sts服务端对象    receive_data:接收数的消息数据函数返回值:    成功:0    失败:error num*/static int32_t parse_end_request_data(void *handle, void *receive_data){    DBG_OUT("Called parse end request data");    struct sts_server *sts_server = handle;//接收sts服务端对象    struct sts_end_request_data *auth_ack_request = receive_data;//用sts_end_request_data结构体接收ack消息    struct uint8_buff out_plain;//定义输出明文缓冲区    out_plain.val = (uint8_t *)MALLOC(HC_STS_REQUEST_LEN);//为明文缓冲区申请空间    if (out_plain.val == NULL) { LOGE("Malloc failed"); return HC_MALLOC_FAILED;    }    (void)memset_s(out_plain.val, HC_STS_REQUEST_LEN, 0, HC_STS_REQUEST_LEN);//清空该空间    out_plain.size = HC_STS_REQUEST_LEN;//赋值缓冲区大小为HC_STS_REQUEST_LEN    out_plain.length = 0;//缓冲区实际数据大小    int32_t ret = decrypt_request_message(handle, auth_ack_request, &out_plain);//解密请求消息,即解密对端发来的认证数据    if (ret != HC_OK) {//解密失败 FREE(out_plain.val); LOGE("Object %u aes_gcm_decrypt failed, error code is %d", sts_server_sn(sts_server), ret); return HC_DECRYPT_FAILED;    }    struct signature signature;//定义签名    //将解密后的签名消息拷贝到signature中作为对比签名    if (memcpy_s(signature.signature, sizeof(signature.signature), out_plain.val, out_plain.length) != EOK) { FREE(out_plain.val); return memory_copy_error(__func__, __LINE__);    }    signature.length = out_plain.length;//获取长度    FREE(out_plain.val);    struct uint8_buff message;//定义消息缓冲区    (void)memset_s(&message, sizeof(message), 0, sizeof(message));//清空该缓冲区    ret = generate_sign_message(handle, &message);//生成本端的签名消息:{客户端公钥、客户端认证id、服务端公钥、服务端认证id}    if (ret != HC_OK) { return HC_MALLOC_FAILED;    }    ret = verify_request_data(handle, &message, &signature);//验证请求数据是否正确,即验证对端身份    FREE(message.val);    message.val = NULL;    if (ret != HC_OK) { LOGE("Object %u verify failed, error code is %d", sts_server_sn(sts_server), ret); return HC_VERIFY_PROOF_FAILED;    }    LOGI("Called parse end request data success!");    (void)sts_server;    return HC_OK;}/*函数功能:解密请求消息函数参数:    handle:sts_server对象    request_data:待解密请求数据函数返回值:    成功:0    失败:error num*/static int32_t decrypt_request_message(void *handle, struct sts_end_request_data *request_data,    struct uint8_buff *out_plain){    DBG_OUT("Called decrypt request message");    check_ptr_return_val(handle, HC_INPUT_ERROR);    check_ptr_return_val(request_data, HC_INPUT_ERROR);    struct sts_server *sts_server = handle;//接收sts服务端对象    struct aes_aad aes_aad;//aes GCM附加验证数据    if (memcpy_s(aes_aad.aad, sizeof(aes_aad.aad), sts_server->my_challenge.challenge, sts_server->my_challenge.length) != EOK) {//将本端challenge值拷贝到aes_aad return memory_copy_error(__func__, __LINE__);    }    aes_aad.length = sts_server->my_challenge.length;//获取长度    struct uint8_buff auth_data = {//定义认证数据缓冲区 .val = request_data->auth_data.auth_data, .length = request_data->auth_data.length, .size = request_data->auth_data.length    };    //利用aes gcm算法基于会话密钥和aes_aad对认证数据进行解密,解密内容保存在out_plain中    int32_t ret = aes_gcm_decrypt((struct var_buffer *)&sts_server->session_key, &auth_data, &aes_aad, out_plain);    return ret;}/*函数功能:生成签名消息:{客户端公钥、客户端认证id、服务端公钥、服务端认证id}函数参数:    handle:sts_server对象    message:输出参数,签名消息缓冲区函数返回值:    成功:0    失败:error num*/static int32_t generate_sign_message(void *handle, struct uint8_buff *message){    DBG_OUT("Called generate sign message");    check_ptr_return_val(handle, HC_INPUT_ERROR);//检查参数有效性    check_ptr_return_val(message, HC_INPUT_ERROR);    struct sts_server *sts_server = handle;//接收sts服务端对象    //客户端公钥、客户端认证id、服务端公钥、服务端认证id长度之和    int32_t len = sts_server->peer_public_key.length + sts_server->peer_id.length +    sts_server->self_public_key.length + sts_server->self_id.length;    uint8_t *info1 = (uint8_t *)MALLOC(len);//申请len长度的缓冲区info1    if (info1 == NULL) { LOGE("Malloc failed"); return HC_MALLOC_FAILED;    }    int32_t pos = 0;    //将客户端公钥、客户端认证id、服务端公钥、服务端认证id按顺序拷贝到info1缓冲区中    (void)memcpy_s(info1 + pos, len - pos, sts_server->peer_public_key.stpk, sts_server->peer_public_key.length);    pos += sts_server->peer_public_key.length;    (void)memcpy_s(info1 + pos, len - pos, sts_server->peer_id.auth_id, sts_server->peer_id.length);    pos += sts_server->peer_id.length;    (void)memcpy_s(info1 + pos, len - pos, sts_server->self_public_key.stpk, sts_server->self_public_key.length);    pos += sts_server->self_public_key.length;    (void)memcpy_s(info1 + pos, len - pos, sts_server->self_id.auth_id, sts_server->self_id.length);    //即 info1 = {客户端公钥、客户端认证id、服务端公钥、服务端认证id}    message->val = info1;//将上述内容赋给签名消息缓冲区    message->length = len;    message->size = len;    return HC_OK;}/*函数功能:验证请求数据函数参数:    handle:sts_server对象    message:待验证的消息    signature:对比签名函数返回值:    ok:0    not ok:error num*/static int32_t verify_request_data(void *handle, const struct uint8_buff *message, struct signature *signature){    DBG_OUT("Called verify request data");    check_ptr_return_val(handle, HC_INPUT_ERROR);//检查参数有效性    check_ptr_return_val(message, HC_INPUT_ERROR);    check_ptr_return_val(signature, HC_INPUT_ERROR);    struct sts_server *sts_server = handle;//接收sts服务端对象    //利用会话标识符的HC包名称和HC服务类型通过sha256哈希算法计算出哈希值,作为服务id    struct service_id service_id = generate_service_id(sts_server->identity);    if (service_id.length == 0) { LOGE("Generate service id failed"); return HC_GEN_SERVICE_ID_FAILED;    }    struct hichain *hichain_handle = sts_server->hichain_handle;//获取hichain实例    enum huks_key_alias_type alias_type;//密钥别名类型    if (hichain_handle->type == HC_CENTRE) {//根据hc类型决定密钥别名(密钥对)类型 struct hc_pin pin = { 0, {0} };//PIN码 struct operation_parameter para;//协议操作参数 (void)memset_s(&para, sizeof(para), 0, sizeof(para));//清空参数空间 //获取协议参数 hichain_handle->cb.get_protocol_params(&hichain_handle->identity, GET_PEER_USER_TYPE, &pin, &para); int32_t flag = sts_server->peer_user_type;//对端用户类型 if (flag == PEER_USER_TYPE_EMPTY) {     sts_server->peer_user_type = para.key_length; } if (para.key_length == PEER_USER_TYPE_ACCESSORY) {     sts_server->peer_user_type = HC_USER_TYPE_ACCESSORY; } if (sts_server->peer_user_type == HC_USER_TYPE_CONTROLLER) {//如果对端类型为HC_USER_TYPE_CONTROLLER     if (memcmp(sts_server->peer_id.auth_id, sts_server->self_id.auth_id, sts_server->peer_id.length) == 0) {  alias_type = KEY_ALIAS_LT_KEY_PAIR; /* center(as phone identity) -> phone */     } else {  alias_type = KEY_ALIAS_CONTROLLER_PK; /* center -> phone (other identity) */     } } else {     alias_type = KEY_ALIAS_ACCESSOR_PK; /* center -> accessory */ }    } else { alias_type = KEY_ALIAS_CONTROLLER_PK; /* accessory -> center/phone */    }    //根据服务id和对端认证id生成密钥别名    struct hc_key_alias key_alias = generate_key_alias(&service_id, &sts_server->peer_id, alias_type);    if (key_alias.length == 0) { LOGE("Generate key alias failed"); return HC_GEN_ALIAS_FAILED;    }    //通过ED25519长期公钥验证签名是否正确(用对端公钥解密)    int32_t ret = verify(&key_alias, sts_server->peer_user_type, message, signature);    if (ret != HC_OK) { LOGE("Object %u verify failed, error code is %d", sts_server_sn(sts_server), ret); return HC_VERIFY_PROOF_FAILED;    }    return HC_OK;}
4. 然后继续执行build_end_response_data回调函数,构造end响应数据。
/*函数功能:构造end响应数据函数参数:    handle:sts_client对象    data:待发送数据函数返回值:    成功:0    失败:error num*/static int32_t build_end_response_data(void *handle, void *send_data){    DBG_OUT("Called build end response_data");    struct sts_server *sts_server = handle;//接收sts服务端对象    struct sts_end_response_data *auth_start_response = send_data;//sts_end_response_data数据结构接收该数据    struct uint8_buff auth_ret;//定义认证返回数据缓冲区    auth_ret.size = HC_STS_RESPONSE_LEN;//获取长度    auth_ret.val = (uint8_t *)MALLOC(auth_ret.size);//为该缓冲区申请空间    if (auth_ret.val == NULL) { LOGE("Malloc failed"); return HC_MALLOC_FAILED;    }    (void)memset_s(auth_ret.val, auth_ret.size, 0, auth_ret.size);//清空该空间    auth_ret.length = 0;    struct aes_aad aes_aad;//aes GCM附加验证数据    if (memcpy_s(aes_aad.aad, sizeof(aes_aad.aad), sts_server->peer_challenge.challenge, sts_server->peer_challenge.length) != EOK) {//将对端challenge值拷贝到aes_aad FREE(auth_ret.val); return memory_copy_error(__func__, __LINE__);    }    aes_aad.length = sts_server->peer_challenge.length;//获取长度    struct uint8_buff ret_code;//定义返回码缓冲区    ret_code.val = (uint8_t *)MALLOC(sizeof(uint8_t));//为返回码缓冲区申请空间    if (ret_code.val == NULL) { FREE(auth_ret.val); LOGE("Malloc failed"); return HC_MALLOC_FAILED;    }    ret_code.length = 1;//初始化返回码    ret_code.size = 1;    ret_code.val[0] = 0;    //对返回码进行aes gcm加密,加密结果保存在auth_ret中    int32_t ret = aes_gcm_encrypt((struct var_buffer *)&sts_server->session_key, &ret_code, &aes_aad, &auth_ret);    FREE(ret_code.val);    if (ret != HC_OK) {//加密失败 FREE(auth_ret.val); LOGE("Object %u aes_gcm_encrypt failed, err code is %d", sts_server_sn(sts_server), ret); return HC_ENCRYPT_FAILED;    }    //利用session_key、salt、"hichain_return_key"等信息基于hkdf算法生成派生密钥service_key    generate_output_key(sts_server);    if (memcpy_s(auth_start_response->auth_return.auth_return, sizeof(auth_start_response->auth_return.auth_return), auth_ret.val, auth_ret.length) != EOK) {//将加密后的auth_data拷贝到待发送的响应消息体中 FREE(auth_ret.val); return memory_copy_error(__func__, __LINE__);    }    auth_start_response->auth_return.length = auth_ret.length;//赋值加密认证数据长度    FREE(auth_ret.val);    LOGI("Called build end response data success!");    return HC_OK;}//生成output_keystatic void generate_output_key(struct sts_server *sts_server){    DBG_OUT("sts_server generate output key");    //利用session_key、salt、"hichain_return_key"等信息基于hkdf算法生成派生密钥service_key    int32_t ret = compute_hkdf((struct var_buffer *)&sts_server->session_key, &sts_server->salt, HICHAIN_RETURN_KEY,   sts_server->key_length, (struct var_buffer *)&sts_server->service_key);    if (ret != HC_OK) { LOGE("Object %u generate output key failed, error code is %d", sts_server_sn(sts_server), ret);    }}
5. 最后执行make_auth_ack_response函数,构造json格式的认证ack响应消息。
/*函数功能:构造json格式的认证ack响应消息函数参数:    data:待发送数据函数返回值:    成功:json格式的字符串    失败:NULL*/char *make_auth_ack_response(void *data){    struct sts_end_response_data *auth_ack_response = data;//用sts_end_response_data结构接收数据    /* authdata */    uint8_t *tmp_data_hex = raw_byte_to_hex_string(auth_ack_response->auth_return.auth_return,  auth_ack_response->auth_return.length);//将原始的authdata字节数据转换为十六进制的字符串    if (tmp_data_hex == NULL) { return NULL;    }    char *ret_str = (char *)MALLOC(RET_STR_LENGTH);//为json字符串申请空间    if (ret_str == NULL) { FREE(tmp_data_hex); 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\":%d,\"%s\":{\"%s\":\"%s\"}}", FIELD_AUTH_FORM, AUTH_FORM, FIELD_MESSAGE, AUTH_ACK_RESPONSE, FIELD_PAYLOAD, FIELD_AUTH_RETURN, tmp_data_hex) < 0) { LOGE("String generate failed"); FREE(ret_str); ret_str = NULL;    }//生成json格式的请求消息    FREE(tmp_data_hex);    return ret_str;}

三、小结

经过分析,得到服务端的响应消息格式为:

{    "authForm":0,   //AUTH_FORM    "message":0x8012,    //消息码:AUTH_ACK_RESPONSE    "payload":    { "authReturn":"十六进制格式的字符串"     //认证返回值    }}