上周帮一个童鞋做一个数字认证的实验,要求是编程实现一个基于X.509证书认证的过程,唉!可怜我那点薄弱的计算机网络安全的知识啊!只得恶补一下了。

首先来看看什么是X.509。所谓X.509其实是一种非常通用的证书,什么是证书?唉!这么说吧!当两个人需要进行远程通信而又不想让第三个人知道时就必须建立一种安全措施,因为看不到对方的脸,又不能通过电话直接询问对方,就得想点别的办法,比如我设计一个密码,让后发短信告诉你,这样当我们在网上交流之前就可以对一下密码,暗号之类的。确认后就可以证明你的身份了。这个证书就相当于这里的密码,只是确实比密码要复杂一些,想了解的朋友可以google之~~

那么什么是SSL呢?SSL是一种网络通信的安全协议,在传输层对网络连接进行加密,简单点说就是提过一种方法使我们通过网络进行通信的安全性得到提高。而X.509证书认证的过程就可以通过这个协议来实现。

好了,知道了这些就然我们来开始写这个程序吧!慢着,如果实现这个SSL和X.509呢?我们貌似还是不知道啊!好吧,既然是一种加密通信过程肯定和加密分不开吧,随便查了一下,SSL涉及到的加密方法就不下数十种,而且极其艰深复杂,难道我要自己实现这个过程?自己构建X.509证书?当然不会,互联网就是好啊!让我发现了存在OpenSSL这么个东西,让我们感谢Eric A. Young和Tim J. Hudson这两个人吧!因为他们在1995年就开始做我上面想做的事情了,而且写出了OpenSSL这个没有太多限制的开放源代码的软件包。有了这玩意什么事都好办了。

我先从网上下了openssl-0.9.8的压缩包,然后琢磨了两个多小时终于明白如何安装这么个软件包了。我把自己的安装心得记录下来大家一起分享。

在使用这个软件包之前需要安装PERL组件——ActivePerl-5.8.0.806-MSWin32-x86(PERL和OpenSSL网上有很多免费下载的,这里我就不给出下载地址了),这个安装倒很简单,直接使用安装包就行了。判断perl是否安装成功的方法是通过命令行进入到perl安装目录下的\eg目录里,执行perl example.pl命令,如果显示“Hello from ActivePerl!”,则说明Perl安装成功。然后我们开始安装OpenSSL。

1、将openssl.0.9.8.tar.gz解压到d:盘下。

2、打开命令行窗口进入d: \openssl-0.9.8目录下键入以下命令:perl Configure VC-WIN32。

3、然后键入ms\do_ms命令。

4、然后键入nmake –f ms\ntdll.mak会成功编译很多c文件,如果不成功的话一般就是提示“cl”无法找到之类的错误,这时就需要在系统环境变量PATH里加入VC的bin路径,这样才能找到“cl”命令。

5、接着键入mkdir c:\caroot,这样就会在C盘根目录下生成一个caroot文件夹。

6、然后需要在系统环境变量PATH路径中加入openssl-0.9.8\out32dll路径,并在VC(我使用的是VC编译器)中把include路径增加一个:D:\openssl-0.9.8\include,把library路径增加一个:D:\openssl-0.9.8\out32dll,将D:\openssl-0.9.8\apps下的openssl.cnf文件拷贝到c:\caroot目录下。

到这里可以说我们的安装已经完成了,下面我们需要生成几个证书和密钥,密钥是用来加密的,证书是用来认证的。比如服务器证书、密钥,客户端证书、密钥。但这里我们漏了一个最重要的证书和密钥,就是CA证书和密钥。CA是个什么东东呢?这个解释起来很麻烦,他就像一个中间证明人,证明两方的身份都是真实可信的,这样双方拿着证书才能相互信任,详细解释可以参看这里:http://baike.baidu.com/view/23691.htm#7,维基百科的解释更加详细,不过是英文的我觉得喜欢英文的朋友可以看看:http://en.wikipedia.org/wiki/Certificate_authority

好吧,让我们把这些该死的证书密钥都生成然后开始编码吧:

在上面C:\caroot目录下(其实可以不在这目录下)输入如下:

#产生CA自签名证书

openssl.exe genrsa -out private\ca.key -rand private\.rnd -des 2048

openssl.exe req -new -x509 -days 3650 -key private\ca.key -out private\ca.crt -config openssl.cnf

openssl.exe x509 -in private\ca.crt -noout -text

#产生server的证书过程

openssl.exe genrsa -out private\server.key 1024

openssl.exe req -new -key private\server.key -out newcerts\server.csr -config openssl.cnf

openssl.exe ca -in newcerts\server.csr -cert private\ca.crt -keyfile private\ca.key

-config openssl.cnf -policy policy_anything -out certs\server.crt

openssl.exe x509 -in certs\server.crt -noout -text

#产生proxy的证书过程

openssl.exe genrsa -out private\proxy.key 1024

openssl.exe req -new -key private\proxy.key -out newcerts\proxy.csr -config openssl.cnf

openssl.exe ca -in newcerts\proxy.csr -cert private\ca.crt -keyfile private\ca.key -config openssl.cnf -policy policy_anything -out certs\proxy.crt

openssl.exe x509 -in certs\proxy.crt -noout -text

#产生client的证书过程

openssl.exe genrsa -out private\client.key 1024

openssl.exe req -new -key private\client.key -out newcerts\client.csr -config openssl.cnf

openssl.exe ca -in newcerts\client.csr -cert private\ca.crt -keyfile private\ca.key -config openssl.cnf -policy policy_anything -out certs\client.crt

openssl.exe x509 -in certs\client.crt -noout -text

上面的命令中会给出提示让用户输入一些证书的信息,只要正常输入就可以了。执行上述操作后C:\caroot目录如下:

private目录如下:

newcerts目录如下:

certs目录如下:

其中证书:

ca.crt为自签名证书;

server.crt,server.key为服务器端的证书和私钥文件;

proxy.crt,proxy.key为代理服务器端的证书和私钥文件;

client.crt,client.key为客户端的证书和私钥文件。

乱七八糟的事情终于做完了,下面总算可以开始编码了。看了一下实验要求,要编写简单的Client程序和Server程序,实现Client程序与Server程序之间基于X509证书和SSL协议身份认证和通信加密,服务器能够接收并且显示客户端发送来的文字消息。

看来需要两个程序,一个服务端的,一个客户端的。

具体编程大家直接看代码就行了,涉及到socket通信,其实相当简单,懂一点点就行了,我这里就不要王婆卖瓜了,直接上代码吧。

客户端程序代码:

  1. //client
  2. #include <winsock2.h>
  3. #include <conio.h>
  4. #include <stdio.h>
  5. #include "openssl/x509.h"
  6. #include "openssl/ssl.h"
  7. #include "openssl/err.h"
  8. #include "openssl/rand.h"
  9. #define PORT       1111
  10. #define SERVER     "127.0.0.1"
  11. #define CACERT     "ca.crt"
  12. #define MYCERTF    "yuliding.crt"
  13. #define MYKEYF     "yuliding.key"
  14. #define MSGLENGTH  1024
  15. int main()
  16. {
  17. WSADATA wsadata;
  18. WSAStartup(MAKEWORD(2,2), &wsadata);
  19. sockaddr_in sin;
  20. int seed_int[100]; /*存放随机序列*/
  21. SSL*ssl;
  22. SSL_METHOD *meth;
  23. SSL_CTX *ctx;
  24. //SSL初始化
  25. OpenSSL_add_ssl_algorithms();
  26. //SSL错误信息初始化
  27. SSL_load_error_strings();
  28. //创建本次会话所使用的协议
  29. meth = TLSv1_client_method();
  30. //申请SSL会话的环境
  31. ctx = SSL_CTX_new(meth);
  32. if (NULL == ctx)
  33. exit(1);
  34. //设置会话的握手方式并加载CA证书
  35. SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
  36. SSL_CTX_load_verify_locations(ctx, CACERT, NULL);
  37. //加载自己的证书
  38. if (0 &gt;= SSL_CTX_use_certificate_file(ctx, MYCERTF, SSL_FILETYPE_PEM)) {
  39. ERR_print_errors_fp(stderr);
  40. exit(1);
  41. }
  42. //加载自己的私钥
  43. if (0 &gt;= SSL_CTX_use_PrivateKey_file(ctx, MYKEYF, SSL_FILETYPE_PEM)) {
  44. ERR_print_errors_fp(stderr);
  45. exit(1);
  46. }
  47. //检查自己的证书和私钥是否匹配
  48. if (!SSL_CTX_check_private_key(ctx)) {
  49. printf("Private key does not match the certificate public key\n");
  50. exit(1);
  51. }
  52. /*构建随机数生成机制,WIN32平台必需*/
  53. srand((unsigned)time(NULL));
  54. for (int i = 0; i < 100; i++)
  55. seed_int[i] = rand();
  56. RAND_seed(seed_int, sizeof(seed_int));
  57. //加密方式
  58. SSL_CTX_set_cipher_list(ctx, "RC4-MD5");
  59. //处理握手多次
  60. SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
  61. /*以下是正常的TCP socket建立过程 .............................. */
  62. SOCKET sock;
  63. printf("Begin tcp socket...\n");
  64. sock = socket(AF_INET, SOCK_STREAM, 0);
  65. if (sock == INVALID_SOCKET) {
  66. printf("SOCKET有问题. \n");
  67. }
  68. memset(&sin, '\0', sizeof(sin));
  69. sin.sin_family = AF_INET;
  70. sin.sin_addr.s_addr = inet_addr(SERVER); /* Server IP */
  71. sin.sin_port = htons(PORT); /* Server Port number */
  72. int icnn = connect(sock, (sockaddr *)&sin, sizeof(sin));
  73. if (icnn == SOCKET_ERROR) {
  74. printf("连不上服务器\n", GetLastError());
  75. exit(1);
  76. }
  77. /* TCP 链接已建立.开始 SSL 握手过程.......................... */
  78. //绑定套接字
  79. ssl = SSL_new(ctx);
  80. if (NULL == ssl)
  81. exit(1);
  82. if (0 >= SSL_set_fd(ssl, sock)) {
  83. printf("Attach to Line fail!\n");
  84. exit(1);
  85. }
  86. //SSL握手
  87. //SSL_connect(ssl);
  88. int k = SSL_connect(ssl);
  89. if (0 &gt;= k) {
  90. printf("%d\n", k);
  91. printf("SSL connect fail!\n");
  92. exit(1);
  93. }
  94. printf("连接服务器成功\n");
  95. char sendmsg[MSGLENGTH] = "\0";
  96. char revmsg[MSGLENGTH] = "\0";
  97. int err = SSL_read(ssl, revmsg, sizeof(revmsg));
  98. revmsg[err] = '\0';
  99. printf("%s\n", revmsg);
  100. while (1) {
  101. printf("请输入所要发送的数据:\n");
  102. scanf("%s", sendmsg);
  103. SSL_write(ssl, sendmsg, strlen(sendmsg));
  104. printf("发送消息“ %s ”成功!\n", sendmsg);
  105. }
  106. //关闭套接字
  107. SSL_shutdown(ssl);
  108. SSL_free(ssl);
  109. SSL_CTX_free(ctx);
  110. closesocket(sock);
  111. WSACleanup();
  112. getch();
  113. return 0;
  114. }

服务端程序代码:

  1. //server
  2. #include <winsock2.h>
  3. #include <conio.h>
  4. #include <stdio.h>
  5. #include <winsock.h>
  6. #include "openssl/x509.h"
  7. #include "openssl/ssl.h"
  8. #include "openssl/err.h"
  9. #define MSGLENGTH      1024
  10. #define PORT           1111
  11. #define CACERT         "ca.crt"
  12. #define SVRCERTF       "server.crt"
  13. #define SVRKEYF        "server.key"
  14. int main()
  15. {
  16. WSADATA wsaData;
  17. WSAStartup(MAKEWORD(2,2), &wsaData);
  18. SOCKET sock;
  19. SSL_METHOD *meth;
  20. SSL_CTX* ctx;
  21. SSL* ssl;
  22. //SSL初始化
  23. OpenSSL_add_ssl_algorithms();
  24. //SSL错误信息初始化
  25. SSL_load_error_strings();
  26. //创建本次会话所使用的协议
  27. meth = TLSv1_server_method();
  28. //申请SSL会话的环境
  29. ctx = SSL_CTX_new(meth);
  30. if (NULL == ctx)
  31. exit(1);
  32. //设置会话的握手方式并加载CA证书
  33. SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
  34. SSL_CTX_load_verify_locations(ctx, CACERT, NULL);
  35. //加载服务器端的证书
  36. if (0 &gt;= SSL_CTX_use_certificate_file(ctx, SVRCERTF, SSL_FILETYPE_PEM)) {
  37. ERR_print_errors_fp(stderr);
  38. exit(1);
  39. }
  40. //加载服务器端的私钥
  41. if (0 &gt;= SSL_CTX_use_PrivateKey_file(ctx, SVRKEYF, SSL_FILETYPE_PEM)) {
  42. ERR_print_errors_fp(stderr);
  43. exit(1);
  44. }
  45. //检查服务器端的证书和私钥是否匹配
  46. if (!SSL_CTX_check_private_key(ctx)) {
  47. printf("Private key does not match the certificate public key\n");
  48. exit(1);
  49. }
  50. //加密方式
  51. SSL_CTX_set_cipher_list(ctx, "RC4-MD5");
  52. //处理握手多次
  53. SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
  54. /*以下是正常的TCP socket建立过程 .............................. */
  55. printf("Begin tcp socket...\n");
  56. sock = socket(AF_INET, SOCK_STREAM, 0);
  57. if (sock == INVALID_SOCKET) {
  58. printf("SOCKET有问题. \n");
  59. return 0;
  60. }
  61. sockaddr_in addr;
  62. memset(&addr, '\0', sizeof(addr));
  63. addr.sin_family = AF_INET;
  64. addr.sin_port = htons(PORT); /* Server Port number */
  65. addr.sin_addr.s_addr = INADDR_ANY;
  66. //绑定sock
  67. int nResult = bind(sock, (sockaddr *)&addr, sizeof(addr));
  68. if (nResult == SOCKET_ERROR) {
  69. printf("绑定SOCKET有问题. \n");
  70. return 0;
  71. }
  72. printf("服务器启动成功,端口:%d\n正在等待连接\n", PORT);
  73. /*接受TCP链接*/
  74. sockaddr_in sa_cli;
  75. int err = listen(sock, 5);
  76. if (-1 == err)
  77. exit(1);
  78. int client_len = sizeof(sa_cli);
  79. int ss = accept(sock, (struct sockaddr *) &sa_cli, &client_len);
  80. if (ss == -1) {
  81. exit(1);
  82. }
  83. closesocket(sock);
  84. printf("Connection from %d, port %d\n", sa_cli.sin_addr.s_addr, sa_cli.sin_port);
  85. /* TCP 链接已建立.开始 SSL 握手过程.......................... */
  86. //绑定套接字
  87. ssl = SSL_new(ctx);
  88. if (NULL == ssl)
  89. exit(1);
  90. if (0 &gt;= SSL_set_fd(ssl, ss)) {
  91. printf("Attach to Line fail!\n");
  92. exit(1);
  93. }
  94. //SSL握手
  95. //SSL_accept(ssl);
  96. int k = SSL_accept(ssl);
  97. if (0 &gt;= k) {
  98. printf("%d\n", k);
  99. printf("SSL connect fail!\n");
  100. exit(1);
  101. }
  102. //进行信息验证
  103. X509 *client_cert;
  104. client_cert = SSL_get_peer_certificate(ssl);
  105. printf("发现客户端尝试连接\n");
  106. if (client_cert != NULL) {
  107. printf ("Client certificate:\n");
  108. //读取证书subject名并显示
  109. char *str = X509_NAME_oneline(X509_get_subject_name(client_cert), 0, 0);
  110. if (NULL == str) {
  111. printf("认证出错!\n");
  112. exit(1);
  113. }
  114. printf("subject: %s\n", str);
  115. //读取证书的issuer名并显示
  116. str = X509_NAME_oneline(X509_get_issuer_name(client_cert), 0, 0);
  117. if (NULL == str) {
  118. printf("证书名为空\n");
  119. exit(1);
  120. }
  121. printf("issuer: %s\n", str);
  122. printf("连接成功\n");
  123. X509_free (client_cert);/*如不再需要,需将证书释放 */
  124. OPENSSL_free(str);
  125. }
  126. else {
  127. printf("找不到客户端的认证证书\n");
  128. exit(1);
  129. }
  130. char buf[MSGLENGTH];
  131. SSL_write(ssl, "Server is connect to you!\n", strlen("Server is connect to you!\n"));
  132. printf("Listen to the client: \n");
  133. while (1) {
  134. err = SSL_read(ssl, buf, sizeof(buf));
  135. buf[err] = '\0';
  136. printf("%s\n", buf);
  137. }
  138. //关闭套接字
  139. SSL_shutdown(ssl);
  140. SSL_free(ssl);
  141. SSL_CTX_free(ctx);
  142. WSACleanup();
  143. getch();
  144. return 0;
  145. }

编写完后后首先运行服务端程序,然后运行客户端程序,效果如下:

连接成功后服务端的状态如下:

红色部分为我在生成证书文件时输入的一些信息,具体的你可以通过我上面讲解建立证书时试验一下。这里我通过代码把这些证书信息打印出来是为了判断获取的证书是否正确。

连接成功后客户端的状态:

这样,就可以实现通过客户端向服务端发送信息,如下:

细心的朋友可以发现上面我显示Connection from后面貌似是一串乱码,其实不然,那是一串IP地址,只不过是反序排列的,我曾经在做SIP TRUNK项目时也遇到过这个问题,感兴趣的朋友可以自己写个转义程序把他转成IP地址试试看。

最后提醒一点,因为我的代码中把证书和密钥文件的目录设为当前目录了,所以想要程序正确运行必须把证书文件和密钥文件拷贝到当前工程的目录下,如下:

客户端是一样的。或者你可以把目录改到你生成证书和密钥的目录下。

可以看见,上面的程序有众多漏洞和缺陷,如果有朋友想使用的话请一定仔细debug一下,把很多判断的条件加上,这里我就偷下懒罗~~分享快乐~~

本文出自 “菜鸟浮出水” 博客,请务必保留此出处http://rangercyh.blog.51cto.com/1444712/430652

基于X.509证书和SSL协议的身份认证过程实现(OpenSSL可以自己产生证书,有TCP通过SSL进行实际安全通讯的实际编程代码)good的更多相关文章

  1. 基于SSL协议的双向认证 - 数字证书 [2]

    1.1    数字证书 1.1.1   概念理解 一种文件的名称,例如一个机构或人的签名,能够证明这个机构或人的真实性.简而言之数字证书是一种网络上证明持有者身份的文件,同时还包括有公钥.证书是由国际 ...

  2. 基于SSL协议的双向认证 - SSL协议 [1]

    1  概要说明 在互联网通信方式中,目前用的最广泛的是HTTPS配合SSL和数字证书来保证传输和认证安全了. 2  详细介绍 2.1    HTTPS HTTPS全称:Hypertext Transf ...

  3. 基于SSL协议的双向认证 - 双向认证 [3]

    1      SSL双向认证的实现 这里是基于SSL和Tomcat配置实现的,配置方法如下: 1.1    生成CA数字证书 首先需要配置OPENSSL环境变量. 我的OPENSSL配置文件路径是“D ...

  4. HTTPS协议,SSL协议及完整交互过程

    文章转自 https://blog.csdn.net/dfsaggsd/article/details/50910999 SSL 1.        安全套接字(Secure Socket Layer ...

  5. 加密解密(4)SSL协议及HTTPS握手过程

    SSL协议 简介 SSL (Secure Sockets Layer 安全套接层)是一个安全协议,它提供使用 TCP/IP 的通信应用程序间的隐私与完整性.因特网的 超文本传输协议 (HTTP)使用 ...

  6. SSH协议、HTTPS中SSL协议的完整交互过程

    1.(SSH)公私钥认证原理 服务器建立公钥:每一次启动sshd服务时,该服务会主动去找/etc/ssh/ssh_host*的文件 客户端通过ssh工具进行连接,如Xshell,SecureCRT 服 ...

  7. apache添加ssl协议实现用户认证

    目标 1对服务器的访问由http改为https, 2仅有证书的客户端可以访问服务器, 3.通过服务器端的配置,可以停用某个客户端的证书. 一 Apache服务器相关配置: 在../apache/con ...

  8. 【转】SSL协议、SET协议、HTTPS简介

    一.SSL协议简介 SSL是Secure Socket Layer的缩写,中文名为安全套接层协议层.使用该协议后,您提交的所有数据会首先加密后,再提交到网易邮箱,从而可以有效防止黑客盗取您的用户名.密 ...

  9. SSL身份认证原理 - 目标: 搞清楚数字证书和数字签名的关系

    1  概述 1.1  产生背景 基于万维网的电子商务和网上银行等新兴应用,极大地方便了人们的日常生活,受到人们的青睐.由于这些应用都需要在网络上进行在线交易,它们对网络通信的安全性提出了更高的要求.传 ...

随机推荐

  1. 【b504】等价表达式(NOIP2005第4题)

    Time Limit: 1 second Memory Limit: 50 MB [问题描述] 明明进了中学之后,学到了代数表达式.有一天,他碰到一个很麻烦的选择题.这个题目的题干中首先给出了一个代数 ...

  2. C语言笔试题精选3---死锁发生必要条件是?

    问:以下哪些是死锁发生必要条件? A.相互排斥条件 B.请求和保持 C.不可剥夺 D.循环等待 具体解答: 1.相互排斥使用(资源独占)  一个资源每次仅仅能给一个进程使用 2.不可强占(不可剥夺) ...

  3. MinGW开发工具的安装(还有visual-mingw)

    MinGW是Minimalist GNU for Windows的缩写,是把linux下的GNU开发工具包移植到windows的项目之一.和Cygwin不一样的是,MinGW不提供linux的posi ...

  4. Android 如何检索Android设备的唯一ID

    关于本文档 Android的开发者在一些特定情况下都需要知道手机中的唯一设备ID.例如,跟踪应用程序的安装,生成用于复制保护的DRM时需要使用设备的唯一ID.在本文档结尾处提供了作为参考的示例代码片段 ...

  5. Android的PVPlayer介绍

    1 Player的组成 OpenCore的Player的编译文件是pvplayer/Android.mk,将生成动态库文件 libopencoreplayer.so.这个库包括了双方面的内容:一方是P ...

  6. jQuery插件接口的实现,jquery.extend

    http://www.imooc.com/code/3403 如果jQuery没有插件接口的设计,那么他就像个光杆司令没有兵,就是没有手下,只有自己一个封闭的城堡.因此jQuery城堡需要设计一个大门 ...

  7. jQuery分离构造器

    http://www.imooc.com/code/3401 通过new操作符构建一个对象,一般经过四步: A.创建一个新对象   B.将构造函数的作用域赋给新对象(所以this就指向了这个新对象) ...

  8. 学好Java只需要做到这7点,年薪20W起步

    大道至简,所以扎实有用的方法,其实都是很简单的,难在踏踏实实的执行过程.今天为大家介绍的就是Java学习的7个看起来非常简单的方法,快学起来吧. 为什么要学习java? Java是目前最流行的编程语言 ...

  9. Modbus 通信协议详解

    一.Modbus 协议简介     Modbus 协议是应用于电子控制器上的一种通用语言.通过此协议,控制器相互之间.控制器经由网络(例如以太网)和其它设备之间可以通信.它已经成为一通用工业标准.有了 ...

  10. POJ 1328 Radar Installation(经典贪婪)

    Radar Installation Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 54143   Accepted: 12 ...