一、 安装

安装环境:

操作系统:redhat 12.0

       OpenSSL Version:openssl-0.9.8l

Download

§ 安装包(Linux source) : openssl-0.9.8l.tar.gzor the latest version of openssl

下载地址:http://www.openssl.org/source/

§ 在linux下解压缩下载到的安装包,命令如下.....

tar -xzf openssl-xxx.tar.gz
Our Configuration
§ Install to : /usr/local/ssl
§ Module type : dynamically and staticly loaded modules, *.so *.a
Build Instructions
Configure
.../openssl-0.9.8l]# ./config --prefix=/usr/local/ssl-0.9.8l shared zlib-dynamic enable-camellia
§ --prefix=/usr/local/ssl-0.9.8l 
[this is the installation location; default is '/usr/local/ssl' -- which we will symlink]§ shared 
[in addition to the usual static libraries, create shared libraries]§ zlib-dynamic 
[like "zlib", but has OpenSSL load the zlib library dynamically when needed]§ enable-camellia 
[enables the symmetric cipher 'Camellia' (128-bit, 192-bit, 256-bit key versions), which is now available for royalty-free use]display guess on system made by './config'...
.../openssl-0.9.8l]# ./config -t
Build and Install
§ .../openssl-0.9.8l]# make depend 
[step required since extra cipher was enabled]§ .../openssl-0.9.8l]# make
§ .../openssl-0.9.8l]# make test
§ .../openssl-0.9.8l]# make install
Symlink
Form symlink from '/usr/local/ssl-0.9.8l' to '/usr/local/ssl'(...]代表“/usr/local/”)
§ ...]# cd /usr/local
§ /usr/local]# ln -s ssl-0.9.8l ssl
Update the Run-time Linker
ld.so.cache will need to be updated with the location of the new OpenSSL shared libs: libcrypto.so.0.9.8 and libssl.so.0.9.8
Sometimes it is sufficient to just symlink or copy these two files to /lib, but we recommend you follow these instructions instead.

Edit /etc/ld.so.conf, add to paths...(修改效果如下图1,当然也可以直接在/etc/ld.so.conf.d文件夹下再创建一个.conf文件,把/usr/local/ssl/lib拷贝到里面,另外也可以在现有的.conf文件中添加这个路径,反正ld.so.conf中包含了这个文件夹下的所有.conf文件)

图1

/usr/local/ssl/lib
Update the run-time linker...
...]# ldconfig
Update the PATH
Edit /root/.bash_profile, add to PATH variable...

(若原来没有安装openssl的旧版本,则放在PATH中的任何位置都可以,但是记住要用冒号分隔开,而不是分号分隔,详见后面的截图,若想查看当前的PATH环境变量都设置了什么,可以使用如下的命令实现:

[root@localhost local]# echo $PATH
/usr/local/ssl/bin:/usr/lib/qt-3.3/bin:/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin:/root/bin
)

NOTE:一般在root下直接是看不见.bash_profile(一般为隐藏文件)的,可以在该目录下使用ls –a 命令来显示隐藏了的文件。然后用VI或emacs编辑器来修改其中的内容。编译完成后若要立刻看到效果,可以用命令:source .bash_profile ,若要长期起作用,需要重新登录(当我首次安装的时候是出现的情况是这样的~~~

/usr/local/ssl/bin
Re-login.
[sanity check] OpenSSL
Verify that binary 'openssl' is linking against the correct ssl libraries...
§ [root@localhost /]# cd /usr/local
§ [root@localhost local]# ldd /usr/local/ssl/bin/openssl
§ linux-gate.so.1 => (0x00c4b000)
§ libssl.so.0.9.8 => /usr/local/ssl-0.9.8l/lib/libssl.so.0.9.8 (0x00d5b000)
§ libcrypto.so.0.9.8 => /usr/local/ssl-0.9.8l/lib/libcrypto.so.0.9.8 (0x00110000)
§ libdl.so.2 => /lib/libdl.so.2 (0x005b2000)
§ libc.so.6 => /lib/libc.so.6 (0x00447000)
§ /lib/ld-linux.so.2 (0x0042a000)
...]# which openssl
/usr/local/ssl/bin/openssl
...]# openssl version
OpenSSL 0.9.8l 5 Nov 2009
If another path, or an older version is shown, your system contains a previously installed OpenSSL that is first [relative to the newer openssl] in the path.

Repeate the steps in section 'Update the PATH', except place the specified location at the start of the PATH variable.(在/root/.bash_profile中将PATH设置为如下的顺序,即把当前安装上的openssl的版本放在环境变量的前面,这样优先使用的就是新安装的最新的版本的OpenSSL了)

图2

Note that the older openssl, on most systems, is located under /usr/bin
The location of 'openssl' can be found with...(用下面的命令你就可以查到你的openssl的安装目录了~~~)
...]# which openssl

二、 使用

服务器端源代码如下:

#include <stdio.h> 
#include <stdlib.h> 
#include <errno.h> 
#include <string.h> 
#include <sys/types.h> 
#include <netinet/in.h> 
#include <sys/socket.h> 
#include <sys/wait.h> 
#include <unistd.h> 
#include <arpa/inet.h> 
#include <openssl/ssl.h> 
#include <openssl/err.h> 
#define MAXBUF 1024 
/************关于本文档******************************************** 
*filename: ssl-server.c 
*purpose: 演示利用 OpenSSL 库进行基于 IP层的 SSL 加密通讯的方法,这是服务器端例子 
*wrote by: zhoulifa(zhoulifa@163.com) 周立发(http://zhoulifa.bokee.com) 
Linux爱好者 Linux知识传播者 SOHO族 开发者 最擅长C语言 
*date time:2007-02-02 19:40 
*Note: 任何人可以任意复制代码并运用这些文档,当然包括你的商业用途 
* 但请遵循GPL 
*Thanks to:Google 
*Hope:希望越来越多的人贡献自己的力量,为科学技术发展出力 
* 科技站在巨人的肩膀上进步更快!感谢有开源前辈的贡献! 
*********************************************************************/ 
int main(int argc, char **argv) 
{ 
    int sockfd, new_fd; 
    socklen_t len; 
    struct sockaddr_in my_addr, their_addr; 
    unsigned int myport, lisnum; 
    char buf[MAXBUF + 1]; 
    SSL_CTX *ctx; 
    if (argv[1]) 
        myport = atoi(argv[1]); 
    else 
        myport = 7838; 
    if (argv[2]) 
        lisnum = atoi(argv[2]); 
    else 
        lisnum = 2; 
    /* SSL 库初始化 */ 
    SSL_library_init(); 
    /* 载入所有 SSL 算法 */ 
    OpenSSL_add_all_algorithms(); 
    /* 载入所有 SSL 错误消息 */ 
    SSL_load_error_strings(); 
    /* 以 SSL V2 和 V3 标准兼容方式产生一个 SSL_CTX ,即 SSL Content Text */ 
    ctx = SSL_CTX_new(SSLv23_server_method()); 
    /* 也可以用 SSLv2_server_method() 或 SSLv3_server_method() 单独表示 V2 或 V3标准 */ 
    if (ctx == NULL) { 
        ERR_print_errors_fp(stdout); 
        exit(1); 
    } 
    /* 载入用户的数字证书, 此证书用来发送给客户端。 证书里包含有公钥 */ 
    if (SSL_CTX_use_certificate_file(ctx, argv[4], SSL_FILETYPE_PEM) <= 0) { 
        ERR_print_errors_fp(stdout); 
        exit(1); 
    } 
    /* 载入用户私钥 */ 
    if (SSL_CTX_use_PrivateKey_file(ctx, argv[5], SSL_FILETYPE_PEM) <= 0) { 
        ERR_print_errors_fp(stdout); 
        exit(1); 
    } 
    /* 检查用户私钥是否正确 */ 
    if (!SSL_CTX_check_private_key(ctx)) { 
        ERR_print_errors_fp(stdout); 
        exit(1); 
    } 
    /* 开启一个 socket 监听 */ 
    if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) { 
        perror("socket"); 
        exit(1); 
    } else 
        printf("socket created/n"); 
    bzero(&my_addr, sizeof(my_addr)); 
    my_addr.sin_family = PF_INET; 
    my_addr.sin_port = htons(myport); 
    if (argv[3]) 
        my_addr.sin_addr.s_addr = inet_addr(argv[3]); 
    else 
        my_addr.sin_addr.s_addr = INADDR_ANY; 
    if (bind(sockfd, (struct sockaddr *) &my_addr, sizeof(struct sockaddr)) 
        == -1) { 
        perror("bind"); 
        exit(1); 
    } else 
        printf("binded/n"); 
    if (listen(sockfd, lisnum) == -1) { 
        perror("listen"); 
        exit(1); 
    } else 
        printf("begin listen/n"); 
    while (1) { 
        SSL *ssl; 
        len = sizeof(struct sockaddr); 
        /* 等待客户端连上来 */ 
        if ((new_fd = 
             accept(sockfd, (struct sockaddr *) &their_addr, 
                    &len)) == -1) { 
            perror("accept"); 
            exit(errno); 
        } else 
            printf("server: got connection from %s, port %d, socket %d/n", 
                   inet_ntoa(their_addr.sin_addr), 
                   ntohs(their_addr.sin_port), new_fd); 
        /* 基于 ctx 产生一个新的 SSL */ 
        ssl = SSL_new(ctx); 
        /* 将连接用户的 socket 加入到 SSL */ 
        SSL_set_fd(ssl, new_fd); 
        /* 建立 SSL 连接 */ 
        if (SSL_accept(ssl) == -1) { 
            perror("accept"); 
            close(new_fd); 
            break; 
        } 
        /* 开始处理每个新连接上的数据收发 */ 
        bzero(buf, MAXBUF + 1); 
        strcpy(buf, "server->client"); 
        /* 发消息给客户端 */ 
        len = SSL_write(ssl, buf, strlen(buf)); 
        if (len <= 0) { 
            printf 
                ("消息'%s'发送失败!错误代码是%d,错误信息是'%s'/n", 
                 buf, errno, strerror(errno)); 
            goto finish; 
        } else 
            printf("消息'%s'发送成功,共发送了%d个字节!/n", 
                   buf, len); 
        bzero(buf, MAXBUF + 1); 
        /* 接收客户端的消息 */ 
        len = SSL_read(ssl, buf, MAXBUF); 
        if (len > 0) 
            printf("接收消息成功:'%s',共%d个字节的数据/n", 
                   buf, len); 
        else 
            printf 
                ("消息接收失败!错误代码是%d,错误信息是'%s'/n", 
                 errno, strerror(errno)); 
        /* 处理每个新连接上的数据收发结束 */ 
      finish: 
        /* 关闭 SSL 连接 */ 
        SSL_shutdown(ssl); 
        /* 释放 SSL */ 
        SSL_free(ssl); 
        /* 关闭 socket */ 
        close(new_fd); 
    } 
    /* 关闭监听的 socket */ 
    close(sockfd); 
    /* 释放 CTX */ 
    SSL_CTX_free(ctx); 
    return 0; 
}

客户端源代码如下:

#include <stdio.h> 
#include <string.h> 
#include <errno.h> 
#include <sys/socket.h> 
#include <resolv.h> 
#include <stdlib.h> 
#include <netinet/in.h> 
#include <arpa/inet.h> 
#include <unistd.h> 
#include <openssl/ssl.h> 
#include <openssl/err.h> 
#define MAXBUF 1024 
void ShowCerts(SSL * ssl) 
{ 
    X509 *cert; 
    char *line; 
    cert = SSL_get_peer_certificate(ssl); 
    if (cert != NULL) { 
        printf("数字证书信息:/n"); 
        line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0); 
        printf("证书: %s/n", line); 
        free(line); 
        line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0); 
        printf("颁发者: %s/n", line); 
        free(line); 
        X509_free(cert); 
    } else 
        printf("无证书信息!/n"); 
} 
/************关于本文档******************************************** 
*filename: ssl-client.c 
*purpose: 演示利用 OpenSSL 库进行基于 IP层的 SSL 加密通讯的方法,这是客户端例子 
*wrote by: zhoulifa(zhoulifa@163.com) 周立发(http://zhoulifa.bokee.com) 
Linux爱好者 Linux知识传播者 SOHO族 开发者 最擅长C语言 
*date time:2007-02-02 20:10 
*Note: 任何人可以任意复制代码并运用这些文档,当然包括你的商业用途 
* 但请遵循GPL 
*Thanks to:Google 
*Hope:希望越来越多的人贡献自己的力量,为科学技术发展出力 
* 科技站在巨人的肩膀上进步更快!感谢有开源前辈的贡献! 
*********************************************************************/ 
int main(int argc, char **argv) 
{ 
    int sockfd, len; 
    struct sockaddr_in dest; 
    char buffer[MAXBUF + 1]; 
    SSL_CTX *ctx; 
    SSL *ssl; 
    if (argc != 3) { 
        printf 
            ("参数格式错误!正确用法如下:/n/t/t%s IP地址 端口/n/t比如:/t%s 127.0.0.1 80/n此程序用来从某个 IP 地址的服务器某个端口接收最多 MAXBUF 个字节的消息", 
             argv[0], argv[0]); 
        exit(0); 
    } 
    /* SSL 库初始化,参看 ssl-server.c 代码 */ 
    SSL_library_init(); 
    OpenSSL_add_all_algorithms(); 
    SSL_load_error_strings(); 
    ctx = SSL_CTX_new(SSLv23_client_method()); 
    if (ctx == NULL) { 
        ERR_print_errors_fp(stdout); 
        exit(1); 
    } 
    /* 创建一个 socket 用于 tcp 通信 */ 
    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 
        perror("Socket"); 
        exit(errno); 
    } 
    printf("socket created/n"); 
    /* 初始化服务器端(对方)的地址和端口信息 */ 
    bzero(&dest, sizeof(dest)); 
    dest.sin_family = AF_INET; 
    dest.sin_port = htons(atoi(argv[2])); 
    if (inet_aton(argv[1], (struct in_addr *) &dest.sin_addr.s_addr) == 0) { 
        perror(argv[1]); 
        exit(errno); 
    } 
    printf("address created/n"); 
    /* 连接服务器 */ 
    if (connect(sockfd, (struct sockaddr *) &dest, sizeof(dest)) != 0) { 
        perror("Connect "); 
        exit(errno); 
    } 
    printf("server connected/n"); 
    /* 基于 ctx 产生一个新的 SSL */ 
    ssl = SSL_new(ctx); 
    SSL_set_fd(ssl, sockfd); 
    /* 建立 SSL 连接 */ 
    if (SSL_connect(ssl) == -1) 
        ERR_print_errors_fp(stderr); 
    else { 
        printf("Connected with %s encryption/n", SSL_get_cipher(ssl)); 
        ShowCerts(ssl); 
    } 
    /* 接收对方发过来的消息,最多接收 MAXBUF 个字节 */ 
    bzero(buffer, MAXBUF + 1); 
    /* 接收服务器来的消息 */ 
    len = SSL_read(ssl, buffer, MAXBUF); 
    if (len > 0) 
        printf("接收消息成功:'%s',共%d个字节的数据/n", 
               buffer, len); 
    else { 
        printf 
            ("消息接收失败!错误代码是%d,错误信息是'%s'/n", 
             errno, strerror(errno)); 
        goto finish; 
    } 
    bzero(buffer, MAXBUF + 1); 
    strcpy(buffer, "from client->server"); 
    /* 发消息给服务器 */ 
    len = SSL_write(ssl, buffer, strlen(buffer)); 
    if (len < 0) 
        printf 
            ("消息'%s'发送失败!错误代码是%d,错误信息是'%s'/n", 
             buffer, errno, strerror(errno)); 
    else 
        printf("消息'%s'发送成功,共发送了%d个字节!/n", 
               buffer, len); 
  finish: 
    /* 关闭连接 */ 
    SSL_shutdown(ssl); 
    SSL_free(ssl); 
    close(sockfd); 
    SSL_CTX_free(ctx); 
    return 0; 
}

编译程序用下列命令:
gcc -Wall ssl-client.c -o client
gcc -Wall ssl-server.c -o server
运行程序用如下命令:
./server 7838 1 cacert.pem privkey.pem
./client 127.0.0.1 7838
用下面这两个命令产生上述cacert.pem和privkey.pem文件:
openssl genrsa -out privkey.pem 2048
openssl req -new -x509 -key privkey.pem -out cacert.pem -days 1095 具体请参考 “OpenSSL体系下使用密钥数字证书等” 如果想对SSL有更深入的了解,请学习计算机安全相关的内容,尤其是非对称加密技术。 如果想对SSL库的源代码有深入学习, 下载源码来阅读。 或者阅读“SSL连接建立过程分析”其目录下如: