适用范围:

  • 使用Link kit SDK v2.3.0 、安全SDK v2.0集成安全功能(包括ID²、iTLS)
  • 通过物联网平台创建的产品,节点类型为:网关类型、设备类型。
最佳实践说明: 1,本文所使用的产品,节点类型:网关类型; 2,网关设备下挂的子设备,通过设备证书(三元组)的方式进行认证;
说明 您可以根据实际设备类型选择节点类型,ID²支持设备类型的节点也支持网关类型的节点。

1.1 下载Link kit SDK

下载Link Kit SDK v2.3.0,推荐使用v2.3.0版本,

1.2 配置编译选项

通过 make menuconfig进入编译配置,编译选项中,使能 iTLS 和 网关example,

  • 使能iTLS:

  • 使能gateway:

1.3 配置PK、PS

修改gateway example code,把ProductKey,Product Secret按照步骤1.2中的值进行替换。Device Name,Device Secret可以自行命名,保证unique每个设备唯一即可。

$ vim examples/linkkit/linkkit_example_gateway.c
			

1.4 集成安全SDK库

如果您是针对嵌入式设备平台进行开发集成,那么请联系IoT安全团队沟通提供相关平台的安全库。

2. 集成安全SDK

2.1 集成 安全sdk v0.5

如果您直接使用ubuntu,那么可以确认下Linkkit C-SDK里面prebuilt目录下已经包含了预编译好的安全SDK库,这样您可以进行自行编译集成:

prebuilt/

│├── ubuntu

│ ├── bin

│ │ └── kconfig-mconf

│ ├── include

│ └── libs

│ ├── libalicrypto.a

│ ├── libcurl.a

│ ├── libID²client.a

│ ├── libitls.a

│ ├── libkm.a

│ ├── libmbedcrypto.a

│ └── libplat_gen.a

2.2 Link kit v2.3.0 集成安全sdk v1.0/v2.0

2.2.1 Linkkit接口框图

linkkit整体框图 安全sdk 调用框图

2.2.2 集成安全sdk 相关库

用安全相关库复制到prebuilt/$(os_name)/libs 底下, 复制完之后,prebuilt/$(os_name)/libs 底下的库为:libicrypto.a、libid2.a、libitls.a、libkm.a、libls_hal.a、libls_osa.a。

其中libicrypto.a、libid2.a、libitls.a、libkm.a为安全团队提供的库; libls_osa.a、libls_hal.a为厂商适配的osa 及 hal 层库。

2.2.3 切换tls 的方式为itls 连接方式

make menuconfig

2.2.4 修改示例代码,编译并运行example

修改PRODUCT_KEY 和 PRODUCT_SECRET 为产品的PRODUCT_KEY 和 PRODUCT_SECRET, DEVICE_NAME 保证产品唯一即可, DEVICE_SECRET 可以为任意值。
修改iotkit-embedded/examples/iot.mk 链接选项中添加安全相关库依赖修改iotkit-embedded/src/ref-impl/hal/os/$os_name /HAL_Crypt_Linux.c, 适配alicrypto 的接口。参考代码实现如下:
#include "iot_import.h"
#include "ali_crypto.h"
#define AES_BLOCK_SIZE 16
#define KEY_LEN 16 // aes 128 cbc
#define p_aes128_t p_HAL_Aes128_t
#define PLATFORM_AES_ENCRYPTION HAL_AES_ENCRYPTION
#define PLATFORM_AES_DECRYPTION HAL_AES_DECRYPTION
p_HAL_Aes128_t HAL_Aes128_Init(
           _IN_ const uint8_t *key,
           _IN_ const uint8_t *iv,
           _IN_ AES_DIR_t dir)
{
   ali_crypto_result result;
   void *            aes_ctx;
   size_t            aes_ctx_size, alloc_siz;
   uint8_t *         p;
   bool              is_en = true; // encrypto by default
   if (dir == PLATFORM_AES_DECRYPTION) {
       is_en = false;
   }
   result = ali_aes_get_ctx_size(AES_CBC, &aes_ctx_size);
   if (result != ALI_CRYPTO_SUCCESS) {
       HAL_Printf("get ctx size fail(%08x)", result);
       return NULL;
   }
   alloc_siz = aes_ctx_size + KEY_LEN * 2 + sizeof(bool);
   aes_ctx   = HAL_Malloc(alloc_siz);
   if (aes_ctx == NULL) {
       HAL_Printf("kmalloc(%d) fail", (int)aes_ctx_size);
       return NULL;
   }
   memset(aes_ctx, 0, alloc_siz);
   p = (uint8_t *)aes_ctx + aes_ctx_size;
   memcpy(p, key, KEY_LEN);
   p += KEY_LEN;
   memcpy(p, iv, KEY_LEN);
   p += KEY_LEN;
   *((bool *)p) = is_en;
   return aes_ctx;
}
int HAL_Aes128_Destroy(_IN_ p_HAL_Aes128_t aes)
{
   if (aes) {
       HAL_Free(aes);
   }
   return 0;
}
static int platform_aes128_encrypt_decrypt(p_HAL_Aes128_t aes_ctx,
                                          const void *src, size_t siz,
                                          void *dst, aes_type_t t)
{
   ali_crypto_result result;
   size_t            dlen, in_len = siz, ctx_siz;
   uint8_t *         p, *key, *iv;
   bool              is_en;
   if (aes_ctx == NULL) {
       HAL_Printf("platform_aes128_encrypt_decrypt aes_ctx is NULL");
       return -1;
   }
   result = ali_aes_get_ctx_size(AES_CBC, &ctx_siz);
   if (result != ALI_CRYPTO_SUCCESS) {
       HAL_Printf("get ctx size fail(%08x)", result);
       return 0;
   }
   p   = (uint8_t *)aes_ctx + ctx_siz;
   key = p;
   p += KEY_LEN;
   iv = p;
   p += KEY_LEN;
   is_en = *((uint8_t *)p);
   in_len <<= t == AES_CBC ? 4 : 0;
   dlen = in_len;
   result = ali_aes_init(t, is_en, key, NULL, KEY_LEN, iv, aes_ctx);
   if (result != ALI_CRYPTO_SUCCESS) {
       HAL_Printf("ali_aes_init fail(%08x)", result);
       return 0;
   }
   result = ali_aes_finish(src, in_len, dst, &dlen, SYM_NOPAD, aes_ctx);
   if (result != ALI_CRYPTO_SUCCESS) {
       HAL_Printf("aes_finish fail(%08x)", result);
       return -1;
   }
   return 0;
}
int HAL_Aes128_Cbc_Encrypt(
           _IN_ p_HAL_Aes128_t aes,
           _IN_ const void *src,
           _IN_ size_t blockNum,
           _OU_ void *dst)
{
   return platform_aes128_encrypt_decrypt(aes, src, blockNum, dst, AES_CBC);
}
int HAL_Aes128_Cbc_Decrypt(
           _IN_ p_HAL_Aes128_t aes,
           _IN_ const void *src,
           _IN_ size_t blockNum,
           _OU_ void *dst)
{
   return platform_aes128_encrypt_decrypt(aes, src, blockNum, dst, AES_CBC);
}
int HAL_Aes128_Cfb_Encrypt(
           _IN_ p_HAL_Aes128_t aes,
           _IN_ const void *src,
           _IN_ size_t length,
           _OU_ void *dst)
{
   return platform_aes128_encrypt_decrypt(aes, src, length, dst, AES_CFB128);
}
int HAL_Aes128_Cfb_Decrypt(
           _IN_ p_HAL_Aes128_t aes,
           _IN_ const void *src,
           _IN_ size_t length,
           _OU_ void *dst)
{
   return platform_aes128_encrypt_decrypt(aes, src, length, dst, AES_CFB128);
}
			
运行make, 编译成功后, 运行iotkit-embedded/output/release/bin 文件夹下的mqtt-example,出现以下log信息表示已成功切换成itls的链接方式,出现以下log信息表示mqtt 测试成功。

2.2.5 调试

如需更多的调试log, 用debug 版本的itls 及id2 库,替换原prebuilt/ubuntu/libs 文件夹中的libitls.a 和 libid2.a。修改src/ref-impl/hal/ssl/itls/HAL_TLS_itls.c, 在该文件中添加宏定义MBEDTLS_DEBUG_C, 并将DEBUG_LEVEL 修改为4, 如下所示:

-#define DEBUG_LEVEL 0

+#define MBEDTLS_DEBUG_C

+#define DEBUG_LEVEL 4

重新编译运行测试程序。

2.2.6 错误码

查看 iTLS错误码

备注:1,上面的消息警告,是在通信过程中,服务端发生异常,主动向设备端发送的消息通告。2,上面的消息类型,是指iTLS Native返回的警告类型,Android Linkkit接口返回的值已做加权(10000)处理。

3. 编译

make编译链接生成gateway exampe程序,并且运行该网关例子程序。

./output/release/bin/linkkit-example-gw 5 auto
			

最后两个参数您可以手工输入,请参见实际代码。

查看日志:注意Host端口后缀为 itls.cn-shanghai.aliyuncs.com

查看日志:注意建联成功

4. 验证

登录阿里云物联网平台,在“设备管理”->“设备”列表查看Device Name与(步骤1.3中)gateway example代码中设置的Device Name一致。如果一致,则该设备已经通过ID²认证并且接入物联网平台,您可以进行后续设备topic订阅与推送等。