安全通信系统--OpenSSL服务器和客户端

  1. 环境配置
  2. SSL的初始化

这一步主要使用OpenSSL提供的函数设置算法、证书等,一般步骤都固定了的,初始化流程示意图如下所示:

SSL初始化流程图

主要代码为:

[cpp] view plain copy

print?

  1. SSL_load_error_strings(); /*为打印调试信息作准备*/
  2. OpenSSL_add_ssl_algorithms(); /*初始化*/
  3. //meth = TLSv1_server_method(); /*采用什么协议(SSLv2/SSLv3/TLSv1)在此指定*/
  4. //注意这里是server,客户端那里会是client
  5. ctx = SSL_CTX_new (TLSv1_server_method());
  6. CHK_NULL(ctx);
  7. SSL_CTX_set_verify(ctx,SSL_VERIFY_PEER,NULL); /*验证与否*/
  8. SSL_CTX_load_verify_locations(ctx,CACERT,NULL); /*若验证,则放置CA证书*/
  9. if (SSL_CTX_use_certificate_file(ctx, CERTF, SSL_FILETYPE_PEM) <= 0) {
  10. ERR_print_errors_fp(stderr);
  11. getchar();
  12. exit(3);
  13. }
  14. if (SSL_CTX_use_PrivateKey_file(ctx, KEYF, SSL_FILETYPE_PEM) <= 0) {
  15. ERR_print_errors_fp(stdout);
  16. getchar();
  17. exit(4);
  18. }
  19. if (!SSL_CTX_check_private_key(ctx)) {
  20. printf("Private key does not match the certificate public keyn");
  21. getchar();
  22. exit(5);
  23. }
  24. SSL_CTX_set_cipher_list(ctx,"RC4-MD5");

3.SSL连接通信

建立TCP套接字,并且进入监听,当接收到客户端连接请求后,使用accept建立和客户端通信的套接字s,从初始化的SSL_CTX创建一个SSL,将该SSL和与客户端通信的套接字s绑定,然后使用SSL_accept建立和客户端的SSL连接,如果建立成功就可以检查客户端的证书并获取客户端的证书信息,实现相互认证。之后,可以使用异步通信机制处理该SSL连接的消息。原理图如下图所示:

控制台的非异步通信的SSL通信代码如下所示。(非异步通信的代码原理看起来原理更好理解)

服务器端代码

[cpp] view plain copy

print?

  1. //创建监听套接字
  2. sListen = socket (AF_INET, SOCK_STREAM, 0);
  3. if(sListen == INVALID_SOCKET)
  4. {
  5. cout << "监听套接字创建失败" << endl;
  6. exit(0);
  7. }
  8. //创建地址
  9. sockaddr_in sin = {0};
  10. sin.sin_family = AF_INET;
  11. sin.sin_addr.s_addr = INADDR_ANY;
  12. sin.sin_port = htons (PORT);
  13. //套接字绑定
  14. err = bind(sListen, (struct sockaddr*) &sin,sizeof(sin));
  15. if(err == -1)
  16. {
  17. cout << "监听套接字绑定失败" << endl;
  18. exit(0);
  19. }
  20. /*接受TCP链接*/
  21. err = listen (sListen, 5);
  22. if(err == -1)
  23. {
  24. cout << "监听套接字开启监听失败" << endl;
  25. exit(0);
  26. }
  27. //接受客户端连接
  28. SOCKET sd = accept(sListen, (struct sockaddr *)&sa_cli, (socklen_t*)&client_len);
  29. if(err == -1)
  30. {
  31. cout << "监听套接字accept失败" << endl;
  32. exit(0);
  33. }
  34. closesocket (sListen);
  35. /*TCP连接已建立,进行服务端的SSL过程. */
  36. cout << "TCP连接建立,创建SSL连接中....\n" << endl;
  37. //从初始化的ctx新建SSL
  38. ssl = SSL_new (ctx);
  39. if(ssl == NULL)
  40. {
  41. cout << "SSL创建失败" << endl;
  42. exit(0);
  43. }
  44. //套接字和SSL绑定
  45. SSL_set_fd (ssl, sd);
  46. //SSL连接建立
  47. err = SSL_accept (ssl);
  48. if(err == -1)
  49. {
  50. cout << "创建SSL连接失败" << endl;
  51. exit(0);
  52. }
  53. else
  54. {
  55. cout << "创建SSL连接成功" << endl;
  56. exit(0);
  57. }
  58. /*打印所有加密算法的信息(可选)*/
  59. cout << "SSL连接算法信息:" << SL_get_cipher (ssl) << endl;
  60. /*得到服务端的证书并打印些信息(可选) */
  61. client_cert = SSL_get_peer_certificate (ssl);
  62. if (client_cert != NULL) {
  63. cout << "客户端证书:" << endl;
  64. cout << "subject:" << X509_get_subject_name (client_cert), 0, 0) << endl;
  65. cout << "issuer:" << X509_NAME_oneline (X509_get_issuer_name (client_cert),0,0) << endl;
  66. CHK_NULL(str);
  67. X509_free (client_cert);/*如不再需要,需将证书释放 */
  68. }
  69. else cout << "客户端没有证书信息!" << endl; //客户端认证失败
  70. //SSL通信,用SSL_write,SSL_read代替send和recv
  71. while(true)
  72. {
  73. //接收消息
  74. err = SSL_read (ssl, buf, sizeof(buf) - 1);
  75. if(err == -1)
  76. {
  77. cout << "SSL_read接收消息失败" << endl;
  78. exit(0);
  79. }
  80. buf[err] = ‘\0‘;
  81. cout << "【客户端】:" << buf << endl;
  82. cin >> buf;
  83. //发送消息
  84. err = SSL_write(ssl, buf, strlen(ssl));
  85. if(err == -1)
  86. {
  87. cout << "SSL_write发送消息失败" << endl;
  88. exit(0);
  89. }
  90. cout << "【服务器】:" << buf << endl;
  91. }
  92. //关闭套接字和ssl
  93. shutdown (sd,2);
  94. SSL_free (ssl);
  95. SSL_CTX_free (ctx);

客户端代码

[cpp] view plain copy

print?

  1. //
  2. #include "openssl/rsa.h"
  3. #include "openssl/crypto.h"
  4. #include "openssl/x509.h"
  5. #include "openssl/pem.h"
  6. #include "openssl/ssl.h"
  7. #include "openssl/err.h"
  8. #include "openssl/rand.h"
  9. #pragma comment(lib, "libeay32.lib")
  10. #pragma comment(lib, "ssleay32.lib")
  11. /*所有需要的参数信息都在此处以#define的形式提供*/
  12. #define CERTF "C:\\client.crt" /*服务端的证书(需经CA签名)*/
  13. #define KEYF "C:\\client.key" /*服务端的私钥(建议加密存储)*/
  14. #define CACERT "C:\\ca.crt" /*CA 的证书*/
  15. #define PORT 7758 /*服务端的端口*/
  16. int main ()
  17. {
  18. int err;
  19. int sd;
  20. struct sockaddr_in sa;
  21. SSL_CTX* ctx;
  22. SSL* ssl;
  23. X509* server_cert;
  24. char* str;
  25. char buf [4096] = {0};
  26. char szMsg[4096] = {0};
  27. //SSL_METHOD *meth;
  28. int seed_int[100]; /*存放随机序列*/
  29. WSADATA wsaData;
  30. if(WSAStartup(MAKEWORD(2,2),&wsaData) != 0){
  31. printf("WSAStartup()fail:%d\n",GetLastError());
  32. return -1;
  33. }
  34. OpenSSL_add_ssl_algorithms(); /*初始化*/
  35. SSL_load_error_strings(); /*为打印调试信息作准备*/
  36. //注意这里是client和和服务器不同
  37. ctx = SSL_CTX_new (TLSv1_client_method());
  38. CHK_NULL(ctx);
  39. SSL_CTX_set_verify(ctx,SSL_VERIFY_PEER,NULL); /*验证与否*/
  40. SSL_CTX_load_verify_locations(ctx,CACERT,NULL); /*若验证,则放置CA证书*/
  41. if (SSL_CTX_use_certificate_file(ctx, CERTF, SSL_FILETYPE_PEM) <= 0)
  42. {
  43. cout << "客户端证书检查失败!" << endl;
  44. exit(0);
  45. }
  46. if (SSL_CTX_use_PrivateKey_file(ctx, KEYF, SSL_FILETYPE_PEM) <= 0)
  47. {
  48. cout << "客户端key检查失败!" << endl;
  49. exit(0);
  50. }
  51. if (!SSL_CTX_check_private_key(ctx))
  52. {
  53. cout << "客户端证书和key不匹配!" << endl;
  54. exit(0);
  55. }
  56. /*构建随机数生成机制,WIN32平台必需*/
  57. srand( (unsigned)time( NULL ) );
  58. for( int i = 0; i < 100;i++ ) seed_int[i] = rand();
  59. RAND_seed(seed_int, sizeof(seed_int));
  60. //创建TCP连接请求
  61. sd = socket (AF_INET, SOCK_STREAM, 0);
  62. if(sd == INVALID_SOCKET)
  63. {
  64. cout << "套接字创建失败!" << endl;
  65. exit(0);
  66. }
  67. memset(&sa,‘\0‘, sizeof(sa));
  68. sa.sin_family = AF_INET;
  69. sa.sin_addr.s_addr = inet_addr ("127.0.0.1");
  70. sa.sin_port = htons (PORT); /* Server Port number */
  71. //TCP连接
  72. err = connect(sd, (struct sockaddr*) &sa,
  73. if(err == -1)
  74. {
  75. cout << "TCP连接失败!" << endl;
  76. exit(0);
  77. }
  78. else
  79. {
  80. cout << "SSL连接成功!" << endl;
  81. exit(0);
  82. }
  83. //SSL连接
  84. //新建SSL
  85. ssl = SSL_new (ctx);
  86. if(ssl == NULL)
  87. {
  88. cout << "新建SSL失败!" << endl;
  89. exit(0);
  90. }
  91. //套接字和SSL绑定
  92. SSL_set_fd (ssl, sd);
  93. //SLL连接
  94. err = SSL_connect (ssl);
  95. if(err == -1)
  96. {
  97. cout << "SSL连接失败" << endl;
  98. exit(0);
  99. }
  100. else
  101. {
  102. cout << "SSL连接成功" << endl;
  103. exit(0);
  104. }
  105. //打印连接信息
  106. cout << "SSL连接算法信息:" << SSL_get_cipher (ssl) << endl;
  107. /*得到服务端的证书并打印些信息(可选) */
  108. server_cert = SSL_get_peer_certificate (ssl);
  109. if (server_cert != NULL) {
  110. cout << "服务器证书:" << endl;
  111. cout << "subject:" << X509_get_subject_name (server_cert), 0, 0) << endl;
  112. cout << "issuer:" << X509_NAME_oneline (X509_get_issuer_name (server_cert),0,0) << endl;
  113. CHK_NULL(str);
  114. X509_free (server_cert);/*如不再需要,需将证书释放 */
  115. }
  116. else cout << "服务器没有证书信息!" << endl; //服务器端认证失败
  117. //SSL通信,用SSL_write,SSL_read代替send和recv
  118. while(true)
  119. {
  120. cout << "请输入要发送的消息:";
  121. cin >> buf;
  122. //发送消息
  123. err = SSL_write(ssl, buf, strlen(ssl));
  124. if(err == -1)
  125. {
  126. cout << "SSL_write发送消息失败" << endl;
  127. exit(0);
  128. }
  129. cout << "【客户端】:" << buf << endl;
  130. //接收消息
  131. err = SSL_read (ssl, buf, sizeof(buf) - 1);
  132. if(err == -1)
  133. {
  134. cout << "SSL_read接收消息失败" << endl;
  135. exit(0);
  136. }
  137. buf[err] = ‘\0‘;
  138. cout << "【服务器】:" << buf << endl;
  139. }
  140. /* 收尾工作 */
  141. SSL_shutdown (ssl);
  142. shutdown (sd,2);
  143. SSL_free (ssl);
  144. SSL_CTX_free (ctx);
  145. return 0;
  146. }

时间: 2024-10-27 08:26:40

安全通信系统--OpenSSL服务器和客户端的相关文章

Ubuntu ssh服务器和客户端的安装和使用

1. 安装服务器端 sudo apt-get install openssh-server 确认是否开启ssh ps -e| grep ssh 如果有sshd进程表示启动了. 配置文件 /etc/ssh/sshd_config 2. 启动.停止.重启 启动 sudo /etc/init.d/ssh start 停止 sudo /etc/init.d/ssh stop 重启 sudo /etc/init.d/ssh restart 退出ssh exit 3. 客户端登录 SecureCRT 5.1

Windows操作系统下搭建Git服务器和客户端。

本文将介绍如何在Windows操作系统下搭建Git服务器和客户端.服务器端采用的是Bonobo Git Server,一款用ASP.NET MVC开发的Git源代码管理工具,界面简洁,基于Web方式配置,简单易用.客户端是采用的TortoiseGit工具,UI操作,省去输入命令的麻烦,对于windows用户来说更易于使用. 所需软件: Git服务器端: BONOBO GIT SERVER,下载最新版:http://bonobogitserver.com/ Git客户端: msysgit,下载最新

yum介绍及 基于yum服务器和客户端例子

因为都知道安装linux软件包rpm 很好用:但是不能解决软件包的个别依赖关系:所以安装数据包时出现依赖时.yum到可以解决这类数据包依赖关系:而且还能便于管理大量数据包更新的问题:它的特点  .可以同时配置多个资源库(Repository) ,简洁的配置文件(/etc/yum.conf)  ,自动解决增加或删除rpm包时遇到的倚赖性问题,保持与RPM数据库的一致性这也是它的优势.因此解决数据包的依赖关系:也是基于服务器和客户端的一种应用. 首先呢 介绍一下YUM 的简单指令: yum info

python编写socket服务器和客户端

本次使用的主要模块是socket模块,在这个模块中可以找到socket()函数,该函数用于创建套接字对象.套接字也有自己的方法集,这些方法可以实现基于套接字的网络通信. socket()模块函数 要创建套接字,必须使用socket.socket()函数,语法如下: socket(socket_family,socket_type,protocol=0) 其中socket_family是AF_UNIX(基于文件)或AF_INET(面向网络),socket_type是SOCK_STREAM(TCP)

蓝懿IOS网络服务器与客户端

服务器和客户端 网络架构: CS:Client  Server :优势:用户体验度高  缺点:不能跨平台 BS:Browser Server:优势:跨平台,缺点:性能依赖于网速 长连接和短连接 长连接:保证数据的实时性 TCP协议:需要建立连接 保证数据安全  属于长连接 UDP协议:可以实现1对多(广播)传输效率高(因为不用建立连接)不能保证数据准确到达 Socket:是在TCP或UDP协议上所提供的数据传输的方法集 连接:请求响应式,大部分网络请求都是短连接 TTP ip:内网(局域网之内1

10、使用TCP协议完成一个客户端一个服务器。客户端从键盘输入读取一个字符串,发送到服务器。 服务器接收客户端发送的字符串,反转之后发回客户端。客户端接收并打印。

/**10.使用TCP协议完成一个客户端一个服务器.客户端从键盘输入读取一个字符串,发送到服务器. 服务器接收客户端发送的字符串,反转之后发回客户端.客户端接收并打印. * 客户端*/ import java.io.*; import java.net.*; public class Test10_Client { public static void main(String[] args) throws Exception { Socket s = new Socket("192.168.0.

Muduo网络库实战(二):实现服务器与客户端的连接

1. 方案的确定 1)基本需求 用户1000+, IO压力不大: 多个客户端打开网站,输入查询字符串strclient,发送给服务器=>服务器接收客户端发过来的数据并处理,将结果返回给客户端: 2)并发网络服务程序设计方案 详见:<Muduo_网络库使用手册>的1.6节-<详解Muduo多线程模型> @ muduo中TcpServer模式的选择:多线程模式 模式一:单线程,accept与TcpConnection用同一个线程做IO; 模式二:多线程,accept与EventL

SignalR实现服务器与客户端的实时通信

介绍SignalR ASP.NET SignalR 是一个为 ASP.NET 开发人员的库,简化了将实时 web 功能添加到应用程序的过程.实时Web功能使服务端代码推送内容到链接可客服端并立即应用成为可能,而不需要服务端等待客户端去请求数据. SignalR可用于任何你想添加实时Web功能到ASP.NET应用程序的情形,聊天室是一个常用的例子,用户可以刷新Web页面来获得新的数据,或者页面使用一个长轮询来取回数据,这都是SignalR可以应用的场景.比如说仪表盘和监视系统,实时游戏等. Sig

python web编程-CGI帮助web服务器处理客户端编程

这几篇博客均来自python核心编程 如果你有任何疑问,欢迎联系我或者仔细查看这本书的地20章 另外推荐下这本书,希望对学习python的同学有所帮助 概念预热 eb客户端通过url请求web服务器里的静态页面,但是要怎么做到洞察不同用户同的输入?比如说表单提交等来产生不同的返回结果呢 一个简单的思路是web服务器把这些请求提交给另外一个程序,它接受用户输入然后处理,根据输入生成一个静态的html文件交给web服务器 复杂上面这样的流程程序就是CGI,是单独出来的 创建HTML 的CGI 应用程