当前位置:   article > 正文

基于SSL协议的安全网络通信程序_ssl ctx set cipher list

ssl ctx set cipher list

 基于SSL协议的安全网络通信程序


****************************************

目录结构:

1. SSL理解
1.1 SSL的优点
1.2 SSL密文会话的安全机制
1.3 SSL工作过程
(1) SSL分层结构
(2) SSL握手过程
(3) 利用Wireshark分析SSL工作过程
2. X.509证书相关文件的生成
3. 实现SSL服务器和客户端

****************************************


1. SSL理解


1.1 SSL的优点

(1)提供较高的安全性保证。SSL利用数据加密、身份验证和消息完整性验证机制,保证数据传输的安全性。

(2)支持各种应用层协议。虽然SSL设计的初衷是为了解决Web安全性问题,但是由于SSL位于应用层和传输层之间,它可以为任何基于TCP等可靠连接的应用层协议提供安全性保证

(3)部署简单。目前SSL己经成为网络中用来鉴别网站和网页浏览者身份,在客户端浏览器和Web服务器之间进行密文数据通信的全球化标准。SSL协议已被集成到大部分的浏览器中,如IE、Netscape、Firefox等。这就意味着几乎任意一台装有浏览器的计算机都支持SSL连接,不需要安装额外的客户端软件。


1.2 SSL密文会话的安全机制

(1)数据加密传输:数据需要加密后再进行传输,加密解密算法为对称密钥算法。

(2)身份验证:建立链接时需要对各通信对端进行身份验证,身份验证利用证书和数字签名技术,其中客户端的验证是可选的

(3)消息完整性验证:消息传输过程中使用MAC算法来检验消息的完整性。

数据加密传输

与非对称密钥体制相比,对称密钥体制具有计算速度快的优点,通常用于对大量数据进行加密(如对整个数据流加密);而非对称密钥体制,一般用于数字签名和对少量的信息进行加密。SSL加密管道上的数据加解密使用对称密钥体制,目前主要支持的算法有DES、 3DES、 AES等,这些算法都可以有效地防止传输的数据被窃听。

身份验证

电子商务和网上银行等Web应用中必须保证客户要登录的Web服务器是真实的,以免重要信息被非法窃取。SSL安全协议利用数字签名来进行通信对端的身份验证。非对称密钥体制可以用来实现数字签名。由于通过私钥加密后的数据只能利用对应的公钥进行解密,因此根据解密是否成功,就可以判断发送者的身份,如同发送者对数据进行了 "签名"

SSL客户端必须验证SSL服务器的身份,SSL服务器是否验证SSL客户端的身份,则由SSL服务器决定。使用数字签名验证身份时,需要确保被验证端的公钥是真实的,否则,非法用户可能会冒充被验证端与验证端通信。

消息完整性验证

为了避免网络中传输的数据被非法篡改,SSL利用基于MD5SHAMAC(消息认证码)算法来保证消息的完整性。

MAC算法要求通信双方具有相同的密钥,否则MAC值附件验证将会失败。因此,利用MAC算法验证消息完整性之前,需要在数据通信的双方部署相同的密钥

利用非对称密钥算法保证密钥本身的安全

SSL利用非对称密钥体制加密密钥的方法來实现密钥交换,保证非授权的第三方无法获取相应的密钥。

利用非对称密钥算法加密对称密钥之前,Alice需要获取Bob的公钥,并保证该公钥确实属于Bob,否则,密钥可能会被未授权的非法用户窃取。SSL利用PKI提供的机制保证公钥的真实性

PKI保证公钥的真实性

数字证书(简称证书)是一个包含用户的公钥及其身份信息的文件,证明了客户与公钥的关联。数字证书由权威机构(CA)签发,并由CA保证数字证书的真实性。

验证SSL服务器/SSL客户端的身份之前,SSL服务器和SSL客户端需要将从CA获取的证书发送给通信对端,对端通过PKI判断该证书的真实性。如果该证书确实属于SSL服务器和SSL客户端,则通信对端利用该证书中的公钥验证SSL服务器和SSL客户端的身份。


1.3 SSL工作过程

(1) SSL分层结构

 



(2) SSL握手过程

SSL握手协议是SSL协议中最复杂的协议。SSL通过握手过程在客户端和服务器之间协商会话参数,并建立会话。会话包含的主要参数有会话ID、对方的证书、加密套件(密钥交换算法、数据加密算法和MAC算法等)以及主密钥(mastersecret)通过SSL会话传输的数据,都将采用此次会话的主密钥和加密套件进行加密、计算MAC等。

SSL握手协议由一系列报文组成,根据功能基本上可以分为四个阶段:

1)      第一阶段是建立安全能力。

2)      第二阶段是服务器鉴别和密钥交换。

3)      第三个阶段是客户鉴别和密钥交换。

4)      第四个阶段是完成握手阶段。

(3)利用Wireshark分析SSL工作过程

1.handshake--client hello


注释:

ECC算法和DH结合使用,用于密钥磋商,这个密钥交换算法称为ECDH

使用RC4加密体制算法对通信数据加密(密钥长度128位)

使用SHA哈希算法进行消息完整性验证

使用RSA公钥体制算法进行证书验证和对称密钥交换

【既然密钥交换算法有很多种(RSA 和DH)那SSL握手期间用哪种呢,这个就是之前由选择的ciphersuit决定的,比如选择的是SSL_RSA_WITH_RC4_128_MD5 = 0x0004,那就是RSA的密钥交换算法即用非对称加密对称将密钥传送到对方,若选择的是SSL_DHE_RSA_EXPORT….那就使用DH交换算法】

2.handshake--server hello

3.S—>C handshake—certificate 服务器端向客户端发送服务器证书


【Certificate(可选):服务器发一个证书或一个证书链到客户端,证书链开始于服务器公共钥匙并结束于证明权威的根证书。该证书用于向客户端确认服务器的身份,该消息是可选的。如果配置服务器的SSL需要验证服务器的身份,会发送该消息。多数电子商务应用都需要服务器端身份验证。】

4.S-->Chandshake—sever key exchange   handshake—sever hello done 


服务器发送公钥和签名信息

【如果服务器发送的公共密钥对加密密钥的交换不是很合适,则发送一个服务器密钥交换消息。即和客户端协商密钥。

RSA方式密钥交换消息则把消息中的加密用公钥放入会话缓存中,作为客户端这边握手阶段的写密钥而不是用服务器证书中的公钥。

DH 方式的消息就把消息中的 p,g,Ys三个参数ECDH密钥交换情况下是G和A)记录下来,有这些 client端就可以计算出 pre-master了,只要回头再把自己这边的Yc参数发过去, server端就也能计算出相同的 pre-maseter了。

为了防止消息被恶意篡改,Server Key exchange消息中还要包含一个对密钥参数(pubKey签名(Signature)

(1)serverkey exchange Pubkey  signature

(2)Server hello done

5.C->S  handshake—clientkey exchange


客户端产生一个会话密钥与服务器共享。在SSL握手协议完成后,客户端与服务器端通信信息的加密就会使用该会话密钥。如果使用RSA加密算法客户端将使用服务器的公钥将会话密钥之后再发送给服务器。服务器使用自己的私钥对接收的消息进行解密得到共享的会话密钥

若是 RSA 方式密钥交换,则产生一个 48 位随机数作为 pre-master 并用服务器公钥加密后发出去若是 DH 方式的密钥交换,则根据 sever 的 g,p,Ys ,产生 Xa 和 Yc , Xa 和 Ys 能计算出 pre-master ,把产生的 Yc 放入消息中发给server ,这样 server 用它的 Xb 和 Yc 也能计算出 pre-master 了。计算出预主密码后就顺便把主密码 (master secret) 给算出来了。算出主密码就把对称密钥产生出来了(预主要密码à主密码à对称密钥)

clientkey exchange, change cipher spec ,encrypted handshakemessage

【Change cipher spec:客户端要求服务器在后续的通信中使用加密模式

6.S->C handshake—new session ticket

New session ticket,change cipher spec,encrypted handshake message

【Change cipher spec:服务器要求客户端在后续的通信中使用加密模式


“session Ticket”(RFC 5077)取代机制被引入,目标是消除服务器需要维护每个客户端的会话状态缓存的要求。相反,如果客户指示它支持Session Ticket,在TLS握手的最后一步中服务器将包含一个“NewSession Ticket”信息,包含了一个加密通信所需要的信息,这些数据采用一个只有服务器知道的密钥进行加密。

【引:http://cache.baiducontent.com/cm=9f65cb4a8c8507ed4fece763105392230e54f7257b8c8148228a8448e435061e5a35a3fd7c734e5392d8781f79fb3e18feb56b32610c7ce0dedf883b9cecd36974d57b23706dc01a438a4ee9&p=b47ac64ad4af5ae508e297790a4d82&newp=8b2a971a818c11a05bea936213528c231610db2151d7d5122083dc&user=baidu&fm=sc&query=New+session+ticket&qid=&p1=5

以上1-6步,握手完成。下面开始客户端和服务器端开始传输加密信息。

7.C-->传送正式数据

【淘宝网登陆页面SSL连接建立分析】

42.156.196.14 https://login.taobao.com/member/login.jhtml



(1)C-->S  client hello


(2)S-->C server hello

     Ciphersuite:TLS_RSA_WITH_RC4_128_SHA

(3)S-->C certificate 证书链

(4)C-->S Client Key Exchange

    RSA Encrypted Secret

(5)C-->S New Session Ticket


2. X.509证书相关文件的生成

【参考:基于X.509证书和SSL协议的身份认证过程实现http://h2appy.blog.51cto.com/609721/1181234】

生成数字证书相关文件的步骤:

1.生成服务器端的私钥(key文件),执行命令

openssl genrsa -des3 -out server.key1024   

Enter pass phrase for server.key:123456

2.生成服务器端的csr文件

openssl req -new -key server.key -outserver.csr -config openssl.cnf 

===拷贝 openssl\apps 下的openssl.cnf文档到out32dll目录下,就可以使用 Openssl了。

Enter pass phrase for server.key:123456

A challenge password:147258

3.客户端生成key文件

openssl genrsa -des3 -out client.key1024    

Enter pass phrase for client.key:123456

4.生成客户端的csr文件

openssl req -new -key client.key -outclient.csr -config openssl.cnf

Enter pass phrase for client.key:123456

A challenge password:147258

5.生成自己的CA

 openssl req -new -x509 -keyout ca.key -outca.crt -config openssl.cnf

Enter PEM pass phrase:123456

生成ca.key和ca.crt证书文件

6.用生成的ca给服务器的csr文件签名,生成服务器端的证书

openssl ca -in server.csr -out server.crt-cert ca.crt -keyfile ca.key -config openssl.cnf

===将apps目录下的demoCA目录以及根目录下的crypto目录复制到out32dll目录下;并在demoCA目录下新建文件夹newcerts.

Enter pass phrase for ca.key:123456

7.用生成的ca给客户端的csr文件签名,生成客户端的证书

openssl ca -in client.csr -out client.crt-cert ca.crt -keyfile ca.key -config openssl.cnf

===清空index.txt文件内容后正常生成

Enter pass phrase for ca.key:123456

生成的相关文件如下图所示:


3. 实现SSL服务器和客户端

对于上面的证书生成过程中,SSL服务器和客户端中所需要使用的只有五个文件,分别是ca.crt,client.crt,client.key,server.crt和server.key。

客户端需要ca.crt,client.crt,client.key这三个文件,

服务器端需要ca.crt,server.crt,server.key这三个文件。

源代码:

 SSL Server端:

  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. #include <iostream>
  10. using namespace std;
  11. #pragma comment(lib, "libeay32.lib")
  12. #pragma comment(lib, "ssleay32.lib")
  13. /*所有需要的参数信息都在此处以#define的形式提供*/
  14. #define CERTF "D:\\openssl-1.0.1e\\out32dll\\server.crt" /*客户端的证书(需经CA签名)*/
  15. #define KEYF "D:\\openssl-1.0.1e\\out32dll\\server.key" /*客户端的私钥(建议加密存储)*/
  16. #define CACERT "D:\\openssl-1.0.1e\\out32dll\\ca.crt" /*CA 的证书*/
  17. #define PORT 7758 /*服务端的端口*/
  18. #define CHK_NULL(x) if ((x)==NULL) { printf("null\n"); }
  19. #define MAXLEN 4096
  20. int main ()
  21. {
  22. int err;
  23. int ListenSock;//监听套接字
  24. int ConnectSock;//连接套接字
  25. SSL_CTX* ctx;
  26. SSL* ssl;
  27. X509* client_cert;
  28. // char* str;
  29. char buf [MAXLEN] = {0};
  30. // char szMsg[4096] = {0};
  31. //SSL_METHOD *meth;
  32. WSADATA wsaData;
  33. system("title SSL_SERVER");
  34. system("color 0a");
  35. if(WSAStartup(MAKEWORD(2,2),&wsaData) != 0){
  36. printf("WSAStartup()fail:%d\n",GetLastError());
  37. return -1;
  38. }
  39. OpenSSL_add_ssl_algorithms(); /*初始化*/
  40. SSL_load_error_strings(); /*为打印调试信息作准备*/
  41. //注意这里是server和和客户端不同
  42. //meth=TLSv1_server_method();
  43. ctx = SSL_CTX_new (TLSv1_server_method()); //采用什么协议(SSLv2/SSLv3/TLSv1)在此指定
  44. CHK_NULL(ctx);
  45. SSL_CTX_set_verify(ctx,SSL_VERIFY_PEER,NULL); /*验证与否*/
  46. SSL_CTX_load_verify_locations(ctx,CACERT,NULL); /*若验证,则放置CA证书*/
  47. if (SSL_CTX_use_certificate_file(ctx, CERTF, SSL_FILETYPE_PEM) <= 0)
  48. {
  49. cout<<"服务器端证书检查失败!"<<endl;
  50. exit(0);
  51. }
  52. if (SSL_CTX_use_PrivateKey_file(ctx, KEYF, SSL_FILETYPE_PEM) <= 0)
  53. {
  54. cout <<"服务器端key检查失败!"<<endl;
  55. system("pause");
  56. exit(0);
  57. }
  58. else
  59. {
  60. cout<<"服务器端key检查成功!"<<endl;
  61. }
  62. if (!SSL_CTX_check_private_key(ctx))
  63. {
  64. cout << "服务器端证书和key不匹配!"<<endl;
  65. exit(0);
  66. }
  67. SSL_CTX_set_cipher_list(ctx,"AES128-SHA");//*********加密方式 1.4******
  68. SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY); //不需要任何重试请求
  69. //创建监听套接字
  70. ListenSock = socket (AF_INET, SOCK_STREAM, 0);
  71. if(ListenSock == INVALID_SOCKET)
  72. {
  73. cout << "监听套接字创建失败" << endl;
  74. exit(0);
  75. }
  76. //创建地址
  77. sockaddr_in sin = {0};
  78. sin.sin_family = AF_INET;
  79. sin.sin_addr.s_addr = INADDR_ANY;
  80. sin.sin_port = htons (PORT); //Servert Port Number
  81. //套接字绑定
  82. err = bind(ListenSock, (struct sockaddr*)&sin,sizeof(sin));
  83. if(err == -1)
  84. {
  85. cout << "监听套接字绑定失败" << endl;
  86. exit(0);
  87. }
  88. /*接受TCP链接*/
  89. err = listen (ListenSock, 5); //等待连接的队列的最大长度为5
  90. if(err == -1)
  91. {
  92. cout << "监听套接字开启监听失败" << endl;
  93. exit(0);
  94. }
  95. //接受客户端连接
  96. struct sockaddr_in sa_client;
  97. int len=sizeof(struct sockaddr);
  98. ConnectSock = accept(ListenSock, (struct sockaddr *)&sa_client, &len);
  99. if(err == -1)
  100. {
  101. cout << "监听套接字accept失败" << endl;
  102. exit(0);
  103. }
  104. cout<<"Connection from "<<inet_ntoa(sa_client.sin_addr)<<",port:"<<ntohs(sa_client.sin_port)<<"............"<<endl;
  105. closesocket (ListenSock); //**********
  106. /*--------------------TCP连接已建立,进行服务端的SSL过程.--------------- */
  107. cout << "TCP连接建立,创建SSL连接中....\n" << endl;
  108. //从初始化的ctx新建SSL
  109. ssl = SSL_new (ctx);
  110. if(ssl == NULL)
  111. {
  112. cout << "SSL创建失败" << endl;
  113. exit(0);
  114. }
  115. //(连接)套接字和SSL绑定 //<------------key
  116. SSL_set_fd (ssl, ConnectSock);
  117. // SSL连接建立
  118. err = SSL_accept (ssl);//等待一个TLS / SSL客户端启动TLS / SSL握手,类似于socket中的accept。
  119. if(err == -1)
  120. {
  121. cout << "创建SSL连接失败" << endl;
  122. exit(0);
  123. }
  124. else
  125. {
  126. cout << "创建SSL连接成功" << endl;
  127. }
  128. /*打印所有加密算法的信息(可选)*/
  129. cout << "SSL连接算法信息:" << SSL_get_cipher (ssl) << endl;
  130. /*得到客户端的证书并打印些信息(可选) */
  131. client_cert = SSL_get_peer_certificate (ssl);
  132. if (client_cert != NULL) {
  133. cout << "客户端证书:" << endl;
  134. cout << "subject:" <<X509_NAME_oneline(X509_get_subject_name (client_cert), 0, 0)<< endl;
  135. cout << "issuer:" <<X509_NAME_oneline(X509_get_issuer_name (client_cert),0,0) << endl;
  136. // CHK_NULL(str);
  137. X509_free (client_cert);/*如不再需要,需将证书释放 */
  138. }
  139. else cout << "客户端没有证书信息!" << endl; //客户端认证失败
  140. //SSL通信,用SSL_write,SSL_read代替send和recv
  141. while(true)
  142. {
  143. //接收消息
  144. err = SSL_read (ssl, buf, sizeof(buf) - 1);
  145. if(err == -1)
  146. {
  147. cout << "SSL_read接收消息失败" << endl;
  148. exit(0);
  149. }
  150. buf[err] = '\0';
  151. cout << "【Client】:" << buf << endl;
  152. //发送消息
  153. cout << "请输入要发送的消息:";
  154. gets(buf);//end with CRLF or EOF
  155. err = SSL_write(ssl, buf, strlen(buf));
  156. if(err == -1)
  157. {
  158. cout << "SSL_write发送消息失败" << endl;
  159. exit(0);
  160. }
  161. cout << "【Server】:" << buf << endl;
  162. }
  163. //关闭套接字和ssl
  164. SSL_shutdown (ssl);
  165. shutdown (ConnectSock,2);
  166. SSL_free (ssl);
  167. SSL_CTX_free (ctx);
  168. closesocket(ConnectSock);
  169. return 0;
  170. }

SSL Client 端:

  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. #include <iostream>
  10. using namespace std;
  11. #pragma comment(lib, "libeay32.lib")
  12. #pragma comment(lib, "ssleay32.lib")
  13. /*所有需要的参数信息都在此处以#define的形式提供*/
  14. #define CERTF "D:\\openssl-1.0.1e\\out32dll\\client.crt" /*客户端的证书(需经CA签名)*/
  15. #define KEYF "D:\\openssl-1.0.1e\\out32dll\\client.key" /*客户端的私钥(建议加密存储)*/
  16. #define CACERT "D:\\openssl-1.0.1e\\out32dll\\ca.crt" /*CA 的证书*/
  17. #define PORT 7758 /*服务端的端口*/
  18. #define CHK_NULL(x) if ((x)==NULL) { printf("null\n"); }
  19. #define MAXLEN 4096
  20. int main ()
  21. {
  22. int err;
  23. int sd;
  24. struct sockaddr_in sa;
  25. SSL_CTX* ctx;
  26. SSL* ssl;
  27. X509* server_cert;
  28. // char* str;
  29. char buf [MAXLEN] = {0};
  30. // char szMsg[MAXLEN] = {0};
  31. //SSL_METHOD *meth;
  32. //int seed_int[100]; /*存放随机序列*/
  33. WSADATA wsaData;
  34. if(WSAStartup(MAKEWORD(2,2),&wsaData) != 0){
  35. printf("WSAStartup()fail:%d\n",GetLastError());
  36. return -1;
  37. }
  38. system("title SSL_CLIENT");
  39. system("color 0a");
  40. OpenSSL_add_ssl_algorithms(); /*1.SSL初始化*/
  41. SSL_load_error_strings(); /*2.SSL错误信息初始化 为打印调试信息作准备*/
  42. //注意这里是client和和服务器不同
  43. ctx = SSL_CTX_new (TLSv1_client_method()); //3.创建本次会话所使用的协议(TLSv1); 4.申请SSL会话的环境
  44. CHK_NULL(ctx);
  45. //SSL_VERIFY_PEER:希望验证对方的证书
  46. SSL_CTX_set_verify(ctx,SSL_VERIFY_PEER,NULL); /*验证与否*/ //5.设置会话的握手方式
  47. SSL_CTX_load_verify_locations(ctx,CACERT,NULL); /*若验证,则放置CA证书*/ //6.并加载CA证书
  48. if (SSL_CTX_use_certificate_file(ctx, CERTF, SSL_FILETYPE_PEM) <= 0) //7.加载自己(客户端)的整数
  49. {
  50. cout << "客户端证书检查失败!" << endl;
  51. exit(0);
  52. }
  53. if (SSL_CTX_use_PrivateKey_file(ctx, KEYF, SSL_FILETYPE_PEM) <= 0) //8.加载客户端的私钥
  54. {
  55. cout << "客户端key检查失败!" << endl;
  56. system("pause");
  57. exit(0);
  58. }
  59. else
  60. {
  61. cout<<"客户端证key检查成功!"<<endl;
  62. }
  63. if (!SSL_CTX_check_private_key(ctx))//9.检查自己的证书和私钥是否匹配
  64. {
  65. cout << "客户端证书和key不匹配!" << endl;
  66. exit(0);
  67. }
  68. //10.加密方式
  69. // SSL_CTX_set_cipher_list(ctx, "RC4-MD5");
  70. SSL_CTX_set_cipher_list(ctx, "AES128-SHA");
  71. //处理握手多次
  72. //设置ssl的模式为SSL_MODE_AUTO_RETRY,使用这个选项进行设置,如果服务器突然希望进行一次新的握手,那么OpenSSL可以在后台处理它。
  73. SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
  74. /*构建随机数生成机制,WIN32平台必需*/
  75. /* srand( (unsigned)time( NULL ) );
  76. for( int i = 0; i < 100;i++ ) seed_int[i] = rand();
  77. RAND_seed(seed_int, sizeof(seed_int));*/
  78. //11.创建TCP连接请求
  79. sd = socket (AF_INET, SOCK_STREAM, 0);
  80. if(sd == INVALID_SOCKET)
  81. {
  82. cout << "套接字创建失败!" << endl;
  83. exit(0);
  84. }
  85. memset(&sa,'\0', sizeof(sa));
  86. sa.sin_family = AF_INET;
  87. // 获取本地地址信息
  88. // unsigned int SrcIp;
  89. /* char szLocalName[MAXLEN]={0};
  90. gethostname(szLocalName,MAXLEN);
  91. hostent* pHost=gethostbyname(szLocalName);
  92. if(pHost!=NULL)
  93. memcpy(&(sa.sin_addr.s_addr),pHost->h_addr_list[0],pHost->h_length);
  94. else
  95. exit(0);*/
  96. sa.sin_addr.s_addr = inet_addr ("127.0.0.1");
  97. // sa.sin_addr.s_addr = inet_addr ("192.168.146.1");
  98. sa.sin_port = htons (PORT); /* Server Port number *///SERVER PORT
  99. //TCP连接 等待服务器的响应
  100. cout<<"等待连接中..."<<endl;
  101. int try_count=0;
  102. while(1)
  103. {
  104. err = connect(sd, (struct sockaddr*) &sa,sizeof(sa));
  105. if(try_count>5)
  106. {
  107. cout<<"TCP 连接超时..."<<endl;
  108. system("pause");
  109. exit(1);
  110. }
  111. else
  112. {
  113. if(err == -1)
  114. {
  115. // cout << "TCP连接失败!" << endl;
  116. try_count++;
  117. continue;
  118. }
  119. else
  120. {
  121. cout << "TCP连接成功!" << endl;
  122. break;
  123. }
  124. }
  125. }
  126. /* 12.TCP 链接已建立.开始 SSL 握手过程.......................... */
  127. //SSL连接
  128. //新建SSL
  129. ssl = SSL_new (ctx); //利用SSL会话的环境ctx申请SSL
  130. if(ssl == NULL)
  131. {
  132. cout << "新建SSL失败!" << endl;
  133. exit(0);
  134. }
  135. //13. 套接字sd和SSL绑定
  136. SSL_set_fd (ssl, sd);
  137. //14.SLL连接(SSL handshake)
  138. //设置等待服务器响应的超时时间
  139. while(1)
  140. {
  141. err = SSL_connect (ssl);
  142. if(err == -1)
  143. {
  144. cout << "SSL连接失败" << endl;
  145. continue;
  146. }
  147. else
  148. {
  149. cout << "SSL连接成功" << endl;
  150. break;
  151. }
  152. }
  153. //打印连接信息
  154. cout << "SSL连接算法信息:" << SSL_get_cipher (ssl) << endl;
  155. /*得到服务端的证书并打印些信息(可选) */
  156. server_cert = SSL_get_peer_certificate (ssl);//从SSL套接字中提取对方的证书信息,这些信息已经被SSL验证过了
  157. if (server_cert != NULL) {
  158. cout << "服务器证书:" << endl;
  159. cout << "subject:" << X509_NAME_oneline( X509_get_subject_name (server_cert), 0, 0)<< endl;//得到证书所用者的名字
  160. cout << "issuer:" << X509_NAME_oneline (X509_get_issuer_name (server_cert),0,0) << endl;
  161. // CHK_NULL(str);
  162. X509_free (server_cert);/*如不再需要,需将证书释放 */
  163. }
  164. else cout << "服务器没有证书信息!" << endl; //服务器端认证失败
  165. //SSL通信,用SSL_write,SSL_read代替send和recv
  166. while(true)
  167. {
  168. //发送消息 int SSL_write(SSL *ssl,const void *buf,int num);
  169. cout << "请输入要发送的消息:";
  170. gets(buf);
  171. err = SSL_write(ssl, buf, strlen(buf));
  172. if(err == -1)
  173. {
  174. cout << "SSL_write发送消息失败" << endl;
  175. exit(0);
  176. }
  177. cout << "【Client】:" << buf << endl;
  178. //接收消息 int SSL_read(SSL *ssl,void *buf,int num);
  179. err = SSL_read (ssl, buf, sizeof(buf) - 1);
  180. if(err == -1)
  181. {
  182. cout << "SSL_read接收消息失败" << endl;
  183. exit(0);
  184. }
  185. buf[err] = '\0';
  186. cout << "【Server】:" << buf << endl;
  187. }
  188. /* 收尾工作 */
  189. SSL_shutdown (ssl);//关闭SSL套接字
  190. //shutdown( SOCKET s, int how); 0关闭套接字的读功能 1关闭套接字的写功能 2关闭套接字的读写功能
  191. //请注意shutdown()函数并不关闭套接口,且套接口所占有的资源将被一直保持到closesocket()调用。
  192. //shutdown (sd,2);//
  193. SSL_free (ssl);//释放SSL套接字
  194. SSL_CTX_free (ctx);//释放SSL会话环境
  195. closesocket(sd);//
  196. return 0;
  197. }

运行结果示例:

 

 


声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/472716
推荐阅读
相关标签
  

闽ICP备14008679号