mbedtls下載路徑:
https://github.com/ARMmbed/mbedtls
交叉編譯:
先在shell里設置好編譯器: export CC=....(gcc的全路徑)
然后執行編譯命令:make
最后在library目錄下找到.a文件,我們可以鏈接使用的靜態庫,將其鏈接進我們的系統。
我在君正X1000平台上鏈接mbedtls時,提示找不到 read,write,close等幾個與文件操作的函數,就自己實現了幾個空函數給它鏈接,因為我用不到文件操作的功能,我只需要使用它來實現固件升級時固件的合法性驗證。基本思路是編譯好固件后,對其簽名,生成的簽名結果數據加在固件最后面,升級時,MCU端收到所有數據(反正這個芯片內存足夠大)后,按固定長度(簽名結果是定長的)計算固件的hash值,將hash值與簽名結果傳給mbedtls相關的函數進行驗證。
如果內存不夠大,不足以裝下固件,可能需要在flash上划分一片區域來臨時存放即將升級的固件。收到固件時一邊寫入FLASH,一邊計算hash值。當所有固件都接收完,用最終的hash值與簽名結果驗證通過后再燒寫到正確的位置。這個只是一個想法,並沒有真正實現。
固件中驗證的代碼:
int make_hash( char * buffer ,int bufLen, char * hash, int hashLen)
{
int ret = -1;
mbedtls_md_context_t ctx;
const mbedtls_md_info_t *md_info=mbedtls_md_info_from_type( MBEDTLS_MD_SHA256 );
if( md_info == NULL )
goto cleanup;
mbedtls_md_init( &ctx );
ret = mbedtls_md_setup( &ctx, md_info, 0 );
if( ret != 0 )
goto cleanup;
ret = mbedtls_md_starts( &ctx );
if( ret != 0 )
goto cleanup;
ret = mbedtls_md_update(&ctx, buffer, bufLen );
if( ret != 0 )
goto cleanup;
ret = mbedtls_md_finish( &ctx, hash );
cleanup:
mbedtls_md_free( &ctx );
return( ret );
}
int checkFWValidity( uint8_t * buffer, uint32_t length )
{
int fwLen = length - KEY_SIZE;
uint8_t * signature = buffer+ fwLen;
int ret=0;
char hash[64];
mbedtls_rsa_context rsa;
mbedtls_rsa_init( &rsa, MBEDTLS_RSA_PKCS_V21, 0 );
ret=mbedtls_mpi_read_string(&rsa.N,16,pubKey);
ret=mbedtls_mpi_read_string(&rsa.E,16,keyEValue);
rsa.len = ( mbedtls_mpi_bitlen( &rsa.N ) + 7 ) >> 3;
ret= make_hash(buffer, fwLen, hash, sizeof(hash) );
ret = mbedtls_rsa_pkcs1_verify( &rsa, NULL,NULL,MBEDTLS_RSA_PUBLIC, MBEDTLS_MD_SHA256,0x20, hash,signature );
mbedtls_md_hmac_finish(NULL,NULL);
return ret;
}
其中 pubKey和keyEValue是我們使用的public key相關的信息,保存在全局變量里即可。這個函數需要的public key不是pem格式的數據,具體叫什么格式我也沒有明白。
PC上需要運行的命令:
交叉編譯的同時可以編譯一個X86版本的mbedtls, 與簽名及驗證相關的程序在programs\pkey目錄中,將其中的
運行gen_key,生成 keyfile.key
運行:./key_app_writer mode=private filename=keyfile.key output_mode=public output_file=public.key 得到public key
運行: ./key_app_writer mode=public filename=public.key output_mode=public
將其輸出保存下來,大概內容如下(省略號代表的是很長的字符串)
N: CBDB69551C.....08E5
E: 010001
N:開頭的第一行為
pubKey的內容(去掉N:)
E:開頭的第二行為
keyEValue的內容(同理去掉E:)
private key要保存好,以后用它來做簽名
簽名的命令: rsa_sign_pss keyfile.key file(要簽名的文件)
簽名的結果自動寫入file.sig文件中,可以使用命令 cat file file.sig > signed
將源文件和簽名結果合並寫入到一個新文件:signed中。
在君正X1000上,支持mbedtls之后,固件大小增加了100K,如果想要減少,應該可以通過修改config.h來實現。