天天看點

OPENSSL BIO伺服器端僞代碼

最近在做伺服器端的SSL支援,伺服器端用的網絡IO庫是libuv,由于libuv官方是不會支援ssl的,是以得自己實作。

原理應該是将 libuv擷取到的資料喂給OPENSSL的BIO,然後判斷是否握手完畢。注意:SSL的用戶端發送給伺服器端的資料首先是SSL握手資料,然後再是http等頭資料。

本文僅僅是記錄了在伺服器端初始化的流程,便于以後參考。

在用OPENSSL做伺服器端時 ,伺服器端需要首先配置證書與私鑰檔案,然後用 SSL_set_accept_state()  來設定為伺服器端,這個函數告訴SSL等待用戶端連接配接hello握手。然後将從原始SOCKET讀取到的用戶端資料寫入BIO的 reader(rbio),等待握手完成。

ctx = SSL_CTX_new(SSLv3_server_method()); // This is the server!
SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);

ssl = SSL_new(ctx);
rbio = BIO_new(BIO_s_mem());
wbio = BIO_new(BIO_s_mem());

SSL_set_bio(ssl, rbio, wbio);
SSL_set_accept_state(ssl); // 用SSL_set_accept_state來設定為伺服器端


//将從用戶端讀取到的資料寫入到 SSL的 reader BIO,這些資料是用戶端發送的握手資料
do {
    uint8_t  buf[1024];
    
    int buf_size = read_from_client_socket(client, buf, 1024);
         

    BIO_write(rbio, buf, buf_size);

    if (!SSL_is_init_finished(ssl)) {
        SSL_do_handshake(ssl);
    }
    else {
        break;
    }
}while(1);

do {
    //準備要發送給用戶端的資料,例如從檔案或者其它地方擷取的

    uint8_t data[4096];
    int data_len;
    ....

    BIO_write(rbio, data, data_len);
   
    char buf[4096];

    int ret = SSL_read(ssl, buf, sizeof(buf));
    if (ret < 0) {
        int err = SSL_get_error(client -> ssl, ret);
        if (err == SSL_ERROR_WANT_READ) {
            
        } else if (err == SSL_ERROR_WANT_WRITE) {
            
        }
    }

}while(1);
           

用 SSL_is_init_finished(ssl)  函數判斷握手是否完成,如果沒有完成,就調用 SSL_do_handshake(ssl)。然後從 BIO_writer 裡讀取資料并發送給用戶端。