使用ID²-KM将设备接入自建的物联网系统

本文介绍了设备如何通过更安全的身份认证方式(ID²)连接到您自建的物联网系统(设备管理平台)。

1. 术语

  1. Soft-KM(Key Management)密钥管理,由阿里提供的软件安全沙箱,基于软件加固和虚拟化技术提供对密钥(IoT ID²)的安全保护。

  2. OSA(Operation System Abstractor Layer)操作系统抽象层,定义内存申请和释放、日志打印、系统时间、网络通信等接口,非遵循POSIX标准的OS,需重新适配这些接口。

  3. HAL(Hardware Abstractor Layer)硬件抽象层,根据设备硬件特性,完成对加解密算法、设备唯一ID、密钥管理和数据安全存储的接口适配。

  4. ID² OTP(One-Time Provisioning)一次性烧录,也称ID²空发,指设备在第一次联网时,通过网络请求,下发ID²数据烧录到设备中。

  5. TLS(Transport Layer Security)安全传输层协议, 用于两个通信实体之间,保护通信数据的私密性和完整性。

  6. IoT(Internet of things)物联网,基于互联网实现万物互联。

2. ID²产品架构

  1. ID²控制中心:

  • ID²的Web控制台,提供对ID²产线灌装、ID²产品和配额申请、以及ID²使用统计的管理。

  1. ID²服务中心:

  • ID²在云端的应用,提供ID²的各种安全能力,包括ID²密钥安全分发、设备认证、基于ID²的安全连接协议等;同时,提供各种能力的云端接口,支持业务平台的二次开发,支持不同的安全业务需求和场景。

  1. ID² Client SDK(ID²设备端SDK):

  • ID²在设备端的功能组件和软件开发框架,可支持不同操作系统和不同硬件,为IoT设备提供基于ID²的端到端的设备认证、数据加解密等各种安全能力。

3. ID²接入流程

3.1 概述

  • 客户自建服务的方式,ID²通过云端和设备端接口的方式,提供基于ID²的设备认证和会话密钥加密下发,应用数据通过下发的会话密钥进行加密传输。

  • ID²对接步骤如下:

image.png

3.2 购买ID²授权:

  1. 单机购买链接 - 购买ID²认证授权

  2. 选择地域和可用区、规格、购买数量和有效期:

image.png

3.3 创建产品:

  1. 登录IoT安全产品控制台控制台,在左侧导航栏,选择入门 > IoT设备身份认证,单击独立使用卡片的开始接入按钮。

  2. 配置产品页面创建新产品&分配ID²授权,然后单击下一步按钮。

  • 选择产品:请选择创建新产品,并输入产品名称。

  • ID²有效期:请选择1年、3年、或5年。

  • 分配ID²授权数量:请输入ID²授权数量,最小值为1,最大值为1000。

image.png

  1. 查看配置信息页面,记录下ProductKey、ProductSecret

  • ProductKey:设备所属产品的ProductKey。

  • ProductSecret:由IoT设备身份认证颁发的产品密钥,与 ProductKey 成对出现。

3.4 选择设备认证算法:

IoT设备身份认证支持国际算法(AES-128、AES-192、AES-256)和国密算法(SM1、SM2、SM4-128),能满足企业不同安全等级的需求。

说明

国密算法SM1需要配合ID²安全芯片使用,SM2用于业务数据完整性校验和加密。

创建的ID²产品默认选择的设备认证算法是AES-128;如需选择其他设备认证算法,请按如下步骤操作:

  • 查看配置信息页面,单击设备认证算法后的更换按钮,查看支持的密钥类型(如SM4-128),并确认。

image.png

  • 查看配置信息页面,记录下实例ID、ProductKey、ProductSecret

  • 实例ID:阿里云物联网平台的实例标识。企业实例ID是字符串,公共实例ID是符号“-”。

  • ProductKey:设备所属产品的ProductKey。

  • ProductSecret:由IoT设备身份认证颁发的产品密钥,与 ProductKey 成对出现

3.5 集成云端SDK

3.5.1 阿里云账号的AccessKey

  • AccessKey是调用阿里云API的身份凭证,请参见获取AccessKey

  • 需要注意的是AccessKey的归属账号必须与创建产品时的账号保持一致。

3.5.2 下载云端SDK

  1. 登录IoT安全产品控制台控制台,在左侧导航栏,选择文档与工具,在IoT设备身份认证云端SDK中单击立即下载右侧的复制按钮获取最新的下载地址,在云端环境执行命令获取云端SDK。

wget https://id2-schip-online.oss-cn-shanghai.aliyuncs.com/static_resources/id2_server_sdk/ID2_Server_SDK.tar
  1. 在云端环境执行命令tar -xvf ID2_Server_SDK.tar 完成解压,执行命令cd <解压SDK后的目录>。设备端SDK的目录说明见表格内容:

目录/文件

说明

demos

ID²云端的示例代码

lib

ID²云端的Jar包

3.5.3 集成云端SDK

  1. 添加Maven项目依赖,引入阿里云Java SDK公共包。

<dependency>
    <groupId>com.aliyun</groupId>
    <artifactId>aliyun-java-sdk-core</artifactId>
    <version>4.5.6</version>
</dependency>
  1. 导入云端SDK中的lib/aliyun-java-sdk-id2-1.1.4.jar到项目工程中,初始化云端SDK。

public static String ACCESS_KEY = null;
public static String ACCESS_SECRET = null;

public static String REGION_ID = "cn-shanghai";
public static String END_POINT = "id2." + REGION_ID + ".aliyuncs.com";

// Load ACCESS_KEY and ACCESS_SECRET From Config File
loadConfigProperties("xxx.conf");

IClientProfile profile = DefaultProfile.getProfile(REGION_ID, ACCESS_KEY, ACCESS_SECRET);
DefaultProfile.addEndpoint(REGION_ID, PRODUCT_CODE, END_POINT);
client = new DefaultAcsClient(profile);
  1. 发起调用,ID²云端SDK为每个API封装了一个类,命名为${API名称}+"Request",如VerifyRequest,用于API的调用请求,ID²云端API列表请参考服务端API

  • ID²空发

OtpGetId2Request request = new OtpGetId2Request();
request.setDeviceAuthCode(authCode);
request.setApiVersion(1.1.2);

OtpGetId2Response response = client.getAcsResponse(request);
  • 获取ID²认证挑战字

GetServerRandomRequest request = new GetServerRandomRequest();
request.setId2(id2Id);
request.setApiVersion(1.1.2);

GetServerRandomResponse response = client.getAcsResponse(request);
System.out.println("GetServerRadom requestId:" + response.getRequestId());
  • ID²设备认证和业务密钥加密

VerifyAndEncryptRequest request = new VerifyAndEncryptRequest();
request.setApiVersion(1.1.2);
request.setProductKey(productKey);
request.setId2(id2Id);
request.setAuthCode(authCode);
request.setData(keyInfo);

VerifyAndEncryptResponse response = client.getAcsResponse(request);
System.out.println("VerifyAndEncrypt requestId:" + response.getRequestId());
  1. 应用集成ID²云端SDK的示例代码,请参考demos/ID2SPMessage

3.6 集成设备端SDK:

3.6.1 ID²设备端SDK框架:

image.png

  1. iTLS:轻量的安全连接协议TLS,基于ID²完成TLS的握手认证和密钥协议,提供应用数据的加密传输。

  2. ID²:IoT设备认证和数据加密的对外接口,上层应用/协议基于此接口进行开发。

  3. KM:密钥管理模块,支持不同形式的载体:

    1. Soft-KM:软件沙箱,基于软件加固和虚拟化技术提供对ID²密钥的安全保护。

      1. SE(Secure Element):安全芯片,基于物理防护机制,提供对ID²密钥的安全保护,通过AT指令对设备提供ID²的运算指令。

  4. Crypto:提供统一的加解密算法接口。

  5. OSA:操作系统适配接口,厂商需根据使用的OS,重新进行接口适配。

  6. HAL:硬件适配接口,提供算法库和Soft-KM的适配接口,厂商需根据选择的硬件平台,重新进行接口适配。

3.6.2 下载设备端SDK:

  1. 登录IoT安全产品控制台,在左侧导航栏,选择文档与工具,在IoT设备身份认证设备端SDK中单击立即下载右侧的复制按钮获取最新的下载地址,执行命令获取设备端SDK。

wget https://id2-schip-online.oss-cn-shanghai.aliyuncs.com/static_resources/id2_client_sdk/ID2_Client_SDK.tar
  1. 执行命令tar -xvf ID2_Client_SDK.tar完成解压,执行命令cd <解压SDK后的目录>。设备端SDK的目录说明见表格内容:

目录/文件

说明

demos

ID²设备端的示例代码:

  • mqtt:提供不同MQTT组件(如lk_4.x)+ ID²连接阿里云物联网平台的演示示例。

    • lk_4.x:提供针对LinkSDK v4.x的示例代码。

    • 其他组件:提供基于其他MQTT组件的示例代码。

  • spdemo:自建系统的SPDemo Client示例代码

external

用于存放外部的组件:

  • mqtt - MQTT的外部组件

    • lk_4.x:阿里云物联网平台提供的LinkSDK。

    • 其他组件:添加其他的MQTT组件,并修改makefile指向此组件。

include

ID²的头文件目录

libs

ID²的静态库

make.rules

编译规则文件,可配置编译工具链和编译参数

make.settings

编译配置文件,可配置ID²的密钥类型(如AES、SM4)

makefile

编译脚本

src

ID²的源码目录

tests

ID²的测试用例,包括HAL和ID²的测试。

3.6.3 集成设备端SDK:

调用设备端ID²的接口,完成ID²空发,ID²设备认证和数据加密等功能,工作原理图如下:

  • ID²空发:

image.png

  • 通过ID²产品的ProductSecret,生成ID²的空发认证码(AuthCode),发送到云端调用ID²服务端的接口,完成ID²的申请和下发

  • ID²设备认证和数据加密:

image.png

  • 基于挑战字认证方式,通过在设备端调用ID² SDK生成ID²的设备认证码,发送到云端调用ID²的云端SDK,完成ID²的设备认证和会话密钥的加密;然后,在设备端调用ID² SDK的解密接口,完成会话密钥的解密

使用自有的应用,完成如下的集成工作:

  1. 设备硬件及系统层集成,详情请参考ID²安全Agent适配接口

  • OSA接口适配:实现src/osa/ls_osa.c中的接口,参考目录下__DEMO__的实现。

  • HAL接口适配:实现src/hal/km/demo/ls_hal_km.c中的接口,通过hal_test测试用例验证(成功日志: “HAL KM Test Pass”),参考目录下__DEMO__的实现。

  1. 设备应用层集成,详情请参考设备端API

  • 设备应用首先调用ID²的初始化函数,完成设备端SDK的初始化。

{
    int ret;

     ret = id2_client_init();
     if (ret != IROT_SUCCESS) {
        ls_osa_print("id2 client init fail, %d\n", ret);
        return -1;
     }
}
  • 获取ID²设备端的烧录状态:

    • 如ID²已烧录(is_prov == true),退出ID²空发流程

{
    int ret = 0;
    bool is_prov = false;

    ret = id2_client_get_prov_stat(&is_prov);
    if (ret != IROT_SUCCESS) {
        ls_osa_print("id2 client get prov stat fail, %d\n", ret);
        return -1;
    } 
}
  • 生成ID²设备端的空发认证码。

{
    int ret = 0;
    uint8_t auth_code[ID2_MAX_AUTH_CODE_LEN] = {0};
    uint32_t auth_code_len = ID2_MAX_AUTH_CODE_LEN;

    ret = id2_client_get_otp_auth_code(
              (uint8_t *)product_secret, (int)strlen(product_secret),
               auth_code, &auth_code_len);
    if (ret != IROT_SUCCESS) {
        ls_osa_print("id2_client_get_otp_auth_code fail, %d\n", ret);
        return -1;
    }
}
  • ID²空发的网络请求和响应。

    • authCode:ID²空发认证码的Base64编码

    • otpData:ID²云端下发的空发数据(Base64格式)

# ID²空发请求:
{commandId:xxx, authCode: xxx}

# ID2空发响应:
{commandId:xxx, otpData: xxx}
  • 存储ID²密钥到设备安全存储区。

{
    int ret = 0;

    ret = id2_client_load_otp_data(otp_data, otp_len);
    if (ret != IROT_SUCCESS) {
        ls_osa_print("id2 load otp data fail, %d\n", ret);
        return -1;
    }
}
  • 获取设备端的ID² ID。

{
    int ret = 0;
    uint8_t id2_id[ID2_ID_MAX_LEN + 1] = {0};
    uint32_t id2_id_len = ID2_ID_MAX_LEN;

    ret = id2_client_get_id(id2_id, &id2_id_len);
    if (ret != IROT_SUCCESS) {
        ls_osa_print("id2 client get id fail, %d\n", ret);
        return -1;
    }
}{
    int ret = 0;
    uint8_t id2_id[ID2_ID_MAX_LEN + 1] = {0};
    uint32_t id2_id_len = ID2_ID_MAX_LEN;

    ret = id2_client_get_id(id2_id, &id2_id_len);
    if (ret != IROT_SUCCESS) {
        ls_osa_print("id2 client get id fail, %d\n", ret);
        return -1;
    }
}
  • ID²认证挑战字的网络请求和响应。

# ID²认证挑战字的请求:
{commandId:xxx, Id2Id: xxx}

# ID2认证挑战字的响应:
{commandId:xxx, challenge: xxx}
  • 获取设备端的ID²认证码。

{
    int ret = 0;
    uint8_t auth_code[ID2_MAX_AUTH_CODE_LEN] = {0};
    uint32_t auth_code_len = ID2_MAX_AUTH_CODE_LEN;

    ret = id2_client_get_challenge_auth_code(
              challenge, NULL, 0, auth_code, &auth_code_len);
    if (ret != IROT_SUCCESS) {
        ls_osa_print("id2 client get challenge auth code fail, %d\n", ret);
        return -1;
    }
}
  • 设备端认证和数据加密的网络请求和响应。

    • cipherData:ID²云端下发的加密数据

# ID²设备认证和数据加密的请求:
{commandId:xxx, productKey:xxx, Id2Id:xxx, authCode:xxx}

# ID2设备认证和数据加密的响应:
{commandId:xxx, cipherData: xxx}
  • 解密ID²云端加密下发的数据。

{
    int ret = 0;

    ret = id2_client_decrypt(cipher_data, cipher_len, cipher_data, &cipher_len);
    if (ret != IROT_SUCCESS) {
        ls_osa_print("id2 client decrypt fail\n");
        return -1;
    }
}
  • 应用集成ID²设备SDK的示例代码,请参考demos/spdemo

  1. 设备端SDK的编译:

  • 在ID² SDK的根目录,执行命令vi ./make.settings打开文件, 修改CONFIG_LS_ID2_KEY_TYPE的值

    • 同ID²产品选择的认证算法保持相同

image.png

  • 执行命令“make clean & make plat=xxx”进行编译

    • Linux x86_64默认使用系统中的GCC作为编译工具,且默认指定“plat=x86_64”参数

    • 如要编译其他架构,如armhf,在make.rules中配置编译工具,运行编译命令“make clean & make plat=armhf”

image.png

3.7 业务数据加密

  1. 方式一:运行设备端自有的应用和自建的SP Server,进行ID²认证和加密,以及业务数据加密的调试。

  2. 方式二:使用演示示例:

  • 部署EMQX物联网平台,详情参见EMQX安装和部署

    • 本节描述在Ubuntu 22.04上通过Docker部署EMQX物联网平台的示例

    • 安装和启动Docker工具:

# Install Docker
curl -fsSL get.docker.com -o get-docker.sh
sudo sh get-docker.sh --mirror Aliyun

# Start Docker
sudo systemctl enable docker
sudo systemctl start docker

# Get Docker Version
docker -v
  • 使用Docker安装EMQX物联网平台:

# Get emqx-5.1.3 docker image
docker pull emqx/emqx:5.1.3

# Start docker emqx instance
docker run -d --name emqx -p 1883:1883 emqx/emqx:5.1.3

# Get docker instance info
docker ps

  • 部署云端演示示例,在ID²云端SDK根目录,配置vi demos/ID2SPMessage/Id2SpDemo.conf文件中的AccessKey和AccessSecret信息。

image.png

  • 执行命令cd demos/ID2SPMessage,执行命令java -jar Id2SpDemo.jar启动云端演示示例。

image.png

  • 在ID²设备端SDK目录,执行命令vi tools/ls_sp_demo.sh填写如下参数:

    • HostAddr:云端演示示例的IP地址,localhost代表本机网络。

    • ProductKey:ID²产品的ProductKey。

    • ProductSecret:ID²产品的ProductSecret。

    • PublishData:设备端应用上报的业务数据,建议不超过1024字节。

image.png

  • 执行命令./tools/ls_sp_demo.sh运行设备端演示示例,查看设备端打印的日志。

    • 在设备端日志中,可以看到完成ID²的设备认证,以及通过ID²加密下发SP Key Info;设备端通过ID²设备端接口解密后,获得明文的Key ID和Data

    • 在设备端日志中,可看到由SPKey加密下发的业务数据(“SP Server Subscribed Cipher Data”);通过在调用SPKey解密后,可得到明文的下行业务数据(“SP_Server_Hello”)

image.png

  • 在云端查看打印的日志。

    • 可看到由SPKey加密的业务数据("Device Published Cipher Data")

    • 使用SPKey解密后,可得到正确的上行业务数据(“SP_Client_Hello”)

  1. 查看设备状态:

  • 登录产品控制台,在左侧导航栏,选择资产>设备,查看设备状态为正常,安全状态为安全。

image.png