IoT设备身份认证ID²(Internet Device ID),是一种物联网设备的可信身份标识,具备不可篡改、不可伪造、全球唯一的安全属性;轻量安全连接协议(iTLS),基于ID²进行双向身份认证,提供与标准TLS相同的安全能力,同时减少协议对设备和网络的依赖,满足物联网(IoT)对连接安全的需求。

SSL_Wrapper

1,基于Link Kit代码抽取机制,完成SDK功能代码的抽取和HAL接口适配。

2,要实现安全连接协议(iTLS)和ID²在目标平台的移植,OSA和HAL需厂商根据接口进行适配;其他模块由厂商提供编译工具,阿里云ID²团队进行适配。ID²

3,Link Kit “HAL_Crypt_”文件的适配可调用ID²中的Crypto模块,参考实现如下:

  #include "infra_compat.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

 void *HAL_Malloc(uint32_t size);
 void HAL_Free(void *ptr);

 p_HAL_Aes128_t HAL_Aes128_Init(
             const uint8_t *key,
             const uint8_t *iv,
             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(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(
            p_HAL_Aes128_t aes,
            const void *src,
            size_t blockNum,
            void *dst)
{
    return platform_aes128_encrypt_decrypt(aes, src, blockNum, dst, AES_CBC);
}

int HAL_Aes128_Cbc_Decrypt(
            p_HAL_Aes128_t aes,
            const void *src,
            size_t blockNum,
            void *dst)
{
    return platform_aes128_encrypt_decrypt(aes, src, blockNum, dst, AES_CBC);
}

int HAL_Aes128_Cfb_Encrypt(
            p_HAL_Aes128_t aes,
            const void *src,
            size_t length,
            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);
}
		

4,Link Kit SSL HAL的适配:

1)添加HAL_TLS_itls.c和HAL_DTLS_itls.c到eng/wrappers/tls目录。

2)删除eng/wrappers/tls目录下的HAL_TLS_mbedtls.c和HAL_DTLS_mbedtls.c文件。

5,Link Kit ID²库集成:

1)添加头文件和静态库:

  A. 添加ID²相关头文件到eng/wrappers/include目录。
  B. 添加ID²相关静态库release/lib目录。
		

2)修改编译脚本Makefile:

A. 链接ID²相关的静态库:     
CFLAGS  += -DSUPPORT_ITLS
LDFLAGS += -L./release/lib -litls -lid2 -lkm -licrypt -lls_hal -lls_osa

B. 移除默认mbedtls模块的链接:  
WRAPPER_IMPL_C := $(shell find $(SRCDIR) -name "*.c" -path "*wrappers*" -not -path "*mbedtls*")

6,样例程序演示:

1)填写设备证书到例程(wrappers/os/xxx/HAL_OS_xxx.c)中:

char _product_key[IOTX_PRODUCT_KEY_LEN + 1]       = "a1M******";
char _product_secret[IOTX_PRODUCT_SECRET_LEN + 1] = "h4I******";
char _device_name[IOTX_DEVICE_NAME_LEN + 1]       = "tes******";
char _device_secret[IOTX_DEVICE_SECRET_LEN + 1]   = "t9******";
		
说明 product_key和product_secret在产品创建(选择开通ID²服务)时生成。 device_name为设备名称,使用ID²服务时,由厂商自行确定,需保证产品维度内的唯一性。 device_secret设备密钥,使用ID²服务时,可设置为任意合法的字符串。

2)在样例程序中,配置使用ID²服务:

如examples/mqtt_example.c:

     /**
      *
      *  MQTT connect hostname string
      *
      *  MQTT server's hostname can be customized here
      *
      *  default value is ${productKey}.iot-as-mqtt.cn-shanghai.aliyuncs.com
      */
     /* mqtt_params.host = "something.iot-as-mqtt.cn-shanghai.aliyuncs.com"; */

    char host[64] = {0};

    HAL_Snprintf(host, 64, "%s.itls.cn-shanghai.aliyuncs.com", DEMO_PRODUCT_KEY);
    mqtt_params.host = host;
    mqtt_params.port = 1883;
    mqtt_params.customize_info = "authtype=id2";
		

7,样例程序演示:

1)在SDK顶层目录运行如下命令。

make clean
make
		

2)在已烧录ID²的设备上运行mqtt example,得到如下日志。

 [inf] Connecting to /a1WO4Z9qHRw.itls.cn-shanghai.aliyuncs.com/1883...
 [inf]  ok
 [inf]   . Setting up the SSL/TLS structure...
 [inf]  ok
 <LS_LOG> ID2 Client Version: 0x00020000
 <LS_LOG> ID2 Client Build Time: Sep 26 2019 15:29:43
 <LS_LOG> -------------------------------------------
 <LS_LOG> CONFIG_ID2_DEBUG is not defined!
 <LS_LOG> CONFIG_ID2_OTP is defined!
<LS_LOG> CONFIG_ID2_KEY_TYPE: ID2_KEY_TYPE_AES
<LS_LOG> -------------------------------------------
[inf] Performing the SSL/TLS handshake...
<LS_LOG> id2_client_get_id 655: ID2: 00F******
<LS_LOG> mbedtls_parse_auth_code_ext 407:   . Verify iTLS Server authCode OK!
[inf]  ok
....
< {
<     "message": "hello!"
< }

example_message_arrive|031 :: Message Arrived:
example_message_arrive|032 :: Topic  : /a1WO4Z9qHRw/example1/user/get
example_message_arrive|033 :: Payload: {"message":"hello!"}
		

8,ID²相关调试:

1)iTLS建连失败时,首先可以通过查看消息警告(alert message)进行问题排查。

 [inf] Connecting to /a1WO4Z9qHRw.itls.cn-shanghai.aliyuncs.com/1883...
 [inf]  ok
 [inf]   . Setting up the SSL/TLS structure...
 [inf]  ok
 <LS_LOG> ID2 Client Version: 0x00020000
 <LS_LOG> ID2 Client Build Time: Sep 26 2019 15:29:43
 <LS_LOG> -------------------------------------------
 <LS_LOG> CONFIG_ID2_DEBUG is not defined!
 <LS_LOG> CONFIG_ID2_OTP is defined!
<LS_LOG> CONFIG_ID2_KEY_TYPE: ID2_KEY_TYPE_AES
<LS_LOG> -------------------------------------------
[inf] Performing the SSL/TLS handshake...
<LS_LOG> id2_client_get_id 655: ID2: 00F******
<LS_LOG> mbedtls_ssl_handle_message_type 4194: got an alert message, type: [2:162]
[err] failed  ! mbedtls_ssl_handshake returned -0x7780
		
说明 iTLS常见的错误警告参见文档:iTLS常见错误码

2)通过查看消息警告不能确定错误原因,可使用iTLS和ID²调试版本进行调试。

  A. 使用iTLS和ID²调试库替换SDK中的正式库。
  B. 在HAL_xx_itls.c中配置调试级别宏(DEBUG_LEVEL):
		
/*< set debug log level, 0 close*/
#define DEBUG_LEVEL     0
		

其中:0 - No debug,日志关闭,只有极少错误信息输出。

 1 - Error,错误日志。

 2 - State change,错误日志和状态日志。

 3 - Informational,错误日志、状态日志和调试日志。

 4 - Verbose,所有日志输出。