天天看點

mbedtls 基礎及其應用

摘要

SSL/TLS加密的介紹,重點是mbedtls的基礎以及移植說明。

1、引言

1.1 為什麼要加密

網際網路是開放環境,通信雙方都是未知身份,為通信雙方的有效資訊不被第三方竊聽、篡改或者被冒充身份進行通信,需要為資訊加上保護措施。也就是對所有資訊都進行加密,避免被第三方竊聽;采用校驗機制,可以識别出資訊是否被篡改,配備身份認證防止被冒充身份。網際網路的通信安全,就是建立在SSL/TLS協定之上。

1.2 SSL/TLS協定的曆史

1996年,在前面的基礎上,SSL 3.0版問世并得到大規模應用;

1999年,網際網路标準化組織ISOC接替NetScape公司,釋出了SSL的更新版TLS 1.0版,也稱為SSL 3.1;SSL和TLS指的是同一套加密協定,隻是不同時期的名字差異。

2006年和2008年,TLS進行了兩次更新,分别為TLS 1.1版和TLS 1.2版。

一般推薦使用TLS 1.2,主流的浏覽器都支援。

2、SSL/TLS演化

熟悉一套技術的演進步驟,比直接看最新版本,更容量了解。

2.1 明文時代

小帥向小美發送資訊,直接以明文形式發送。

mbedtls 基礎及其應用

缺點顯而易見,第三方小黑很容易就竊取到資訊,也可以進行篡改後發給小美,而且小美收到後并不知情,以為是小帥發來的。

2.2 對稱加密時代

小帥和小美儲存一份相同的秘鑰,小帥發出的資訊先經過加密,小美收到後使用同樣的密碼進行解密。這種加密和解密使用同一個密鑰的算法稱為對稱加密算法。

mbedtls 基礎及其應用

短期内小黑對加密資料無能為力,但是每次變更秘鑰需要事先協商,如果協商出問題,小帥告知小美新秘鑰時,秘鑰被小黑截取,那後續的密文對小黑來說,他也可以解密成明文。也可以篡改明文資訊後,再使用同樣的秘鑰加密後發給小美。

2.3 非對稱加密時代

既然進行秘鑰交換存在風險,小帥和小美采用非對稱加密算法。雙方各自儲存私鑰、公鑰,兩者配對,私鑰自己儲存,公鑰由私鑰運算生成發給對方,不能由公鑰反推算出私鑰;但是使用公鑰加密的密文,卻可以使用私鑰解密;使用私鑰簽名,使用公鑰驗證;這種加密和解密使用不同的密鑰的算法成為非對稱加密算法。

mbedtls 基礎及其應用

通信前,雙發先将自己的公鑰發給對方,私鑰保密;小帥先使用小美提供的公鑰加密資料,同時也使用自己的私鑰進行簽名标記,一起打包後發給小美,小美使用自己的私鑰進行解密,再使用小帥的公鑰進行驗證,确認收到的資訊是否來自小帥。

這種形式的加密通信,協商傳輸的是公鑰,即使被小黑截取,他也不能解密後續的資訊,因為解密得使用私鑰。

但是百密一疏,如果小黑子在最初互動公鑰時,截取公鑰,把小帥發給小美的公鑰截取,把自己的假公鑰發給小美;截取小美發出的資料,小黑用自己的私鑰解密,然後再使用自己的私鑰加密後發給小帥。

mbedtls 基礎及其應用

整了這麼複雜的一套加密協定,結果還是存在隐患。

2.4 公證時代

問題就出在公鑰交換,小美收到一份公鑰,如何證明這公鑰确實是小帥發出的?譬如買房,隻有房管局确認蓋章導入系統的房産證,才是真的房産證,才能放心進行交易。通過CA(Certificate Authority)證書頒發機構來保證公鑰的真實性,為公鑰的真實性進行擔保公證。

CA也是基于非對稱加密算法,小帥先先把自己的公鑰交給CA,CA用自己的私鑰加密這些資料,加密完的資料稱為小帥的數字證書,先前小帥發給小美的公鑰,改為發送CA加密之後的數字證書。小美收到以後,通過CA釋出的CA憑證(包含了CA的公鑰),來解密小帥的數字證書,進而獲得小帥的公鑰。

mbedtls 基礎及其應用

問題是小美怎麼確定CA憑證不是小黑僞造的?CA憑證是提前預置在浏覽器或作業系統,或者嵌入式裝置内,不需要聯網擷取,自然也不存在劫持篡改的問題。

雖然小黑還是可以攔截帶公鑰的數字簽名證書,可以用CA公鑰解密看到内容;但是他沒CA的秘鑰,無法僞造出正确的數字簽名證書,也就是小帥的真實公鑰小黑可見不可改,改了小美會發現異常,但隻有公鑰并沒什麼價值。

2.5 TLS協定時代

公證時代的解決方案就是SSL/TLS協定加密通信基礎。因為使用非對稱加密算法比對稱加密算法要複雜,消耗運算資源,為考慮效率,非對稱加密隻會用來傳遞一條資訊,即對稱加密的密鑰。對稱加密的密鑰确定,後續有效資訊使用對稱加密算法進行網絡傳輸。既保證了網絡通信的安全性,又不影響效率。

SSL/TLS協定的基本過程:

1、通過CA體系交換公鑰

2、使用非對稱加密算法,交換用于對稱加密的密鑰 

3、有效資料使用對稱加密算法,進行密文傳輸

前兩步又稱為"握手階段"(handshake),是SSL/TLS加密通信的基礎。

2.6 TLS的應用

在SSL/TLS出現之前,很多應用層協定(http、ftp、smtp等)都存在着網絡安全問題。最常見的http協定,在傳輸過程中使用的是明文資訊,傳輸封包一旦被截獲便會洩露傳輸内容;傳輸過程中封包如果被篡改,對方無法輕易發現;無法保證消息交換的對端身份的可靠性。為了解決此類安全問題,在應用層和傳輸層之間加入了SSL/TLS協定,更新為https。SSL/TLS目前已經廣泛用于資料安全協定。關于SSL/TLS有很多開源軟體包,如openSSL,mbedtls等。openSSL功能更強大,mbedtls小巧更适合嵌入式裝置。

3、 mbedtls

随着物聯網的發展,裝置節點的安全問題也越來越重要,相比網際網路的openSSL,物聯網的嵌入式裝置适合小巧靈活的MbedTLS,曾用名PolarSSL,可以根據需求進行配置,降低對硬體資源的消耗。mbedtls内置了非常多的加密解密,雜湊演算法源碼,即使不使用tls加密,也從裡面挖掘各種算法,諸如AES/RSA/MD5等。但是openSSL功能更強大,

mbedtls是一款采用Apache 2.0許可證協定開源軟體加密庫,使用标準C語言編寫;獨立的子產品設計,降低子產品之間的耦合度。從功能上看,主要包括加密庫、X509證書、SSL/TLS協定三部分。

3.1 軟體包

進入​​https://tls.mbed.org/​​[1],點選download,在​​https://github.com/ARMmbed/mbedtls​​[2]下載下傳源碼。

Git下載下傳界面有說明編譯方式

Compiling

There are currently three active build systems used within Mbed TLS releases:

GNU Make

CMake

Microsoft Visual Studio (Microsoft Visual Studio 2013 or later)

目前個人接觸的晶片SDK内置mbedtls有v2.4.0,v2.4.2和v2.14.1三種,将git版本切到v2.14.1,最後送出是2018年。前期先在電腦模拟測試,選擇Visual Studio 2013。

3.2 軟體結構

mbedtls源碼結構如下圖

mbedtls 基礎及其應用

mbedtls\include\mbedtls下面,可以version.h檢視版本資訊,重點是config.h配置,mbedtls是一套加密集合,實際項目使用中僅需選擇少部分即可,配置功能宏裁剪代碼,簡化運算,畢竟mbedtls跑一遍,一般的arm單片機不一定扛得住。

programs\ssl下是參考範例,TLS的用戶端和服務端範例,以及UDP版本的DTLS。嵌入式裝置以用戶端應用居多,主要參考​

​ssl_client2.c​

​​裡面很多配置參數可選,也可以針對應用替換​

​ssl_client1.c​

​。

測試TLS用戶端首先要準備3個檔案,CA憑證,用戶端公鑰數字證書以及私鑰。一般情況下命名字尾如下:

.crt CA憑證

.pem 公鑰,經CA加密後的公鑰,也稱為數字證書

.key 私鑰

有時crt和pem混用,其本質都是CA公鑰加密後的檔案

如果沒有伺服器聯調,也可以使用自身的ssl_server2.c做伺服器。

3.3 demo流程分析

ssl_client2.c範例都在main函數,其大體流程如下:

  • 1、先加載各種證書、秘鑰,配置opt結構體成員初始化,如TLS版本,加密套件類型等
  • 2、然後開始連接配接伺服器  mbedtls_net_connect
  • 3、初始化tls參數 mbedtls_ssl_config_defaults,設定網絡收發回調函數等
  • 4、SSL/TLS握手流程,過程比較複雜,簡化就是通信雙方校驗對方身份,擷取對方的公鑰,确認加密方式,後續資料進行加密或解密做準備 mbedtls_ssl_handshake
  • 5、校驗服務端傳回的證書 mbedtls_ssl_get_verify_result
  • 6、如果前面流程順暢,就可以使用mbedtls_ssl_write,mbedtls_ssl_read收發資料了
  • 7、測試結束後的清理工作
  • 8、與标準socket程式設計對比,接口存在一定的對應關系:
    mbedtls 基礎及其應用

4、 mbedtls移植

先在電腦端模拟測試,确定參數,簡化範例裡的指派,因為實際項目參數不會經常變更,優化代碼,尤其是秘鑰加載,嵌入式都是以數組儲存檔案内容,而不會使用檔案形式加載。另外結合加密等級,确定加密套件類型。

模拟測試正常後,再移植到ARM平台,主要改動涉及網絡連接配接、記憶體管理和定時器三個方面。

4.1 網絡接口

mbedtls預設的網絡接口​

​mbedtls/library/net_socket.c​

​,可以在windows下運作,特别注意,預設的socket操作都是阻塞模式;一般不适合ARM平台,關閉MBEDTLS_NET_C,結合硬體平台重新實作網絡接口。主要包括以下函數:

void mbedtls_net_init( mbedtls_net_context *ctx );
int mbedtls_net_connect( mbedtls_net_context *ctx, const char *host, const char *port, int proto );
int mbedtls_net_recv( void *ctx, unsigned char *buf, size_t len );
int mbedtls_net_recv_timeout( void *ctx, unsigned char *buf, size_t len, uint32_t timeout );
int mbedtls_net_send( void *ctx, const unsigned char *buf, size_t len );
void mbedtls_net_free( mbedtls_net_context *ctx );      

若需要DUP版本的DTLS,還需要實作該檔案下另外幾個接口,具體流程參考​

​dtls_client.c​

​。

自定義實作的網絡收發接口,需要注冊mbedtls_ssl_set_bio告知底層。

mbedtls_ssl_set_bio(&ssl, &server_fd,
        mbedtls_custom_send,//改寫後的mbedtls_net_send,為底層提供發送接口
        mbedtls_custom_recv,//為底層提供接收接口
        mbedtls_custom_recv_timeout)      

4.2 記憶體管理

自定義實作類型如下記憶體的申請和釋放接口:

void* calloc(unsigned int num,unsigned int size)
void free(void * ptr)      

實作後将函數注冊給底層

mbedtls_platform_set_calloc_free(custom_calloc, custom_free)      

4.3 定時器

對DTLS定時器接口,并注冊到底層。

#if defined (__MBEDTLS_DTLS__)
    
    //Set delays to watch
    void platform_timing_set_delay(void *data, uint32_t int_ms, uint32_t fin_ms)
    {
     platform_timing_delay_context *ctx = (platform_timing_delay_context *) data;
     
     ctx->int_ms = int_ms;
     ctx->fin_ms = fin_ms;
     
     if(fin_ms != 0)
     {
      ctx->snapshot = custom_get_systicks();
     }    
    }    

    //Get number of delays expired
    int platform_timing_get_delay(void *data)
    {
     platform_timing_delay_context *ctx = (platform_timing_delay_context *) data;
     unsigned long elapsed_ms;
     
     if(ctx->fin_ms == 0)
  {
   return(-1);
  }
     
     elapsed_ms = custom_ticks_to_milli_secs(custom_get_systicks() - ctx->snapshot); //轉換成毫秒
     
     if(elapsed_ms >= ctx->fin_ms)
     {
      return(2);
     }
     
     if(elapsed_ms >= ctx->int_ms)
     {
      return(1);
     }
     
     return 0;
    }

    #endif /* __MBEDTLS_DTLS__ */
    
    //注冊到底層
    mbedtls_ssl_set_timer_cb( &ssl, &platform_timer, platform_timing_set_delay, platform_timing_get_delay );      

4.4  網絡阻塞與非阻塞機制

mbedtls在電腦模拟測試時其網絡連接配接非常順暢,而且測試隻是跑這一項功能,即使采用阻塞模式也不會有其它問題。實際嵌入式裝置在聯網時,肯定還有其他任務需要執行。

如果裝置支援作業系統,可以為mbedtls單獨配置設定一個線程或者任務,推薦使用阻塞機制實作接口,而且容易調試,尤其是https下載下傳這種場景。但是特殊情況下不支援阻塞的,在改寫網絡接口時,需要特殊處理。

例如範例mbedtls_net_connect進行域名解析、連接配接伺服器,嵌入式裝置的無線網絡在這個步驟,基本會傳回異常表示阻塞等待中,要解決這個問題,需要将後續的握手流程拆分執行。原本聯網後執行mbedtls_ssl_handshake,在while裡面等待握手流程MBEDTLS_SSL_HANDSHAKE_OVER結束或者錯誤,改為每次收到讀消息的事件,執行一次或多次mbedtls_ssl_handshake_step。(這個并沒親自驗證)

mbedtls_ssl_set_bio注冊的讀寫接口支援設為非阻塞,mbedtls_ssl_write和mbedtls_ssl_read對應用層接口,在底層socket上報read_ready之後,判斷目前握手已經完成,再執行mbedtls_ssl_read。

4.5 證書與密鑰

測試可以使用mbedtls範例自帶的證書和公鑰、私鑰,但實際項目需要自己根據伺服器域名生成ca證書,以及雙方的公鑰、私鑰。在源碼programs\pkey下有秘鑰生成的代碼,作為用戶端,需要驗證伺服器提供的公鑰證書,是以本地還要CA憑證,類似首次登入12306提示要下載下傳的證書,再加上用戶端自身的公鑰和私鑰,一共3個檔案。gen_key.c生成keyfile.key私鑰,預設秘鑰長度是4096,雖然1024理論上有風險,但是運算更快;後面再使用openSSL 指令行生成公鑰。

OpenSSL> rsa -in private.key -pubout -out public.key

openSSL下載下傳位址 https://www.openssl.org/,安裝後提示使用收費,實際使用未見異常。秘鑰也可使用openSSL生成

OpenSSL>genrsa -out private.key 2048

如果使用未知,使用help檢視說明。至于CA憑證,需要平台側生成再提供給裝置端。

4.6 加密套件與配置裁剪

确定合适的加密套件,未使用的算法就可以屏蔽;在電腦運作瞬間完成,在實際arm硬體可能需要較長時間,比如使用RSA在握手階段可能需要較長時間,可以選擇ECDSA或者減小秘鑰長度。

5、 小節

目前的物聯網對資料安全不是很關注,使用自定義協定近似明文的方式互動,或者使用單一加密方式,未來智能家居、涉及财物計費的、特殊行業的裝置節點,可能會逐漸使用加密通信,而mbedtls則是較好的選擇之一。即使不使用TLS,也可以選擇簡單的對稱加密,mbedtls也是一個加密算法庫,可根據需求提取合适的源碼內建。

end

長按二維碼關注公衆号