软讯网络 > 网络安全 > 黑客技术 > 使用 OpenSSL API 进行安全编程(2)
【标 题】:使用 OpenSSL API 进行安全编程(2)
【关键字】:
API,编程,安全,SSL,OpenSSL,OpenSSL,API
【来 源】:网络
使用 OpenSSL API 进行安全编程(2)
清单 1. 必需的头文件
/* OpenSSL headers */
#include "openssl/bio.h"
#include "openssl/ssl.h"
#include "openssl/err.h"
/* Initializing OpenSSL */
SSL_load_error_strings();
ERR_load_BIO_strings();
OpenSSL_add_all_algorithms();
建立非安全连接
不管连接是安全的还是不安全的,OpenSSL 都使用了一个名为 BIO 的抽象库来处理包括文件和套接字在内的各种类型的通信。您还可以将 OpenSSL 设置成为一个过滤器,比如用于 UU 或 Base64 编码的过滤器。
在这里对 BIO 库进行全面说明有点麻烦,所以我将根据需要一点一点地介绍它。首先,我将向您展示如何建立一个标准的套接字连接。相对于使用 BSD 套接字库,该操作需要的代码行更少一些。
在建立连接(无论安全与否)之前,要创建一个指向 BIO 对象的指针。这类似于在标准 C 中为文件流创建 FILE 指针。
清单 2. 指针
BIO * bio;
打开连接
创建新的连接需要调用 BIO_new_connect。您可以在同一个调用中同时指定主机名和端口号。也可以将其拆分为两个单独的调用:一个是创建连接并设置主机名的 BIO_new_connect 调用,另一个是设置端口号的 BIO_set_conn_port(或者 BIO_set_conn_int_port)调用。
不管怎样,一旦 BIO 的主机名和端口号都已指定,该指针会尝试打开连接。没有什么可以影响它。如果创建 BIO 对象时遇到问题,指针将会是 NULL。为了确保连接成功,必须执行 BIO_do_connect 调用。
清单 3. 创建并打开连接
bio = BIO_new_connect("hostname:port");
if(bio == NULL)
{
/* Handle the failure */
}
if(BIO_do_connect(bio) <= 0)
{
/* Handle failed connection */
}
在这里,第一行代码使用指定的主机名和端口创建了一个新的 BIO 对象,并以所示风格对该对象进行 格式化。例如,如果您要连接到 www.ibm.com 的 80 端口,那么该字符串将是 www.ibm.com:80。调用 BIO_do_connect 检查连接是否成功。如果出错,则返回 0 或 -1。
与服务器进行通信
不管 BIO 对象是套接字还是文件,对其进行的读和写操作都是通过以下两个函数来完成的:BIO_read 和 BIO_write。很简单,对吧?精彩之处就在于它始终如此。
BIO_read 将尝试从服务器读取一定数目的字节。它返回读取的字节数、 0 或者 -1。在受阻塞的连接中,该函数返回 0,表示连接已经关闭,而 -1 则表示连接出现错误。在非阻塞连接的情况下,返回 0 表示没有可以获得的数据,返回 -1 表示连接出错。可以调用 BIO_should_retry 来确定是否可能重复出现该错误。
清单 4. 从连接读取
int x = BIO_read(bio, buf, len);
if(x == 0)
{
/* Handle closed connection */
}
else if(x < 0)
{
if(! BIO_should_retry(bio))
{
/* Handle failed read here */
}
/* Do something to handle the retry */
}
BIO_write 会试着将字节写入套接字。它将返回实际写入的字节数、0 或者 -1。同 BIO_read,0 或 -1 不一定表示错误。 BIO_should_retry 是找出问题的途径。如果需要重试写操作,它必须使用和前一次完全相同的参数。
清单 5. 写入到连接
if(BIO_write(bio, buf, len) <= 0)
{
if(! BIO_should_retry(bio))
{
/* Handle failed write here */
}
/* Do something to handle the retry */
}
关闭连接
关闭连接也很简单。您可以使用以下两种方式之一来关闭连接:BIO_reset 或 BIO_free_all。如果您还需要重新使用对象,那么请使用第一种方式。如果您不再重新使用它,则可以使用第二种方式。
BIO_reset 关闭连接并重新设置 BIO 对象的内部状态,以便可以重新使用连接。如果要在整个应用程序中使用同一对象,比如使用一台安全的聊天客户机,那么这样做是有益的。该函数没有返回值。
BIO_free_all 所做正如其所言:它释放内部结构体,并释放所有相关联的内存,其中包括关闭相关联的套接字。如果将 BIO 嵌入于一个类中,那么应该在类的析构函数中使用这个调用。
清单 6. 关闭连接
/* To reuse the connection, use this line */
BIO_reset(bio);
/* To free it from memory, use this line */
BIO_free_all(bio);
建立安全连接
现在需要给出建立安全连接需要做哪些事情。惟一要改变的地方就是建立并进行连接。其他所有内容都是相同的。
安全连接要求在连接建立后进行握手。在握手过程中,服务器向客户机发送一个证书,然后,客户机根据一组可信任证书来核实该证书。它还将检查证书,以确保它没有过期。要检验证书是可信任的,需要在连接建立之前提前加载一个可信任证书库。
只有在服务器发出请求时,客户机才会向服务器发送一个证书。该过程叫做客户机认证。使用证书,在客户机和服务器之间传递密码参数,以建立安全连接。尽管握手是在建立连接之后才进行的,但是客户机或服务器可以在任何时刻请求进行一次新的握手。
参考资料 部分中列出的 Netscasp 文章和 RFC 2246 ,对握手以及建立安全连接的其他方面的知识进行了更详尽的论述。
为安全连接进行设置
为安全连接进行设置要多几行代码。同时需要有另一个类型为 SSL_CTX 的指针。该结构保存了一些 SSL 信息。您也可以利用它通过 BIO 库建立 SSL 连接。可以通过使用 SSL 方法函数调用 SSL_CTX_new 来创建这个结构,该方法函数通常是 SSLv23_client_method。
还需要另一个 SSL 类型的指针来保持 SSL 连接结构
(这是短时间就能完成的一些连接所必需的)。以后还可以用该 SSL 指针来检查连接信息或设置其他 SSL 参数。
|