聊聊 Mbedtls 基礎(chǔ)及其應(yīng)用
1、引言
1.1 為什么要加密
互聯(lián)網(wǎng)是開放環(huán)境,通信雙方都是未知身份,為通信雙方的有效信息不被第三方竊聽、篡改或者被冒充身份進(jìn)行通信,需要為信息加上保護(hù)措施。也就是對所有信息都進(jìn)行加密,避免被第三方竊聽;采用校驗機制,可以識別出信息是否被篡改,配備身份認(rèn)證防止被冒充身份?;ヂ?lián)網(wǎng)的通信安全,就是建立在SSL/TLS協(xié)議之上。
1.2 SSL/TLS協(xié)議的歷史
1996年,在前面的基礎(chǔ)上,SSL 3.0版問世并得到大規(guī)模應(yīng)用;
1999年,互聯(lián)網(wǎng)標(biāo)準(zhǔn)化組織ISOC接替NetScape公司,發(fā)布了SSL的升級版TLS 1.0版,也稱為SSL 3.1;SSL和TLS指的是同一套加密協(xié)議,只是不同時期的名字差異。
2006年和2008年,TLS進(jìn)行了兩次升級,分別為TLS 1.1版和TLS 1.2版。
一般推薦使用TLS 1.2,主流的瀏覽器都支持。
2、SSL/TLS演化
熟悉一套技術(shù)的演進(jìn)步驟,比直接看最新版本,更容量理解。
2.1 明文時代
小帥向小美發(fā)送信息,直接以明文形式發(fā)送。
缺點顯而易見,第三方小黑很容易就竊取到信息,也可以進(jìn)行篡改后發(fā)給小美,而且小美收到后并不知情,以為是小帥發(fā)來的。
2.2 對稱加密時代
小帥和小美保存一份相同的秘鑰,小帥發(fā)出的信息先經(jīng)過加密,小美收到后使用同樣的密碼進(jìn)行解密。這種加密和解密使用同一個密鑰的算法稱為對稱加密算法。
短期內(nèi)小黑對加密數(shù)據(jù)無能為力,但是每次變更秘鑰需要事先協(xié)商,如果協(xié)商出問題,小帥告知小美新秘鑰時,秘鑰被小黑截取,那后續(xù)的密文對小黑來說,他也可以解密成明文。也可以篡改明文信息后,再使用同樣的秘鑰加密后發(fā)給小美。
2.3 非對稱加密時代
既然進(jìn)行秘鑰交換存在風(fēng)險,小帥和小美采用非對稱加密算法。雙方各自保存私鑰、公鑰,兩者配對,私鑰自己保存,公鑰由私鑰運算生成發(fā)給對方,不能由公鑰反推算出私鑰;但是使用公鑰加密的密文,卻可以使用私鑰解密;使用私鑰簽名,使用公鑰驗證;這種加密和解密使用不同的密鑰的算法成為非對稱加密算法。
通信前,雙發(fā)先將自己的公鑰發(fā)給對方,私鑰保密;小帥先使用小美提供的公鑰加密數(shù)據(jù),同時也使用自己的私鑰進(jìn)行簽名標(biāo)記,一起打包后發(fā)給小美,小美使用自己的私鑰進(jìn)行解密,再使用小帥的公鑰進(jìn)行驗證,確認(rèn)收到的信息是否來自小帥。
這種形式的加密通信,協(xié)商傳輸?shù)氖枪€,即使被小黑截取,他也不能解密后續(xù)的信息,因為解密得使用私鑰。
但是百密一疏,如果小黑子在最初交互公鑰時,截取公鑰,把小帥發(fā)給小美的公鑰截取,把自己的假公鑰發(fā)給小美;截取小美發(fā)出的數(shù)據(jù),小黑用自己的私鑰解密,然后再使用自己的私鑰加密后發(fā)給小帥。
整了這么復(fù)雜的一套加密協(xié)議,結(jié)果還是存在隱患。
2.4 公證時代
問題就出在公鑰交換,小美收到一份公鑰,如何證明這公鑰確實是小帥發(fā)出的?譬如買房,只有房管局確認(rèn)蓋章導(dǎo)入系統(tǒng)的房產(chǎn)證,才是真的房產(chǎn)證,才能放心進(jìn)行交易。通過CA(Certificate Authority)證書頒發(fā)機構(gòu)來保證公鑰的真實性,為公鑰的真實性進(jìn)行擔(dān)保公證。
CA也是基于非對稱加密算法,小帥先先把自己的公鑰交給CA,CA用自己的私鑰加密這些數(shù)據(jù),加密完的數(shù)據(jù)稱為小帥的數(shù)字證書,先前小帥發(fā)給小美的公鑰,改為發(fā)送CA加密之后的數(shù)字證書。小美收到以后,通過CA發(fā)布的CA證書(包含了CA的公鑰),來解密小帥的數(shù)字證書,從而獲得小帥的公鑰。
問題是小美怎么確保CA證書不是小黑偽造的?CA證書是提前預(yù)置在瀏覽器或操作系統(tǒng),或者嵌入式設(shè)備內(nèi),不需要聯(lián)網(wǎng)獲取,自然也不存在劫持篡改的問題。
雖然小黑還是可以攔截帶公鑰的數(shù)字簽名證書,可以用CA公鑰解密看到內(nèi)容;但是他沒CA的秘鑰,無法偽造出正確的數(shù)字簽名證書,也就是小帥的真實公鑰小黑可見不可改,改了小美會發(fā)現(xiàn)異常,但只有公鑰并沒什么價值。
2.5 TLS協(xié)議時代
公證時代的解決方案就是SSL/TLS協(xié)議加密通信基礎(chǔ)。因為使用非對稱加密算法比對稱加密算法要復(fù)雜,消耗運算資源,為考慮效率,非對稱加密只會用來傳遞一條信息,即對稱加密的密鑰。對稱加密的密鑰確定,后續(xù)有效信息使用對稱加密算法進(jìn)行網(wǎng)絡(luò)傳輸。既保證了網(wǎng)絡(luò)通信的安全性,又不影響效率。
SSL/TLS協(xié)議的基本過程:
1、通過CA體系交換公鑰
2、使用非對稱加密算法,交換用于對稱加密的密鑰
3、有效數(shù)據(jù)使用對稱加密算法,進(jìn)行密文傳輸
前兩步又稱為"握手階段"(handshake),是SSL/TLS加密通信的基礎(chǔ)。
2.6 TLS的應(yīng)用
在SSL/TLS出現(xiàn)之前,很多應(yīng)用層協(xié)議(http、ftp、smtp等)都存在著網(wǎng)絡(luò)安全問題。最常見的http協(xié)議,在傳輸過程中使用的是明文信息,傳輸報文一旦被截獲便會泄露傳輸內(nèi)容;傳輸過程中報文如果被篡改,對方無法輕易發(fā)現(xiàn);無法保證消息交換的對端身份的可靠性。為了解決此類安全問題,在應(yīng)用層和傳輸層之間加入了SSL/TLS協(xié)議,升級為https。SSL/TLS目前已經(jīng)廣泛用于數(shù)據(jù)安全協(xié)議。關(guān)于SSL/TLS有很多開源軟件包,如openSSL,mbedtls等。openSSL功能更強大,mbedtls小巧更適合嵌入式設(shè)備。
3、mbedtls
隨著物聯(lián)網(wǎng)的發(fā)展,設(shè)備節(jié)點的安全問題也越來越重要,相比互聯(lián)網(wǎng)的openSSL,物聯(lián)網(wǎng)的嵌入式設(shè)備適合小巧靈活的MbedTLS,曾用名PolarSSL,可以根據(jù)需求進(jìn)行配置,降低對硬件資源的消耗。mbedtls內(nèi)置了非常多的加密解密,散列算法源碼,即使不使用tls加密,也從里面挖掘各種算法,諸如AES/RSA/MD5等。但是openSSL功能更強大,
mbedtls是一款采用Apache 2.0許可證協(xié)議開源軟件加密庫,使用標(biāo)準(zhǔn)C語言編寫;獨立的模塊設(shè)計,降低模塊之間的耦合度。從功能上看,主要包括加密庫、X509證書、SSL/TLS協(xié)議三部分。
3.1 軟件包
進(jìn)入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內(nèi)置mbedtls有v2.4.0,v2.4.2和v2.14.1三種,將git版本切到v2.14.1,最后提交是2018年。前期先在電腦模擬測試,選擇Visual Studio 2013。
3.2 軟件結(jié)構(gòu)
mbedtls源碼結(jié)構(gòu)如下圖
mbedtls\include\mbedtls下面,可以version.h查看版本信息,重點是config.h配置,mbedtls是一套加密集合,實際項目使用中僅需選擇少部分即可,配置功能宏裁剪代碼,簡化運算,畢竟mbedtls跑一遍,一般的arm單片機不一定扛得住。
programs\ssl下是參考范例,TLS的客戶端和服務(wù)端范例,以及UDP版本的DTLS。嵌入式設(shè)備以客戶端應(yīng)用居多,主要參考ssl_client2.c里面很多配置參數(shù)可選,也可以針對應(yīng)用替換ssl_client1.c。
測試TLS客戶端首先要準(zhǔn)備3個文件,CA證書,客戶端公鑰數(shù)字證書以及私鑰。一般情況下命名后綴如下:
.crt CA證書 .pem 公鑰,經(jīng)CA加密后的公鑰,也稱為數(shù)字證書 .key 私鑰 有時crt和pem混用,其本質(zhì)都是CA公鑰加密后的文件
如果沒有服務(wù)器聯(lián)調(diào),也可以使用自身的ssl_server2.c做服務(wù)器。
3.3 demo流程分析
ssl_client2.c范例都在main函數(shù),其大體流程如下:
- 1、先加載各種證書、秘鑰,配置opt結(jié)構(gòu)體成員初始化,如TLS版本,加密套件類型等
- 2、然后開始連接服務(wù)器 mbedtls_net_connect
- 3、初始化tls參數(shù) mbedtls_ssl_config_defaults,設(shè)置網(wǎng)絡(luò)收發(fā)回調(diào)函數(shù)等
- 4、SSL/TLS握手流程,過程比較復(fù)雜,簡化就是通信雙方校驗對方身份,獲取對方的公鑰,確認(rèn)加密方式,后續(xù)數(shù)據(jù)進(jìn)行加密或解密做準(zhǔn)備 mbedtls_ssl_handshake
- 5、校驗服務(wù)端返回的證書 mbedtls_ssl_get_verify_result
- 6、如果前面流程順暢,就可以使用mbedtls_ssl_write,mbedtls_ssl_read收發(fā)數(shù)據(jù)了
- 7、測試結(jié)束后的清理工作
- 8、與標(biāo)準(zhǔn)socket編程對比,接口存在一定的對應(yīng)關(guān)系:
4、mbedtls移植
先在電腦端模擬測試,確定參數(shù),簡化范例里的賦值,因為實際項目參數(shù)不會經(jīng)常變更,優(yōu)化代碼,尤其是秘鑰加載,嵌入式都是以數(shù)組保存文件內(nèi)容,而不會使用文件形式加載。另外結(jié)合加密等級,確定加密套件類型。
模擬測試正常后,再移植到ARM平臺,主要改動涉及網(wǎng)絡(luò)連接、內(nèi)存管理和定時器三個方面。
4.1 網(wǎng)絡(luò)接口
mbedtls默認(rèn)的網(wǎng)絡(luò)接口mbedtls/library/net_socket.c,可以在windows下運行,特別注意,默認(rèn)的socket操作都是阻塞模式;一般不適合ARM平臺,關(guān)閉MBEDTLS_NET_C,結(jié)合硬件平臺重新實現(xiàn)網(wǎng)絡(luò)接口。主要包括以下函數(shù):
- 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,還需要實現(xiàn)該文件下另外幾個接口,具體流程參考dtls_client.c。
自定義實現(xiàn)的網(wǎng)絡(luò)收發(fā)接口,需要注冊mbedtls_ssl_set_bio告知底層。
- mbedtls_ssl_set_bio(&ssl, &server_fd,
- mbedtls_custom_send,//改寫后的mbedtls_net_send,為底層提供發(fā)送接口
- mbedtls_custom_recv,//為底層提供接收接口
- mbedtls_custom_recv_timeout)
4.2 內(nèi)存管理
自定義實現(xiàn)類型如下內(nèi)存的申請和釋放接口:
- void* calloc(unsigned int num,unsigned int size)
- void free(void * ptr)
實現(xiàn)后將函數(shù)注冊給底層
- 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); //轉(zhuǎn)換成毫秒
- 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 網(wǎng)絡(luò)阻塞與非阻塞機制
mbedtls在電腦模擬測試時其網(wǎng)絡(luò)連接非常順暢,而且測試只是跑這一項功能,即使采用阻塞模式也不會有其它問題。實際嵌入式設(shè)備在聯(lián)網(wǎng)時,肯定還有其他任務(wù)需要執(zhí)行。
如果設(shè)備支持操作系統(tǒng),可以為mbedtls單獨分配一個線程或者任務(wù),推薦使用阻塞機制實現(xiàn)接口,而且容易調(diào)試,尤其是https下載這種場景。但是特殊情況下不支持阻塞的,在改寫網(wǎng)絡(luò)接口時,需要特殊處理。
例如范例mbedtls_net_connect進(jìn)行域名解析、連接服務(wù)器,嵌入式設(shè)備的無線網(wǎng)絡(luò)在這個步驟,基本會返回異常表示阻塞等待中,要解決這個問題,需要將后續(xù)的握手流程拆分執(zhí)行。原本聯(lián)網(wǎng)后執(zhí)行mbedtls_ssl_handshake,在while里面等待握手流程MBEDTLS_SSL_HANDSHAKE_OVER結(jié)束或者錯誤,改為每次收到讀消息的事件,執(zhí)行一次或多次mbedtls_ssl_handshake_step。(這個并沒親自驗證)
mbedtls_ssl_set_bio注冊的讀寫接口支持設(shè)為非阻塞,mbedtls_ssl_write和mbedtls_ssl_read對應(yīng)用層接口,在底層socket上報read_ready之后,判斷當(dāng)前握手已經(jīng)完成,再執(zhí)行mbedtls_ssl_read。
4.5 證書與密鑰
測試可以使用mbedtls范例自帶的證書和公鑰、私鑰,但實際項目需要自己根據(jù)服務(wù)器域名生成ca證書,以及雙方的公鑰、私鑰。在源碼programs\pkey下有秘鑰生成的代碼,作為客戶端,需要驗證服務(wù)器提供的公鑰證書,因此本地還要CA證書,類似首次登錄12306提示要下載的證書,再加上客戶端自身的公鑰和私鑰,一共3個文件。gen_key.c生成keyfile.key私鑰,默認(rèn)秘鑰長度是4096,雖然1024理論上有風(fēng)險,但是運算更快;后面再使用openSSL 命令行生成公鑰。
- OpenSSL> rsa -in private.key -pubout -out public.key
openSSL下載地址 https://www.openssl.org/,安裝后提示使用收費,實際使用未見異常。秘鑰也可使用openSSL生成
- OpenSSL>genrsa -out private.key 2048
如果使用未知,使用help查看說明。至于CA證書,需要平臺側(cè)生成再提供給設(shè)備端。
4.6 加密套件與配置裁剪
確定合適的加密套件,未使用的算法就可以屏蔽;在電腦運行瞬間完成,在實際arm硬件可能需要較長時間,比如使用RSA在握手階段可能需要較長時間,可以選擇ECDSA或者減小秘鑰長度。
5、小節(jié)
目前的物聯(lián)網(wǎng)對數(shù)據(jù)安全不是很關(guān)注,使用自定義協(xié)議近似明文的方式交互,或者使用單一加密方式,未來智能家居、涉及財物計費的、特殊行業(yè)的設(shè)備節(jié)點,可能會逐漸使用加密通信,而mbedtls則是較好的選擇之一。即使不使用TLS,也可以選擇簡單的對稱加密,mbedtls也是一個加密算法庫,可根據(jù)需求提取合適的源碼集成。
本文轉(zhuǎn)載自微信公眾號「 嵌入式系統(tǒng)」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請聯(lián)系 嵌入式系統(tǒng)公眾號。