OpenSSL一直以來各類被詬病,具體挑了哪些刺,本文就不深究。做爲OpenSSL有不少替代,我瞭解到的有cyaSSL(WolfSSL)和PolorSSL。其中PolarSSL已經被ARM收購了,更名爲mbedTLS。本文列舉了做爲一個SSL client端,應該如何使用mbedTLS。
本文能夠搭配我上一篇文章OpenSSL一塊兒看;單獨看也沒問題node
本文地址:http://www.javashuo.com/article/p-fdggnoih-s.htmlgit
mbed TLS tutorial - Knowledge Base
ARMmbed / mbedtls / programs / ssl / ssl_client1.cgithub
傳統的socket-based的程序,依照順序,做爲client要作如下的函數調用:segmentfault
gethostbyname() socket() connect() write() read()
改爲SSL以後,mbedTLS對應上述函數,分別對應爲:session
gethostbyname() \ socket() -+--> mbedtls_net_connect() + mbedtls_ssl_handshake() connect() / write() ----> mbedtls_ssl_write() read() ----> mbedtls_ssl_read()
固然,實際狀況下,會使用更多的其餘函數。具體(最簡單的)流程見下文數據結構
mbedtls_net_context
:目前只有文件描述符,能夠用於適配異步I/O庫mbedtls_ssl_context
:保存SSL基本數據mbedtls_ssl_config
mbedtls_ctr_drbg_context
mbedtls_entropy_context
:保存熵配置mbedtls_x509_crt
:保存認證信息dom
下面是init階段須要調用的各函數。函數的參數,在調用的時候按照上面的函數類型一個一個傳入就好了異步
mbedtls_net_init() mbedtld_ssl_init() mbedtld_ssl_config_init() mbedtls_ctr_drbg_init() mbedtld_x509_crt_init() mbedtls_entropy_init() mebdtls_ctr_drbg_seed()
其中mebdtls_ctr_drbg_seed()
能夠指定熵函數。若是回調使用默認的mbedtls_entropy_func
的話,能夠傳入一個初始的熵seed,也能夠NULLsocket
mbedtls_net_connect()
:參數是server和端口,均爲字符串。server可使域名或者IP字符串。最後一個參數使用MBEDTLS_NET_PROTO_TCP
便可。端口號不單單能夠傳入數字字符串,也能夠相似於get_addrinfo
函數的protocol
參數那樣,傳入相似於「HTTPS」這樣的可讀化字符串。函數
mbedtls_ssl_config_defaults()
:
經實驗,mbedTLS是能夠順利適配libev
的,Good!(libuv沒有實際試過,不過應該也是OK的)
什麼?問我怎麼不適配libevent
? 要用libevent的話就用封裝了OpenSSL
的bufferevent
去啦
適配的具體思路,能夠查看本文的評論中我和 breeze0924 的留言。
此外,還有兩位同窗也作了相應的適配:
各位都是大神啊~~歡迎參考~~
如下是僞代碼,有點多,從最簡單的main()
入手就好:
一些自定義的數據結構
typedef struct _MBEDTLS_SESSION { mbedtls_net_context mbedNetCtx; mbedtls_ssl_context mbedSslCtx; mbedtls_ssl_config mbedSslConf; mbedtls_ctr_drbg_context mbedDrbgCtx; mbedtls_entropy_context mbedEtpyCtx; mbedtls_x509_crt mbedX509Crt; } MbedTLSSession_st; typedef struct SSL_SESSION { struct ev_io *libevWatcher; MbedTLSSession_st mbedIntf; } SSLSession_st;
MbedTLS初始化
MbedTlsClientInit(MbedTLSSession_st *session, void *entropy, size_t entropyLen) { mbedtls_net_init(&(session->mbedNetCtx)); mbedtls_ssl_init(&(session->mbedSslCtx)); mbedtls_ssl_config_init(&(session->mbedSslConf)); mbedtls_ctr_drbg_init(&(session->mbedDrbgCtx)); mbedtls_x509_crt_init(&(session->mbedX509Crt)); mbedtls_entropy_init(&(session->mbedEtpyCtx)); mbedtls_ctr_drbg_seed(&(session->mbedDrbgCtx), mbedtls_entropy_func, &(session->mbedEtpyCtx), (unsigned char *)entropy, entropyLen); }
MbedTLS的 connect 動做
AMCMbedTlsClientConnect(MbedTLSSession_st *session, const char *serverHost, int serverPort) { int callStat; char portStrBuff[16]; snprintf(portStrBuff, sizeof(portStrBuff), "%d", serverPort); callStat = mbedtls_net_connect(&(session->mbedNetCtx), serverHost, portStrBuff, MBEDTLS_NET_PROTO_TCP); _RETURN_IF_ERROR(callStat); callStat = mbedtls_ssl_config_defaults(&(session->mbedSslConf), MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT); _RETURN_IF_ERROR(callStat); mbedtls_ssl_conf_authmode(&(session->mbedSslConf), MBEDTLS_SSL_VERIFY_OPTIONAL); mbedtls_ssl_conf_ca_chain(&(session->mbedSslConf), &(session->mbedX509Crt), NULL); mbedtls_ssl_conf_rng(&(session->mbedSslConf), mbedtls_ctr_drbg_random, &(session->mbedDrbgCtx)); //edtls_ssl_conf_dbg(&(session->mbedSslConf), NULL, NULL); mbedtls_ssl_set_bio(&(session->mbedSslCtx), &(session->mbedNetCtx), mbedtls_net_send, mbedtls_net_recv, mbedtls_net_recv_timeout); callStat = mbedtls_ssl_setup(&(session->mbedSslCtx), &(session->mbedSslConf)); _RETURN_IF_ERROR(callStat); while((callStat = mbedtls_ssl_handshake(&(session->mbedSslCtx))) != 0) { if ((callStat != MBEDTLS_ERR_SSL_WANT_READ) && (callStat != MBEDTLS_ERR_SSL_WANT_WRITE)) { return callStat; } } return 0; }
主函數:
static SSLSession_st *g_session = NULL; main() { SSLSession_st session; char *pers = "hello world"; MbedTlsClientInit(&(session.mbedIntf), pers, strlen(pers)); mbedtls_ssl_write(...); // 發送請求。我用的是https://www.bing.com,因此發送的是HTTP請求 /* 下面開始配置 libev */ session.libevWatcher = malloc(sizeof(session.libevWatcher)); set_nonblock(session.mbedNetCtx.fd) ev_io_init(&(session.libevWatcher), _libev_callback, fd, EV_READ); // 在callback 調用 mbedtls_ssl_read() ev_io_start(loop, &(session.libevWatcher)); ev_loop(loop, 0); }