一:编译
前置工作:
1.下载openssl.网址:http://www.openssl.org/source/
2.解压缩.
3.下载activeperl,并安装.
编译:
用vs2005编译,编译之前要先根据配置生成makefile,具体为下面a,b,c三步:
a.C:/OpenSSL/openssl-0.9.8>Perl Configure VC-WIN32
b.C:/OpenSSL/openssl1-0.9.8>ms/do_ms.bat
c.C:/OpenSSL/openssl-0.9.8>nmake -f ms/ntdll.mak
编译选项:
我们必须在生成makefile前使得openssl得到正确配置,方法就是在Perl Configure VC-WIN32命令行加入编译选项,具体为:Perl Configure VC-WIN32 XXX,其中XXX为下列三大类
全局选项
第一类是全局性选项:
zlib
zlib-dynamic
no-zlib使用静态的zlib压缩库、使用动态的zlib压缩库、不使用zlib压缩功能。
threads
no-threads是否编译支持多线程的库。默认支持。
shared
no-shared是否生成动态连接库。(重点)
enable-sse2
no-sse2启用/禁用SSE2指令集加速。如果你的CPU支持SSE2指令集,就可以打开,否则就要关闭。
gmp
no-gmp启用/禁用GMP库
rfc3779
no-rfc3779启用/禁用实现X509v3证书的IP地址扩展
krb5
no-krb5启用/禁用 Kerberos 5 支持
ssl
no-ssl
ssl2
ssl3
no-ssl2
no-ssl3
tls
no-tls 启用/禁用 SSL(包含了SSL2/SSL3) TLS 协议支持。
算法选项
可选的目录如下:
no-md2,no-md4,no-mdc2,no-ripemd这些都是摘要算法,含义一目了然。
no-des,no-rc2,no-rc4,no-rc5,no-idea,no-bf,no-cast,no-camellia这些都是对称加密算法,含义一目了然。"bf"是"Blowfish"的意思。
no-ec,no-dsa,no-ecdsa,no-dh,no-ecdh这些都是不对称加密算法,含义一目了然。
no-comp数据压缩算法。因为目前实际上并没有压缩算法,所以只是定义了一些空接口。
no-store对象存储功能。更多细节可以查看 crypto/store/README 文件。
编译器选项(略)
编译完成:
成功编译以后,会在编译的当前目录下生成一个目录:out32dll。进入此目录之后,里面的libeay32.lib,ssleay32.lib为lib文件,如果前面的编译选项选择了shared,那么还会出现两个动态库文件:libeay32.dll,ssleay32.dll。至此,编译成功。
二.应用:
命令行应用:(略)
Api应用:
要想在自己的代码里用openssl的api,则必须要有相应的openssl的头文件和库文件,头文件的路径是编译目录的include子目录,库的目录是编译目录的out32dll子目录,当然,你可以将它们复制到任何你觉得方便的地方。最终,只需要在自己的代码开头引入openssl的头文件即可。对于win32平台,就是:
#include
#include
#include
#include
……
#pragma comment(lib, "libeay32")
#pragma comment(lib, "ssleay32")
……
Openssl网络应用的一般性描述:
在传统的套接字程序中,我们需要一系列的操作,最终建立了一个连接。Ssl协议是一个介于传输层和应用层之间的一个协议,这就要求在传统的套接字建立之后不能直接进行通信,必须再封装一层ssl协议。基于openssl的网络应用分为客户端和服务器端两个方面,以下将分别论述:
1.客户端
SSL_CTX* ctx;
SSL* ssl;
X509* server_cert;
SSL_METHOD *meth;
加载算法列表,服务器会根据客户端和服务器的算法列表简单协商
SSLeay_add_ssl_algorithms();
如果是客户端,以下函数是必须要调用的,它包含了在ssl握手过程中的回调函数
meth = SSLv2_client_method();
加载错误字符串
SSL_load_error_strings();
初始化一个新的SSL_CTX,SSL_CTX是一个ssl连接的上下文,它包含了一个ssl连接必须的函数,变量。传入的参数就是之前初始化好的客户端方法,在服务器端就是服务器端方法。
ctx = SSL_CTX_new(meth);
加载本地证书,用于验证服务器的证书合法性,真实性。实际上这些本地证书一般就是ca的根证书,在我们的应用中我们把证书称作伪证书,这里的本地证书就是我们的证书服务器签发的伪证书,在以下例子中我们知道是cacert1.pem。
int re = SSL_CTX_load_verify_locations(ctx,"cacert.pem",".");
如果需要验证客户端,那么以下函数的调用是必须的,将来在握手的过程中客户端要将通过下面函数加载的证书回传给服务器,服务器进行验证。
SSL_CTX_use_certificate_file(ctx, "testres.pem", SSL_FILETYPE_PEM)
如果我们要实现自定义的验证的话,那么以下这个函数是必须的,它设置了验证证书的回调函数verify_callback,在这个叫做verify_callback的函数的实现中,我们可以实现自定义的证书验证,当然也可以清除掉前面的验证结果,从而设置我们自己的结果,以便握手返回后我们的主程序根据不同的设置结果采取不同的策略。结果码定义在x509_vfy.h文件中,我们可以在系统定义的结果码范围之外定义自己的结果码。如果不需要自定义的验证逻辑,直接将最后一个参数赋空即可。
SSL_CTX_set_verify(ctx,SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE,verify_callback);
传统的BSD套接字或windows套接字
socket();
connect();
初始化一个新的SSL套接字,参数是一个ssl的上下文,之后所有的读写工作将在这个ssl上展开。
ssl = SSL_new(ctx);
封装了传统的套接字
SSL_set_fd (ssl, sd);
开始ssl握手。注意,前面的标准connect只是建立了标准的tcp连接,这里的connect才是ssl的连接,内部也要进行握手,握手过程中要验证服务器发来的证书,然后经过标准验证程序以后根据我们自定义的那么回调函数进行验证。所以在这个connect被调用之前,不要指望任何数据通信是安全的,结论是,真正的数据通信必须在这个函数之后进行。
err = SSL_connect (ssl);
得到验证结果,根据结果不同采取不同的行为。
int res = SSL_get_verify_result(ssl);
switch(res)
{
}
如果上面的验证通过,之后就可以用SSL_read,SSL_write进行数据通信了,此后数据就是安全的了。
2.服务器端:
前置工作和客户端一样,除了以下的调用,这里我们必须初始化为服务器的方法。
meth = SSLv23_server_method();
ctx = SSL_CTX_new (meth);
如果需要验证客户端,那么下面的调用是必须的,默认不对客户端进行验证。
SSL_CTX_set_verify(ctx,SSL_VERIFY_PEER,verify_callback);
加载服务器证书,将来在握手过程中,此证书要发送到客户端进行验证。
SSL_CTX_use_certificate_file(ctx, "testres.pem", SSL_FILETYPE_PEM)
加载本地私钥文件
SSL_CTX_use_PrivateKey_file(ctx, "testkey.pem", SSL_FILETYPE_PEM)
验证本地私钥和本地证书的匹配。
SSL_CTX_check_private_key(ctx))
以下同客户端
socket()
bind()
listen()
accept()
ssl = SSL_new (ctx);
SSL_set_fd (ssl, newsd);
这里就是accept了,对应于客户端的connect
err = SSL_accept (ssl);
如果需要客户端验证,这里得到客户端的证书
client_cert = SSL_get_peer_certificate (ssl);
之后就是SSL_read,SSL_write 安全通信了。
关键Openssl的api:
头:#include
参数:void
返回值:SSL_METHOD结构
说明:此函数返回一个服务器的方法集结构,应用SSLv2 协议
SSL_METHOD *SSLv2_server_method(void)
头:#include
参数:void
返回值:SSL_METHOD结构
说明:此函数返回一个客户端的方法集结构,应用SSLv2 协议
SSL_METHOD* SSLv2_client_method (void)
头:#include
参数:SSL_METHOD结构体,可由SSLv2_server_method或者SSLv2_client_method返回,取决于本端是服务器还是客户端
返回值:SSL_CTX结构
说明:此函数返回一个SSL_CTX结构,这个结构构成了ssl安全通信的基础上下文。
SSL_CTX* SSL_CTX_new (SSL_METHOD*)
头:#include
参数:第一个参数是当前的CTX 指针,第二个是验证方式,如果是要验证对方的话,就使用 SSL_VERIFY_PEER。不需要的话,使用SSL_VERIFY_NONE.一般情况下,客户端需要验证对方,而服务器不需要。第三个参数是处理 验证的回调函数,如果没有特殊的需要,使用空指针就可以了。
返回值:void
说明:此函数设置证书验证的方式
void SSL_CTX_set_verify (SSL_CTX* , int , int* (int, X509_STORE_CTX*) )
头:#include
参数:第一个参数是SSL_CTX指针,第二个参数是证书文件的名称,第三个参数是证书文件的路径
返回值:void
说明:此函数加载验证证书,一般为CA的证书
void SSL_CTX_load_verify_locations(SSL_CTX*, const char* , const char*)
头:#include
参数:第一个参数是SSL_CTX指针,第二个参数是证书文件的名称,第三个参数是证书类型
返回值:失败返回-1
说明:此函数加载本地的证书
int SSL_CTX_use_certificate_file(SSL_CTX *ctx, const char *file, int type)
头:#include
参数:第一个参数是SSL_CTX指针,第二个参数是私钥文件的名称,第三个参数是私钥文件的类型
返回值:失败返回-1
说明:此函数加载自己的私钥
int SSL_CTX_use_PrivateKey_file(SSL_CTX *ctx, const char *file, int type)
头:#include
参数:SSL_CTX指针
返回值:一个SSL结构,将来通信就是在这个ssl上进行的
说明:此函数申请一个SSL 套节字
SSL* SSL_new (SSL_CTX*)
头:#include
参数:第一个参数为SSL指针,第二个参数为套接字句柄
返回值:绑定成功返回 1, 失败返回0
说明:此函数榜定一个只读套接字
int SSL_set_rfd (SSL*,int)
头:#include
参数:第一个参数为SSL指针,第二个参数为套接字句柄
返回值:绑定成功返回 1, 失败返回0
说明:此函数绑定一个只写套接字
int SSL_set_wfd (SSL*,int)
头:#include
参数:第一个参数为SSL指针,第二个参数为套接字句柄
返回值:绑定成功返回 1, 失败返回0
说明:此函数绑定一个读写套接字
int SSL_set_fd (SSL*,int)
头:#include
参数:SSL指针
返回值:失败返回-1
说明:此函数开始SSL 握手的动作,对于服务器端就是SSL_accept了
int SSL_connect (SSL*)
头:#include
参数:第一个参数是SSL指针,第二个参数是要写缓冲区,第三个参数是写入长度
返回值:同标准write
说明:此函数将缓冲区写入套接字。
int SSL_write (SSL *ssl, char *buf, int num )
头:#include
参数:第一个参数是SSL指针,第二个参数是读入缓冲区,第三个参数是读入长度
返回值:同标准read
说明:此函数将信息从套接字读出,并写入buf缓冲区。
int SSL_read (SSL *ssl, char *buf, int num )
头:#include
参数:SSL指针
返回值:连接完全关闭返回1,不完全关闭返回0,这时需要再次调用此函数,出错返回-1
说明:此函数关闭SSL套接字
int SSL_shutdown(SSL *ssl)
头:#include
参数: SSL指针
返回值:void
说明:此函数释放SSL套接字
void SSL_free (SSL *)
头:#include
参数:SSL_CTX指针
返回值:void
说明:此函数释放SSL环境
void SSL_CTX_free (ctx)
头:#include
参数:SSL指针
返回值:验证结果
说明:如果在握手过程中存在证书验证的话,这个函数将返回验证结果,具体的结果值可以查看:openssl/x509_vfy.h
long SSL_get_verify_result(const SSL *ssl)
其它Openssl的api帮助文档:
http://www.openssl.org/docs/ssl/ssl.html