mbedTLS(PolarSSL)簡單思路和函數筆記(Client端)

OpenSSL一直以來各類被詬病,具體挑了哪些刺,本文就不深究。做爲OpenSSL有不少替代,我瞭解到的有cyaSSL(WolfSSL)和PolorSSL。其中PolarSSL已經被ARM收購了,更名爲mbedTLS。本文列舉了做爲一個SSL client端,應該如何使用mbedTLS。
本文能夠搭配我上一篇文章OpenSSL一塊兒看;單獨看也沒問題node

本文地址:http://www.javashuo.com/article/p-fdggnoih-s.htmlgit

Reference

mbed TLS tutorial - Knowledge Base
ARMmbed / mbedtls / programs / ssl / ssl_client1.cgithub

mbedTLS 基本使用

與傳統 socket 的對比

傳統的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 階段

下面是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

Connect 階段

mbedtls_net_connect():參數是server和端口,均爲字符串。server可使域名或者IP字符串。最後一個參數使用MBEDTLS_NET_PROTO_TCP便可。端口號不單單能夠傳入數字字符串,也能夠相似於get_addrinfo函數的protocol參數那樣,傳入相似於「HTTPS」這樣的可讀化字符串。函數

mbedtls_ssl_config_defaults()

適配異步I/O庫

經實驗,mbedTLS是能夠順利適配libev的,Good!(libuv沒有實際試過,不過應該也是OK的)
什麼?問我怎麼不適配libevent? 要用libevent的話就用封裝了OpenSSLbufferevent去啦

適配的具體思路,能夠查看本文的評論中我和 breeze0924 的留言。

此外,還有兩位同窗也作了相應的適配:

  1. @gemini 寫了一個 libuv demo
  2. @yorkie 則把 mbedTLS 的客戶端實現成功移植到了 ShadowNode

各位都是大神啊~~歡迎參考~~

姊妹篇

OpenSSL 簡單思路和函數筆記

做爲 client 適配 libev 調用過程

如下是僞代碼,有點多,從最簡單的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);
}
相關文章
相關標籤/搜索