热门关键字:  ubuntu  分区  Fedora  linux系统进程  函数

当前位置 :| 主页>Linux教程>编程开发>

使用 OpenSSL API 进行安全编程

来源: 作者: 时间:2007-07-03 Tag: 点击:
如果没有安全的服务器应用程序,那么也就不需要安全的客户机应用程序。使用 OpenSSL,我们可以创建安全的服务器应用程序,尽管文档让这一切看起来非常复杂,但实际上并非如此。本文中我们将学习如何使用在这个 3 部分系列文章 的 第 1 部分 中学习到的概念来构建安全的服务器应用程序。

本系列文章的前两部分讨论了使用 OpenSSL 来创建客户机端应用程序的内容。第 1 部分 讨论了使用 OpenSSL 创建基本安全客户机的问题,而 第 2 部分 则深入讨论了有关数字证书的问题。在阅读本文的读者给我发回很多 e-mail 和正面反馈之后,我非常清楚,接下来的一期理论介绍应该是有关服务器的。

服务器为网络和 Internet 提供了访问诸如文件和设备之类的资源的访问能力。有时我们必须要通过一个安全通道来提供这些服务。OpenSSL 让我们可以使用安全通道和开放通道来编写服务。

使用 OpenSSL 来创建基本的服务器应用程序从本质上来说几乎 等同于创建一个基本的客户机应用程序。二者之间的区别不多。显然,区别之一就是服务器将被设置为接收到达的连接,而不是建立外发的连接。并且,正如我们可以从本系列的第 2 部分有关数字证书的讨论中看到的一样,服务器还必须要在握手过程中提供安全证书。

等待

服务器基本上就是呆在那里等待到达的连接。毕竟,这就是服务器存在的原因。Web 服务器要等待浏览器请求页面,FTP 服务器要等待客户机请求文件,聊天服务器要等待聊天客户机所发出的连接。因此服务器要做的事情就是等待。

在客户机和服务器通信之间差别不大,惟一的差别就是对于握手来说,服务器就像是硬币的反面。其他东西都是相同的。

这让我们可以使用 OpenSSL 来编写安全的服务器应用程序,再次假设您已经了解如何使用 OpenSSL 来编写客户机应用程序。(如果您还不了解相关知识,请参阅本系列第 1 部分 “API 概述” 来学习如何设置 OpenSSL 库。)

两种形式的标识

SSL 上下文

要设置本文中使用的 SSL 上下文,请使用下面的代码。这个函数在出错时会返回 NULL:

SSL_CTX *ctx = SSL_CTX_new(SSLv23_server_method());

也可以说是标识的两部分。

服务器要负责提供在握手过程中使用的安全证书。完整的服务器证书包括两个部分:公钥和私钥。公钥是发送给客户机的,而私钥则是保密的。

就像是信任证书必须要提供给客户机应用程序使用的库一样,服务器密钥也必须要提供给服务器应用程序使用的库。有几个函数都提供了这种功能:


清单 1. 加载服务器证书的函数

SSL_CTX_use_certificate(SSL_CTX *, X509 *)
SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, int len, unsigned char *d);
SSL_CTX_use_certificate_file(SSL_CTX *ctx, const char *file, int type);

这个函数的 ASN1 变种可以将指定内存位置处的使用 ASN1 编码的数字证书加载到 SSL 环境中。这个函数会加载给定内存结构中所提供的一个 X.509 证书;而最后一个函数,即带有 _file 的那个,会从文件中加载一个使用 PEM 编码的数字证书。这个函数的 type 参数让我们可以加载使用 DER 编码的证书。

要加载私钥,请使用下面函数之一:


清单 2. 加载私钥使用的函数

SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey);
SSL_CTX_use_PrivateKey_ASN1(int pk, SSL_CTX *ctx, unsigned char *d, long len);
SSL_CTX_use_PrivateKey_file(SSL_CTX *ctx, const char *file, int type);
SSL_CTX_use_RSAPrivateKey(SSL_CTX *ctx, RSA *rsa);
SSL_CTX_use_RSAPrivateKey_ASN1(SSL_CTX *ctx, unsigned char *d, long len);
SSL_CTX_use_RSAPrivateKey_file(SSL_CTX *ctx, const char *file, int type);

需要的交互

私钥最适合用来加密存储。不过,问题是加载证书的函数并没有请求使用加密证书的密码。相反,OpenSSL 为获得密码提供了一种回调机制。

回调格式如下:


清单 3. 回调格式

int password_callback(char *buf, int size, int rwflag, void *userdata);

就本文的目的来说,最后一个参数 userdata 是不需要的。缓冲区在调用这个函数之前被调用,因此对于这个缓冲区的大小我们无法控制。

服务器私钥

注意对于服务器证书来说,私钥不应该加密进行保存。否则,管理员可能会被过于频繁地要求输入密码。

参数 rwflag 是读/写标记。使用它的目的是使我们可以编程确定这个密码是正在用来加密信息(rwflag = 1)还是解密信息(rwflag = 0)。如果正在使用回调函数来请求对数据进行加密使用的密码,最好是以某种方式请求两次,这样可以多一次机会接收用户的输入。

在证书加载时,这个密码只会请求一次,这样它就可以进行解密并保存到内存中了。如何从用户那里获取密码,完全取决于您的实现。

一旦我们创建好密码回调函数,就可以按照下面的方法使用 SSL_CTX_set_default_passwd_cb 将其安装到 SSL 环境中:


清单 4. 安装回调函数

/* ctx is a pointer to a previously created SSL context, and cb is the pointer
 * to the callback function you created.
 */

SSL_CTX_set_default_passwd_cb(ctx, cb);

发动引擎

现在提示用户输入密码的回调函数已经创建好了,然后我们就可以使用真正导入证书的函数了。证书可以从现有的内存结构或文件中导入。

为了更加符合处理数字证书的常用情况,例如 Apache HTTP Server Project 项目所作的一样,我将展示如何从文件中加载证书。如果我们已经阅读了本系列文章的 第 1 部分,那么加载证书的的方式就非常类似于在前面文章中给出的加载信任存储的方式。

我们将从公用证书开始介绍,这个证书会发送给客户机。



相关文章:
ioctl函数
struts与spring三种整合方法
进程的创建fork
jsp速成
Hibernate单向一对多应注意的问题
Java RMI之HelloWorld篇
常用的Eclipse快捷键
sparc linux 系统调用
一个关于jboss "Halting VM"的情况处理
编写更好的Linux程序3(这次只讲void *)
Tikiwiki 2.2+ Ucenter 1.5(Discuz)整合
玩转ptrace(一)
玩转ptrace(二)
dup2
pipe
Jboss的学习
gcc用法
将UI从代码中解放出来
数据结构与算法(2)
有关于JAVA中的CLASSPATH的作用
const成员函数
虚函数
《c和指针》读书笔记2
初次接触Zend Framework需要掌握的内容
php中require和include的简单区别
正则表达式在PHP中的应用
在PHP中使用与Perl兼容的正则表达式
Zend Studio 生成 wsdl
freebsd7 + php5.2.6 + xdebug2.0.2安装
PHP抓取远程网站数据的代码