openssl之BIO系列之24---SSL類型的BIO,openssl24---ssl

來源:互聯網
上載者:User

openssl之BIO系列之24---SSL類型的BIO,openssl24---ssl

SSL類型的BIO

    ---根據openssl doc\crypto\bio_f_ssl.pod翻譯和自己的理解寫成

    (作者:DragonKing, Mail: wzhah@263.net ,發佈於:http://openssl.126.com之

openssl專業論壇)

    從名字就可以看出,這是一個非常重要的BIO類型,它封裝了openssl裡面的ssl規則

和函數,相當於提供了一個使用SSL很好的有效工具,一個很好的助手。其定義(opens

sl\bio.h,openssl\ssl.h)如下:

     BIO_METHOD *BIO_f_ssl(void);

     #define BIO_set_ssl(b,ssl,c) BIO_ctrl(b,BIO_C_SET_SSL,c,(char *)ssl)

     #define BIO_get_ssl(b,sslp) BIO_ctrl(b,BIO_C_GET_SSL,0,(char *)sslp)

     #define BIO_set_ssl_mode(b,client) BIO_ctrl(b,BIO_C_SSL_MODE,client,NUL

L)

     #define BIO_set_ssl_renegotiate_bytes(b,num) BIO_ctrl(b,BIO_C_SET_SSL_R

ENEGOTIATE_BYTES,num,NULL);

     #define BIO_set_ssl_renegotiate_timeout(b,seconds) BIO_ctrl(b,BIO_C_SET

_SSL_RENEGOTIATE_TIMEOUT,seconds,NULL);

     #define BIO_get_num_renegotiates(b) BIO_ctrl(b,BIO_C_SET_SSL_NUM_RENEGO

TIATES,0,NULL);

     BIO *BIO_new_ssl(SSL_CTX *ctx,int client);

     BIO *BIO_new_ssl_connect(SSL_CTX *ctx);

     BIO *BIO_new_buffer_ssl_connect(SSL_CTX *ctx);

     int BIO_ssl_copy_session_id(BIO *to,BIO *from);

     void BIO_ssl_shutdown(BIO *bio);

     #define BIO_do_handshake(b) BIO_ctrl(b,BIO_C_DO_STATE_MACHINE,0,NULL)

    該類型BIO的實現檔案在ssl\bio_ssl.c裡面,大家可以參看這個檔案得到詳細的函

數實現資訊。

    【BIO_f_ssl】

    該函數返回一個SSL類型的BIO_METHOD結構,其定義如下:

    static BIO_METHOD methods_sslp=

     {

     BIO_TYPE_SSL,"ssl",

     ssl_write,

     ssl_read,

     ssl_puts,

     NULL, /* ssl_gets, */

     ssl_ctrl,

     ssl_new,

     ssl_free,

     ssl_callback_ctrl,

     };

    可見,SSL類型BIO不支援BIO_gets的功能。

    BIO_read和BIO_write函數調用的時候,SSL類型的BIO會使用SSL協議進行底層的I/

O操作。如果此時SSL串連並沒有建立,那麼就會在調用第一個IO函數的時候先進行串連

的建立。

    如果使用BIO_push將一個BIO附加到一個SSL類型的BIO上,那麼SSL類型的BIO讀寫數

據的時候,它會被自動調用。

    BIO_reset調用的時候,會調用SSL_shutdown函數關閉目前所有處於串連狀態的SSL

,然後再對下一個BIO調用BIO_reset,這功能一般就是將底層的傳輸串連斷開。調用完

成之後,SSL類型的BIO就處於初始的接受或串連狀態。

    如果設定了BIO關閉標誌,那麼SSL類型BIO釋放的時候,內部的SSL結構也會被SSL_

free函數釋放。

    【BIO_set_ssl】

    該函數設定SSL類型BIO的內部ssl指標指向ssl,同時使用參數c設定了關閉標誌。

    【BIO_get_ssl】

    該函數返回SSL類型BIO的內部的SSL結構指標,得到該指標後,可以使用標誌的SSL

函數對它進行操作。

    【BIO_set_ssl_mode】

    該函數設定SSL的工作模式,如果參數client是1,那麼SSL工作模式為用戶端模式,

如果client為0,那麼SSL工作模式為伺服器模式。

    【BIO_set_ssl_renegotiate_bytes】

    該函數設定需要重新進行session協商的讀寫資料的長度為num。當設定完成後,在

沒讀寫的資料一共到達num位元組後,SSL串連就會自動重新進行session協商,這可以加強

SSL串連的安全性。參數num最少為512位元組。

    【BIO_set_ssl_renegotiate_timeout】

    該函數跟上述函數一樣都是為了加強SSL串連的安全性的。不同的是,該函數採用的

參數是時間。該函數設定重新進行session協商的時間,其單位是秒。當SSL session連

接建立的時間到達其設定的時間時,串連就會自動重新進行session協商。

    【BIO_get_num_renegotiates】

    該函數返回SSL串連在因為位元組限制或時間限制導致session重新協商之前總共讀寫

的資料長度。

    【BIO_new_ssl】

    該函數使用ctx參數所代表的SSL_CTX結構建立一個SSL類型的BIO,如果參數client

為非零值,就使用用戶端模式。

    【BIO_new_ssl_connect】

    該函數建立一個包含SSL類型BIO的新BIO鏈,並在後面附加了一個連線類型的BIO。

 

    方便而且有趣的是,因為在filter類型的BIO裡,如果是該BIO不知道(沒有實現)

BIO_ctrl操作,它會自動把該操作傳到下一個BIO進行調用,所以我們可以在調用本函數

得到BIO上直接調用BIO_set_host函數來設定伺服器名字和連接埠,而不需要先找到串連B

IO。

    【BIO_new_buffer_ssl_connect】

    建立一個包含buffer型的BIO,一個SSL類型的BIO以及一個連線類型的BIO。

    【BIO_ssl_copy_session_id】

    該函數將BIO鏈from的SSL Session ID拷貝到BIO鏈to中。事實上,它是通過尋找到

兩個BIO鏈中的SSL類型BIO,然後調用SSL_copy_session_id來完成操作的。

    【BIO_ssl_shutdown】

    該函數關閉一個BIO鏈中的SSL串連。事實上,該函數通過尋找到該BIO鏈中的SSL類

型BIO,然後調用SSL_shutdown函數關閉其內部的SSL指標。

    【BIO_do_handshake】

    該函數在相關的BIO上啟動SSL握手過程並建立SSL串連。串連成功建立返回1,否則

返回0或負值,如果串連BIO是非阻塞型的BIO,此時可以調用BIO_should_retry函數以決

定釋放需要重試。如果調用該函數的時候SSL串連已經建立了,那麼該函數不會做任何事

情。一般情況下,應用程式不需要直接調用本函數,除非你希望將握手過程跟其它IO操

作分離開來。

    需要注意的是,如果底層是阻塞型(openssl協助文檔寫的是非阻塞型,non blocki

ng,但是根據上下文意思已經BIO的其它性質,我個人認為是阻塞型,blocking才是正確

的)的BIO,在一些意外的情況SSL類型BIO下也會發出意外的重試請求,如在執行BIO_r

ead操作的時候如果啟動了session重新協商的過程就會發生這種情況。在0.9.6和以後的

版本,可以通過SSL的標誌SSL_AUTO_RETRY將該類行為禁止,這樣設定之後,使用阻塞型

傳輸的SSL類型BIO就永遠不會發出重試的請求。

    【例子】

    1.一個SSL/TLS用戶端的例子,完成從一個SSL/TLS伺服器返回一個頁面的功能。其

中IO操作的方法跟連線類型BIO裡面的例子是相同的。

     BIO *sbio, *out;

     int len;

     char tmpbuf[1024];

     SSL_CTX *ctx;

     SSL *ssl;

     ERR_load_crypto_strings();

     ERR_load_SSL_strings();

     OpenSSL_add_all_algorithms();

     //如果系統平台不支援自動進行隨機數種子的設定,這裡應該進行設定(seed PRN

G)

     ctx = SSL_CTX_new(SSLv23_client_method());

     //通常應該在這裡設定一些驗證路徑和模式等,因為這裡沒有設定,所以該例子可

以跟使用任意CA簽發認證的任意伺服器建立串連

     sbio = BIO_new_ssl_connect(ctx);

     BIO_get_ssl(sbio, &ssl);

     if(!ssl) {

     fprintf(stderr, "Can't locate SSL pointer\n");

     }

     /* 不需要任何重試請求*/

     SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);

     //這裡你可以添加對SSL的其它一些設定

     BIO_set_conn_hostname(sbio, "localhost:https");

     out = BIO_new_fp(stdout, BIO_NOCLOSE);

     if(BIO_do_connect(sbio) <= 0) {

     fprintf(stderr, "Error connecting to server\n");

     ERR_print_errors_fp(stderr);

     }

     if(BIO_do_handshake(sbio) <= 0) {

     fprintf(stderr, "Error establishing SSL connection\n");

     ERR_print_errors_fp(stderr);

     }

     /* 這裡可以添加檢測SSL串連的代碼,得到一些串連資訊*/

     BIO_puts(sbio, "GET / HTTP/1.0\n\n");

     for(;;) {

     len = BIO_read(sbio, tmpbuf, 1024);

     if(len <= 0) break;

     BIO_write(out, tmpbuf, len);

     }

     BIO_free_all(sbio);

     BIO_free(out);

    2.一個簡單的伺服器的例子。它使用了buffer類型的BIO,從而可以使用BIO_gets從

一個SSL類型的BIO讀取資料。它建立了一個包含用戶端請求的隨機web頁,並把請求資訊

輸出到標準輸出裝置。

     BIO *sbio, *bbio, *acpt, *out;

     int len;

     char tmpbuf[1024];

     SSL_CTX *ctx;

     SSL *ssl;

     ERR_load_crypto_strings();

     ERR_load_SSL_strings();

     OpenSSL_add_all_algorithms();

     //可能需要進行隨機數的種子處理(seed PRNG)

     ctx = SSL_CTX_new(SSLv23_server_method());

     if (!SSL_CTX_use_certificate_file(ctx,"server.pem",SSL_FILETYPE_PEM)

     || !SSL_CTX_use_PrivateKey_file(ctx,"server.pem",SSL_FILETYPE_PEM)

     || !SSL_CTX_check_private_key(ctx)) {

     fprintf(stderr, "Error setting up SSL_CTX\n");

     ERR_print_errors_fp(stderr);

     return 0;

     }

     //可以在這裡設定驗證路徑,DH和DSA演算法的臨時密鑰回呼函數等等

     /* 建立一個新的伺服器模式的SSL類型BIO*/

     sbio=BIO_new_ssl(ctx,0);

     BIO_get_ssl(sbio, &ssl);

     if(!ssl) {

     fprintf(stderr, "Can't locate SSL pointer\n");

     }

     /* 不需要任何重試請求 */

     SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);

     /* 建立一個Buffer類型BIO */

     bbio = BIO_new(BIO_f_buffer());

     /* 加到BIO鏈上*/

     sbio = BIO_push(bbio, sbio);

     acpt=BIO_new_accept("4433");

     /*

     當一個新串連建立的時候,我們可以將sbio鏈自動插入到串連所在的BIO鏈中去。

這時候,這個BIO鏈(sbio)就被accept類型BIO吞併了,並且當accept類型BIO釋放的時候

,它會自動被釋放。

     */

     BIO_set_accept_bios(acpt,sbio);

     out = BIO_new_fp(stdout, BIO_NOCLOSE);

     /* 設定 accept BIO */

     if(BIO_do_accept(acpt) <= 0) {

     fprintf(stderr, "Error setting up accept BIO\n");

     ERR_print_errors_fp(stderr);

     return 0;

     }

     /* 等待串連的建立 */

     if(BIO_do_accept(acpt) <= 0) {

     fprintf(stderr, "Error in connection\n");

     ERR_print_errors_fp(stderr);

     return 0;

     }

     /*

     因為我們只想處理一個串連,所以可以刪除和釋放 accept BIO了

     */

     sbio = BIO_pop(acpt);

     BIO_free_all(acpt);

     if(BIO_do_handshake(sbio) <= 0) {

     fprintf(stderr, "Error in SSL handshake\n");

     ERR_print_errors_fp(stderr);

     return 0;

     }

     BIO_puts(sbio, "HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n");

     BIO_puts(sbio, "<pre>\r\nConnection Established\r\nRequest headers:\r\n

");

     BIO_puts(sbio, "--------------------------------------------------\r\n"

);

     for(;;) {

     len = BIO_gets(sbio, tmpbuf, 1024);

     if(len <= 0) break;

     BIO_write(sbio, tmpbuf, len);

     BIO_write(out, tmpbuf, len);

     /* 尋找要求標頭的結束標準空白行*/

     if((tmpbuf[0] == '\r') || (tmpbuf[0] == '\n')) break;

     }

     BIO_puts(sbio, "--------------------------------------------------\r\n"

);

     BIO_puts(sbio, "</pre>\r\n");

     /* 因為使用了buffer類型的BIO,我們最好調用BIO_flush函數 */

     BIO_flush(sbio);

     BIO_free_all(sbio);

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.