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工作模式为server模式。

【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

为非零值,就使用client模式。

【BIO_new_ssl_connect】

该函数创建一个包括SSL类型BIO的新BIO链。并在后面附加了一个连接类型的BIO。

方便并且有趣的是,由于在filter类型的BIO里。假设是该BIO不知道(没有实现)

BIO_ctrl操作。它会自己主动把该操作传到下一个BIO进行调用。所以我们能够在调用本函数

得到BIO上直接调用BIO_set_host函数来设置server名字和port。而不须要先找到连接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/TLSclient的样例。完毕从一个SSL/TLSserver返回一个页面的功能。其

中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签发证书的随意server建立连接

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.一个简单的server的样例。它使用了buffer类型的BIO,从而能够使用BIO_gets从

一个SSL类型的BIO读取数据。

它创建了一个包括client请求的随机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算法的暂时密钥回调函数等等

/* 创建一个新的server模式的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);

openssl之BIO系列之24---SSL类型的BIO的更多相关文章

  1. openssl之BIO系列之18---接受(accept)类型BIO

    接受(accept)类型BIO ---依据openssl doc\crypto\bio_s_accept.pod翻译和自己的理解写成 (作者:DragonKing, Mail: wzhah@263.n ...

  2. openssl之BIO系列之20---缓冲(buffer)类型BIO

    缓冲(buffer)类型BIO ---依据openssl doc\crypto\bio_f_buffer.pod翻译和自己的理解写成 (作者:DragonKing, Mail: wzhah@263.n ...

  3. openssl之BIO系列之22---Cipher类型的BIO

    Cipher类型BIO ---依据openssl doc\crypto\bio_f_cipher.pod翻译和自己的理解写成 (作者:DragonKing, Mail: wzhah@263.net , ...

  4. openssl之BIO系列之12---文件描写叙述符(fd)类型BIO

    文件描写叙述符(fd)类型BIO ---依据openssl doc\crypto\bio_s_fd.pod翻译和自己的理解写成 (作者:DragonKing Mailwzhah@263.net 公布于 ...

  5. openssl之BIO系列之9---BIO对的创建和应用

    BIO对的创建和应用 ---依据openssl doc/crypto/bio/bio_new_bio_pair.pod翻译和自己的理解写成 (作者:DragonKing Mail:wzhah@263. ...

  6. openssl之BIO系列之6---BIO的IO操作函数

    BIO的IO操作函数     ---依据openssl doc/crypto/bio/bio_read.pod翻译和自己的理解写成          (作者:DragonKing Mail:wzhah ...

  7. openssl之EVP系列之1---算法封装

    openssl之EVP系列之1---算法封装     ---依据openssl doc/crypto/EVP.pod翻译和自己的理解写成     (作者:DragonKing, Mail: wzhah ...

  8. openssl之EVP系列之7---信息摘要算法结构概述

    openssl之EVP系列之7---信息摘要算法结构概述     ---依据openssl doc/crypto/EVP_DigestInit.pod翻译和自己的理解写成     (作者:Dragon ...

  9. openssl之EVP系列之12---EVP_Seal系列函数介绍

    openssl之EVP系列之12---EVP_Seal系列函数介绍     ---依据openssl doc/crypto/EVP_SealInit.pod翻译和自己的理解写成     (作者:Dra ...

随机推荐

  1. SQL使用总结——集合操作函数

    Oracle中集合操作符专门用于合并多条select 语句的结果,包括:UNION, UNION ALL, INTERSECT, MINUS.当使用集合操作符时,必须确保不同查询的列个数和数据类型匹配 ...

  2. jquery.reveal弹出框

     一款js弹出框,嵌入其它页面: 引用: <script src="../../js/jquery.reveal.js" type="text/javascript ...

  3. 用户注册登录验证 多版本集合 + hashlib加密

    #!/usr/bin/env python# -*- coding: utf-8 -*-# @Time : 2018/5/6 0006 12:22# @Author : Anthony.Waa# @S ...

  4. 实验6 Bezier曲线生成

    1.实验目的: 了解曲线的生成原理,掌握几种常见的曲线生成算法,利用VC+OpenGL实现Bezier曲线生成算法. 2.实验内容: (1) 结合示范代码了解曲线生成原理与算法实现,尤其是Bezier ...

  5. 定时器篇---java.util.TimerTask和quartz

    最近项目中出现了定时执行任务的东西,研究了一下,觉得挺不错的,以后还用得到,就总结了下. 这里只介绍两种java.util.Timer 和 quartz java.util.Timer java自带的 ...

  6. CorelDRAW最高立返500元!还剩30个名额!速抢!

    由于上月CDR X7返利活动收获众多好评 本月官方继续将活动进行到底! 而此次活动不但有上月意犹未尽的CDR X7版,更增加了CDR X6.CDR 2017以及可望不可即的CDR 2018版,可谓是优 ...

  7. Jenkins 部署 PHP 应用

    安装 Jenkins 方式一:docker方式安装 拉取jenkins官方镜像,按照镜像文档启动镜像就可以了 方式二:手动安装 以下所有操作都使用 root 用户进行操作. 在各项目官网,下载 Jav ...

  8. Python爬虫3-----浏览器伪装

    1.浏览器伪装技术原理 当爬取CSDN博客时,会发现返回403,因为对方服务器会对爬虫进行屏蔽,故需伪装成浏览器才能爬取.浏览器伪装一般通过报头进行. 2.获取网页的报头 3.代码: import u ...

  9. mysql新建用户,修改权限

    (1)登录:mysql -u root -p (2)查看现有用户(mysql8.0.1) mysql> select host,user,authentication_string from m ...

  10. 51nod1072 - 威佐夫游戏【威佐夫博弈】

    有2堆石子.A B两个人轮流拿,A先拿.每次可以从一堆中取任意个或从2堆中取相同数量的石子,但不可不取.拿到最后1颗石子的人获胜.假设A B都非常聪明,拿石子的过程中不会出现失误.给出2堆石子的数量, ...