7.5.2 CMS ID 组件
7.5.2 CMS ID 组件
📚 本节导读
学习时长:约 25 分钟
难度级别:⭐⭐⭐⭐☆
前置知识:CWT/CBOR 基础、设备认证概念、第 7.5.1 节 CMS Connect
🎯 学习目标
- 理解 CMS ID 组件的注册与认证机制
- 掌握实体认证令牌 CWT 的原理
- 掌握
cms_id_*核心 API 及CMS_TYPE_T枚举 - 掌握 CMS ID 的 Menuconfig 配置方法
- 掌握设备注册(regist)→ 认证(authorize)的完整流程
一、CMS ID 组件概述
CMS ID 组件承接端侧设备注册、设备认证服务,向开发者提供设备统一的实体认证令牌(EAT,Entity Attestation Token),并提供设备认证、EAT 校验、设备 ID 信息查询等接口。
一句话核心:开发者通过 CMS 云平台注册项目,用轻量级实体认证令牌 CWT 实现设备端与云平台之间的身份互信——设备先 cms_id_regist 注册,再 cms_id_authorize 认证,认证通过后即可使用云平台的 FOTA 升级、设备定位等服务。
1.1 架构设计
┌───────────────────────────────┐
│ CMS ID 组件 │
├──────────────┬────────────────┤
│ 管理模块 │ CWT 模块 │
│ 设备注册管理 │ Token 制作 │
│ 设备认证管理 │ 挑战码签名 │
│ 数据报文交互 │ CBOR 编码/验证 │
├──────────────┼────────────────┤
│ 密钥管理 │ 数据存储 │
│ 密钥派生服务 │ 注册认证信息存储 │
└──────────────┴────────────────┘各模块职责:
- 管理模块:提供端侧与平台间的数据报文交互服务、设备注册管理、设备认证管理;
- 密钥管理:提供密钥的派生服务;
- 数据存储:提供端侧注册认证信息的存储与查询服务;
- CWT:提供实体认证令牌的制作、挑战码的签名、Token 的 CBOR 编码、Token 的验证等相关服务。
关键理解:CMS ID 的核心不是简单的"DeviceSecret 比对",而是基于 CWT(CBOR Web Token) 的挑战码签名与令牌互信。设备注册后,端侧/平台各自签发 CWT 令牌(
CWT_DEVICE/CWT_PLATFORM),通过挑战码(CTI_DEVICE/CTI_PLATFORM)签名实现双向身份互信。
1.2 线上管理组件(需远程下载)
CMS ID 与 CMS Connect 同属 CMS 线上管理组件,官方源码不随 OneOS 内核/组件默认打包。使用前需先通过 OneOS Studio 的组件远程下载/管理功能把 CMS 组件下载到本地工程(components/cms/),之后才可在 Menuconfig(Components → CMS)配置与代码中使用。
二、Menuconfig 配置
2.1 CMS 版本选择
完整源码(components/cms/source/Kconfig):
choice
prompt "CMS Version"
default CMS_LITE
config CMS_LITE
bool "CMS Lite"
config CMS_STD
bool "CMS Standard"
endchoiceCMS 组件分 CMS Lite(默认)与 CMS Standard 两个版本,按资源与功能需求选择。
2.2 CMS ID 配置
路径:(Top) → Components → CMS → CMS ID。完整源码(source/Kconfig 的 menu "CMS ID"):
menu "CMS ID"
config CMS_USING_ID
bool "Enable CMS_ID for register and verification"
default n
if CMS_USING_ID
config CMS_ID_SET_PID
prompt "Pid config"
help
config pid
string
default "BfGoACQ38Q"
config CMS_ID_KEY
prompt "key config"
help
config key by hex
string
default "E6004E3F46ED3627F7C72E3AE2346FD6"
choice
prompt "Auth Mode"
default UNILATERALISM_AUTH
config MUTUAL_AUTH
bool "Mutual Auth"
config UNILATERALISM_AUTH
bool "Unilateralism Auth"
endchoice
endif
endmenu配置项说明:
| 配置项 | 说明 |
|---|---|
CMS_USING_ID | Enable CMS_ID for register and verification,CMS ID 总开关(默认 n) |
CMS_ID_SET_PID | Pid config:CMS 云平台所注册项目的产品 ID,可在项目详情中查看 |
CMS_ID_KEY | key config:CMS 云平台所注册项目的产品密钥(hex 格式),可在项目详情中查看 |
MUTUAL_AUTH | Auth Mode = 双向认证:设备与平台互签令牌互验 |
UNILATERALISM_AUTH | Auth Mode = 单向认证(默认):仅平台校验设备 |
关键理解:配置好 CMS_ID_SET_PID(产品 ID)与 CMS_ID_KEY(产品密钥)后,CMS ID 组件才能完成注册与认证;Auth Mode 决定是单向(默认)还是双向认证。
三、数据结构(CMS_TYPE_T)
完整源码(source/include/cms_id.h):
typedef enum
{
PID = 0,
OID,
DID,
CTI_DEVICE,
CTI_PLATFORM,
CWT_DEVICE,
CWT_PLATFORM,
KEY_MASTER,
OS_VER
} CMS_TYPE_T;枚举详解(可查询的 ID 列表):
| 枚举 | 值 | 释义 |
|---|---|---|
PID | 0 | 产品(项目)ID |
OID | 1 | 全球唯一的对象标识(遵循 OID 标识体系) |
DID | 2 | 设备硬件标识 |
CTI_DEVICE | 3 | 端侧挑战码 |
CTI_PLATFORM | 4 | 平台挑战码 |
CWT_DEVICE | 5 | 设备令牌 |
CWT_PLATFORM | 6 | 平台令牌 |
KEY_MASTER | 7 | 主密钥 |
OS_VER | 8 | 操作系统版本 |
关键理解:CMS_TYPE_T 就是 cms_id_get_id_len/cms_id_get_id 的 type 参数取值。PID/OID/DID 是字符串标识(strdump 查看),CTI/CWT 是字节数据(hexdump 查看);注册认证过程中,设备与平台通过 CTI(挑战码)签名、CWT(令牌)互验实现互信。
四、核心 API 详解
4.1 接口总览
完整源码(头文件声明,source/include/cms_id.h):
int cms_id_get_id_len(const CMS_TYPE_T type, size_t *len);
int cms_id_get_id(const CMS_TYPE_T type, uint8_t *buf, const size_t len);
int cms_id_cwt_check(uint8_t *cwt, const uint8_t len);
int cms_id_regist_check(void);
int cms_id_auth_check(void);
int cms_id_regist(void);
int cms_id_authorize(void);| 接口 | 说明 |
|---|---|
cms_id_get_id_len | 获取指定 ID 的长度 |
cms_id_get_id | 获取指定 ID 的值 |
cms_id_cwt_check | 校验平台令牌 CWT(仅 UDP 连接协议场景) |
cms_id_regist_check | 检查当前设备是否已注册 |
cms_id_auth_check | 检查当前设备是否已认证 |
cms_id_regist | 发起设备注册请求 |
cms_id_authorize | 发起设备认证请求 |
4.2 cms_id_get_id_len —— 获取 ID 长度
函数原型:
int cms_id_get_id_len(const CMS_TYPE_T type, size_t *len)| 参数 | 说明 |
|---|---|
type | 查询的 ID 类型(CMS_TYPE_T) |
len | 输出:ID 长度值 |
| 返回 | 0 读取成功;非 0 读取失败 |
分步详解:
第一步:声明长度变量(无条件执行)
size_t len = 0;第二步:按类型查询(无条件执行)
cms_id_get_id_len(PID, &len); /* 读取产品 ID 长度到 len */4.3 cms_id_get_id —— 获取 ID 值
函数原型:
int cms_id_get_id(const CMS_TYPE_T type, uint8_t *buf, const size_t len)| 参数 | 说明 |
|---|---|
type | 查询的 ID 类型(CMS_TYPE_T) |
buf | 输出:存储读取到的 ID |
len | ID 长度值(由 cms_id_get_id_len 取得) |
| 返回 | 0 读取成功;非 0 读取失败 |
分步详解:
第一步:先取长度(条件 cms_id_get_id_len 成功)
size_t len = 0;
uint8_t id[128] = {0};
cms_id_get_id_len(PID, &len); /* 先取长度 */
cms_id_get_id(PID, id, len); /* 再按长度取 ID 到 id */必须先 cms_id_get_id_len 拿到长度,再传入 cms_id_get_id(官方 Atest 示例 atest_cms_id_get_id 即此用法)。
4.4 cms_id_regist / cms_id_regist_check —— 注册
函数原型:
int cms_id_regist(void) /* 发起注册请求,0 成功/非 0 失败 */
int cms_id_regist_check(void) /* 检查是否已注册,0 已注册/非 0 未注册 */分步详解(注册流程):
第一步:检查当前注册状态(条件 cms_id_regist_check)
int rc = cms_id_regist_check();
if (rc != CMS_ERROR_SUCCESS) {
printf("Device is don't regist.\r\n"); /* 未注册 */
} else {
printf("Device has registed.\r\n"); /* 已注册 */
}第二步:发起注册(无条件执行)
cms_id_regist(); /* 发起注册请求 */注册成功后,设备端获得平台签发的令牌与密钥(写入数据存储),供后续认证使用。
4.5 cms_id_authorize / cms_id_auth_check —— 认证
函数原型:
int cms_id_authorize(void) /* 发起认证请求,0 成功/非 0 失败 */
int cms_id_auth_check(void) /* 检查是否已认证,0 已认证/非 0 未认证 */分步详解(认证流程):
第一步:检查当前认证状态(条件 cms_id_auth_check)
int rc = cms_id_auth_check();
if (rc != CMS_ERROR_SUCCESS) {
printf("Device is don't auth.\r\n"); /* 未认证 */
} else {
printf("Device was authed.\r\n"); /* 已认证 */
}第二步:发起认证(无条件执行)
cms_id_authorize(); /* 发起认证请求 */4.6 cms_id_cwt_check —— 校验平台令牌(UDP 场景)
函数原型:
int cms_id_cwt_check(uint8_t *cwt, const uint8_t len)| 参数 | 说明 |
|---|---|
cwt | 存储 CWT 的 buffer |
len | CWT 长度 |
| 返回 | 0 校验成功;非 0 校验失败 |
关键理解:cms_id_cwt_check 仅用于 UDP 连接协议场景(TCP/MQTT 场景由协议栈自动完成令牌校验)。它校验平台下发的 CWT 令牌是否有效,是 UDP 场景下实现平台身份验证的关键。
五、应用示例(官方 Atest)
CMS ID 官方示例依赖 Atest 与 Shell 组件,需先开启(
Components → Atest、Components → Shell)。
#include <shell.h>
#include <atest.h>
#include <string.h>
#include <stdio.h>
#include "oneos_config.h"
#include "cms_id.h"
/* 查询并打印各类 ID */
static void atest_cms_id_get_id(void)
{
size_t len = 0;
CMS_TYPE_T TYPE = PID;
uint8_t id[128];
for (; TYPE <= CWT_PLATFORM; TYPE++)
{
cms_id_get_id_len(TYPE, &len);
cms_id_get_id(TYPE, id, len);
memset(id, 0, sizeof(id));
}
}
/* 检查是否已注册 */
static void atest_cms_id_regist_check(void)
{
int rc = cms_id_regist_check();
if (rc != CMS_ERROR_SUCCESS)
{
printf("Device is don't regist.\r\n");
}
else
{
printf("Device has registed.\r\n");
}
}
/* 发起注册 */
static void atest_cms_id_regist(void)
{
cms_id_regist();
}
/* 检查是否已认证 */
static void atest_cms_id_auth_check(void)
{
int rc = cms_id_auth_check();
if (rc != CMS_ERROR_SUCCESS)
{
printf("Device is don't auth.\r\n");
}
else
{
printf("Device was authed.\r\n");
}
}
/* 发起认证 */
static void atest_cms_id_auth(void)
{
cms_id_authorize();
}
/* 完整流程:检查 → 注册 → 检查 → 认证 → 检查 → 查 ID */
static void cms_id_all(void)
{
ATEST_UNIT_RUN(atest_cms_id_regist_check);
ATEST_UNIT_RUN(atest_cms_id_auth_check);
ATEST_UNIT_RUN(atest_cms_id_regist);
ATEST_UNIT_RUN(atest_cms_id_regist_check);
ATEST_UNIT_RUN(atest_cms_id_auth);
ATEST_UNIT_RUN(atest_cms_id_auth_check);
ATEST_UNIT_RUN(atest_cms_id_get_id);
}
ATEST_TC_EXPORT(cms.id.all, cms_id_all, NULL, NULL, TC_PRIORITY_LOW);
ATEST_TC_EXPORT(cms.id.getid, atest_cms_id_get_id, NULL, NULL, TC_PRIORITY_LOW);
ATEST_TC_EXPORT(cms.id.check.auth, atest_cms_id_auth_check, NULL, NULL, TC_PRIORITY_LOW);
ATEST_TC_EXPORT(cms.id.auth, atest_cms_id_auth, NULL, NULL, TC_PRIORITY_LOW);
ATEST_TC_EXPORT(cms.id.regist, atest_cms_id_regist, NULL, NULL, TC_PRIORITY_LOW);
ATEST_TC_EXPORT(cms.id.check.regist, atest_cms_id_regist_check, NULL, NULL, TC_PRIORITY_LOW);分步详解(cms_id_all 完整流程):
- 注册前检查:
atest_cms_id_regist_check(未注册则提示); - 注册:
atest_cms_id_regist调cms_id_regist(); - 注册后复查:
atest_cms_id_regist_check确认已注册; - 认证前检查:
atest_cms_id_auth_check; - 认证:
atest_cms_id_auth调cms_id_authorize(); - 认证后复查:
atest_cms_id_auth_check确认已认证; - 查 ID:
atest_cms_id_get_id遍历 PID~CWT_PLATFORM 查询打印。
Shell 调用:编译后可执行 atest 命令或 cms.id.all 等测试用例名(Atest 自动注册为 Shell 命令)。
📝 本节小结
核心要点回顾
- 定位:CMS ID 承接端侧设备注册与认证,基于实体认证令牌 EAT/CWT 实现设备与云平台身份互信,认证通过后可用 FOTA、设备定位等服务。
- 四大模块:管理模块(注册/认证/报文交互)、密钥管理(派生)、数据存储、CWT(制作/挑战码签名/CBOR 编码/验证)。
- 真实 API:
cms_id_get_id_len/cms_id_get_id(查 ID)、cms_id_regist/cms_id_regist_check(注册)、cms_id_authorize/cms_id_auth_check(认证)、cms_id_cwt_check(校验平台令牌,仅 UDP 场景)。 - CMS_TYPE_T:PID/OID/DID/CTI_DEVICE/CTI_PLATFORM/CWT_DEVICE/CWT_PLATFORM/KEY_MASTER/OS_VER 九个枚举,作为查询 type 参数。
- 注册认证流程:
regist_check(未注册)→regist→regist_check(已注册)→auth_check(未认证)→authorize→auth_check(已认证)。 - 配置:Menuconfig
Components → CMS → CMS ID——CMS_USING_ID(总开关)+CMS_ID_SET_PID(产品 ID)+CMS_ID_KEY(产品密钥)+MUTUAL_AUTH/UNILATERALISM_AUTH(单向/双向认证)。 - 版本:CMS 分 CMS Lite(默认)与 CMS Standard。
- 依赖:示例依赖 Atest 与 Shell;CMS ID 为 CMS Connect 提供链路鉴权(两者都需线上远程下载)。
关键易错点速查
| 易错点 | 正确做法 |
|---|---|
用 cms_id_init/cms_id_set_device_info/cms_id_auth_by_device_secret/cms_id_generate_sign | 不存在 → 用真实的 cms_id_regist/cms_id_authorize/cms_id_get_id 等 |
用 cms_id_info_t/cms_dynamic_register_t 结构体 | 不存在 → 无独立信息结构体,类型用 CMS_TYPE_T |
用 CMS_AUTH_TYPE_DEVICE_SECRET 常量 | 不存在 → 认证类型在 Kconfig 的 Auth Mode(MUTUAL_AUTH/UNILATERALISM_AUTH) |
| 认为 CMS ID 是"DeviceSecret 比对" | 实际是 CWT 令牌 + 挑战码签名 的互信机制 |
用 OS_USING_CMS/CMS_USING_CONNECT/CMS_USING_OTA/CMS_USING_DYNAMIC_REGISTER 配置 | 不存在 → CMS ID 用 CMS_USING_ID,CMS Connect 用 USING_CMS_CONNECT |
cms_id_get_id 不先取长度 | 需先 cms_id_get_id_len 拿长度再传 → 先取长度再取 ID |
在 TCP/MQTT 场景调 cms_id_cwt_check | 该接口仅 UDP 场景 → 只在 UDP 接入时用 |
未配置 CMS_ID_SET_PID/CMS_ID_KEY | 注册认证失败 → 在项目详情查看并正确配置 |
| 忘开 Atest/Shell | 官方示例无法运行 → 先开 Components → Atest/Shell |
| 未远程下载 CMS 组件 | Menuconfig 无 CMS 菜单 → 先通过 OneOS Studio 下载到 components/cms/ |
下一步
- 7.6 OneNET 组件:CMS ID 已完成设备认证,下一节学习 OneNET 云平台对接组件,掌握 OneNET 平台接入与数据交互,丰富设备上云的平台选择。