当前位置:Linux教程 - Linux - OpenSSL FAQ

OpenSSL FAQ

OpenSSL - 经常问到的问题
--------------------------------------

* 目前的 OpenSSL 的版本是什么?
* 文档在哪里?
* 我怎样和 OpenSSL 的开发人员联系?
* 要使用 OpenSSL 我需要申请专利许可证吗?
* OpenSSL 线程安全吗?
* 为什么我收到 ""PRNG not seeded"" 这样的错误信息?
* 为什么链接器抱怨说有未定义的符号?
* 我在哪里能得到编译好了的 OpenSSL 版本?
* 我在 Windows 下编译了一个程序,可它崩溃了:为什么?
* 怎样使用ASN1的函数读写DER编码的缓冲区?
* 我想使用 这样的宏,但却给我一个错误,为什么?
* 我调用了 <某个函数> 但是却失败了,为什么?
* 我的错误输出只是一大堆数字,它们是什么意思?
* 为什么我收到什么未知算法的错误信息?
* 怎么创建证书或者认证请求?
* 我为什么不能创建认证请求?
* 为什么 会因为证书认证错误而失败?
* 为什么我与使用OpenSSL的服务器联接的时候总是只能使用弱加密?
* 我怎样才能创建DSA证书?
* 为什么我不能和一台使用DSA证书的服务器建立SSL联接?
* 我怎么才能删除一个私钥上的口令保护?
* 为什么OpenSSH 的 configure 脚本不能检测到 OpenSSL?
* 为什么 OpenSSL 测试带着 ""bc: command not found"" 信息失败?
* 为什么 OpenSSL 测试带着 ""bc: 1 no implemented信息失败?
* 为什么 OpenSSL 在 Alpha True64 Unix 上编译失败?
* 为什么 OpenSSL 带着""ar: command not found"" 这样的错误信息编译失败?


* 目前的 OpenSSL 的版本是什么?

目前的版本可以从获得.OpenSSL 0.9.6 在
2000 年 9 月 24 日发布.

除了当前的稳定版本以外,你还可以获取 OpenSSL 的每日开发快照,在
,或者你也可以通过匿名 CVS 访问
获取.


* 文档在哪里?

OpenSSL 是一个库,它为类似安全 web 服务器这样的应用提供加密功能.
请仔细阅读你想用的应用的文档.INSTALL 文件解释了如何安装这个库的问题.

OpenSSL 包含一个可以用于执行加密功能的命令行工具.在 openssl(1) 手册页
里有描述.给开发人员使用的文档正在写.有几个手册页已经可以用了;libcrypto
和 libssl 库的概述在 crypto(3) 和 ssl(3)的手册页里描述.

OpenSSL 手册页安装在 /usr/local/ssl/man (或者你象 INSTALL 里描述的那样声明
的另外一个目录).另外,你可以在阅读大多数
当前版本的文档.

有关 libcrypto 里面的部件的更多内容,你可以阅读 Ariel Glenn 的关于 SSLeay 0.9
的文档,它是 OpenSSL 的前身,它的文档在



那些文档中有许多仍然适用于 OpenSSL.

在 doc/openssl.txt 里有一些关于证书扩展和 PKCS#12 的文档.

最早的 SSLeay 的文档放在 OpenSSL 的 doc/ssleay.txt 里.如果其他的资源都
不能帮助你的话,那么它也许有用,不过你一定要知道它反映的是过时的 SSLeay
0.6.6 的版本.


* 我怎样和 OpenSSL 的开发人员联系?

README 文件描述了如何向 OpenSSL 提交臭虫报告和补丁.OpenSSL 邮件列表
的信息可以在 获得.


* 要使用 OpenSSL 我需要申请专利许可证吗?

README 文件的专利(patent)段列出了你使用OpenSSL时可能要遵循的专利.
请咨询一位律师获取关于版权的信息.OpenSSL 开发组不提供法律建议.

你可以配置你的 OpenSSL 不使用 RC5 和 IDEA.用下面的命令:
./config no-rc5 no-idea


* OpenSSL 线程安全吗?

是(有一个局限:一次 SSL 联接不能使用多线程进行并发).在 Windows 和许多
Unix 系统上,OpenSSL 自动使用标准库的多线程版本.如果你的平台不是这些平台
之一,请参考 INSTALL 文件.

多线程应用必须给 OpenSSL 提供两个回调函数.这些都在 thread(3) 手册页里描述.


* 为什么我收到 ""PRNG not seeded"" 这样的错误信息?


加密软件需要一个非周期的数据源才能正确运转.
许多开放源码的操作系统提供一个""随机设备""为这个用途服务.而在其他系统上,
应用在生成密钥或者执行公钥加密之前必须用合适的数据调用 RAND_add()或
RAND_seed()函数.

有些有缺陷的应用不做这件事.到版本 0.9.5,OpenSSL 里面的需要随机数
的函数如果在随机数发生器没有收到一个128位的随机值就会报一个错误.
如果出现这个错误,请与你使用的应用的作者联系.很可能是他/她就没有正确
使用这些东西.OpenSSL 0.9.5 和以后的版本会拒绝执行那些有潜在的不安全加密
的动作,以此把错误显示出来.

在没有 /dev/urandom 的系统上,使用熵收集守护(Entropy Gathering Demon)
也是一个好计策);参阅 RAND_egd() 的手册页获取细节.

大多数 openssl 的命令行工具会试图使用文件 $HOME/.rnd (或者 $RANDFILE,
--如果设置了这个环境变量)用做产生 PRNG 种子.如果这个文件不存在或者太短,
就有可能出现那个 ""PRNG not seeded"" 错误信息.

[ OpenSSL 0.9.5 的用户注意了:版本0.9.5的命令""openssl rsa""
并不做这件事,并且在那些没有 /dev/urandom 的系统上用口令加密一个
RSA密钥时会失效!这是一个库里面的臭虫;请使用更高版本的软件.]

对于 Solaris 2.6 而言,Tim Nibbe 和另外一些人建议
安装 SUNski 包.该包来自 Sun 补丁 105710-01 (Sparc),它会增加一个
/dev/random 设备并确保其投入使用,通常是通过 $RANDFILE.其他 Solaris
版本也可能有类似补丁.不过,我们必须警告你 /dev/random 通常是一个块设备,
这一点可能对 OpenSSL 有些影响.


* 为什么链接器抱怨说有未定义的符号?


可能是因为编译中断了,而且 make 没有认识到还缺少某些东西.运行
""make clean; make"".

如果你用的是 ./Configure 而不是 ./config,请确信你选用了正确的目标机器.

在不同的 OS 版本之间的文件格式可能有些许区别(比如 sparcv8/sparcv9,
或者 a.out/elf).

如果你看到的错误信息包含下面的符号,请使用 ""no-asm"" 配置选项,
就象 INSTALL 里描述的那样:

BF_cbc_encrypt, BF_decrypt, BF_encrypt, CAST_cbc_encrypt,
CAST_decrypt, CAST_encrypt, RC4, RC5_32_cbc_encrypt, RC5_32_decrypt,
RC5_32_encrypt, bn_add_words, bn_div_words, bn_mul_add_words,
bn_mul_comba4, bn_mul_comba8, bn_mul_words, bn_sqr_comba4,
bn_sqr_comba8, bn_sqr_words, bn_sub_words, des_decrypt3,
des_ede3_cbc_encrypt, des_encrypt, des_encrypt2, des_encrypt3,
des_ncbc_encrypt, md5_block_asm_host_order, sha1_block_asm_data_order

如果这些东西都不能帮你解决问题,那你可以试试当前的快照(源程序).
如果问题依旧,请提交一个错误报告.


* 我在哪里能得到编译好了的 OpenSSL 版本?

有些使用 OpenSSL 的应用是以二进制的形式发布的.当使用这样的应用时,
你不需要自己安装 OpenSSL;该应用会包含所需要的部分(比如,DLL)

如果你想在 Windows 系统上安装 OpenSSL,但是你没有 C 编译器,请阅读
INSTALL.W32 里的 ""mingw32"" 节,获取如何获取和安装自由的 GNU C 编译器的信息.

许多 Linux 和 *BSD 发布版带有 OpenSSL.


* 我在 Windows 下编译了一个程序,可它崩溃了:为什么?

通常是因为你忽略了 INSTALL.W32 里的注解.你必须和多线程版本的 VC++ 运行时间
DLL 库链接,否则冲突会导致程序崩溃:通常是在第一次 BIO 相关的读写操作的时候.


* 怎样使用ASN1的函数读写DER编码的缓冲区?

你有两个选择.一个是用一个内存BIO和 i2d_XXX_bio()或 d2i_XX_bio()一起使用,
另一个是你可以直接使用 i2d_XXX(),d2i_XXX() 函数.
因为这个问题是最常见的导致痛苦的问题,所以我们在这里包含了一个使用PKCS7
的代码片段做例子:(靠,我花了整整一周读程序才找到方法,眼前一黑...)

unsigned char *buf, *p;
int len;

len = i2d_PKCS7(p7, NULL);
buf = OPENSSL_malloc(len); /* or Malloc, error checking omitted */
p = buf;
i2d_PKCS7(p7, &p);

到这里的时候,buf 包含 len 字节的 p7的DER编码.

反过来,假设我们在 buf 里已经有 len 字节的数据:

unsigned char *p;
p = buf;
p7 = d2i_PKCS7(NULL, &p, len);

这个时候 p7 包含一个有效的 PKCS7 结构,如果发生错误则是一个 NULL.
如果有错误发生, ERR_print_errors(bio) 应该能给出更多信息.

使用临时变量 ''p'' 是因为 ASN1 函数把传入的指针增一,这样它就做好
读写下一个结构的准备了.这样常常会导致问题:如果不用临时变量,
那么缓冲区指针就会刚好指向正在被读写的数据的后面.而那个地方很可能是
未初始化的数据,而且如果试图释放该缓冲区就有可能会导致不可预料的后果,
因为它不再指向同一个地址.?


* 我想使用 这样的宏,但却给我一个错误,为什么?

通常在你用一个C++编译器编译某些使用PKCS#12宏的东西的时候会出现这个现象.
在程序里几乎没有使用PKCS#12的机会,分析和创建PKCS#12文件的更简单的方法是
使用在 doc/openssl.txt 里有文档的 PKCS12_parse() 和 PKCS12_create()函数,
在 demos/pkcs12 里有例子.''pkcs12'' 应用程序必须使用该宏是因为它打印出
调试信息.


* 我调用了 <某个函数> 但是却失败了,为什么?


在提交一个报告或者在邮件列表里询问某人之前,你应该试着先判断原因.
尤其是你应该在失败调用后调用ERR_print_errors() 或者 ERR_print_errors_fp()
然后看看该信息是否有助于你解决问题.不过要注意的是问题发生的地方可能比你
认为的地方
要早--如果可能地话,你应该在每个调用后面检查错误,否则实际的问题可能会
被隐藏起来,因为有些 OpenSSL 函数会清理错误状态.


* 我的错误输出只是一大堆数字,它们是什么意思?

实际的格式在 ERR_print_errors() 手册页里描述.
你应该先调用函数 ERR_load_crypto_strings() ,这样信息就会以文本形式输出.
如果你做不到这一点(比如那是预先编译好了的二进制),你可以直接在错误
码(第二个冒号后面的十六进制数)上使用 errstr 工具.


* 为什么我收到什么未知算法的错误信息?


在好几种情况下都有可能发生这样的问题,比如读取一个加密了的私钥文件
或者试图解密一个 PKCS#12 文件等.原因是忘了用OpenSSL_add_all_algorithms()
装载OpenSSL 的算法表.参阅手册页获取更多信息.


* 怎么创建证书或者认证请求?

看看CA.pl(1)的手册页.它是一个封装了''req'',''verify'',''ca''和''pkcs12''工具的
简单容器.想要获得更好的控制,请检查相应的独立工具的手册页以及证书扩展
文档(目前在 doc/openssl.txt).


* 我为什么不能创建认证请求?

通常你看到的错误是:

unable to find ''distinguished_name'' in config
problems making Certificate Request

这是因为程序找不到配置文件.请察看 req(1) 的 DIAGNOSTICS 节获取更多信息.


* 为什么 会因为证书认证错误而失败?

这个问题通常是由日志信息标识出来的,日志会象
""unable to get local issuer certificate"" 或者 ""self signed certificate"" 这样.
当我们验证一个证书的时候,其根CA必须被OpenSSL""信任"",通常这就意味着该CA的证书
必须放在一个目录或者文件中,而且相关的程序还要配置成读取它.
OpenSSL 的程序 ''verify'' 表现得类似这个性质,并且发出类似的错误信息:
请查阅 verify(1) 程序的手册页获取更多信息.


* 为什么我与使用OpenSSL的服务器联接的时候总是只能使用弱加密?


几乎肯定是因为你使用了老旧的""出口级""的浏览器,它们只支持弱加密.升级你的
浏览器以支持128位加密.


* 我怎样才能创建DSA证书?

检查 CA.pl(1) 的手册页获取DSA证书的例子.


* 为什么我不能和一台使用DSA证书的服务器建立SSL联接?

通常你会看到一条信息说没有共享的加密套件,而同样的设置用RSA证书跑得很好.
有两个可能原因.首先是客户端可能不支持于DSA服务器的联接,大多数web浏览器
(包括 Netscape 和 MSIE)都只支持与使用RSA加密套件的服务器联接.
另外一个原因是没有给服务器提供一套DH参数.DH参数可以用 dhparam(1) 命令
创建然后用 SSL_CTX_set_tmp_dh() 装载,例子可以看:
app/s_server.c 里的 s_server 的源程序.


* 我怎么才能删除一个私钥上的口令保护?

首先你必须绝对确信你想这么做.让一个私钥不加加密地存在是一个首要的安全
漏洞.如果你决定要这么做,请查看 rsa(1) 和 dsa(1) 的手册页.


* 为什么OpenSSH 的 configure 脚本不能检测到 OpenSSL?

在 OpenSSH 1.2.2p1 里有个毛病,就是 configure 脚本不能找到安装的 OpenSSL 库.
这个问题实际上是个小毛病,很容易修补,只要给 OpenSSH 发布打下面的一个补丁就行了:

----- snip:start -----
--- openssh-1.2.2p1/configure.in.orig Thu Mar 23 18:56:58 2000
+++ openssh-1.2.2p1/configure.in Thu Mar 23 18:55:05 2000
@@ -152,10 +152,10 @@
AC_MSG_CHECKING([for OpenSSL/SSLeay directory])

for ssldir in """" $tryssldir /usr /usr/local/openssl /usr/lib/openssl /usr/local/ssl /usr/lib/ssl /usr/local /usr/pkg /opt /opt/openssl ; do
if test ! -z ""$ssldir"" ; then
- LIBS=""$saved_LIBS -L$ssldir""
+ LIBS=""$saved_LIBS -L$ssldir/lib""
CFLAGS=""$CFLAGS -I$ssldir/include""
if test ""x$need_dash_r"" = ""x1"" ; then
- LIBS=""$LIBS -R$ssldir""
+ LIBS=""$LIBS -R$ssldir/lib""
fi
fi
LIBS=""$LIBS -lcrypto""
--- openssh-1.2.2p1/configure.orig Thu Mar 23 18:55:02 2000
+++ openssh-1.2.2p1/configure Thu Mar 23 18:57:08 2000
@@ -1890,10 +1890,10 @@
echo ""configure:1891: checking for OpenSSL/SSLeay directory"" >&5
for ssldir in """" $tryssldir /usr /usr/local/openssl /usr/lib/openssl /usr/local/ssl /usr/lib/ssl /usr/local /usr/pkg /opt /opt/openssl ; do
if test ! -z ""$ssldir"" ; then
- LIBS=""$saved_LIBS -L$ssldir""
+ LIBS=""$saved_LIBS -L$ssldir/lib""
CFLAGS=""$CFLAGS -I$ssldir/include""
if test ""x$need_dash_r"" = ""x1"" ; then
- LIBS=""$LIBS -R$ssldir""
+ LIBS=""$LIBS -R$ssldir/lib""
fi

fi
LIBS=""$LIBS -lcrypto""
----- snip:end -----


* 为什么 OpenSSL 测试带着 ""bc: command not found"" 信息失败?

你没安装""bc"",Unix 计算器.如果你想运行测试,从 ftp://ftp.gnu.org
获取GNU bc或从你的OS提供商那里获取.


* 为什么 OpenSSL 测试带着 ""bc: 1 no implemented信息失败?

在有些SCO的安装或版本中的 bc 有些臭虫,会在运行测试套件(使用""make test"")
的时候被触发.返回的信息是""bc: 1 not implemented"".对付这个问题的最好的方法
是找另外一个 bc 的实现然后编译/安装之.比如,GNU bc(见
http://www.gnu.org/software/software.html 获取下载指导)就可以很好地使用.


* 为什么 OpenSSL 在 Alpha True64 Unix 上编译失败?

在一些运行True64 Unix 和 Compaq C 的 Alpha 安装上,编译 crypto/sha/sha_dgst.c
会出错,错误信息是''Fatal: Insufficient virtual memory to continue compilation.''
从我们的测试看来,这个臭虫好象来自编译器.现象是它使用了大量的驻留内存编译某些
东西,很可能是一个表.问题很明显地来自优化代码,因为如果我们完全不进行优化(-O0)
那么编译就可以通过(并且编译器只使用了大概 2MB 驻留内存,而不是 24MB 或者你的
当前极限).

有三个解决方法:

1. 把你当前数据段的大小的软限制设得高一些.我们的经验表明在AlphaServer DS10上大约
241000 KB 就够了.你可以用命令 ''ulimit -Sd nnnnnn'' 实现这些,这里 ''nnnnnn'' 是
把限制值设置的 KB 数.

2. 如果你有一个比你需要的数量低的硬限制,而且你不能改变它,你可以用 -O0
做为优化级别来编译 OpenSSL.不过这样做对那些希望从 OpenSSL 中获取最大性能
的人来说不是特别好.更复杂一点儿的解决方法是否下面的方法:

----- snip:start -----
make DIRS=crypto SDIRS=sha ""``grep ''^CFLAG='' Makefile.ssl |
sed -e ''s/ -O[0-9] / -O0 /''``""
rm ``ls crypto/*.o crypto/sha/*.o | grep -v ''sha_dgst.o''``
make
----- snip:end -----

这样将只用 -O0 编译 sha_dgst.c,而其它的仍然用配置过程选取的优化级别.当完成
上面的工作后,进行测试和安装,最后你就成了.


* 为什么 OpenSSL 带着""ar: command not found"" 这样的错误信息编译失败?

在 Solaris 2 上常见这个问题,因为 Sun 把 ''ar'' 和其它开发命令隐藏在一个
缺省时不在 $PATH 的目录里了.其中一个目录是 ''/usr/ccs/bin''.修补这个问题的
最快手段是按照下面的方法做(假设你使用的是 sh 或者任意 sh 兼容的 shell):

----- snip:start -----
PATH=${PATH}:/usr/ccs/bin; export PATH
----- snip:end -----

然后重新编译.你实际上要做的是确保 ''/usr/ccs/bin'' 永久地存在于你的 $PATH 里,
比如通过你的 ''.profile'' 文件(同样,假设你使用一个 sh 兼容的 shell).