随着计算机网络技术的发展,方便快捷的互连网使人们渐渐习惯了从Web页上收发E-mail、购物和
交易,这时Web页面上需要传输重要或敏感的数据,例如用户的银行帐户、密码等,所以网络安全
就成为现代计算机网络应用急需解决的问题。

现行网上银行和电子商务等大型的网上交易系统普遍采用HTTP和SSL相结合的方式。服务器端采用
支持SSL的Web服务器,用户端采用支持SSL的浏览器实现安全通信。
SSL是Secure Socket Layer(安全套接层协议)的缩写,可以在Internet上提供秘密性传输。
Netscape公司在推出第一个Web浏览器的同时,提出了SSL协议标准,目前已有3.0版本。SSL采用公
开密钥技术。其目标是保证两个应用间通信的保密性和可靠性,可在服务器端和用户端同时实现支
持。目前,利用公开密钥技术的SSL协议,已成为Internet上保密通讯的工业标准。本文着重在
SSL协议和SSL程序设计两方面谈谈作者对SSL的理解。

SSL协议初步介绍
安全套接层协议能使用户/服务器应用之间的通信不被***者窃听,并且始终对服务器进行认证,
还可选择对用户进行认证。SSL协议要求建立在可靠的传输层协议(TCP)之上。SSL协议的优势在于
它是与应用层协议独立无关的,高层的应用层协议(例如:HTTP,FTP,TELNET等)能透明地建立于
SSL协议之上。SSL协议在应用层协议通信之前就已经完成加密算法、通信密钥的协商及服务器认证
工作。在此之后应用层协议所传送的数据都会被加密,从而保证通信的私密性。
通过以上叙述,SSL协议提供的安全信道有以下三个特性:
1.数据的保密性
信息加密就是把明码的输入文件用加密算法转换成加密的文件以实现数据的保密。加密的过程需要
用到密匙来加密数据然后再解密。没有了密钥,就无法解开加密的数据。数据加密之后,只有密匙
要用一个安全的方法传送。加密过的数据可以公开地传送。
2.数据的一致性
加密也能保证数据的一致性。例如:消息验证码(MAC),能够校验用户提供的加密信息,接收者可
以用MAC来校验加密数据,保证数据在传输过程中没有被篡改过。
3.安全验证
加密的另外一个用途是用来作为个人的标识,用户的密匙可以作为他的安全验证的标识。
SSL是利用公开密钥的加密技术(RSA)来作为用户端与服务器端在传送机密资料时的加密通讯协定。
目前,大部分的Web 服务器及浏览器都广泛支持SSL 技术。当浏览器试图连接一个具有SSL认证加
密的服务器时,就会唤醒一个SSL会话,浏览器检查认证,必须具备下面三个条件:
1)有一个权威机构发放证书,当然可以创建自我签订的证书(x509 结构)。
2)证书不能过期。
3)证书是属于它所连接的服务器的。
只有全部具备了这三个条件,浏览器才能成功完成认证。通过这三个条件,用户能确认其浏览器连接
到正确的服务器,而不是连接到一些想盗取用户密码等重要信息的虚假的服务器上。
在当今的电子商务中还有一项被广泛使用的安全协议是SET协议。SET(Secure Electronic Transaction,
安全电子交易)协议是由VISA和MasterCard两大信用卡公司于1997年5月联合推出的规范。SET能在电
子交易环节上提供更大的信任度、更完整的交易信息、更高的安全性和更少受欺诈的可能性。SET交
易分三个阶段进行:用户向商家购物并确定支付;商家与银行核实;银行向商家支付货款。每个阶段都
涉及到RSA对数据加密,以及RSA数字签名。使用SET协议,在一次交易中,要完成多次加密与解密操作,
故有很高的安全性,但SET协议比SSL协议复杂,商家和银行都需要改造系统以实现互操作。
在Linux 下,比较流行支持SSL认证的是OpenSSL服务器。OpenSSL项目是一个合作的项目,开发一个
健壮的、商业等级的、完整的开放源代码的工具包,用强大的加密算法来实现安全的Socket层
(Secure Sockets Layer,SSL v2/v3)和传输层的安全性(Transport Layer Security,TLS v1)。
这个项目是由全世界的志愿者管理和开发OpenSSL工具包和相关文档。
如何在Linux下配置OpenSSL服务器,首先从OpenSSL的主页([url]http://www.openssl.org/[/url])上下载
openssl-version.tar.gz软件包来编译安装,与Apache服务器配合可以建立支持SSL的Web服务器,
并可以使用自我签订的证书做认证,关于如何编译、安装OpenSSL服务器,可以参考一下OpenSSL HOWTO
文档。

SSL 程序设计初步介绍
SSL 通讯模型为标准的C/S 结构,除了在 TCP 层之上进行传输之外,与一般的通讯没有什么明显的区
别。在这里,我们主要介绍如何使用OpenSSL进行安全通讯的程序设计。关于OpenSSL 的一些详细的信
息请参考OpenSSL的官方主页 [url]http://www.openssl.org[/url]。
在使用OpenSSL前,必须先对OpenSSL 进行初始化,以下的三个函数任选其一:
SSL_library_init(void);
OpenSSL_add_ssl_algorithms();
SSLeay_add_ssl_algorithms();
事实上 后面的两个函数只是第一个函数的宏。
如果要使用OpenSSL的出错信息,使用SSL_load_error_strings (void)进行错误信息的初始化。以后
可以使用void ERR_print_errors_fp(FILE *fp) 打印SSL的错误信息。
一次SSL连接会话一般要先申请一个SSL 环境,基本的过程是:
1. SSL_METHOD* meth = TLSv1_client_method(); 创建本次会话连接所使用的协议,如果是客户端可
以使用
SSL_METHOD* TLSv1_client_method(void); TLSv1.0 协议
SSL_METHOD* SSLv2_client_method(void); SSLv2 协议
SSL_METHOD* SSLv3_client_method(void); SSLv3 协议
SSL_METHOD* SSLv23_client_method(void); SSLv2/v3 协议
服务器同样需要创建本次会话所使用的协议:
SSL_METHOD *TLSv1_server_method(void);
SSL_METHOD *SSLv2_server_method(void);
SSL_METHOD *SSLv3_server_method(void);
SSL_METHOD *SSLv23_server_method(void);
需要注意的是客户端和服务器需要使用相同的协议。
2.申请SSL会话的环境 CTX,使用不同的协议进行会话,其环境也是不同的。申请SSL会话环
境的OpenSSL函数是
SSLK_CTX* SSL_CTX_new (SSL_METHOD*); 参数就是前面我们申请的 SSL通讯方式。返回当前
的SSL 连接环境的指针。
然后根据自己的需要设置CTX的属性,典型的是设置SSL 握手阶段证书的验证方式和加载自己
的证书。
void SSL_CTX_set_verify (SSL_CTX* , int , int* (int, X509_STORE_CTX*) )
设置证书验证的方式。
第一个参数是当前的CTX 指针,第二个是验证方式,如果是要验证对方的话,就使用
SSL_VERIFY_PEER。不需要的话,使用SSL_VERIFY_NONE.一般情况下,客户端需要验证对方,而
服务器不需要。第三个参数是处理验证的回调函数,如果没有特殊的需要,使用空指针就可以了。
void SSL_CTX_load_verify_locations(SSL_CTX*, const char* , const char*);
加载证书;
第一个参数同上,参数二是证书文件的名称,参数三是证书文件的路径;
int SSL_CTX_use_certificate_file(SSL_CTX *ctx, const char *file, int type);
加载本地的证书;type 指明证书文件的结构类型;失败返回-1
int SSL_CTX_use_PrivateKey_file(SSL_CTX *ctx, const char *file, int type);
加载自己的私钥;type 参数指明私钥文件的结构类型;失败返回-1
加载了证书和文件之后,就可以验证私钥和证书是否相符:
BOOl SSL_CTX_check_private_key (SSL_CTX*);
3.既然SSL 使用TCP 协议,当然需要把SSL attach 到已经连接的套接字上了:
SSL* SSL_new (SSL_CTX*); 申请一个SSL 套节字;
int SSL_set_rfd (SSL*); 绑定只读套接字
int SSL_set_wfd (SSL*); 绑定只写套接字
int SSL_set_fd ( SSL*); 绑定读写套接字
绑定成功返回 1, 失败返回0;
4. 接下来就是SSL 握手的动作了
int SSL_connect (SSL*); 失败返回 -1
5. 握手成功之后,就可以进行通讯了,使用SSL_read 和SS_write 读写SSL 套接字代替传统的
read 、write
int SSL_read (SSL *ssl, char *buf, int num );
int SSL_write (SSL *ssl, char *buf, int num);
如果是服务器,则使用 SSL_accept 代替传统的 accept 调用
int SSL_accept(SSL *ssl);
6. 通讯结束,需要释放前面申请的 SSL资源
int SSL_shutdown(SSL *ssl); 关闭SSL套接字;
void SSL_free (ssl); 释放SSL套接字;
void SSL_CTX_free (ctx); 释放SSL环境;
OpenSSL 虽然已经发展到了0.9.96版本,但是它的文档还很少,甚至连最基本的man 函数手
册都没有完成。所以,本文紧紧是讲述了使用OpenSSL 进行程序设计的框架。更加详细的资
料可以参考OpenSSL 的文档或者 Apache mod_ssl 的文档。
通过以上的介绍,我想读者对SSL协议已经有了一定的了解,作者有机会将会继续给大家介绍
SSL协议的其他方面的内容。


SSL原理解密
本文出自:
[url]http://noc.cstnet.net.cn/[/url]
范晓明

RSA公钥加密在计算机产业中被广泛使用在认证和加密。可以从RSA Data Security Inc.获得的RSA公钥加密许可证。公钥加密是使用一对非对称的密码加密或解密的方法。每一对密码由公钥和私钥组成。公钥被广泛发布。私钥是隐密的,不公开。用公钥加密的数据只能够被私钥解密。反过来,使用私钥加密的数据只能用公钥解密。这个非对称的特性使得公钥加密很有用。

使用公钥加密法认证

认证是一个身份认证的过程。在下列例子中包括甲和乙,公钥加密会非常轻松地校验身份。符号{数据} key意味着"数据"已经使用密码加密或解密。假如甲想校验乙的身份。乙有一对密码,一个是公开的,另一个是私有的。乙透露给甲他的公钥。甲产生一个随机信息发送给乙。甲——〉乙:random-message

乙使用他的私钥加密消息,返回甲加密后的消息。 乙——〉甲:{random-message}乙的私钥

甲收到这个消息然后使用乙的以前公开过的公钥解密。他比较解密后的消息与他原先发给乙的消息。如果它们完全一致,就会知道在与乙说话。任意一个中间人不会知道乙的私钥,也不能正确加密甲检查的随机消息。

除非你清楚知道你加密的消息。用私钥加密消息,然后发送给其他人不是一个好主意。因为加密值可能被用来对付你,需要注意的是:因为只有你才有私钥,所以只有你才能加密消息。所以,代替加密甲发来的原始消息,乙创建了一个信息段并且加密。信息段取自随机消息(random-message)并具有以下有用的特性:

1. 这个信息段难以还原。任何人即使伪装成乙,也不能从信息段中得到原始消息;

2. 假冒者将发现不同的消息计算出相同的信息段值;

3. 使用信息段,乙能够保护自己。他计算甲发出的随机信息段,并且加密结果,并发送加密信息段返回甲。甲能够计算出相同的信息段并且解密乙的消息认证乙。

这个技术仅仅描绘了数字签名。通过加密甲产生的随机消息,乙已经在甲产生的消息签名。因此我们的认证协议还需要一次加密。一些消息由乙产生:

甲——〉乙:你好,你是乙么?

乙——〉甲:甲,我是乙

{信息段[甲,我是乙] } 乙的私钥

当你使用这个协议,乙知道他发送给乙的消息,他不介意在上面签名。他先发送不加密的信息,"甲,我是乙。",然后发送信息段加密的消息版本。甲可以非常方便地校验乙就是乙,同时,乙还没有在他不想要的信息上签名。

提交公钥

那么,乙怎样以可信的方式提交他的公钥呢?看看认证协议如下所示:

甲——〉乙:你好

乙——〉甲:嗨,我是乙,乙的公钥

甲——〉乙:prove it

乙——〉甲:甲,我是乙 {信息段[甲,我是乙] } 乙的私钥

在这个协议下,任何人都能够成为"乙"。所有你所要的只是公钥和私钥。你发送给甲说你就是乙,这样你的公钥就代替了乙的密码。然后,你发送用你的私钥加密的消息,证明你的身份。甲却不能发觉你并不是乙。为了解决这个问题,标准组织已经发明了证书。一个证书有以下的内容:

* 证书的发行者姓名

* 发行证书的组织

* 标题的公钥

* 邮戳

证书使用发行者的私钥加密。每一个人都知道证书发行者的公钥(这样,每个证书的发行者拥有一个证书)。证书是一个把公钥与姓名绑定的协议。通过使用证书技术,每一个人都可以检查乙的证书,判断是否被假冒。假设乙控制好他的私钥,并且他确实是得到证书的乙,就万事大吉了。

这些是修订后的协议:

甲——〉乙:你好

乙——〉甲:嗨,我是乙,乙的校验

甲——〉乙:prove it

乙——〉甲:甲,我是乙 {信息段[甲, 我是乙] } 乙的私钥

现在当甲收到乙的第一个消息,他能检查证书,签名(如上所述,使用信息段和公钥解密),然后检查标题(乙的姓名),确定是乙。他就能相信公钥就是乙的公钥和要求乙证明自己的身份。乙通过上面的过程,制作一个信息段,用一个签名版本答复甲。甲可以校验乙的信息段通过使用从证书上得到的公钥并检查结果。

如果一个***,叫H

甲——〉H:你好

H——〉不能建立一个令甲相信的从乙的消息。

交换密码(secret)

一旦甲已经验证乙后,他可以发送给乙一个只有乙可以解密、阅读的消息:

甲——〉乙:{secret}乙的公钥

唯一找到密码的方法只有使用乙的私钥解码上述的信息。交换密码是另一个有效使用密码加密的方法。即使在甲和乙之间的通讯被侦听,只有乙才能得到密码。

使用密码作为另一个secret-key增强了网络的安全性,但是这次这是一个对称的加密算法(例如DES、RC4、IDE甲)。因为甲在发送给乙之前产生了密码,所以甲知道密码。乙知道密码因为乙有私钥,能够解密甲的信息。但他们都知道密码,他们都能够初始化一个对称密码算法,而且开始发送加密后的信息。这儿是修定后的协议:

甲——〉乙:你好

乙——〉甲:嗨,我是乙,乙的校验

甲——〉乙:prove it

乙——〉甲:甲,我是乙 {信息段[甲,我是乙] }乙的私钥

甲——〉乙:ok 乙,here is a secret {secret}乙的公钥

乙——〉甲:{some message}secret-key

***窃听

那么如果有一个恶意的***H在甲和乙中间,虽然不能发现甲和乙已经交换的密码,但能干扰他们的交谈。他可以放过大部分信息,选择破坏一定的信息(这是非常简单的,因为他知道甲和乙通话采用的协议)。

甲——〉H:你好

H——〉乙:你好

乙——〉H:嗨,我是乙,乙的校验

H——〉甲:嗨,我是乙,乙的校验

甲——〉H:prove it

H——〉乙:prove it

乙——〉H:甲,我是乙 {信息段[甲,我是乙] }乙的私钥

H——〉甲:甲,我是乙 {信息段[甲,我是乙] }乙的私钥

甲——〉H:ok 乙,here is a secret {secret} 乙的公钥

H——〉乙:ok 乙,here is a secret {secret} 乙的公钥

乙——〉H:{some message}secret-key

H——〉甲:Garble[{some message}secret-key ]

H忽略一些数据不修改,直到甲和乙交换密码。然后H干扰乙给甲的信息。在这一点上,甲相信乙,所以他可能相信已经被干扰的消息并且尽力解密。

需要注意的是,H不知道密码,他所能做的就是毁坏使用秘钥加密后的数据。基于协议,H可能不能产生一个有效的消息。但下一次呢?

为了阻止这种破坏,甲和乙在他们的协议中产生一个校验码消息(message authentication code)。一个校验码消息(MAC)是一部分由密码和一些传输消息产生的数据。信息段算法描述的上述特性正是它们抵御H的功能:

MAC= Digest[some message,secret ]

因为H不知道密码,他不能得出正确的值。即使H随机干扰消息,只要数据量大,他成功的机会微乎其微。例如,使用HD5(一个RSA发明的好的加密算法),甲和乙能够发送128位MAC值和他们的消息。H猜测正确的MAC的几率将近1/18,446,744,073,709,551,616约等于零。

这是又一次修改后的协议:

甲——〉乙:你好

乙——〉甲:嗨,我是乙,乙的校验

甲——〉乙:prove it

乙——〉甲:嗨,我是乙,乙的校验

甲,我是乙

{信息段[甲,我是乙] } 乙的私钥

ok 乙,here is a secret {secret} 乙的公钥

{some message,MAC}secret-key

现在H已经无技可施了。他干扰了得到的所有消息,但MAC计算机能够发现他。甲和乙能够发现伪造的MAC值并且停止交谈。H不再能与乙通讯。

OpenSSL FAQ

[url]http://www.linuxforum.net[/url]
何伟平 译
                            
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 计算器.如果你想运行测试,从 [url]ftp://ftp.gnu.org[/url] 
获取GNU bc或从你的OS提供商那里获取.


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

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


* 为什么 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).