openharmony 软总线-设备发现流程
6.1 设备发现流程
6.1.1 Wi-Fi设备发现
6.1.1.1 Wi-Fi设备发现流程
Wi-Fi设备在出厂状态或者恢复出厂状态下,设备上电默认开启SoftAP模式,SoftAP的工作信道在1,6,11中随机选择,SoftAP的Beacon消息中携带的SSID element满足表3要求。当通用互联APP发起主动扫描Probe Request请求,此时设备如果收到Probe Request请求需要回复Probe Respone消息,Probe Respone消息中携带的SSID element也需要满足表3要求。如果设备长时间未进行被配网或点到点本地控操作,建议30分钟后关闭Beacon广播。
6.1.1.2 Wi-Fi设备发现字段
【适用范围】IF1.2 【描 述】SoftAP的Beacon消息和Probe Respone消息中携带的SSID element字段。
参数 | 名称 |
---|---|
SSID | 如下表 3:SSID格式 |
Hidden SSID | SSID不需要隐藏 |
BSSID | 设备的MAC地址 |
Channel | 工作信道在1, 6,11中随机选择 |
Security | 开放(Open) |
Beacon Interval | 100 TUs |
DTIM Interval | 无特殊要求 |
表2:Beacon要求
字段 | 长度(字节) | 说明 |
---|---|---|
Oh- | 3 | 固定前缀,作为设备识别的标识。 |
AA…AA | 长度之和≤14 | 企业英文名(可简写)。字符串可以由字母、数字或空格组成。例如HUAWEI。 |
BB…BB | 品类英文名(可简写)。字符串可以由字母、数字或空格组成。例如Smart TV或TV。 | |
-X | 2 | 设备识别的标识。其中,-为固定分割符;X为SoftAP版本号。 |
YYYYY | 5 | PID:产品标识 |
RRRR | 4 | 随机生成,避免出现设备重复 |
表3:SSID IE格式
6.1.2 BLE设备发现
6.1.2.1 BLE设备发现流程
BLE设备在出厂状态或者恢复出厂状态下,设备上电默认开启Advertising广播,广播类型为ADV IND。当通用互联APP发起主动扫描Scan Request请求,此时设备如果收到Scan Request请求需要回复Scan Respone消息,Scan Respone消息中携带的Ad Structure也需要满足6.1.2.2章节要求。
6.1.2.2 BLE设备发现字段
【适用范围】IF1.1 【描 述】蓝牙设备发送的广播包advertising和扫描响应scan response消息。
6.1.2.2.1 总体结构
蓝牙设备发送的广播包advertising和扫描响应scan response消息的Payload均包含AdvA、Data两部分,如下图所示。
AdvA:表示广播方的地址,即蓝牙设备的MAC地址,长度为6字节。 注意:MAC地址必须使用Public MAC,不得使用随机MAC。
Data:表示数据包,可以为AdvData(广播数据)或ScanRspData(扫描响应数据)。每个数据包均由有效数据(significant)和无效数据(non-significant)两部分组成,长度固定为31字节。
有效数据:包含若干个广播数据单元(即AD Structure),AD Structure的结构=Length+AD Type+AD data。
Length:表示该AD Structure数据的总长度,即为AD Type与AD Data的长度和(即不含Length字段本身的1字节)。
AD Type:表示该广播数据代表的含义,如设备名、UUID等。
AD Data:表示具体的数据内容。
无效数据:当有效数据长度不满31字节时,其余的用0补全。这部分的数据是无效的。
6.1.2.2.2 AD Structure1结构(Flags)
AD Structure1用于描述设备支持的BLE、BR等信息,其结构需要遵循蓝牙标准协议保持,长度为3个字节。
字段 | 长度(字节) | 取值 | 说明 |
---|---|---|---|
Length | 1字节 | 0x02 | 表示AD Type与AD Data的总长度。 |
AD Type | 1字节 | 0x01 | 表示该广播数据代表的含义。此处取值固定为0x01,对应的数据类型为Flags。 |
AD Data | 1字节 | 0x06 | 表示蓝牙设备的物理连接能力。对应Bit位的取值为1时,代表True;取值为0时,代表False。· bit0:LE受限可发现模式。· bit1:LE通用可发现模式。· bit2:不支持BR/EDR。· bit3:对Same Device Capable(控制器)同时支持BLE和BR/EDR。· bit4:对Same Device Capable(主机)同时支持BLE和BR/EDR。· bit5~7:预留。 |
在本规范中,不同类型的数据包的AD Structure1字段取值是一致的,固定为0x020106。
6.1.2.2.3 AD Structure2结构(Complete Local Name)
未注册到云端设备的前缀为“Oh-”,已注册到云端设备的前缀为“OH-”。已注册设备包含可选字段“MPP”。如果不携带MPP字段,则网关默认不回连该设备。
字段 | 长度(字节) | 值 | 是否必选 | 说明 | ||
---|---|---|---|---|---|---|
Length | 1 | 0xXX | 是 | AD Type与AD Data的总长度。 | ||
AD Type | 1 | 0x09 | 是 | 广播数据代表的含义,0x09表示蓝牙设备名称Complete Local Name。 | ||
AD Data | 未注册 | Oh- | 3 | 0x4F682D | 是 | 固定前缀,作为设备识别的标识。 |
AA…BB | ≤10 | 0xXX……XX | 自定义,由产品品牌名与设备名称组成。字符串可以由字母、数字、下划线组成,不支持其他字符。 | |||
-X | 2 | 0x2D31 | -为固定分割符;X为协议版本号,不能填0,默认填1。 | |||
YYYYY | 5 | 0xXXXXXXXXXX | PID:产品标识 | |||
NNNN | 4 | 0xXXXXXXXX | 设备序列号SN的后四位,用于区分同款产品的不同设备。字符串可以由字母、数字、下划线组成,不支持其他字符。 | |||
已注册 | OH- | 3 | 0x4F482D | 是 | 固定前缀,作为设备识别的标识。 | |
AA…BB | ≤10 | 0xXX……XX | 自定义,由产品品牌名与设备名称组成。字符串可以由字母、数字、下划线组成,不支持其他字符。 | |||
-X | 2 | 0x2D31 | -为固定分割符;X为协议版本号,不能填0,默认填1。 | |||
YYYYY | 5 | 0xXXXXXXXXXX | PID:产品标识 | |||
NNNN | 4 | 0xXXXXXXXX | 设备序列号SN的后四位,用于区分同款产品的不同设备。字符串可以由字母、数字、下划线组成,不支持其他字符。 | |||
M | 0.5 | 0xX | 否 | 可选字段,如果不携带MPP字段,则网关默认不回连该设备。· bit0:0-心跳广播报文,1-设备主动回连请求广播报文(例如设备有数据上报,需要连接网关)。· bit1:心跳间隔时长的单位。0-毫秒(ms),1-秒(s)。 | ||
PP | 1.5 | 0xXXX | 设备心跳间隔时长。数据类型为unsigned int,需转换为16进制。取值范围为20ms~3600s,如果小于20ms或大于3600s,分别按照20ms和3600s进行处理。 |
6.1.2.2.4 发送要求
设备名称广播报文按固定的时间间隔发送,单条广播的重发次数不低于5次。
对于功耗敏感设备(例如传感器、牙刷、水杯等):
当用户通过物理按键对设备机芯操作时,比如按牙刷按键、打开水杯盖、触碰传感器等场景,广播发送间隔推荐值为100ms。
当用户长时间无操作时,广播发送间隔取值范围为1s-60s,推荐值为30s。
对于非功耗敏感设备(有外接电源或电池容量较大的设备):广播发送间隔为200ms-2000ms,推荐取值1000ms。
6.2 安全协商流程
6.2.1 SPEKE协商流程图
• APP作为SPEKE协商的客户端启动SPEKE协商,传入PIN码;APP发送协商的请求到设备,其中消息携带了所支持的密钥协商的版本信息。
• 设备调用三方厂商的实现的接口,获取默认PIN码或预制PIN码;之后调用iot_connect SDK接口,启动SPEKE协商,传入PIN码。
• 设备侧集成的iot_connect SDK生成随机数salt,随机数challenge1,而后根据salt和PIN码生成设备侧的公私钥对pk1,sk1。
| salt=RND
secret=HKDF(PIN, salt, "ohos_connect_speke_base_info", 32B);
base=X25519.Hash2Point(secret)
sk1=RND
pk1=X25519.computeSharedSecret(sk1,base) |
---|
• 设备发送SPEKE协商的响应消息,携带设备侧支持的协商version、salt、challenge1、pk1(设备侧公钥)发送给APP。
• APP根据salt+PIN码生成APP侧的公私钥对pk2、sk2。
• APP侧根据设备侧的公钥pk1,自身的私钥sk2生成共享密钥SharedSecret(其原理就是DH密钥交换算法);然后使用SharedSecret和salt派生出SessionKey1(用于数据加密)和SessionKey2(用于挑战值hamc的计算);使用SessionKey2、challenge1、challenge2生成kcfData2;使用SessionKey1、salt生成真正用于加密的密钥DataEncKey。
| secret = HKDF(PIN, salt, "ohos_connect_speke_base_info", 32B);
base = X25519.Hash2Point(secret)
sk2 = RND
pk2 = X25519.computeSharedSecret(sk2,base)
SharedSecret = X25519.computeSharedSecret(sk2,pk1)
SessionKey1 || SessionKey2 = HKDF(Sharedsecret, salt, "ohos_connect_speke_sessionkey_info", 32B);
kcfData2 = HMAC(SessionKey2, challenge2||challenge1);
DataEncKey = HKDF(SessionKey1, salt, "ohos_connect_return_key", 16B); |
---|
• APP侧发送自身的pk2(APP侧公钥)、challenge2、kcfData2给到设备侧。
• 设备侧根据APP侧的公钥pk2、自身的私钥sk1生成共享密钥SharedSecret(其原理就是DH密钥交换算法);然后使用SharedSecret和salt派生出SessionKey1和SessionKey2;使用使用SessionKey2、challenge1、challenge2生成new_kcfData2,并且kcfData2验证;如果两者相等,则计算kcfData1,进一步求出使用SessionKey1、salt生成真正用于加密的密钥DataEncKey。
| SharedSecret=X25519.computeSharedSecret(sk1,pk2)
SessionKey1 || SessionKey2 = HKDF(SharedSecret, salt, "ohos_connect_speke_sessionkey_info", 32B);
new_kcfData2 = HMAC(SessionKey2, challenge2||challenge1);
new_kcfData2 ?= kcfData2
kcfData1 = HMAC(SessionKey2, challenge1||challenge2);
DataEncKey = HKDF(SessionKey1, salt, "ohos_connect_return_key", 16B); |
---|
• 设备侧发送SPEKE密钥协商结束的响应,携带kcfData1。
• APP侧使用SessionKey2、challenge1、challenge2生成new_kcfData1,并且kcfData1验证,验证通过然后结束SPEKE密钥协商。
new_kcfData1 = HMAC(SessionKey2, challenge1||challenge2); |
---|
new_kcfData1 ?= kcfData1 |
说明: 1.SessionKey1,SessionKey2和DataEncKey都是16B;
2.challenge1和challenge2是安全随机数,长度为16B,不能使用不安全的伪随机数,例如C语言的rand;
3.pk1和pk2是安全随机数,长度为32B;
4.HKDF采用mbedTLS库的mbedtls_hkdf;
5.HMAC采用HMAC_SHA_256。
6.2.2 SPEKE Over CoAP(Wi-Fi设备、以太网设备)
6.2.2.1 SPEKE协商开始请求消息
【描述】APP与设备首次配网或注册时需要在IP层进行SPEKE协商,单播报文。
【方向】配置器->生态设备
【请求】coap+udp://设备IP:5683/SPEKE
Header:
ver 0x01 //版本,固定值
type 0x00 //Confirmable, OHOS_COAP_MSG_TYPE_CON
tokenlen 0x08 //token长度,最大8字节
code 0x02 //0.02 POST
msgid 0x95CE //每次+1
Token: 0xAABBCCDDEEFF0011 //每次对话随机生成
Options:
0x0B SPEKE //OHOS_COAP_OPTION_TYPE_URI_PATH, SPEKE
0x0C 2 //OHOS_COAP_OPTION_TYPE_CONTENT_FORMAT, application/json
Body
{
"sessionId": "cee042fc402447199aa38354c272faba",
"puuid": "f645f5ee5329f2f317bac83f388e2818c628e249",
"authId": "6636343566356565353332396632663*",**
"authType": 1,
"cmd": "nego",
"securityData": {
"message": 1,
"payload": {
"version": {
"currentVersion": "1.0.0",
"minVersion": "1.0.0"
},
"operationCode": 6,
"support256mod": true
}
}
}
Body参数说明见下表:
Body参数说明
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
sessionId | 必选 | String(32) | 安全会话标识ID |
puuid | 必选 | String(40) | 通用互联APP的唯一标识,可以由APP随机生成的UUID。APP登陆其它账号时,需要重新为该账号重启生成UUID。 |
authId | 必选 | String(80) | |
authType | 必选 | Integer | Auth类型 |
cmd | 必选 | String(8) | 协商命令类型 |
securityData | 必选 | Structure | 安全协商响应数据信息,包括消息序列号、报文载荷 |
securityData格式见下表:
securityData格式
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
message | 必选 | Integer | 应用终端响应消息序列号 |
payload | 必选 | Structure | 有效载荷 |
payload格式见下表:
payload格式
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
Version | 必选 | Structure | 版本号信息 |
challenge | 必选 | String(32) | 应用终端安全随机数 |
salt | 必选 | String(32) | 应用终端随机盐值 |
epk | 必选 | String(512) | 应用终端公钥 |
version格式见下表:
version格式
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
currentVersion | 必选 | String(32) | 应用终端当前版本号 |
minVersion | 必选 | String(32) | 应用终端支持最小版本号 |
6.2.2.2 SPEKE协商开始返回消息
【描述】APP与设备首次配网或注册时需要在IP层进行SPEKE协商返回,单播报文。
【方向】配置器<-生态设备
【返回】
2.05
Header:
ver 0x01 //版本,固定值
type 0x02 //Ack, OHOS_COAP_MSG_TYPE_ACK
tokenlen 0x08 //token长度,最大8字节
code 0x45 //2.05 Response Content
msgid 0x95CE //与msg1中保持一致
Token: 0xAABBCCDDEEFF0011 //与msg1中保持一致
Options:
Body:
{
"sessionId": "cee042fc402447199aa38354c272faba",
"securityData": {
"message": 32769,
"payload": {
"version": {
"currentVersion": "1.0.0",
"minVersion": "1.0.0"
},
"challenge": "c0c6f07e0360fbd412535ddc428130e3",
"salt": "517d68aa92d6f8fd0779c1ddc339934c",
"epk": "eb7156dadcdc31c*"**
}
}
}
Body参数说明见下表:
Body参数说明
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
sessionId | 必选 | String(32) | 安全会话标识ID,与请求报文一致。 |
securityData | 必选 | Structure | 安全协商响应数据信息,包括消息序列号、报文载荷 |
securityData格式见下表:
securityData格式
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
message | 必选 | Integer | 应用终端响应消息序列号 |
payload | 必选 | Structure | 有效载荷 |
payload格式见下表:
payload格式
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
Version | 必选 | Structure | 版本号信息 |
challenge | 必选 | String(32) | 应用终端安全随机数 |
salt | 必选 | String(32) | 应用终端随机盐值 |
epk | 必选 | String(512) | 应用终端公钥 |
version格式见下表:
version格式
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
currentVersion | 必选 | String(32) | 应用终端当前版本号 |
minVersion | 必选 | String(32) | 应用终端支持最小版本号 |
6.2.2.3 SPEKE协商结束请求消息
【描述】APP跟设备首次配网或注册时需要在IP层进行SPEKE协商,单播报文。
【方向】配置器->生态设备
【请求】coap+udp://设备IP:5683/SPEKE
Header:
ver 0x01
type 0x00
tokenLen 0x08
code 0x02
msgid 0x95CE
protocol: 0
Token: AC7ED11B329540CE
Options:
0x0B SPEKE //URI “SPEKE”
0x0C 2 //Content-Format, application/json
Body:
{
"sessionId": "cee042fc402447199aa38354c272faba",
"puuid": "f645f5ee5329f2f317bac83f388e2818c628e249",
"cmd": "nego",
"securityData": {
"message": 2,
"payload": {
"challenge": "00e32ac4f5b4a9adc77ebb305b98aa0f",
"epk": "b022065e78a8f170e*",**
"kcfData": "7b1822756a6bb*"**
}
}
}
Body参数说明见下表:
Body参数说明
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
sessionId | 必选 | String(32) | 安全会话标识ID |
puuid | 必选 | String(40) | 通用互联APP的唯一标识,可以由APP随机生成的UUID。APP登陆其它账号时,需要重新为该账号重启生成UUID。 |
cmd | 必选 | String(8) | 协商命令类型 |
securityData | 必选 | Structure | 安全协商请求数据信息,包括消息序列号、报文载荷 |
securityData格式见下表:
securityData格式
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
message | 必选 | Integer | 配网终端请求消息序列号 |
payload | 必选 | Structure | 有效载荷 |
payload格式见下表:
payload格式
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
challenge | 必选 | String(32) | 配网终端安全随机数 |
epk | 必选 | String(512) | 配网终端公钥 |
kcfData | 可选 | String(64) | 配网终端会话密钥HMAC,携带该字段时,需做key confirmation校验计算 |
6.2.2.4 SPEKE协商结束返回消息
【描述】APP与设备首次配网或注册时需要在IP层进行SPEKE协商返回,单播报文。
【方向】配置器<-生态设备
【返回】
Header: ver 0x01 //版本,固定值
type 0x02 //Ack, OHOS_COAP_MSG_TYPE_ACK
tokenlen 0x08 //token长度,最大8字节
code 0x45 //2.05 Response Content
msgid 0x95CE //与msg3中保持一致 Token: 0xAABBCCDDEEFF0022 //与msg3中保持一致
**Options: **
Body:
{
"sessionId": "cee042fc402447199aa38354c272faba",
"securityData": {
"message": 32770,
"payload": {
"kcfData": "a50618402de7f7bd08abc2*"**
}
}
}
Body参数说明见下表:
Body参数说明
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
sessionId | 必选 | String(32) | 安全会话标识ID |
securityData | 必选 | Structure | 安全协商响应数据信息,包括消息序列号、报文载荷 |
securityData格式见下表:
securityData格式
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
message | 必选 | Integer | 应用终端响应消息序列号 |
payload | 可选 | Structure | 有效载荷 |
payload格式见下表:
payload格式
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
kcfData | 可选 | String(64) | 配网终端会话密钥HMAC,携带该字段时,需做key confirmation校验计算 |
6.2.2.5 SPEKE协商message定义
message | 取值 | 描述 |
---|---|---|
PAKE_REQUEST | 1 | 协商请求消息 |
PAKE_CLIENT_CONFIRM | 2 | 客户端确认消息 |
PAKE_RESPONSE | 32769 | 协商回应消息 |
PAKE_SERVER_CONFIRM | 32770 | 服务端确认消息 |
INFORM_MESSAGE | 32896 | 当异常发生时,使用这条消息通知对方 |
异常 | 错误码 | 描述 |
---|---|---|
FAILED | 0x00000001 | 操作失败 |
CONFLICT_REQUEST | 0x80000001 | 请求被拒绝 |
REQUEST_NOT_FOUND | 0x80000003 | 请求未找到 |
REQUEST_REJECTED | 0x80000005 | 请求被调用者拒绝 |
INVALID_PARAMETERS | 0xF0000001 | 非法参数 |
TIMEOUT | 0xF0000003 | 请求超时 |
UNSUPPORTED_VERSION | 0xF000000A | 版本与对端不对应 |
BAD_PAYLOAD | 0xF000000B | 接收的数据内容格式不符合预期 |
ALGORITHM_UNSUPPORTED | 0xF000000C | 算法不支持 |
PIN_ERROR | 0x0F000011 | PIN码错误 |
PEER_INVALID_PARAMETERS | 0xFF000001 | 对端参数异常 |
PEER_TIMEOUT | 0xFF000003 | 对方返回操作超时 |
PEER_BAD_PAYLOAD | 0xFF00000B | 对方操作返回解析数据异常 |
NOT_INIT | 0xFFFFFFFF | 未初始化 |
6.2.3 SPEKE Over BLE(BLE设备、Wi-Fi/BLE Combo设备)
BLE设备或Wi-Fi/BLE Combo的BLE辅助配网,由于BLE上无法直接承载CoAP,因此SPEKE协商消息与CoAP上有一定差异,本章将详细说明。BLE协议由于受限于BLE GATT报文MTU长度,需要进行分包,分包规则详见9.2.4章节。BLE GATT服务详见9.2.3章节。
6.2.3.1 SPEKE协商开始请求消息
【描述】APP与设备首次配网或注册时需要进行SPEKE协商,需要用BLE分包机制进行分包。
【方向】配置器->生态设备
【请求】
Service:
speke
Body:
{
"sessionId":"365ad1a8e2fd48a88f526e6798247514",
"puuid":"C545DB3CA52CD0B5",
"cmd":"nego",
"securityData":{
"requestId":"5311012805701433766",
"pakeData":"{
"message":64,
"supportedVersion":"1",
"groupAndModuleVersion":"2.0.16",
"groupOp":5}",
"dataLength":82
}
Body参数说明见下表:
Body参数说明
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
sessionId | 必选 | String(32) | 安全会话标识ID |
puuid | 必选 | String(40) | 通用互联APP的唯一标识,可以由APP随机生成的UUID。APP登陆其它账号时,需要重新为该账号重启生成UUID。 |
cmd | 必选 | String(80) | 协商命令类型 |
securityData | 必选 | Structure | 安全协商响应数据信息,包括消息序列号、报文载荷 |
securityData格式见下表:
securityData格式
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
message | 必选 | Integer | 应用终端响应消息序列号 |
payload | 必选 | Structure | 有效载荷 |
payload格式见下表:
payload格式
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
Version | 必选 | Structure | 版本号信息 |
challenge | 必选 | String(32) | 应用终端安全随机数 |
salt | 必选 | String(32) | 应用终端随机盐值 |
epk | 必选 | String(512) | 应用终端公钥 |
version格式见下表:
version格式
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
currentVersion | 必选 | String(32) | 应用终端当前版本号 |
minVersion | 必选 | String(32) | 应用终端支持最小版本号 |
6.2.3.2 SPEKE协商开始返回消息
【方向】配置器<-生态设备
【回应】:
Service:
speke
Body:
{
"sessionId":"365ad1a8e2fd48a88f526e6798247514",
"securityData":{
"requestId":"5311012805701433766",
"pakeData":"{
"message":65,
"supportedVersion":"1",
"payload":"B8255619DD8A9BA0570DF837065C107EC17954D5AC2E8789B1FB975AAB74F5DB",
"salt":"99ECAC05E87984476FB446E10CB7EF76",
"epk":"W06LZEq1YbrV0LXvcj/JDXFqwbazXlRHqlIbwVKnlpvZUMKH25+eTfsCCVOsOL0mS4VbMmzZhwdkIbSqvD94ImMVabGOfs6JeLkbhbovNUqc8zaMMWPGKUWXaIDWyS7kL/7bGTvJY2raOx0PRh3WzWYKMOjXKqdhAWAX22OTqVUyAil3zsRxbqvm/G3nKGzdKM60JmKUJ3C57M+mELEOioDI8hMXgze9Hq2umkEvXBF4cP5RW4PVSUm5SfjDUYap8rh6oJHRWaDaH33nWcgueGQvWqU2K8m99Qu7QVRtRrSyk4pfEcaz+lHpHbRaRKMsu7NXm3T32QgMRkActmG8N7==",
"groupAndModuleVersion":"2.0.16",
"groupOp":5}",
"dataLength":555,
"errorCode":0}
}
Body参数说明见下表:
Body参数说明
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
sessionId | 必选 | String(32) | 安全会话标识ID,与请求报文一致。 |
securityData | 必选 | Structure | 安全协商响应数据信息,包括消息序列号、报文载荷 |
securityData格式见下表:
securityData格式
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
message | 必选 | Integer | 应用终端响应消息序列号 |
payload | 必选 | Structure | 有效载荷 |
payload格式见下表:
payload格式
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
Version | 必选 | Structure | 版本号信息 |
challenge | 必选 | String(32) | 应用终端安全随机数 |
salt | 必选 | String(32) | 应用终端随机盐值 |
epk | 必选 | String(512) | 应用终端公钥 |
version格式见下表:
version格式
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
currentVersion | 必选 | String(32) | 应用终端当前版本号 |
minVersion | 必选 | String(32) | 应用终端支持最小版本号 |
6.2.3.3 SPEKE协商结束请求接口
【描述】APP与设备首次配网或注册时需要进行SPEKE协商,需要用BLE分包机制进行分包。
【方向】配置器->生态设备
【请求】
Service:
speke
Body:
{
"sessionId":"365ad1a8e2fd48a88f526e6798247514",
"puuid":"C545DB3CA52CD0B5",
"cmd":"nego",
"securityData":{
"requestId":"5311012805701433766",
"pakeData":"{
"message":66,
"payload":"F36B32DC037A930ED84C44899BAC96BA0A8196ADA12677D5ECFB905472E2EC01",
"kcfData":"31252D75F8463D004B1CBCCC0FDB22585AA60C08C1D34D03AE593C1FF6D8233E",
"epk":"nFY91emAs0FcWxm4U5W4/NjpNhfOPJtDi2LlWYvQZ/dgt+01TLBkVUGAEvPpHNCK01nj4DJbL5cQnwcprPYibFiQlcKAQTATxXau/mG7/itIYSHzwgvmzte3WioxcuBdBVgUcQQr5FE6bHzJlFFBbP3bXGuM5Z9jnIvYXIG0UfeouOBcy2y1hbofjoPAuRoClo4TGDmYAFBeqbuF66L9ukgzTxGOEuQ3pvyfmd0VRWjP61boinHpNXVaUOwXo6MIFVYGzIGk3/CwuHFXtnV2XCxGHQfg/x1N3fzqthAglheifKUYQFlqBfQBUxtbRuRWzX+AOU4nj8EpCE5ji9qlYQ==",
"groupAndModuleVersion":"2.0.16",
"groupOp":5}",
"dataLength":566}
}
Body参数说明见下表:
Body参数说明
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
sessionId | 必选 | String(32) | 安全会话标识ID |
puuid | 必选 | String(40) | 通用互联APP的唯一标识,可以由APP随机生成的UUID。APP登陆其它账号时,需要重新为该账号重启生成UUID。 |
securityData | 必选 | Structure | 安全协商请求数据信息,包括消息序列号、报文载荷 |
securityData格式见下表:
securityData格式
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
message | 必选 | Integer | 配网终端请求消息序列号 |
payload | 必选 | Structure | 有效载荷 |
payload格式见下表:
payload格式
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
challenge | 必选 | String(32) | 配网终端安全随机数 |
epk | 必选 | String(512) | 配网终端公钥 |
kcfData | 可选 | String(64) | 配网终端会话密钥HMAC,携带该字段时,需做key confirmation校验计算 |
6.2.3.4 SPEKE协商结束返回消息
【方向】配置器<-生态设备
【回应】:
Service:
speke
Body:
{
"sessionId":"365ad1a8e2fd48a88f526e6798247514",
"securityData":{
"requestId":"5311012805701433766",
"pakeData":"{
"message":67,
"kcfData":"D34624A7415AE20367EFCF59692C6CA64FE2AF07BAFF1F0926D5419B4D0C6424""groupAndModuleVersion":"2.0.16",
"groupOp":5}",
"dataLength":137,
"errorCode":0}
}
Body参数说明见下表:
Body参数说明
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
sessionId | 必选 | String(32) | 安全会话标识ID |
securityData | 必选 | Structure | 安全协商响应数据信息,包括消息序列号、报文载荷 |
securityData格式见下表:
securityData格式
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
message | 必选 | Integer | 应用终端响应消息序列号 |
payload | 可选 | Structure | 有效载荷 |
payload格式见下表:
payload格式
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
kcfData | 可选 | String(64) | 配网终端会话密钥HMAC,携带该字段时,需做key confirmation校验计算 |
6.2.3.5 SPEKE协商message定义
message | 取值 | 描述 |
---|---|---|
PAKE_REQUEST | 64 | 协商请求消息 |
PAKE_CLIENT_CONFIRM | 65 | 客户端确认消息 |
PAKE_RESPONSE | 66 | 协商回应消息 |
PAKE_SERVER_CONFIRM | 67 | 服务端确认消息 |
INFORM_MESSAGE | 32896 | 当异常发生时,使用这条消息通知对方 |
6.3 设备认证流程
6.3.1 基于证书的设备认证
6.3.1.1 证书简介
证书可以实现离线认证,且安全性较高。对安全要求比较高的设备,宜采用证书方式。为了实现证书的互相认证,本文件采用多级CA证书颁发机制,各级CA都源自统一的根证书。采用四级证书链结构:根证书RCA->厂家证书VCA->产品证书PCA->设备证书DCA。
6.3.1.2 证书发放
CA认证中心用于为中间证书VCA进行授权或者交叉签名,不直接进行证书的颁发。厂商生成证书公私钥对,并在互联互通开发者平台上进行证书签名授权申请,授权申请通过以后,云平台会保存VID和VCA的对应关系。厂家采用自己的VCA签名生成PCA,并PCA证书添加到云平台,云平台会保存PID与PCA的对应关系。
图3 证书发放架构
1.2.1.3 证书有效性检验 设备证书的有效性检验可采用CRL或者OCSP的方式,由设备云平台所在的CA中心来维护。接入云平台可定期或在线从设备云所在的CA中心获取最新证书撤销列表信息。在进行设备合法性认证时,认证中心或认证代理根据证书撤销列表来判断该设备证书是否已被吊销。 云平台证书的撤销可采用CRL、OCSP或者短周期更新的方式,由云平台所在的CA中心来维护。这三种方式必须都支持,从而适配不同能力的设备。终端设备可根据自身的能力,选择对云平台证书撤销检测方式:如设备有较多的存储空间,可选择CRL的方式来存储云平台的证书撤销列表;如设备存储空间有限,但可连接互联网,则可采用OCSP的方式来获得云平台的证书撤销信息;如设备能力更低,则可采用短周期平台证书,在连接云平台时,不检测撤销信息,仅根据过期时间来判断。
6.3.1.4 证书格式与预置
证书格式采用X.509标准,详细的根证书、中间证书和设备证书格式定义参见附录。 云平台、厂家、生态设备应按下列规则预置证书: — 云平台:RCA证书,RCA私钥;VCA证书,PCA证书 — 厂 家:VCA证书,VCA私钥;PCA证书,PCA私钥;DCA证书,DCA私钥 — 设备预制:DCA证书,DCA私钥。
6.3.1.5 证书认证
生态设备接入云平台,云平台需要对设备进行认证。设备在认证请求时需要提供设备证书DCA,还需要提供设备证书签发的中间证书PID和VID,由云平台生成RCA/VCA/PCA的证书链,对设备进行验证。
6.3.2 基于预共享秘钥的设备认证
6.3.2.1 预共享密钥简介
生态设备预共享密钥为对称式凭证,实现简单,对设备要求低,适用于安全要求级别比较低的生态设备。
6.3.2.2 预共享密钥发放
生态设备预共享密钥由设备云生成,出厂时在生态设备侧进行预置。同时,设备云需保留生态设备PID、MAC与生态设备预共享密钥之间的对应关系。
6.3.2.3 预共享密钥格式与预制
生态设备预共享密钥生成方式由设备厂家自行确定,但密钥长度应不少于256bit。对于没有TEE和硬件根秘钥保护机制芯片,预共享秘钥需要通过HUKS导入进行加密存储。对于没有TEE和硬件根秘钥保护机制芯片,预共享秘钥需要通过HUKS导入进行加密存储
6.3.2.4 预共享密钥认证
生态设备预共享密钥存于设备云中。当生态设备接入云平台时,请求接入云,随后接入云与设备云建立接口,并进行设备预共享密钥认证。
6.4 配网注册流程
6.4.1 Wi-Fi设备配网注册
1.用户进入添加设备界面,APP触发Wi-Fi扫描,并将扫描到设备显示到APP界面,需要根据信号强度对设备进行排序;
2.用户点击连接设备,APP与设备进行SPEKE协商,根据设备SSID element确定设备SPEKE PIN来源;
3.APP获取设备certificate证书,生态设备返回证书;
4.APP将设备返回证书PID/VID/Certificate并向云端进行授权;
5.云根据设备上报的PID/VID生成RCA/VCA/PCA证书链,用证书链对设备Certificate进行验证,验证通过返回成功;
6.认证通过以后,向云端申请注册码,云判断设备已经认证通过,则返回注册码;
7.APP将注册码发送通过cloudsetup给设备;
8.设备根据cloudsetup,下发的Wi-Fi SSID和密码,连接路由器网络;
9.设备与端协商psk,协商成功后,生成对称加密秘钥;
10.设备到云端激活;
11.设备登录云端;
12.设备进行初始数据上报;
13.设备向云端获取authcode,基于authcode创建局域网本地控制接口。
6.4.2 BLE设备配网注册
TODO
6.4.3 以太设备配网注册
1.用户进入添加设备界面,APP触发CoAP扫描,并将扫描到设备显示到APP界面;
2.用户点击连接设备,APP与设备进行SPEKE协商;
3.APP获取设备certificate证书,设备返回证书;
4.APP将设备返回证书PID/VID/Certificate并向云端进行授权;
5.云根据设备上报的PID/VID生成RCA/VCA/PCA证书链,用证书链对设备Certificate进行验证,验证通过返回成功;
6.认证通过以后,向云端申请注册码,云判断设备已经认证通过,则返回注册码;
7.APP将注册码发送通过cloudsetup给设备;
8.设备根据cloudsetup保存psk;
9.设备与云端协商psk,协商成功后,生成对称加密秘钥;
10.设备到云端激活; 11.设备登录云端;
12.设备进行初始数据上报;
13.设备向云端获取authcode,基于authcode创建局域网本地控制接口。
6.4.4 Wi-Fi/BLE Combo设备配网注册
1.用户进入添加设备界面,APP触发CoAP扫描,并将扫描到设备显示到APP界面;
2.用户点击连接设备,APP与设备进行SPEKE协商;
3.APP获取设备certificate证书,设备返回证书;
4.APP将设备返回证书PID/VID/Certificate并向云端进行授权;
5.云根据设备上报的PID/VID生成RCA/VCA/PCA证书链,用证书链对设备Certificate进行验证,验证通过返回成功;
6.认证通过以后,向云端申请注册码,云判断设备已经认证通过,则返回注册码;
7.APP将注册码发送通过cloudsetup给设备;
8.设备根据cloudsetup保存psk;
9.设备与云端协商psk,协商成功后,生成对称加密秘钥;
10.设备到云端激活;
11.设备登录云端;
12.设备进行初始数据上报;
13.设备向云端获取authcode,基于authcode创建局域网本地控制接口。
7 通信安全
7.1 应用层加密
7.1.1 总体流程
应用层加密方案主要涉及几个步骤: 1、 双方协商随机数 2、 根据双方共享的PSK推导加密的密钥 3、 根据加密密钥加密报文的Payload 4、 继续根据密钥推导HMAC的secret,通过该secret计算报文的HMAC,并把固定长度MAC加在Payload的末尾,作为Payload的内容;用于保护报文不被篡改
7.1.2 PSK密钥推导算法
PBKDF2的算法需要结合SHA-256进行HASH计算,参考的OpenSSL接口如下: int PKCS5_PBKDF2_HMAC(const char *pass, int passlen, const unsigned char *salt, int saltlen, int iter, const EVP_MD *digest, int keylen, unsigned char *out); 其中salt为sn1(hex变为binary后为8 bytes)和sn2(hex变为binary后为8 bytes)的拼装,salt长度为16 bytes;digest为SHA-256;keylen为32 bytes。局域网本地控sn1和sn2通过IF1-APP-DEV接口进行协商;与云端通信时sn1和sn2通过IF2-DEV-WAN-PSK接口进行协商。蓝牙设备通过createSession接口进行协商。 瘦设备Device上PBKDF2的迭代次数为1次。
局域网本地控制(即LAN侧应用层加密)使用云下发的authcode计算摘要,使用此authcode计算PBKDF2;远程控制(即WAN侧应用层加密),云端为每个设备都分配了一个唯一的PSK,使用此PSK计算PBKDF2。
7.1.3 加解密
AES加密采用CBC模式,原始待加密的数据是通过PKCS5Padding的方式进行填充的。该算法全名为AES128-CBC-PKCS5Padding。
具体方法如下,原始数据必须补齐到16字节对齐,补齐的每个字节内容为补齐的长度。如: 一个字节的a补齐为:['a', 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F] 两个字节的a补齐为:['a', 'a', 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E]
AES-CBC加密时,需要两个密钥参数:Key和IV。这两个参数都是16 byte,刚好从上一步的PBKDF2的摘要中获取,摘要的前16 bytes用作AES的加密密钥Key;后16 bytes用作AES加密的IV值。。 OpenSSL的参考代码为: AES_KEY enc_key; AES_set_encrypt_key(key, key_len, &enc_key); AES_cbc_encrypt(padded_buf, enc_out, enc_len, &enc_key, ivec, AES_ENCRYPT);
openssl命令进行加密验证: root@wuhphis07722:/vdb/enkey# echo -n "helloworld" | openssl aes-128-cbc -K 451cd24c734b489b7c4b59090d3ba600 -iv f5b52ba4a6806a554388074a2bcc99f1 > enc.bin root@wuhphis07722:/vdb/enkey# xxd -ps enc.bin 78f4fb4634dc6f8b108e63eceb545055
openssl命令进行解密验证: root@wuhphis07722:/vdb/enkey# openssl enc -aes-128-cbc -in enc.bin -d -K 451cd24c734b489b7c4b59090d3ba600 -iv f5b52ba4a6806a554388074a2bcc99f1 | xxd 00000000: 6865 6c6c 6f77 6f72 6c64 helloworld
7.1.4 完整性保护
为了防止报文在传输过程中被篡改,需要保证报文的完整性。采用HMAC算法: HMAC(EVP_sha256(), secret, secret_len, input, input_len, mac, &ulMacLen); 需要输入secret对input进行MAC计算,采用SHA256哈希算法,算出的MAC长度为32 byte。
secret也是通过PBKDF2算法产生,其pass为第一步digest输出的32 byte前16 byte,salt仍然为sn1+sn2。
input的构造方法为:coap报文头+payload;计算出MAC后,追加在payload的末尾。 注意,coap over TCP时,coap头里的长度需要包括32 byte的MAC。
7.1.5 防重放机制
应用层加密使用COAP_OPT_SEQ_NUM_ID来表示每个请求的序号,在刚开始的会话握手过程中,通信双方各自产生一个随机的seq,后续每次发送报文时,必须在COAP_OPT_SEQ_NUM_ID Option中带上seq,且每次请求后seq都要加1;翻转后自动清零。 以下是SEQ_NUM交互过程中的变化逻辑示例:
7.2 通信安全
7.2.1 通用互联APP与云通信安全
通用互联APP与云端通信采用https方式,TLS的版本要≥v1.2,通用互联APP预制云端根证书,并对云端设备证书进行校验。
7.2.2 设备与云通信安全
设备与云通信接口,在设备资源受限时采用CoAP Over TCP,在资源不受限时采CoAP Over TLS。安全要求CoAP Over TLS采用传输层加密;CoAP Over TCP采用应用层加密。
8 通信接口
8.1 IF1接口 APP与设备通信接口
8.1.1 IF1-APP-DEV-DISCOVERY设备发现
Wi-Fi设备发现详见章节6.1.1:Wi-Fi设备发现。BLE设备发现详见章节6.1.2:BLE设备发现。以太网设备详见章节6.1.3:以太网设备发现。Wi-Fi/BLE Combo设备发现详见章节6.1.4:Wi-Fi/BLE Combo设备发现。
8.1.2 IF1-APP-DEV-SPEKE协商
Wi-Fi/以太网设备SPEKE协商详见章节6.2.2:SPEKE Over CoAP(Wi-Fi设备、以太网设备)。BLE设备和Wi-Fi/BLE Combo设备发现详见章节6.2.3:SPEKE Over BLE(BLE设备、Wi-Fi/BLE Combo设备)。
8.1.3 IF1-APP-DEV配网接口
Wi-Fi设备配网接口详见章节6.4.1,BLE设备配网接口详见章节6.4.2,以太网设备配网接口详见章节6.4.3,,Wi-Fi/BLE Combo设备配网接口详见章节6.4.4。
8.1.4 IF1-APP-DEV点到点本地控接口
点到点本地控接口详见。 APP和设备完整的激活过程参考设备与云端的握手及激活过程流程。其中,APP和设备的握手过程是通过发现设备的cloudSetup服务,并对设备进行云端激活,其交互过程如下图所示:
图1 APP和设备的握手过程示意图
如上所示,第一步搜索后,APP和Device之间会产生一个会话ID(sessId),以及两个随机数sn1和sn2,分别由APP和Device生成。后续APP和Device之间的报文交互都需要在CoAP报头中附带sessId,且CoAP报体都通过PBKDF2算法算出的密钥进行加密。具体安全相关的算法说明参考7.1 应用层加密。
瘦设备上电启动获取到IP地址后,如果发现自己还没有到云端激活,则自动处于待激活状态,对外提供cloudSetup服务;APP搜索这个服务时,设备可以返回,等待APP与设备建立会话sessId,并下发云端激活码;如果发现有已经注册过网关提供的homeCenter服务,则直接向网关注册,只维护与网关之间的会话sessId。 瘦设备至少要支持两个sessId,一个sessId用于向网关注册,并且维护心跳;另一个会话用于响应APP的搜索与激活。一旦与云端激活后,可以不回应此请求。
8.1.5 IF1-DEV-APP-DIS APP发现设备接口
【适用范围】IF1.2,IF1.3,IF5 【描述】APP通过组播的方式发现OpenHarmony设备;设备也可以通过组播方式发现其它OpenHarmony设备提供的服务 【请求】该请求发布给固定的组播地址:Broadcast IP**:5683**
GET /.well-known/core?st=ohCloudSetup
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
st | 可选 | String(40) | 待搜索的服务类型,提供了该服务的设备需要按照要求返回搜索结果。 |
【回应】:
{ "errcode": 0,
"devId": "2323-1221-...",
"devInfo": {
"sn": "00E0FC018008",
"model": "SmartSpeaker",
"devType": "004",
"manu": "002",
"prodId": "000b",
"hiv": "1.0",
"fwv": "10.01",
"hwv": "VER.C",
"swv": "V100R001C01B010",
"protType": 1
},
"services": [
{
"st": "light",
"sid": "light1"
},
{
"st": "ohCloudSetup",
"sid": "ohCloudSetup"
}
],
"sts": 1 // 默认0 , 0 不需要sts加密协商, 1 需要sts加密协商
}
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
devId | 必选 | String(40) | 设备ID,如果为空,表示设备还没有被绑定。 |
devInfo | 必选 | devInfoPublic | 设备公开的基本信息,参见链接内容 |
services | 必选 | serviceInfo[] | 该设备支持的OpenHarmony服务信息列表 |
sts | 可选 | 枚举 | 默认0 , 0 不需要sts加密协商, 1 需要sts加密协商 |
【错误码】: 无
8.1.6 IF1-DEV-SESS-ADD 设备会话创建接口
【适用范围】IF1-DEV,IF4
【描述】在调用Device的接口前,需要先通过此接口协商一个会话,通过协商出的会话进行操作。
【请求】
POST /.sys/sessMngr
{
"type": 1,
"modeSupport": 3,
"sn1": "2122232425262728",
"seq": 67
}
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
type | 必选 | Integer | Session会话的类型;OpenHarmony会话分为几种情况:1:匿名会话;通过OpenHarmony预置PSK创建的会话,无认证过程,需要限定使用场景。2:已配对设备的会话;已配对的OpenHarmony设备之间会产生相互信任的PSK,通过该PSK可以产生会话。 |
modeSupport | 必选 | Integer | APP支持的加密方式;必须把支持的模式或起来。当前APP要求支持AES以及DTLS加密方式,因此,需要设置为3。OpenHarmony报文加密的方式,支持以下几种方式:1:AES应用层加密方式2:DTLS加密方式 |
sn1 | 必选 | String(17) | 当协商出的modeResp为1时,需要使用应用层加密。加密的密钥使用PBKDF2算法协商,协商时APP侧需要产生随机数sn1,设备返回随机数sn2。sn1及sn2都是8 byte的随机数,在JSON报文传递时,都变成了16 byte的HEX字符串。 |
seq | 必选 | Integer | 本段的请求序列号,后续对端通过此会话发请求时,必须在COAP_OPT_SEQ_NUM_ID中带此seq数值,每个请求需递增此seq值。seq翻转后,继续从0开始。为了规避设备/网关侧JSON解析不支持大Unsigned Integer(超过0x7FFFFFFF)的问题,在初始协商时,随机生成的seq值不能超过0x7FFFFFFF;后续在OPTION中添加seq时,各设备都支持uint,可以强制转换成uint。 |
【回应】:
{
"errcode": 0,
"sessId": "232384789843",
"sn2": "2122232425262728",
"modeResp": 1,
"seq": 1
}
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
sessId | 可选 | String(16) | OpenHarmony会话应用层ID,握手后,后续所有的CoAP报文交互都需要在COAP_OPT_SESSION_ID Option中附带此ID。 |
modeResp | 必选 | Integer | Device选定的报文加密模式。 |
sn2 | 可选 | String(17) | 当modeResp为1时,应用层加密的Device侧随机数,用于应用层加密的握手协商。sn2为8 byte的随机数,在JSON报文传递时,变成了16 byte的HEX字符串。 |
dtlsPort | 可选 | Integer | 当modeResp为2时,设备采用DTLS的端口号。 |
seq | 必选 | Integer | 对端回应的序列号,后续给对端发请求时,必须在COAP_OPT_SEQ_NUM_ID中带此seq数值,每个请求需递增此seq值。seq翻转后,继续从0开始。为了规避设备/网关侧JSON解析不支持大Unsigned Integer(超过0x7FFFFFFF)的问题,在初始协商时,随机生成的seq值不能超过0x7FFFFFFF;后续在OPTION中添加seq时,各设备都支持uint,可以强制转换成uint。 |
【错误码】: OHOS_CONNECT_SESSION_DENY
8.1.7 IF1-DEV-APP-PROV2 APP为设备下发配网&注册信息
【适用范围】IF1 【描述】APP为设备下发配网&注册信息。 【请求】 POST /CloudSetup/v2 Speke({ "data": { "cloudUrl": "wh2iomplatform.hwcloudtest.cn", "code": "8Kjoruvj", "devId": "e83c4e7b-2158-4710-ad5d-7e1881f5f867", "password": "12345678", "psk": "65a71521277e1af38d8fa5f4ba185b0c", "ssid": "HUAWEI-9SEQLE ", "WifiBgnSwitch": 0 //0-不切换,默认bgn 1-autoswitch ** }** })
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
cloudUrl | 必选 | String(256) | 云url |
code | 必选 | String(40) | 注册码 |
devId | 必选 | String(40) | 设备的唯一ID |
psk | 必选 | String(40) | 预共享密钥 |
ssid | 可选 | String(32) | Wi-Fi AP的SSID |
password | 可选 | String(32) | Wi-Fi AP的密码 |
WifiBgnSwitch | 可选 | Integer | Wi-Fi AP的带宽 |
【回应】:
Speke({:
"errcode": 0,:
"lastStep": 100, //设备上一次添加失败错误码
"lastErr": 100 //设备上一次添加失败错误码
} )
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
errcode | 必选 | Integer | 0 成功 |
lastStep | 可选 | Integer | 设备上一次添加失败错误码 |
lastErr | 可选 | Integer | 设备上一次添加失败错误码 |
【错误码】:
8.1.8 IF1-DEV-APP-QRCode-PROV2 APP为设备通过二维码下发配网&注册信息
【适用范围】IF1
【描述】APP为设备通过二维码下发配网&注册信息。
【请求】
{ "u": "wh2iomplatform.hwcloudtest.cn", // cloudUrl
"c": "8Kjoruvj", // code
"d": "e83c4e7b-2158-4710-ad5d-7e1881f5f867", // devId
"p": "pnooFCk5mvStLKuu5aLkkQ==", //password,AES128,密钥通过预置PSK前面16字符进行加密
"k": "65a71521277e1af38d8fa5f4ba185b0c", // psk
"a": "HUAWEI-9SEQLE", // ssid
"w": 0 //0//0-不切换,默认bgn 1-autoswitch // WifiBgnSwitch,可选,默认是0
//二维码里面需要去掉空格,注释
}
8.1.9 IF1-DEV-APP-ONLINENOTIFY 设备配网成功的广播通知
【适用范围】IF1
【描述】设备在配网连接路由器WIFI成功后在IP层广播上报成功通知,连续发5次。
【请求】
POST /onlinenotify
{
"devId": "2323-1221-...", //设备id,Sha256(devId)
"sts": 1 // 默认0 , 0 不需要sts加密协商, 1 需要sts加密协商
}
8.2-8.4 (TODO)
8.5 IF5接口 APP与设备和设备与设备局域网本地接口
8.5.1 IF5-DEV-LOCAL-CTL APP本地控制智能设备
APP本地控制智能设备时,有三个阶段APP搜索周边的智能设备(已绑定且属于该账户的设备)、APP和智能设备进行握手协商、APP向智能设备下发控制命令。交互过程如下图所示:
图1 APP本地控制过程示意图
APP通过/.well-known/core?st=ohLocalControl搜索支持本地控制的智能设备;APP和智能设备进行会话协商;APP根据用户的控制动作向智能设备下发控制命令。本地控制特性使用UDP,端口为5686。 申请会话过程复用原有的“IF1-DEV-SESS-ADD 设备会话创建接口”;
控制命令的下发过程复用原有的“OHOS-CTRL-POST-API 设备控制接口”消息格式。只是在其中增加了字段,用于消息的去重以及维侧信息。下面是本地控制和控制命令的响应说明:
对于没有上报bridgeVersion字段,或者其版本号低于2的设备(详见2.6节),响应如下:
POST /{sid}
{
"characteristicName1": "value1",
"characteristicName2": "value2"
}
对于有上报bridgeVersion字段,且其版本号不低于2的设备,响应如下:
POST /{sid}
{
"subDeviceId": "2323-1221-...",
"subDeviceInfo": [
{
"characteristicName1": "value1",
"characteristicName2": "value2"
}
]
}
其中devId为被控设备的deviceId。
【回应】:
{
"errcode": 0,
"devId": "2323-1221-...",
"services": [
{
"sid": "sid1",
"reportId": "5753309600007",
"data": {
"characteristicName1": "value1",
"characteristicName2": "value2"
}
}
],
"devicedelay": 20
}
payload参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
devId | 必选 | String(40) | 被控制的设备ID。如果是桥下子设备的控制命令,则为对应子设备的设备ID。 |
services | 必选 | String | 服务及服务的状态 |
reportId | 可选 | String(16) | 数据标识,用于数据去重 |
取时间戳中去掉毫秒部分,然后与数据序号进行拼接。 | |||
devicedelay | 可选 | Integer | 设备侧控制命令执行时长(毫秒),用于维侧。 |
8.5.2 IF5-DEV-APP-LOCAL-DIS APP发现本地控制设备接口
【适用范围】IF1
【描述】APP通过组播的方式发现支持本地控制的OpenHarmony设备;
【请求】
该请求发布给固定的组播地址:Broadcast IP**:5686**
GET /.well-known/core?st=ohLocalControl
【回应】:
{
"errcode": 0,
"devId": "2323-1221-...",
"authCodeId": "658932612345",
"sessId": "232384789843",
"protocal": 0,
"bridgeVersion": "2"
}
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
devId | 必选 | String(40) | 设备ID,如果为空,表示设备还没有被绑定。 |
authCodeId | 必选 | String(32) | authCode以及authCodeId不定期更新。 |
sessId | 必选 | String(16) | 标识设备sdk当前协商的sessId,当apk发现此sessId不一致时需要重新协商。设备下电后该变量会清零。当手机侧发现sessId不一致时,需要重新和设备进行协商。 |
protocal | 必选 | Integer | 设备使用的json的版本号。 |
bridgeVersion | 可选 | Integer | 桥设备向APP上报本地控版本号,2及以上的版本支持桥下挂子设备的本地控制。非桥设备可不选。 |
【错误码】:
无
9 传输协议
9.1 CoAP协议
9.1.1 CoAP协议概述
CoAP协议支持CoAP over TLS,CoAP over TCP,CoAP over UDP的方式。生态设备应基于硬件性能、组网环境,选择对应的协议。点到点本地控和局域网本地控采用CoAP over UDP;连接云服务器采用CoAP over TLS,TLS协议应使用1.2及以上版本;性能受限设备可采用CoAP over TCP。
生态设备使用生态设备云服务平台的URL域名和传输协议的端口向云端发起连接请求,URL域名和端口信息在配网阶段动态下发给设备。
CoAP基于UDP承载时,受到链路层报文大小的限制,从而可能导致应用层一次所需传输的数据大于链路层的一次可以传递数据的大小,在该情况下,需进行分包处理。本文件中,定义CoAP的分包机制通过CoAP协议的标准块传输机制RFC7959来实现,应用层无需感知CoAP层的分包处理。
9.1.2 CoAP over TLS连接
基于COAP的信息获取命令示例:
请求:code=GET URI
应答:code=2.05 content
[BODY]
基于COAP的参数设置命令示例:
请求:code=POST URI
[BODY]
应答:code=2.05 content
[BODY]
如上所示,控制命令的基本格式为GET/POST+URI的方式;GET/POST定义是获取还是设置命令,URI标识具体的指令。CoAP层的返回码code都是2.05,具体的错误码在BODY中根据业务定义。CoAP参考规范:https://datatracker.ietf.org/doc/html/rfc7252 ;CoAP Over TLS和CoAP Over TCP参考规范:https://datatracker.ietf.org/doc/html/rfc8323。
9.1.3 CoAP over TCP连接
由于TCP协议不保障数据传输安全,应由CoAP应用层实现数据加密、完整性保护等数据传输安全机制。 设备使用服务端的URL域名、IP地址和端口向服务端发起TCP/UDP连接请求。建立TCP/UDP连接后,生态设备发送会话协商请求,协商CoAP应用层会话密钥。 在端云互联时,设备在调用CoAP会话协商接口后,必须及时调用注册或者登录接口(宜在2秒内),超时后CoAP会话失效,以防止对服务端的DDoS攻击。 CoAP应用层的加密通道建立应使用设备当前支持的密钥协商协议,具体协商协议见7.1章节。 基于COAP的信息获取命令示例:
请求:code=GET URI
应答:code=2.05 content
[BODY]
基于COAP的参数设置命令示例:
请求:code=POST URI
[BODY]
应答:code=2.05 content
[BODY]
如上所示,控制命令的基本格式为GET/POST+URI的方式;GET/POST定义是获取还是设置命令,URI标识具体的指令。CoAP层的返回码code都是2.05,具体的错误码在BODY中根据业务定义。CoAP参考规范:https://datatracker.ietf.org/doc/html/rfc7252;CoAP Over TLS和CoAP Over TCP参考规范:https://datatracker.ietf.org/doc/html/rfc8323。
9.1.4 CoAP over UDP连接
由于UDP协议不保障数据传输安全,应由CoAP应用层实现数据加密、完整性保护等数据传输安全机制。 设备使用服务端的URL域名、IP地址和端口向服务端发起TCP/UDP连接请求。建立TCP/UDP连接后,智能家居设备发送会话协商请求,协商CoAP应用层会话密钥。 在端云互联时,设备在调用CoAP会话协商接口后,必须及时调用注册或者登录接口(宜在2秒内),超时后CoAP会话失效,以防止对服务端的DDoS攻击。 CoAP应用层的加密通道建立应使用设备当前支持的密钥协商协议,具体协商协议见7.1章节。 基于COAP的信息获取命令示例:
请求:Type=Confirmable, code=GET URI
应答:code=2.05 content
[BODY]
基于COAP的参数设置命令示例:
请求:Type=Confirmable, code=POST URI
[BODY]
应答:code=2.05 content
[BODY]
如上所示,控制命令的基本格式为GET/POST+URI的方式;GET/POST定义是获取还是设置命令,URI标识具体的指令。CoAP层的返回码code都是2.05,具体的错误码在BODY中根据业务定义。CoAP参考规范:https://datatracker.ietf.org/doc/html/rfc7252
9.1.5 CoAP方法定义
本协议中支持CoAP的POST方法,均采用CON类型的消息。需支持的Option如下:
Uri-Path:定义接口类型。具体定义见下表。 Uri-Path定义
Uri-Path定义 | 备注 |
---|---|
/SPEKE | 用于speke协商 |
/CloudSetup/v2 | 用于下发设备配网信息 |
/.sys/psk | 用于psk协商 |
/.sys/activate | 用于设备激活 |
/.sys/login | 用于设备登录 |
/.sys/devInfoSync | 用于设备信息同步 |
/.sys/heartbeat | 用于心跳 |
/.sys/refresh | 用于psk刷新 |
/.sys/revoke | 用于设备向云端注销接口 |
/.sys/authCode | 用于下发authCode |
/.sys/diagnosis | 用于诊断信息上报 |
/.well-known/core?st=ohCloudSetup | 用于查询是否有待激活设备 |
/.well-known/core?st=ohLocalControl | 用于查询本地控制 |
Content-Format:如发送方支持JSON编码,则需携带该Option,取值为50(“application/json”)。
9.1.6 重传和容错
在CoAP over TLS或者CoAP over TCP下,重传和容错应通过传输层的重传机制保证,本文件不做规定。在CoAP over UDP下,局域网本地的重传和容错规定如下: 当两端建立IP层连接后,发送方进行第一条报文的发送,发送方将以100ms间隔发送第一条报文,直到收到接收方发送的响应报文。 对于中间报文,每隔1秒重发一次,一共发送5次。两端应对报文的重发做出冗余处理。 在发送最后一条报文时,为确保对端接收成功率,该条报文应发送5次,每次间隔100ms。
9.2 BLE传输
9.2.1 设备连接注册流程
设备连接注册流程主要分为以下三个阶段:
1. 建立连接: 主控设备与蓝牙设备之间使用OpenHarmony通用UUID,建立GATT连接。
2. 代理注册: 主控设备获取蓝牙设备的相关信息,并在云端代理注册。蓝牙设备接收并存储AuthCode,用于数据传输过程的加密。该过程主要涉及如下服务。
• 查询蓝牙辅助配网协议版本(netCfgVer)
• 查询设备配网注册信息(deviceInfo)
• 发送authCode至设备(authSetup)
1. 断开连接: 主控设备与蓝牙设备之间断开GATT连接。
9.2.2 设备控制流程
设备控制流程(含数据加解密)主要分为以下三个阶段:
1. 建立连接: 主控设备与蓝牙设备建立GATT连接。
2. 协商秘钥: 主控设备与蓝牙设备创建会话并协商秘钥(SN1、SN2),详见创建会话(createSession)。
3. 加密传输: 对于控制报文和响应报文,均需要经加密处理后再进行数据传输。传输结束后,断开GATT连接。
数据传输均需使用customSecData服务,典型场景包括:查询设备状态、查询设备所有服务、查询设备信息、控制设备状态、设备主动上报等。
9.2.3 BLE 服务要求
设备连接: 使用OpenHarmony通用UUID建立GATT连接。
OpenHarmony GATT服务声明为Primary Service,包含读、写两个属性,具体说明参见下表。
服务 Service ID | 服务UUID Service UUID | 属性 Characteristics | 属性UUID Characteristic UUID | 操作权限 Permissions | 数据类型Format |
---|---|---|---|---|---|
ConnectData | 15f1e600-a277-43fc-a484-dd39ef8a9100 | - | - | - | - |
- | - | readData | 15f1e601-a277-43fc-a484-dd39ef8a9100 | indicate/read | String |
- | - | writeData | 15f1e602-a277-43fc-a484-dd39ef8a9100 | write | String |
注意: 主控设备与蓝牙设备协商的MTU(Maximum Transmission Unit)范围为160~500字节, 默认协商的MTU为251字节。
设备配对: 推荐使用Just Works配对模式。
Just Works适用于无交互界面的蓝牙设备(例如蓝牙耳机),由主控设备发起连接即可完成配对,用户无需在被连接的蓝牙设备上进行操作。
设备控制: 已存在SIG Profile的设备(如血压计、血糖仪等):采用SIG Profile定义的设备能力。在设备发现、配对阶段,使用OpenHarmony通用UUID的GATT通道,设备注册完成后即断开连接。在设备控制阶段,使用SIG标准UUID建立连接。不存在SIG Profile的设备(如二轮车、点读笔等):优先采用OpenHarmony Profile定义的设备能力。在设备发现、配对、控制阶段,均使用OpenHarmony通用UUID的GATT通道。
9.2.4 数据传输及分包规范
蓝牙设备的数据在应用层传输时,需要遵循OpenHarmony通用的格式要求。数据包采用JSON字符串格式。每一数据包由Header与Payload组成,Header长度为7字节,Payload总长度为0~1500字节。单个数据包最大251字节,当数据包长度超过单包最大长度时,需要进行分包。
BLE数据包结构图
字段 | 长度(字节) | 是否必选 | 说明 | |
---|---|---|---|---|
Header | Version | 0.5 | 是 | 蓝牙BLE应用层协议的版本号,默认为0b0000。根据业务演进递增。 |
Cmd Type | 0.5 | 是 | 消息类型,包括:请求、响应、上报三种。· 0b0000:请求消息(REQ)。· 0b0001:响应消息(RSP)。· 0b0010:主动上报消息(RPT)。 | |
Messg ID | 1 | 是 | 消息序号,默认取值为0。· 0b00:表示该报文不需要分片。· 0x01~0xFF:表示该报文需要分片,取值与报文的token字段相同。 | |
Total Frame | 1 | 是 | 总包数。范围 0~255。· 0x01:不分包时,取值为1。· 0x02~0xFF:分包时,取值为≥2。 | |
Frame Seq | 1 | 是 | 包序号。· 0x00:不分包时取值为0。· 0x01~0xFF:分包时,取值为从1开始依次递增。 | |
Rev | 1 | 是 | 保留字段,便于后续扩展。当前可以设置为0。 | |
Encry | 1 | 是 | 数据加密方式。· 0x00:不加密。BLE需要SMP安全配对,配对建议采用Just works方式。· 0x01:配网SPEKE加密。· 0x02:控制SPEKE加密。· 0x03:Session Key加密。· 0x04:基于AuthCode派生秘钥加密。 | |
Return | 1 | 是 | 消息的执行结果。· 主动上报消息:填写0x00。· 请求消息:填写0x00。· 响应消息:填写执行结果。0x00表示执行成功,0x01表示执行失败。 | |
Payload | Data Format | 0.5 | 是 | 数据格式。当前只支持JSON字符串格式,取值固定为0b01。 |
Opt Type | 0.5 | 是 | 操作类型,取值说明如下:· 00:PUT· 01:GET· 02:REPORT | |
Service Length | 1 | 是 | 服务名长度。 | |
Service Name | n | 是 | 服务名称,ASCII字符,例如netCfgVer:查询蓝牙辅助配网协议版本 deviceInfo:查询设备配网注册信息 createSession:创建会话 authSetup:发送authCode至设备 customSecData:设备操作数据 authdelete:代理删除设备 clearDevRegInfo:恢复出厂设置 speke: SPEKE安全协商 filetrans: 文件传输 | |
Body Length | 2 | 是 | 数据长度。 | |
Body | N | 是 | json格式的数据内容,例如:{"sn": "0EFEEFFAEF","pid": "1234"} |
9.2.5 通用服务规范
9.2.5.1 查询蓝牙辅助配网协议版本(netCfgVer)
功能说明:建立GATT连接后,主控设备会通过netCfgVer服务,查询蓝牙辅助配网协议版本。蓝牙设备收到请求后,返回协议版本。 加密方式:不加密 请求格式: 当请求为空时,表示主控设备为手机。 当请求格式如下时,表示主控设备为网关。 {"source":"gw"} 响应格式: {"ver":%d}
参数 | 类型 | 说明 |
---|---|---|
ver | int | 蓝牙辅助配网协议版本,取值如下:3: 控制采用Speke加密,默认支持设备与手机直连。4: 协商采用Speke方式,控制采用Authcode加密。5:协商采用Authcode,控制采用Authcode加密。既支持设备与手机直连,又支持设备与网关连接。100~199:采用本协议规范接入,默认为100。 |
9.2.5.2 查询设备配网注册信息(deviceInfo)
功能说明:在设备代理注册之前,主控设备会通过deviceInfo服务,查询蓝牙设备的配网注册信息。蓝牙设备收到请求后,返回注册信息。
加密方式:基于AuthCode派生秘钥
请求格式:无
响应格式:
{
"productId":"%s", "sn":"%s", "vendor":[{ "devId":"%s", "deviceInfo":"%s"}]
}
其中,deviceInfo取值格式如下:
Comb设备:
** {"sn":"%s","model":"%s","devType":"%s","manu":"%s","prodId":"%s","mac":"%s","blemac":"%s","hiv":"%s","fwv":"%s","hwv":"%s","swv":"%s","protType":"%s"}
纯BLE设备:
{"sn":"%s","model":"%s","devType":"%s","manu":"%s","prodId":"%s","blemac":"%s", "hiv":"%s","fwv":"%s","hwv":"%s","swv":"%s","protType":"%s","longcon":"1"}**
参数 | 类型 | 说明 | ||
---|---|---|---|---|
productId | - | - | String | 产品ProdID,与Device Partner平台的取值保持一致。 |
sn | - | - | String | 设备SN号。 |
vendor | - | - | String | - |
devId | - | String | 设备ID。 | |
deviceInfo | - | String | - | |
sn | String | 设备SN号。 | ||
model | String | 设备型号。 | ||
devType | String | 设备类型。 | ||
manu | String | 企业名称。 | ||
prodId | String | 产品ProdID,与Device Partner平台的取值保持一致。 | ||
mac | String | Wi-Fi设备MAC地址,仅Comb设备涉及。 | ||
blemac | String | 蓝牙设备的MAC地址。 | ||
hiv | String | HarmonyConnect版本号。 | ||
fwv | String | 固件版本号。 | ||
hwv | String | 硬件版本号。 | ||
swv | String | 软件版本号。 | ||
protType | String | 协议类型。默认取值为4,表示蓝牙BLE连接协议。如果门锁支持BLE+Wi-Fi,则取值为12。0:未定义 1:Wi-Fi 2:Z-Wave 3:ZigBee 4:BlueTooth 5:PLC 6:BLE Mesh 7:NFC 8:Ethernet (以太网) 9:Moblie Network(3G/4G等无线接入设备) 10:USB 11:PLC+Wi-Fi(Wi-Fi用于升级) 12:BLE+Wi-Fi(Wi-Fi用于升级) 13:HiBeacon协议(设备通过蓝牙广播方式完成状态上报) |
9.2.5.3 发送authCode至设备(authSetup)
功能说明: 蓝牙设备注册成功后,主控设备会从云端获取authCode、并通过authSetup服务将authCode下发至蓝牙设备。蓝牙设备需要存储该值,用于后续数据传输的加解密。 加密方式: 不加密
发送格式: {
"devId":"xxxx",
"authCode":"xxxx",
"uidHash":"xxxx",
"authCodeId":"xxxx"
}
其中,authCode的长度为32字节,由16bytes的二进制数据转成16进制字符串而成。
9.2.5.4 创建会话(createSession)
功能说明: 主控设备通过createSession服务,请求创建会话并协商会话秘钥。蓝牙设备返回响应,会话创建成功。 加密方式: 不加密
请求格式:
{
"seq":%s,
"uuid":"%s",
"uidHash":"%s",
"sn1":"%s"
}
参数 | 类型 | 说明 |
---|---|---|
seq | String | 连接序列号,每次递增。 |
uuid | String | 手机的唯一标识。 |
uidHash | String | UID的Hash值。 |
sn1 | String | 协商的sn1参数,用于计算秘钥盐值。 |
响应格式:
{
"seq":%s ,
"sessId":"%s",
"sn2":"%s"** ,**
"authCodeId":"%s"
}
参数 | 类型 | 说明 |
---|---|---|
seq | String | 连接序列号,每次递增。 |
sessId | String | 设备分配给手机的会话ID,长度为32个字节的随机字符串。 |
sn2 | String | 协商的sn2参数,用于计算秘钥盐值。 |
authCodeId | String | 采用的authCode序号。 |
9.2.5.5 查询设备状态(customSecData)
功能说明: 主控设备通过customSecData服务,查询设备状态(携带具体sid)。蓝牙设备收到请求后,返回查询结果或错误码。 加密方式: spekeKey/sessionKey 请求格式:
{
"seq":xxxx,// xxxx为递增数字
"vendor":[{
"sid":"onoff"}]
}
响应格式:
执行成功,返回具体查询结果。
{
"seq":xxxx,// xxxx为递增数字
"vendor":[{
"sid":"onoff",
"data":{"onoff":0}
}]
}
执行失败,返回错误码。
{"errcode": xxx}
9.2.5.6 查询设备所有服务(customSecData)
功能说明: 主控设备通过customSecData服务,查询设备所有服务状态(sid为allservices)。蓝牙设备收到请求后,返回是否查询成功。查询成功后,蓝牙设备还需要主动上报所有服务状态,参见设备主动上报(customSecData)。 加密方式: spekeKey/sessionKey 请求示例:
{ "seq":xxxx,// xxxx为递增数字
"vendor":[{
"sid":"allservices"}]
}
响应示例:
执行成功,返回0。
{"errcode": 0}
设备侧主动上报所查询的所有服务状态。
{
"seq":xxxx,// xxxx为递增数字
"vendor":[{
"sid":"onoff",
"data":{"onoff":0}
},{
"sid":"brushstregth",
"data":{"brushstregth":1}
}]
}
执行失败,返回错误码。
{"errcode": xxx}
9.2.5.7 查询设备信息(customSecData)
功能说明: 主控设备通过customSecData服务,查询设备信息。蓝牙设备收到请求后,返回是否查询成功。查询成功后,蓝牙设备还需要主动上报设备版本号信息,参见设备主动上报(customSecData)。 加密方式: spekeKey/sessionKey 请求示例:
{
"seq":xxxx,// xxxx为递增数字
"vendor":[{
"sid":"deviceinfo",
"source":"gw"** // 如果source字段取值为"gw",表明主控设备为网关;如果不携带该字段,表示主控设备为手机。
}]
}
响应示例:
执行成功,返回0。
{"errcode": 0}**
设备侧主动上报所查询的设备信息。
{
"seq":xxxx,// xxxx为递增数字
"vendor":[{
"sid":"deviceinfo",
"data":[{
"hiv":"1.0", // 可选,HarmonyConnect版本号
"fwv":"1.0", // 必选,固件版本号
"hwv":"1.0", // 必选,硬件版本号
"swv":"1.0", // 可选,软件版本号
}]
}]
}
执行失败,返回错误码。
{"errcode": xxx}
9.2.5.8 控制设备状态(customSecData)
主控设备通过customSecData服务,发送设备状态控制指令。蓝牙设备收到请求后,返回是否执行成功。 操作执行成功后,蓝牙设备还需要主动上报最新的状态,参见设备主动上报(customSecData)。
加密方式: spekeKey/sessionKey
请求示例:
{
"seq":xxxx**,// xxxx为递增数字**
"vendor":[{
"sid":"onoff",
"data":{"onoff":0**}**
},{
"sid":"brushstregth",
"data":{"brushstregth":1**}**
}]
}
响应示例:
执行成功,返回0。
{"errcode": 0}
执行失败,返回错误码。
{"errcode": xxx}
9.2.5.9 设备主动上报(customSecData)
当蓝牙设备的状态发生变化(例如用户执行了设备控制操作)时,需要通过customSecData服务主动上报最新的状态。主动设备会根据最新的状态刷新设备状态。
说明
vendor中各字段的取值必须与OpenHarmony Profile保持一致。
加密方式: spekeKey/sessionKey
消息示例:
{
"seq":xxxx,// xxxx为递增数字
"vendor":[{
"sid":"onoff",
"data":{"onoff":0}
},{
"sid":"brushstregth",
"data":{"brushstregth":1}
}]
}
9.2.5.10 代理删除设备(authdelete)
蓝牙设备在同一时间段只能与一个用户仅绑定。通过authdelete服务,解除蓝牙设备与老用户的绑定关系后,才能与新用户进行绑定。
加密方式: 无
请求格式:
{"challenge": "xxxx"}
响应格式:
执行成功,返回sigvalue取值。
{"sigvalue": "xxxx"} 其中,设备签名参数sigvalue的计算方法如下:
根据prk与info,计算okm的取值。
prk = extract(authcode)
info ="Device-Revoke"
okm= expand(prk, info)
采用hmac-sha256算法,计算签名参数。
sigvalue = hmac(devId+challenge+authcodeId, okm)
其中,authcode、devId、authcodeId在设备注册时均存储在Flash中。devid、challenge、authcodeId以及okm,均使用字面字符的直接byte[]、无需转为原始字节数组byte[],String到byte数组的转换统一按UTF-8处理。 执行失败,返回错误码。
{"errcode": xxx}
9.2.5.11 恢复出厂设置(clearDevRegInfo)
主控设备通过clearDevRegInfo服务,发送恢复出厂设置指令。蓝牙设备收到请求后,清除设备已注册的信息。 注意 在清除设备配网参数时,需要保留Authcode参数。其他用户执行代理删除操作时需要使用该参数。
加密方式: 基于Authcode派生秘钥
请求格式:
{"devId":"%s"}
参数 | 类型 | 说明 |
---|---|---|
devId | String | 设备注册成功后,云端分配给设备的唯一标识。 |
**表7 **参数说明 |
响应格式: 成功,返回0。 {"errcode":"0"} 失败,返回错误码。 {"errcode":"xxxx"}
9.2.5.12 SPEKE安全协商(speke)
蓝牙SPEKE安全协商,详见6.2.3章节。
9.2.5.13 文件传输(filetrans)
主控设备通过filetrans服务,进行文件传输,详细文件传输报文参见8.2.12章节。
9.2.5.14 通用错误码
蓝牙设备需要将指令是否执行成功,通过errcode字段返回给主控设备。errcode取值参见下表。
错误码 | 说明 |
---|---|
0 | 成功。 |
500 | 设备被重置。 |
600 | 设备控制失败。 |
601 | 状态查询失败。 |
602 | 内存不足。 |
603 | 设备异常。 |
604 | BLE协议栈异常。 |
10 数据模型
数据模型定义了生态设备与生态设备,APP与设备,设备与云平台之间交互需要遵循的规范。详细内容请参考《鸿蒙生态设备互联互通互操作 物模型规范》。
11 设备控制和设备管理
11.1 通用设备控制接口
11.1.1 OHOS-CTRL-GET-API
【适用范围】所有
【描述】对设备上的服务发送实时GET操作都如本文的接口定义。
【请求】
IF1及IF5 App ->Device接口请求示例:
GET /{sid}
CoAP点对点操作时,直接通过服务ID对服务进行操作。
IF2 Cloud->Device接口请求示例:
GET /{sid}
COAP_OPT_REQ_ID: requestId
COAP_OPT_USER_ID: userId
COAP_OPT_DEV_ID: devId
云端发给Device的请求在COAP_OPT_REQ_ID扩展Option中附带requestId,标识该请求的唯一ID;Device回应时,需要原封不动的回应此Option值。
云端发给Device的请求在COAP_OPT_USER_ID扩展Option中附带userId,标识哪个用户发起的请求;Device回应时,也需要原封不动的回应此Option值。
云端发给Device的请求在COAP_OPT_DEV_ID扩展Option中附带devId,标识发给哪个设备的请求;Device回应时,也需要原封不动的回应此Option值。
设备上不应该理解上述三个Option值的格式及内容,只需要原封不动的返回即可。
IF3 APP-Cloud接口请求示例: GET /userApp/v1/devices/{devId}/services/{sid} HTTP/1.1
需增加Authorization报头。
【回应】:
IF1及IF5 App<-Device接口返回示例:
{
"characteristicName1": "value1",
"characteristicName2": "value2"
}
IF2 Cloud<-Device接口返回示例:
COAP_OPT_REQ_ID: requestId [CoAP TCP设备需回应此报头]
COAP_OPT_USER_ID: userId [CoAP TCP设备需回应此报头]
COAP_OPT_DEV_ID: devId [CoAP TCP需回应此报头]
{
"characteristicName1": "value1",
"characteristicName2": "value2"
}
对于IF1、IF5、IF2请求的回应,需要进行AES加密。
【错误码】:
如果设备不在线,返回OHOS_CONNECT_DEV_OFFLINE;
如果设备响应超时,返回OHOS_CONNECT_DEV_TIMEOUT。
11.1.2 OHOS-CTRL-POST-API
【适用范围】所有
【描述】对设备上的服务发送实时POST操作都如本文的接口定义。
【请求】
IF1及IF5 App ->Device接口请求示例:
POST /{sid}
{
"characteristicName1": "value1",
"characteristicName2": "value2"
}
CoAP点对点操作时,直接通过服务ID对服务进行操作。
IF2 Cloud->Device接口请求示例:
POST /{sid}
COAP_OPT_REQ_ID: requestId
COAP_OPT_USER_ID: userId
COAP_OPT_DEV_ID: devId
{
"characteristicName1": "value1",
"characteristicName2": "value2"
} 云端发给Device的请求在COAP_OPT_REQ_ID扩展Option中附带requestId,标识该请求的唯一ID;Device回应时,需要原封不动的回应此Option值。
云端发给Device的请求在COAP_OPT_USER_ID扩展Option中附带requestId,标识哪个用户发起的请求;Device回应时,也需要原封不动的回应此Option值。
云端发给Device的请求在COAP_OPT_DEV_ID扩展Option中附带devId,标识发给哪个设备的请求;Device回应时,也需要原封不动的回应此Option值。
设备上不应该理解上述三个Option值的格式及内容,只需要原封不动的返回即可。
IF3 APP-Cloud接口请求示例:
POST /userApp/v1/devices/{devId}/services/{sid} HTTP/1.1
{
"characteristicName1": "value1",
"characteristicName2": "value2"
}
需增加Authorization报头。
【batch Command】:
关于控制命令的下发有一种特殊的处理情况:由于需要支持batch服务(一个控制命令中需要下发多个服务参数),POST命令的body结构体需要做相应的修改。即当下发的是batch服务,那么其对应的POST命令的body的格式规范如下:
POST /batchCmd
{
"type":4,
"actions": [
{
"sid": "sid1",
"data": {
"characteristicName1": "value1"
}
},
{
"sid": "sid2",
"data": {
"characteristicName1": "value1"
}
}
]
}
对于设备控制命令的POST请求头的格式不变(涉及的设备命令接口包括:App->Device,Cloud->Device,APP->Cloud),只需要把“batch”字符串填充到相应的sid里面即可。
11.2 通用数据上报接口
11.2.1 数据上报的场景过程
图1 SSR-DEV-DATA-WAN设备远程上报数据接口
11.2.2 OHOS-DATA-API
【适用范围】IF2
【描述】OpenHarmony设备采集到的数据有变更时,通过此接口上报给云服务器。
【请求】
POST /.sys/data
[
{
"devId": "xxxx",
"services": [
{
"reportId": "123588888", //SDK携带,用于数据上报去重
"sid": "sid1",
"data": {
"characteristicName1": "value1",
"characteristicName2": "value2"
}
}
]
}
]
请求的参数如下:
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
必选 | deviceDataInfo[] | 设备上报的数据 |
【回应】:
成功 { "errcode": 0, "status": 0 }
失败 { "errcode": xxx }
回应的参数如下:
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
errcode | 必选 | Integer | 错误码。 |
status | 可选 | gatewayStatus | 网关当前是否已经登录云的状态。网关和设备之间有此状态值,云和设备/网关之间没有 |
【错误码】:
OHOS_CONNECT_VALIDATE_ERR
11.3 点到点本地控流程
11.3.1 Wi-Fi设备点到点本地控
11.3.1.1 点到点本地控查询操作
【适用范围】点到点本地控
【描述】设备点到点查询操作,向设备发送POST消息,消息中携带的sid来标识需要查询的服务,查询操作会立即返回errcode状态,最终状态通过异步上报方式进行上报。
【请求】POST
【加密】spekekey
IF1.1查询接口请求示例:
POST /e2eCtrl
{
"seq": xxxx, // xxxx为递增数字
"data": [
{
"sid": "sid1"
},
{
"sid": "sid2"
}
]
}
说明:通过服务ID来标识对应具体的服务查询。
IF1.1查询所有服务接口请求示例:
POST /e2eCtrl
{
"seq": xxxx, // xxxx为递增数字
"data": [
{
"sid": "allservices"
}
]
}
说明:通过服务ID固定为allservices。
【回应】:
执行成功,异步方式返回具体查询结果
{
"errcode": 0
}
执行失败,返回错误码。
{
"errcode": xxx
}
11.3.1.2 点到点本地控设置操作
【适用范围】点到点本地控
【描述】对设备上的服务发送实时POST操作都如本文的接口定义。
【请求】POST
【加密】spekekey
IF1.1接口请求示例:
POST /e2eCtrl
{
"seq": xxx, // xxxx为递增数字
"data": [
{
"sid": "sid1",
"data": {
"characteristicName1": "value1"
}
},
{
"sid": "sid2",
"data": {
"characteristicName1": "value1"
}
}
]
}
CoAP点对点操作时,直接通过服务ID对服务进行操作。
【回应】:
执行成功,返回具体查询结果
{
"errcode": 0
}
执行失败,返回错误码。
{
"errcode": xxx
}
11.3.1.3 点到点本地控主动上报
【适用范围】点到点本地控
【描述】对设备上的服务发送实时POST操作都如本文的接口定义。
【请求】POST
【加密】spekekey
请求接口示例
POST /e2eDataChange
{
"seq": xxxx,// xxxx为递增数字
"services": [
{
"sid": "sid1",
"data": {
"characteristicName1": "value1"
}
},
{
"sid": "sid2",
"data": {
"characteristicName1": "value1"
}
}
],
}
执行成功,返回结果
{
"errcode": 0
}
11.3.2 BLE设备点到点本地控
11.3.2.1 查询设备状态(customSecData)
主控设备通过customSecData服务,查询设备状态(携带具体sid)。蓝牙设备收到请求后,返回查询结果或错误码。
说明
vendor中各字段的取值必须与OpenHarmony Profile保持一致。
**加密方式:**spekeKey/sessionKey
请求格式:
{
"seq":xxxx, // xxxx为递增数字
"vendor": [
{
"sid": "sidname"
}
]
}
响应格式:
执行成功,返回具体查询结果。
{
"seq":xxxx, // xxxx为递增数字
"vendor": [
{
"sid": "sidname",
"data": {
"characteristicName1": "value1",
"characteristicName2": "value2"
}
}
]
}
执行失败,返回错误码。
{
"errcode": xxx
}
11.3.2.2 查询设备所有服务(customSecData)
主控设备通过customSecData服务,查询设备所有服务状态(sid为allservices)。蓝牙设备收到请求后,返回是否查询成功。
查询成功后,蓝牙设备还需要主动上报所有服务状态,参见设备主动上报(customSecData)。
说明
vendor中各字段的取值必须与OpenHarmony Profile保持一致。
**加密方式:**spekeKey/sessionKey
请求示例:
{
"seq":xxxx, // xxxx为递增数字
"vendor": [
{
"sid": "allservices"
}
]
}
响应示例:
执行成功,返回0。
{
"errcode": 0
}
设备侧主动上报所查询的所有服务状态。
{
"seq":xxxx, // xxxx为递增数字
"vendor": [
{
"sid": "sidname1",
"data": {
"characteristicName1": "value1",
"characteristicName2": "value2"
}
},
{
"sid": "sidname2",
"data": {
"characteristicName1": "value1",
"characteristicName2": "value2"
}
}
]
}
执行失败,返回错误码。
{
"errcode": xxx
}
11.3.2.3 查询设备信息(customSecData)
主控设备通过customSecData服务,查询设备信息。蓝牙设备收到请求后,返回是否查询成功。
查询成功后,蓝牙设备还需要主动上报设备版本号信息,参见设备主动上报(customSecData)。
说明
vendor中各字段的取值必须与OpenHarmony Profile保持一致。
加密方式: spekeKey/sessionKey
请求示例:
{ "seq":xxxx,// xxxx为递增数字
"vendor":[{
"sid":"deviceinfo",
"source":"gw"** // 如果source字段取值为"gw",表明主控设备为网关;如果不携带该字段,表示主控设备为手机。
}]
}
响应示例:
执行成功,返回0。
{"errcode": 0}**
设备侧主动上报所查询的设备信息。
{
"seq":xxxx,// xxxx为递增数字
"vendor":[{
"sid":"deviceinfo",
"data":[{
"hiv":"1.0", // 可选,HarmonyConnect版本号
"fwv":"1.0", // 必选,固件版本号
"hwv":"1.0", // 必选,硬件版本号
"swv":"1.0", // 可选,软件版本号
}]
}]
}
执行失败,返回错误码。
{"errcode": xxx}
11.3.2.4 控制设备状态(customSecData)
主控设备通过customSecData服务,发送设备状态控制指令。蓝牙设备收到请求后,返回是否执行成功。
操作执行成功后,蓝牙设备还需要主动上报最新的状态,参见设备主动上报(customSecData)。
加密方式: spekeKey/sessionKey
请求示例:
{
"seq":xxxx**,// xxxx为递增数字**
"vendor":[{
"sid":"onoff",
"data":{"onoff":0**}**
},{
"sid":"brushstregth",
"data":{"brushstregth":1**}**
}]
}
响应示例:
执行成功,返回0。
{"errcode": 0}
执行失败,返回错误码。
{"errcode": xxx}
11.4 局域网本地控流程
【适用范围】局域网本地控
【描述】对设备上的服务发送实时GET操作都如本文的接口定义。
【请求】GET
【加密】authcode
IF5接口请求示例:
GET /{sid}
CoAP点对点操作时,直接通过服务ID对服务进行操作。
【回应】:
执行成功,返回具体查询结果
{
"characteristicName1": "value1",
"characteristicName2": "value2"
}
执行失败,返回错误码。
{
"errcode": xxx
}
【适用范围】点到点本地控
【描述】对设备上的服务发送实时POST操作都如本文的接口定义。
【请求】POST
【加密】authcode
IF5接口请求示例:
POST /{sid}
{
"characteristicName1": "value1",
"characteristicName2": "value2"
}
CoAP点对点操作时,直接通过服务ID对服务进行操作。
【回应】:
执行成功,返回具体查询结果
{
"errcode": 0
}
执行失败,返回错误码。
{
"errcode": xxx
}
11.5 设备解除绑定流程(TODO)
11.6 云端删除设备的过程
如下图所示,用户从云端删除设备时,如果设备在线,云端调用删除设备接口删除;如果是离线设备,设备重试登录时,通过返回OHOS_CONNECT_DEV_DELETED错误码告知设备已被删除。已被删除的设备需要自行删除本地的devId和secret、psk以及WiFi参数,并且停止连接云服务器。
图2 SSR-DEV-DEL-ONLINE 用户删除在线的直连云设备过程
图3 SSR-DEV-DEL-OFFLINE 用户删除离线的直连云设备过程
当删除离线设备时,在下次设备上电登录时,也是通过OHOS_CONNECT_DEV_DELETED错误码告知设备已被删除。
11.7 设备恢复出厂流程
智能组网终端有多个途径恢复出厂,恢复出厂后,无法告知平台;智能组网终端清除当前的devId/secret以及PSK等信息,标记下当前处于待激活状态。 下一次设备上电后,一旦获取到IP,并且可以访问平台时,先向平台发起注册(/.sys/register),注册成功后断开与设备的连接,重新再接受新的用户激活。 注:当APP用户发起注册流程的时候,TLS连接将在APP成功激活设备之后重新建立。
11.7.1 直连云设备的恢复出厂过程
如下图所示,直连云的设备恢复出厂后,无法告知云端;设备不能清除当前的devId/secret以及PSK,而是标记下当前处于待注销状态。 下一次设备上电后,一旦获取到IP,并且可以访问云时,需要使用老的登录信息直连到云上,自行注销;然后再接受新的用户激活。
图4 SSR-DEV-RESET 直连云设备的恢复出厂过程