在设备认证过程中,pake协议用于认证会话密钥协商,基于该会话密钥,双方可以安全地交换各自的身份公钥。从本文开始,将对pake协议的详细过程进行介绍,本博客主要介绍客户端发起start请求的过程,协议状态从PROTOCOL_INIT转换为START_REQUEST。
这一模块的源码位于:/base/security/deviceauth。
/*
函数功能:启动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;
}
/*
函数功能:构建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;
}
/*
函数功能:构建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;
}
//构造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;
}
/*
函数功能:触发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;
}
/*
函数功能:发送“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;//赋值新状态
}
}
/*
函数功能:构造结构化的发送消息
函数参数:
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;
}
/*
函数功能:构造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格式的字符串
}
/*
函数功能:设置最终结果信息,即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、操作码等信息发送给服务端,向服务端发起认证会话密钥协商请求。
在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList()Obt
最近在学习CAN,记录一下,也供大家参考交流。推荐几个我觉得很好的CAN学习,本文也是在看了他们的好文之后做的笔记首先是瑞萨的CAN入门,真的通透;秀!靠这篇我竟然2天理解了CAN协议!实战STM32F4CAN!原文链接:https://blog.csdn.net/XiaoXiaoPengBo/article/details/116206252CAN详解(小白教程)原文链接:https://blog.csdn.net/xwwwj/article/details/105372234一篇易懂的CAN通讯协议指南1一篇易懂的CAN通讯协议指南1-知乎(zhihu.com)视频推荐CAN总线个人知识总
Devise是一个Ruby库,它为我提供了这个User类:classUser当写入:confirmable时,注册时会发送一封确认邮件。上周我不得不批量创建300个用户,所以我在恢复之前注释掉了:confirmable几分钟。现在我正在为用户批量创建创建一个UI,因此我需要即时添加/删除:confirmable。(我也可以直接修改Devise的源码,但我宁愿不去调和它)问题:如何即时添加/删除:confirmable? 最佳答案 WayneConrad的解决方案:user=User.newuser.skip_confirmation
我想在Ruby的TCPServer中获取客户端的IP地址。以及(如果可能的话)MAC地址。例如,Ruby中的时间服务器,请参阅评论。tcpserver=TCPServer.new("",80)iftcpserverputs"Listening"loopdosocket=tcpserver.acceptifsocketThread.newdoputs"Connectedfrom"+#HERE!HowcanigettheIPAddressfromtheclient?socket.write(Time.now.to_s)socket.closeendendendend非常感谢!
尝试通过SSL连接到ImgurAPI时出现错误。这是代码和错误:API_URI=URI.parse('https://api.imgur.com')API_PUBLIC_KEY='Client-ID--'ENDPOINTS={:image=>'/3/image',:gallery=>'/3/gallery'}#Public:Uploadanimage##args-Theimagepathfortheimagetoupload#defupload(image_path)http=Net::HTTP.new(API_URI.host)http.use_ssl=truehttp.verify
一、什么是MQTT协议MessageQueuingTelemetryTransport:消息队列遥测传输协议。是一种基于客户端-服务端的发布/订阅模式。与HTTP一样,基于TCP/IP协议之上的通讯协议,提供有序、无损、双向连接,由IBM(蓝色巨人)发布。原理:(1)MQTT协议身份和消息格式有三种身份:发布者(Publish)、代理(Broker)(服务器)、订阅者(Subscribe)。其中,消息的发布者和订阅者都是客户端,消息代理是服务器,消息发布者可以同时是订阅者。MQTT传输的消息分为:主题(Topic)和负载(payload)两部分Topic,可以理解为消息的类型,订阅者订阅(Su
我有一个模型User,它在创建后的回调中创建了选项#Userhas_one:user_optionsafter_create:create_optionsprivatedefcreate_optionsUserOptions.create(user:self)end我对此有一些简单的Rspec覆盖:describe"newuser"doit"createsuser_optionsaftertheuseriscreated"douser=create(:user)user.user_options.shouldbe_kind_of(UserOptions)endend一切正常,直到我将自
我正在尝试使用RubyEventMachine访问使用SSL证书身份验证的HTTPSWeb服务,但我没有让它工作。我编写了以下简单代码块来对其进行端到端测试:require'rubygems'require'em-http'EventMachine.rundourl='https://foobar.com/'ssl_opts={:private_key_file=>'/tmp/private.key',:cert_chain_file=>'/tmp/ca.pem',:verify_peer=>false}http=EventMachine::HttpRequest.new(url).g
是否可以同时传递GET和POST参数?uri=URI.parse("http://www.example.com/post.php?a=1&b=2")req=Net::HTTP::Post.new(uri.path,{'Referer'=>"http://www.example.com/referer",'User-Agent'=>"Mozilla/4.0(compatible;MSIE7.0;WindowsNT5.1)",'Cookie'=>$cookie})req.set_form_data({'foo'=>'bar','bar'=>'foo'})http=Net::HTTP.ne
我正在为需要与API建立SSL连接的客户端开发应用程序。我得到了三个文件;一个信任根证书(.cer)文件、一个中间证书(.cer)文件和一个签名的响应文件。我得到的安装说明与IIS或Javakeytool程序有关;我正在用RubyonRails构建应用程序,所以这两种方法都不是一个选项(据我所知)。证书由运行API服务的组织自签名,看来我获得了客户端证书以相互验证https连接。我不确定如何使用我的应用程序中的证书连接和使用API签名响应文件的作用我读过"Usingaself-signedcertificate"和thisarticleonOpenSSLinRuby但两者似乎都不是很到