分享
 
 
 

openssl之BIO系列之24---SSL类型的BIO

王朝other·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

SSL类型的BIO

---根据openssl doc\crypto\bio_f_ssl.pod翻译和自己的理解写成

(作者:DragonKing, Mail: wzhah@263.net ,发布于:http://openssl.126.com 之openssl专业论坛)

从名字就可以看出,这是一个非常重要的BIO类型,它封装了openssl里面的ssl规则和函数,相当于提供了一个使用SSL很好的有效工具,一个很好的助手。其定义(openssl\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,NULL)

#define BIO_set_ssl_renegotiate_bytes(b,num) BIO_ctrl(b,BIO_C_SET_SSL_RENEGOTIATE_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_RENEGOTIATES,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函数来设置服务器名字和端口,而不需要先找到连接BIO。

【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 blocking,但是根据上下文意思已经BIO的其它性质,我个人认为是阻塞型,blocking才是正确的)的BIO,在一些意外的情况SSL类型BIO下也会发出意外的重试请求,如在执行BIO_read操作的时候如果启动了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 PRNG)

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);

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有