上云安全,有我守护。初观HaaS100中AliOS Things系统安全能力

1、智能设备安全考虑

1.1、消费者关注

根据权威机构调查报告显示消费者在购买智能设备时的考量因素,安全和隐私的因素占比大约在50%。 

1.2、安全风险

著名网络安全公司SonicWall在其2020年发布的网络安全报告中揭露,去年(2019)其记录的针对IoT智能设备的安全攻击增长5%,并且可以预见未来针对IoT智能设备的攻击将会越来越多。

安全在智能设备开发中非常重要, 同时作为普通的开发者和中小企业从0构建一套全面且稳定的安全防护能力,也是比较困难的。 那如何轻松地构建智能设备的安全能力,免遭黑客的攻击呢?

答案就是使用AliOS Things来进行智能设备的开发, AliOS Things是阿里巴巴自主研发、面向 IoT 领域的、高可伸缩的物联网操作系统。  AliOS Things 致力于搭建云端一体化 IoT 基础设施,具备极致性能、极简开发、云端一体、丰富组件、安全防护等关键能力。

2、AliOS Things安全能力

AliOS Things在加速智能设备产品开发的同时, 注重建设智能设备的安全防护能力。

上云安全,有我守护。初观HaaS100中AliOS Things系统安全能力_第1张图片

在端上安全能力的建设是以ID2为中心,目标是为物联网设备提供设备身份认证, 在上方提供使用ID2的tls安全连接协议(itls:基于mbedtls修改,主要修改mbedtls中tls协议的认证部分,改用ID2认证), 在下方需要对接各种不同厂家的不同等级的安全芯片(tee, se, mcu中的安全能力)。应用的开发者可以使用大家比较熟悉的mbedtls api来开发应用。 

 

AliOS Things的安全能力比较丰富,后续会有一系列的文章来阐述。

本文章先从应用开发者接触比较多的Mbed TLS开始介绍。

 

3、Mbed TLS 介绍

3.1、Mbed TLS 是什么

Mbed TLS 是一个提供安全基础能力的库,它提供了安全算法,X.509证书,TLS/DTLS协议的实现。

安全算法方面它主要提供了下列功能

  • 对称加密算法

AES, Blowfish, Triple-DES (3DES), DES, ARC4, Camellia, XTEA, ChaCha20

  • 对称加密算法的工作模式

ECB, CBC, CFB, CTR, GCM, CCM

  • 非对称加密算法

RSA, DH, ECC, ECDHE, ECDSA

  • Hash算法

MD2, MD4, MD5, SHA-1, SHA-224, SHA-256, SHA-384, SHA-512, RIPEMD-160

  • 随机数
  • 消息认证算法

HMAC, Poly1305

  • 编码

ASN.1, BASE64

 

协议实现方面它提供了TLS/DTLS协议的客户端和服务端实现,支持SSL 3.0,TLS 1.0,TLS 1.1,TLS 1.2, DTLS 1.0, DTLS 1.2。 

一言以蔽之, Mbed TLS是OpenSSL的替代品,Mbed TLS比OpenSSL更轻量级,适用于资源比较受限的嵌入式设备上。

3.2、Mbed TLS 使用场景

鉴于Mbed TLS是一个提供安全基础能力的库,提供的能力比较全面,大多功能都可以单独使用。所以它的使用场景特别丰富。

  • 使用Mbed TLS把自己的web server进行安全加固,从http变成https的web站点。
  • 使用Mbed TLS访问一个https的web站点。
  • 使用Mbed TLS对数据进行加密/解密,签名/验签, Hash运算,证书生成/解析,产生随机数等。

4、Mbed TLS 源码分析

前提说明:Transport Layer Security (TLS)  是Secure Sockets Layer (SSL) 的更高级版本, TLS 1.0是在SSL 3.0的基础上开发的,TLS是IETF标准化后的重新命名。在多种代码实现中并不区分TLS与SSL的名称,在API, 数据结构中大多都使用SSL的名称。

4.1、一次握手过程

Mbed TLS的源码特别多, 下面以TLS客户端的一次TLS握手的代码实现为例,来分析一下TLS握手的处理过程。

// 执行SSL握手,协商SSL连接的各个因素。
int mbedtls_ssl_handshake( mbedtls_ssl_context *ssl )
{
    int ret = 0;

    if( ssl == NULL || ssl->conf == NULL )
        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );

    MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> handshake" ) );

    while( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER )
    {
        // 根据SSL握手的状态,循环处理SSL握手的各个阶段,直到握手结束。
        ret = mbedtls_ssl_handshake_step( ssl );

        if( ret != 0 )
            break;
    }

    MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= handshake" ) );

    return( ret );
}
// 处理SSL握手的单个步骤
int mbedtls_ssl_handshake_step( mbedtls_ssl_context *ssl )
{
    int ret = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE;

    if( ssl == NULL || ssl->conf == NULL )
        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );

#if defined(MBEDTLS_SSL_CLI_C)
    if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT )
        // SSL客户端主动发起SSL连接请求,在这里处理SSL握手的单个步骤。
        ret = mbedtls_ssl_handshake_client_step( ssl );
#endif
#if defined(MBEDTLS_SSL_SRV_C)
    if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER )
        // SSL被动接受SSL连接请求,在这里处理SSL握手的单个步骤。
        ret = mbedtls_ssl_handshake_server_step( ssl );
#endif

    return( ret );
}
// SSL客户端的单个阶段的握手处理
int mbedtls_ssl_handshake_client_step( mbedtls_ssl_context *ssl )
{
    int ret = 0;

    // SSL状态和参数和合法性检查
    if( ssl->state == MBEDTLS_SSL_HANDSHAKE_OVER || ssl->handshake == NULL )
        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );

    MBEDTLS_SSL_DEBUG_MSG( 2, ( "client state: %d", ssl->state ) );

    // flush此连接上的数据,防止上一个步骤的数据未完全发出去
    if( ( ret = mbedtls_ssl_flush_output( ssl ) ) != 0 )
        return( ret );

#if defined(MBEDTLS_SSL_PROTO_DTLS)
    // DTLS处理
    if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM &&
        ssl->handshake->retransmit_state == MBEDTLS_SSL_RETRANS_SENDING )
    {
        if( ( ret = mbedtls_ssl_flight_transmit( ssl ) ) != 0 )
            return( ret );
    }
#endif /* MBEDTLS_SSL_PROTO_DTLS */

    /* Change state now, so that it is right in mbedtls_ssl_read_record(), used
     * by DTLS for dropping out-of-sequence ChangeCipherSpec records */
#if defined(MBEDTLS_SSL_SESSION_TICKETS)
    if( ssl->state == MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC &&
        ssl->handshake->new_session_ticket != 0 )
    {
        ssl->state = MBEDTLS_SSL_SERVER_NEW_SESSION_TICKET;
    }
#endif

    switch( ssl->state )
    {
        case MBEDTLS_SSL_HELLO_REQUEST:
            // 切换状态hello request到发送client hello状态
            ssl->state = MBEDTLS_SSL_CLIENT_HELLO;
            break;

       /*
        *  ==>   ClientHello
        */
       case MBEDTLS_SSL_CLIENT_HELLO:
           //发送client hello报文,主要包括ssl协议的版本,随机数,加密算法套件, 压缩算法,协议扩展。
           //此阶段主要是客户端用来告知服务端,自己所具备的能力,如支持的算法,协议版本,协议扩展等,
           //就这些能力与服务端进行协商,如服务端会选择一个算法套件。
           ret = ssl_write_client_hello( ssl );
           break;

       /*
        *  <==   ServerHello
        *        Certificate
        *      ( ServerKeyExchange  )
        *      ( CertificateRequest )
        *        ServerHelloDone
        */
       case MBEDTLS_SSL_SERVER_HELLO:
           // 解析服务端发送过来的server hello报文,处理服务端发来的协议版本,随机数,session id, 
           // 服务端选择的加密算法套件,压缩算法(一般不使用压缩),协议扩展等。
           // 另外如果客户端发来是重协商请求,执行重协商检查和处理。
           ret = ssl_parse_server_hello( ssl );
           break;

       case MBEDTLS_SSL_SERVER_CERTIFICATE:
           // 解析服务端发送过来的server 证书,协议证书,进行证书的合法性检查,
           // 检查通过后利用信任的CA证书进行验证,验证通过后检查证书的用途,检查用途合法后切换状态到
           // 下一个阶 MBEDTLS_SSL_SERVER_KEY_EXCHANGE。
           ret = mbedtls_ssl_parse_certificate( ssl );
           break;

       case MBEDTLS_SSL_SERVER_KEY_EXCHANGE:
           // 解析服务端的key交换,或者key计算的材料。
           ret = ssl_parse_server_key_exchange( ssl );
           break;

       case MBEDTLS_SSL_CERTIFICATE_REQUEST:
           // 解析服务度发送的证书请求报文(可选),只有在服务端要求认证客户端时才有这个报文。
           // 客户端在收到服务端发来的证书请求报文后,发送自己的认证给对端认证。
           ret = ssl_parse_certificate_request( ssl );
           break;

       case MBEDTLS_SSL_SERVER_HELLO_DONE:
           //解析服务度发送的server hello done报文,表示server hello阶段的报文到此结束
           ret = ssl_parse_server_hello_done( ssl );
           break;

       /*
        *  ==> ( Certificate/Alert  )
        *        ClientKeyExchange
        *      ( CertificateVerify  )
        *        ChangeCipherSpec
        *        Finished
        */
       case MBEDTLS_SSL_CLIENT_CERTIFICATE:
           //发送客户端的证书,只有在收到服务端发来的证书请求时才发送。服务端会对发过去的证书进行认证
           //以确定客户端身份的合法性。
           ret = mbedtls_ssl_write_certificate( ssl );
           break;

       case MBEDTLS_SSL_CLIENT_KEY_EXCHANGE:
           //发送客户端的KEY协商报文,主要包括KEY协商的协议如DH, 和协商的材料。
           ret = ssl_write_client_key_exchange( ssl );
           break;

       case MBEDTLS_SSL_CERTIFICATE_VERIFY:
           ret = ssl_write_certificate_verify( ssl );
           break;

       case MBEDTLS_SSL_CLIENT_CHANGE_CIPHER_SPEC:
           // 客户端发送changecipherspec报文,表明接下来开始使用协商计算出来的key,进行加密通信
           ret = mbedtls_ssl_write_change_cipher_spec( ssl );
           break;

       case MBEDTLS_SSL_CLIENT_FINISHED:
           // 客户端发送finished报文,表明握手结束。消息包括客户端交换过的重要信息的MAC,此消息是被加密的
           // 重要信息包括客户端发送的随机数,KEY交换的材料等, 这个报文的意义在于之前协商的报文虽然是明文,
           // 但确是不能被篡改的,所以需要一个握手最后过程的完整性保护。
           ret = mbedtls_ssl_write_finished( ssl );
           break;

       /*
        *  <==   ( NewSessionTicket )
        *        ChangeCipherSpec
        *        Finished
        */
#if defined(MBEDTLS_SSL_SESSION_TICKETS)
       case MBEDTLS_SSL_SERVER_NEW_SESSION_TICKET:
           // 解析服务端的session ticket。
           ret = ssl_parse_new_session_ticket( ssl );
           break;
#endif

       case MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC:
           // 解析服务端发送的changecipherspec报文,表明服务端接下来会使用之前
           // 协商出来的key,进行加密通信。
           ret = mbedtls_ssl_parse_change_cipher_spec( ssl );
           break;

       case MBEDTLS_SSL_SERVER_FINISHED:
           // 解析服务端的finished报文,计算之前协商过程重要信息的MAC值,保证之前的协商信息
           // 虽然是明文的, 但没有被篡改过。
           ret = mbedtls_ssl_parse_finished( ssl );
           break;

       case MBEDTLS_SSL_FLUSH_BUFFERS:
           // flush之前发送的协商报文
           MBEDTLS_SSL_DEBUG_MSG( 2, ( "handshake: done" ) );
           ssl->state = MBEDTLS_SSL_HANDSHAKE_WRAPUP;
           break;

       case MBEDTLS_SSL_HANDSHAKE_WRAPUP:
           // SSL连接已经建立,准备切换当前的ssl session和传输层,并释放之前旧的session和传输层数据。
           mbedtls_ssl_handshake_wrapup( ssl );
           break;

       default:
           //其他无效状态
           MBEDTLS_SSL_DEBUG_MSG( 1, ( "invalid state %d", ssl->state ) );
           return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
   }

    return( ret );
}

4.2、AliOS Things Mbed TLS

AliOS Things Mbed TLS是在开源的Mbed TLS 2.16.0 基础上,适配到AliOS Things。 秉承的宗旨是尽量少改动,API与开源的完全保持一致,方便开发者使用和移植上面的应用。相关代码路径在components/security/mbedtls。

AliOS Things Mbed TLS组件在开源的基础上主要有以下几点修改:

  • thread的实现。
  • network socket的发送和接受实现。
  • 动态内存的管理。
  • 适应AliOS Things的配置, 完整配置文件 components/security/mbedtls/aos/include/mbedtls_config.h 。

为适应嵌入式设备资源非常受限的场景,AliOS Things对Mbed TLS还提供了组件化的配置, 用户可以执行aos make menuconfig, 依次进入到 Utility Configuration -> Mbed TLS 2.16.0 -> Mbedtls Configuration 根据自己的场景需要,进行适当的配置, 我们对Mbed TLS组件提供了默认配置,能覆盖大部分场景。

5、Mbed TLS 使用例程

以一个简单的TLS客户端为例, 该TLS客户端访问阿里云物联网平台(上海站点)iot-as-mqtt.cn-shanghai.aliyuncs.com。

......
#define SERVER_PORT "1883"
#define SERVER_NAME "a1MZxOdcBnO.iot-as-mqtt.cn-shanghai.aliyuncs.com"
#define GET_REQUEST "GET / HTTP/1.0\r\n\r\n"

// 验证对端证书所需要的CA认证
const char* tls_client_test_ca_pem = \
    "-----BEGIN CERTIFICATE-----\r\n"
    "MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG\r\n" \
    "A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv\r\n" \
    "b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw\r\n" \
    "MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i\r\n" \
    "YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT\r\n" \
    "aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ\r\n" \
    "jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp\r\n" \
    "xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp\r\n" \
    "1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG\r\n" \
    "snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ\r\n" \
    "U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8\r\n" \
    "9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E\r\n" \
    "BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B\r\n" \
    "AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz\r\n" \
    "yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE\r\n" \
    "38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP\r\n" \
    "AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad\r\n" \
    "DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME\r\n" \
    "HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==\r\n" \
    "-----END CERTIFICATE-----\r\n";

int tls_client_test( void )
{
    mbedtls_net_context server_fd;
    mbedtls_ssl_context ssl;
    mbedtls_ssl_config conf;
    mbedtls_x509_crt cacert;
    ......

    /* 设置DEBUG级别 */
#if defined(MBEDTLS_DEBUG_C) 
    mbedtls_debug_set_threshold( DEBUG_LEVEL );
#endif

    // 0. 初始化需要的数据结构,
    mbedtls_net_init( &server_fd );
    mbedtls_ssl_init( &ssl );
    mbedtls_ssl_config_init( &conf );
    mbedtls_x509_crt_init( &cacert );

    // 1. 加载信任的CA证书
    mbedtls_x509_crt_parse( &cacert, (const unsigned char *) tls_client_test_ca_pem,
                          strlen( tls_client_test_ca_pem ) + 1 );

    // 2. 建立TCP的连接
	mbedtls_net_connect( &server_fd, SERVER_NAME, SERVER_PORT, MBEDTLS_NET_PROTO_TCP )

    // 3. 使用SSL默认配置, 设定为SSL客户端,采用TCP。
    mbedtls_ssl_config_defaults( &conf,
                    MBEDTLS_SSL_IS_CLIENT,
                    MBEDTLS_SSL_TRANSPORT_STREAM,
                    MBEDTLS_SSL_PRESET_DEFAULT ) ) != 0 )
	
    // 3.1. 配置ssl的认证模式为需要认证对端。
    mbedtls_ssl_conf_authmode( &conf, MBEDTLS_SSL_VERIFY_REQUIRED );
    
    // 3.2. 配置信任的CA链
    mbedtls_ssl_conf_ca_chain( &conf, &cacert, NULL );
    
    // 3.3. 配置系统的随机数发生函数。这里tls_client_random为自己实现的随机数发生函数。
    mbedtls_ssl_conf_rng( &conf, tls_client_random, NULL );
    
    // 3.4. 配置debug函数,这里my_debug为自己实现的debug函数,比如是一个简单的打印到串口的函数。
    mbedtls_ssl_conf_dbg( &conf, my_debug, NULL );

#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH)
    // 3.5. 配置SSL的最大分片长度。
    mbedtls_ssl_conf_max_frag_len( &conf, MBEDTLS_SSL_MAX_FRAG_LEN_4096 );
#endif

    // 3.6. 使以上的配置conf对当前SSL连接 ssl 生效。
    mbedtls_ssl_setup( &ssl, &conf )
	
    // 3.7. 为当前SSL连接ssl设置对端的主机名。
    mbedtls_ssl_set_hostname( &ssl, SERVER_NAME )

	// 3.8. 为当前SSL连接ssl设置ssl的I/O函数分别为mbedtls_net_recv/mbedtls_net_send。
    mbedtls_ssl_set_bio( &ssl, &server_fd, mbedtls_net_send, mbedtls_net_recv, NULL );

    // 4. 发起SSL握手
    mbedtls_ssl_handshake( &ssl );

	// 5. 获得对端证书的认证结果。注意这里只是得到认证结果,真正的认证过程是在上一步SSL握手过程中。
	mbedtls_ssl_get_verify_result( &ssl );


	// 6. 发送数据给对端。SSL握手成功后,SSL连接已经建立,此时可以利用SSL连接
    //    发送出去的数据是被加密和完整性保护的。
    mbedtls_ssl_write( &ssl, buf, len );


	// 7. 从SSL连接中读取数据。
    do {
    	ret = mbedtls_ssl_read( &ssl, buf, buf_len -1 );
        if( ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE )
            continue;
        if( ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY )
            break;
        if(ret <= 0)
            break;
        ......
    } while (1);

    // 8. 关闭SSL连接。
    mbedtls_ssl_close_notify( &ssl );

	// 9. 释放SSL相关资源。
    mbedtls_net_free( &server_fd );
    mbedtls_x509_crt_free( &cacert );
    mbedtls_ssl_free( &ssl );
    mbedtls_ssl_config_free( &conf );
    mbedtls_free(buf);
	......
}

6、Mbed TLS 使用常见问题

1、TLS 握手失败,Debug消息显示"buffer too small ..." 或者 "bad message length"

这可能是TLS消息出来的I/O buffer小于消息的长度, 通过配置增大I/O buffer即可, 下列通过AliOS Things的menuconfig来配置,Mbedtls Configuration -> TLS/DTLS protocol support -> TLS/DTLS maximum incoming/outgoing content length , AliOS Things默认配置的I/O buffer为4KB, 一般扩大到16384 (16KB)可以解决所有的此类问题。

2、支持TLS1.3吗?

暂不支持TLS1.3,  AliOS Things 的Mbeb TLS组件能力与社区的相同版本能力保持一致,目前支持的协议版本:SSL 3.0,TLS 1.0,TLS 1.1,TLS 1.2, DTLS 1.0, DTLS 1.2。 现在主流服务器都会向后兼容支持TLS1.2等,不会强制客户端使用TLS1.3版本。 

7、开发者技术支持

如需更多技术支持,可加入钉钉开发者群

更多技术与解决方案介绍,请访问阿里云AIoT首页https://iot.aliyun.com/

 

你可能感兴趣的:(AliOS,Things物联网操作系统,嵌入式,iot,rtos,安全,操作系统)