基于openssl的单向和双向认证

时间:2021-12-07 13:11:19

1、前言

   最近工作涉及到https,需要修改nginx的openssl模块,引入keyless方案。关于keyless可以参考CloudFlare的官方博客:

https://blog.cloudflare.com/keyless-ssl-the-nitty-gritty-technical-details/?utm_source=tuicool&utm_medium=referral

在openssl的基础上修改私钥校验过程,因此需要对openssl的认证认证流程需要熟悉一下。SSL中涉及到很多概念,开始都不清楚,例如CA,数字签名、数字证书等,本文主要是总结SSL认证的基础知识,openssl的单向和双向认证流程,并写代码测试。

2、基础知识

  SSL:Secure Socket Layer,安全套接字层,它位于TCP层与Application层之间。提供对Application数据的加密保护(密文),完整性保护(不被篡改)等安全服务,它缺省工作在TCP 443 端口,一般对HTTP加密,即俗称的HTTPS。

  TLS:Transport Layer Secure,更关注的是提供安全的传输服务,它很灵活,如果可能,它可以工作在TCP,也可以UDP (DTLS),也可以工作在数据链路层,比如802.1x EAP-TLS。

关于SSL/TSL可以参考:http://www.ruanyifeng.com/blog/2014/02/ssl_tls.html

  公钥:大家公用的,可以通过电子邮件发布,通过网站让别人下载,公钥其用来加密和验章。

  私钥:就是自己的私有的,必须非常小心保存,最好加上 密码,私钥是用来解密和签章。

  数字签名:将报文按双方约定的HASH算法计算得到一个固定位数的报文摘要。在数学上保证:只要改动报文中任何一位,重新计算出的报文摘要值就会与原先的值不相符。这样就保证了报文的不可更改性。将该报文摘要值用发送者的私人密钥加密,然后连同原报文一起发送给接收者,而产生的报文即称数字签名。关于数字签名参考:http://www.ruanyifeng.com/blog/2011/08/what_is_a_digital_signature.htmlhttp://www.youdzone.com/signature.html

  数字证书:数字证书就是互联网通讯中标志通讯各方身份信息的一系列数据,提供了一种在Internet上验证您身份的方式,其作用类似于司机的驾驶执照或日常生活中的身份证。它是由一个由权威机构-----CA机构,又称为证书授权(Certificate Authority)中心发行的,人们可以在网上用它来识别对方的身份。数字证书是一个经证书授权中心数字签名的包含公开密钥拥有者信息以及公开密钥的文件。最简单的证书包含一个公开密钥、名称以及证书授权中心的数字签名。

参考:http://blog.csdn.net/oscar999/article/details/9364101

      CA:Certificate Authority,证书授权中心。是一个单位,来管理发放数字证书的。由它发放的证书就叫 CA 证书,以区别于个人使用工具随意生成的数字证书,查看 CA 证书,里面有两项重要内容,一个是颂发给谁,另一个是由谁颂发的。

参考:http://blog.csdn.net/mostone/article/details/22302035

SSL/TLS协议的基本思路是采用公钥加密法,也就是说,客户端先向服务器端索要公钥,然后用公钥加密信息,服务器收到密文后,用自己的私钥解密。

3、认证流程

单向认证:只需要验证SSL服务器身份,不需要验证SSL客户端身份。

基于openssl的单向和双向认证

 

双向认证:要求服务器和客户端双方都有证书,客户端需要校验服务端,服务端也需要校验客户端。

基于openssl的单向和双向认证

SSL双向认证和SSL单向认证的区别

  双向认证 SSL 协议要求服务器和用户双方都有证书。单向认证 SSL 协议不需要客户拥有CA证书,具体的过程相对于上面的步骤,只需将服务器端验证客户证书的过程去掉,以及在协商对称密码方案,对称通话密钥时,服务器发送给客户的是没有加过密的(这并不影响 SSL 过程的安全性)密码方案。这样,双方具体的通讯内容,就是加过密的数据,如果有第三方攻击,获得的只是加密的数据,第三方要获得有用的信息,就需要对加密的数据进行解密,这时候的安全就依赖于密码方案的安全。而幸运的是,目前所用的密码方案,只要通讯密钥长度足够的长,就足够的安全。这也是我们强调要求使用128位加密通讯的原因。

  一般Web应用都是采用SSL单向认证的,原因很简单,用户数目广泛,且无需在通讯层对用户身份进行验证,一般都在应用逻辑层来保证用户的合法登入。但如果是企业应用对接,情况就不一样,可能会要求对客户端(相对而言)做身份验证。这时就需要做SSL双向认证。

参考:

http://blog.csdn.net/duanbokan/article/details/50847612

http://blog.csdn.net/it_man/article/details/24698093

4、测试代码

证书生成过程:

(1)自签CA证书

#生成根证书私钥(pem文件)                                                                                                   
openssl genrsa
-out cakey.pem 2048
#生成根证书签发申请文件(csr文件)
openssl req
-new -key cakey.pem -out ca.csr -subj "/C=CN/ST=myprovince/L=mycity/O=myorganization/OU=mygroup/CN=myCA"
#自签发根证书(cer文件)
openssl x509
-req -days 365 -sha1 -extensions v3_ca -signkey cakey.pem -in ca.csr -out cacert.pem

(2)服务端私钥和证书

#生成服务端私钥                                                                                                            
openssl genrsa
-out key.pem 2048
#生成证书请求文件
openssl req
-new -key key.pem -out server.csr -subj "/C=CN/ST=myprovince/L=mycity/O=myorganization/OU=mygroup/CN=myServer"
#使用根证书签发服务端证书
openssl x509
-req -days 365 -sha1 -extensions v3_req -CA ../CA/cacert.pem -CAkey ../CA/cakey.pem -CAserial ca.srl -CAcreateserial -in server.csr -out cert.pem
#使用CA证书验证server端证书
openssl verify
-CAfile ../CA/cacert.pem cert.pem

(3)客户端私钥和证书

#生成客户端私钥                                                                                                            
openssl genrsa
-out key.pem 2048
#生成证书请求文件
openssl req
-new -key key.pem -out client.csr -subj "/C=CN/ST=myprovince/L=mycity/O=myorganization/OU=mygroup/CN=myClient"
#使用根证书签发客户端证书
openssl x509
-req -days 365 -sha1 -extensions v3_req -CA ../CA/cacert.pem -CAkey ../CA/cakey.pem -CAserial ../server-cert/ca.srl -in client.csr -out cert.pem
#使用CA证书验证客户端证书
openssl verify
-CAfile ../CA/cacert.pem cert.pem

验证CA证书出现错误处理:

基于openssl的单向和双向认证

http://*.com/questions/19726138/openssl-error-18-at-0-depth-lookupself-signed-certificate

单向认证:

基于openssl的单向和双向认证

客户端代码:不需要配置证书和私钥

  1 #include <stdio.h>
2 #include <string.h>
3 #include <errno.h>
4 #include <sys/socket.h>
5 #include <resolv.h>
6 #include <stdlib.h>
7 #include <netinet/in.h>
8 #include <arpa/inet.h>
9 #include <unistd.h>
10 #include <openssl/ssl.h>
11 #include <openssl/err.h>
12
13 #define MAXBUF 1024
14
15 void ShowCerts(SSL * ssl)
16 {
17 X509 *cert;
18 char *line;
19 cert = SSL_get_peer_certificate(ssl);
20 if (cert != NULL) {
21 printf("数字证书信息:\n");
22 line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
23 printf("证书: %s\n", line);
24 free(line);
25 line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
26 printf("颁发者: %s\n", line);
27 free(line);
28 X509_free(cert);
29 } else {
30 printf("无证书信息!\n");
31 }
32 }
33
34 int main(int argc, char **argv)
35 {
36 int sockfd, len;
37 struct sockaddr_in dest;
38 char buffer[MAXBUF + 1];
39 SSL_CTX *ctx;
40 SSL *ssl;
41
42 if (argc != 3) {
43 printf("参数格式错误!正确用法如下:\n\t\t%s IP地址 端口\n\t比如:\t%s 127.0.0.1 80\n此程序用来从某个"
44 "IP 地址的服务器某个端口接收最多 %d 个字节的消息.\n", argv[0], argv[0], MAXBUF);
45 exit(0);
46 }
47
48 /*SSL初始化*/
49 SSL_library_init();
50 OpenSSL_add_all_algorithms();
51 SSL_load_error_strings();
52 ctx = SSL_CTX_new(SSLv3_client_method());
53
54 if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
55 perror("Socket");
56 exit(errno);
57 }
58
59 bzero(&dest, sizeof(dest));
60 dest.sin_family = AF_INET;
61 dest.sin_port = htons(atoi(argv[2]));
62 if (inet_aton(argv[1], (struct in_addr *) &dest.sin_addr.s_addr) == 0) {
63 perror(argv[1]);
64 exit(errno);
65 }
66
67 if (connect(sockfd, (struct sockaddr *) &dest, sizeof(dest)) != 0) {
68 perror("Connect ");
69 exit(errno);
70 }
71 printf("connectd server successly\n");
72
73 ssl = SSL_new(ctx);
74 SSL_set_fd(ssl, sockfd);
75 if (SSL_connect(ssl) == -1) {
76 ERR_print_errors_fp(stderr);
77 } else {
78 printf("Connected with %s encryption\n", SSL_get_cipher(ssl));
79 ShowCerts(ssl);
80 }
81
82 bzero(buffer, MAXBUF + 1);
83 len = SSL_read(ssl, buffer, MAXBUF);
84 if (len > 0) {
85 printf("接收消息成功:'%s',共%d个字节的数据\n", buffer, len);
86 } else {
87 printf("消息接收失败!错误代码是%d,错误信息是'%s'\n", errno, strerror(errno));
88 goto finish;
89 }
90 bzero(buffer, MAXBUF + 1);
91 strcpy(buffer, "from client->server");
92
93 len = SSL_write(ssl, buffer, strlen(buffer));
94 if (len < 0) {
95 printf("消息'%s'发送失败!错误代码是%d,错误信息是'%s'\n", buffer, errno, strerror(errno));
96 } else {
97 printf("消息'%s'发送成功,共发送了%d个字节!\n", buffer, len);
98 }
99
100 finish:
101 SSL_shutdown(ssl);
102 SSL_free(ssl);
103 close(sockfd);
104 SSL_CTX_free(ctx);
105 return 0;
106 }

服务端代码:

  1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <errno.h>
4 #include <string.h>
5 #include <sys/types.h>
6 #include <netinet/in.h>
7 #include <sys/socket.h>
8 #include <sys/wait.h>
9 #include <unistd.h>
10 #include <arpa/inet.h>
11 #include <openssl/ssl.h>
12 #include <openssl/err.h>
13
14 #define MAXBUF 1024
15 #define SERVER_CERT "/home/waf/test/cert/server-cert/cert.pem"
16 #define SERVER_KEY "/home/waf/test/cert/server-cert/key.pem"
17
18 int main(int argc, char **argv)
19 {
20 int sockfd, new_fd;
21 int reuse = 0;
22 socklen_t len;
23 struct sockaddr_in my_addr, their_addr;
24 unsigned int myport, lisnum;
25 char buf[MAXBUF + 1];
26 SSL_CTX *ctx;
27
28 if (argv[1]) {
29 myport = atoi(argv[1]);
30 } else {
31 myport = 7838;
32 }
33
34 if (argv[2]) {
35 lisnum = atoi(argv[2]);
36 } else {
37 lisnum = 2;
38 }
39
40 SSL_library_init();
41 OpenSSL_add_all_algorithms();
42 SSL_load_error_strings();
43 ctx = SSL_CTX_new(SSLv3_server_method());
44 if (ctx == NULL) {
45 ERR_print_errors_fp(stdout);
46 exit(1);
47 }
48
49 /*加载公钥证书*/
50 if (SSL_CTX_use_certificate_file(ctx, SERVER_CERT, SSL_FILETYPE_PEM) <= 0) {
51 ERR_print_errors_fp(stdout);
52 exit(1);
53 }
54
55 /*设置私钥*/
56 if (SSL_CTX_use_PrivateKey_file(ctx, SERVER_KEY, SSL_FILETYPE_PEM) <= 0) {
57 printf("use private key fail.\n");
58 ERR_print_errors_fp(stdout);
59 exit(1);
60 }
61
62 if (!SSL_CTX_check_private_key(ctx)) {
63 ERR_print_errors_fp(stdout);
64 exit(1);
65 }
66 if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
67 perror("socket");
68 exit(1);
69 }
70 if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0){
71 printf("setsockopet error\n");
72 return -1;
73 }
74 bzero(&my_addr, sizeof(my_addr));
75 my_addr.sin_family = PF_INET;
76 my_addr.sin_port = htons(myport);
77 my_addr.sin_addr.s_addr = INADDR_ANY;
78
79 if (bind(sockfd, (struct sockaddr *) &my_addr, sizeof(struct sockaddr)) == -1) {
80 perror("bind");
81 exit(1);
82 } else {
83 printf("binded\n");
84 }
85
86 if (listen(sockfd, lisnum) == -1) {
87 perror("listen");
88 exit(1);
89 } else {
90 printf("begin listen\n");
91 }
92
93 while (1) {
94 SSL *ssl;
95 len = sizeof(struct sockaddr);
96
97 if ((new_fd = accept(sockfd, (struct sockaddr *) &their_addr, &len)) == -1) {
98 perror("accept");
99 exit(errno);
100 }
101 printf("server: got connection from %s, port %d, socket %d\n",inet_ntoa(their_addr.sin_addr), ntohs(their_addr.sin_port), new_fd);
102
103 ssl = SSL_new(ctx);
104 SSL_set_fd(ssl, new_fd);
105 if (SSL_accept(ssl) == -1) {
106 perror("accept");
107 close(new_fd);
108 break;
109 }
110
111 bzero(buf, MAXBUF + 1);
112 strcpy(buf, "server->client");
113 len = SSL_write(ssl, buf, strlen(buf));
114 if (len <= 0) {
115 printf("消息'%s'发送失败!错误代码是%d,错误信息是'%s'\n", buf, errno, strerror(errno));
116 goto finish;
117 }
118 printf("消息'%s'发送成功,共发送了%d个字节!\n", buf, len);
119
120 bzero(buf, MAXBUF + 1);
121 len = SSL_read(ssl, buf, MAXBUF);
122 if (len > 0) {
123 printf("接收消息成功:'%s',共%d个字节的数据\n", buf, len);
124 } else {
125 printf("消息接收失败!错误代码是%d,错误信息是'%s'\n", errno, strerror(errno));
126 }
127 finish:
128 SSL_shutdown(ssl);
129 SSL_free(ssl);
130 close(new_fd);
131 }
132
133 close(sockfd);
134 SSL_CTX_free(ctx);
135 return 0;
136 }

测试结果:

基于openssl的单向和双向认证

基于openssl的单向和双向认证

双向认证:

客户端代码:需要设置CA证书,客户端证书和私钥,校验服务器。

服务端代码:

  1 #include <stdio.h>
2 #include <string.h>
3 #include <errno.h>
4 #include <sys/socket.h>
5 #include <resolv.h>
6 #include <stdlib.h>
7 #include <netinet/in.h>
8 #include <arpa/inet.h>
9 #include <unistd.h>
10 #include <openssl/ssl.h>
11 #include <openssl/err.h>
12
13 #define MAXBUF 1024
14
15 #define CA_FILE "/home/waf/keyless/test/cert/CA/cacert.pem"
16 #define CLIENT_KEY "/home/waf/keyless/test/cert/client-cert/key.pem"
17 #define CLIENT_CERT "/home/waf/keyless/test/cert/client-cert/cert.pem"
18
19 void ShowCerts(SSL * ssl)
20 {
21 X509 *cert;
22 char *line;
23 cert = SSL_get_peer_certificate(ssl);
24 if (cert != NULL) {
25 printf("数字证书信息:\n");
26 line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
27 printf("证书: %s\n", line);
28 free(line);
29 line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
30 printf("颁发者: %s\n", line);
31 free(line);
32 X509_free(cert);
33 } else {
34 printf("无证书信息!\n");
35 }
36 }
37
38 int main(int argc, char **argv)
39 {
40 int sockfd, len;
41 struct sockaddr_in dest;
42 char buffer[MAXBUF + 1];
43 SSL_CTX *ctx;
44 SSL *ssl;
45 const SSL_METHOD *method;
46
47 if (argc != 3) {
48 printf("参数格式错误!正确用法如下:\n\t\t%s IP地址 端口\n\t比如:\t%s 127.0.0.1 80\n此程序用来从某个"
49 "IP 地址的服务器某个端口接收最多 MAXBUF 个字节的消息", argv[0], argv[0]);
50 exit(0);
51 }
52
53 SSL_library_init();
54 SSL_load_error_strings();
55 OpenSSL_add_all_algorithms();
56 method = TLSv1_2_client_method();
57 ctx = SSL_CTX_new(method);
58
59 if (!ctx) {
60 printf("create ctx is failed.\n");
61 }
62
63 #if 0
64 const char * cipher_list = "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA256:AES128-GCM-SHA256:RC4:HIGH:!MD5:!aNULL:!EDH";
65 if (SSL_CTX_set_cipher_list(ctx, cipher_list) == 0) {
66 SSL_CTX_free(ctx);
67 printf("Failed to set cipher list: %s", cipher_list);
68 }
69 #endif
70
71 /*设置会话的握手方式*/
72 SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, 0);
73
74 /*加载CA FILE*/
75 if (SSL_CTX_load_verify_locations(ctx, CA_FILE, 0) != 1) {
76 SSL_CTX_free(ctx);
77 printf("Failed to load CA file %s", CA_FILE);
78 }
79 if (SSL_CTX_set_default_verify_paths(ctx) != 1) {
80 SSL_CTX_free(ctx);
81 printf("Call to SSL_CTX_set_default_verify_paths failed");
82 }
83 /*加载客户端证书*/
84 if (SSL_CTX_use_certificate_file(ctx, CLIENT_CERT, SSL_FILETYPE_PEM) != 1) {
85 SSL_CTX_free(ctx);
86 printf("Failed to load client certificate from %s", CLIENT_KEY);
87 }
88 /*加载客户端私钥*/
89 if (SSL_CTX_use_PrivateKey_file(ctx, CLIENT_KEY, SSL_FILETYPE_PEM) != 1) {
90 SSL_CTX_free(ctx);
91 printf("Failed to load client private key from %s", CLIENT_KEY);
92 }
93 /*验证私钥*/
94 if (SSL_CTX_check_private_key(ctx) != 1) {
95 SSL_CTX_free(ctx);
96 printf("SSL_CTX_check_private_key failed");
97 }
98 /*处理握手多次*/
99 SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
100
101 if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
102 perror("Socket");
103 exit(errno);
104 }
105
106 bzero(&dest, sizeof(dest));
107 dest.sin_family = AF_INET;
108 dest.sin_port = htons(atoi(argv[2]));
109 if (inet_aton(argv[1], (struct in_addr *) &dest.sin_addr.s_addr) == 0) {
110 perror(argv[1]);
111 exit(errno);
112 }
113
114 if (connect(sockfd, (struct sockaddr *) &dest, sizeof(dest)) != 0) {
115 perror("Connect ");
116 exit(errno);
117 }
118
119 /*创建SSL*/
120 ssl = SSL_new(ctx);
121 if (ssl == NULL) {
122 printf("SSL_new error.\n");
123 }
124 /*将fd添加到ssl层*/
125 SSL_set_fd(ssl, sockfd);
126 if (SSL_connect(ssl) == -1) {
127 printf("SSL_connect fail.\n");
128 ERR_print_errors_fp(stderr);
129 } else {
130 printf("Connected with %s encryption\n", SSL_get_cipher(ssl));
131 ShowCerts(ssl);
132 }
133
134 bzero(buffer, MAXBUF + 1);
135 len = SSL_read(ssl, buffer, MAXBUF);
136 if (len > 0) {
137 printf("接收消息成功:'%s',共%d个字节的数据\n", buffer, len);
138 } else {
139 printf("消息接收失败!错误代码是%d,错误信息是'%s'\n", errno, strerror(errno));
140 goto finish;
141 }
142 bzero(buffer, MAXBUF + 1);
143 strcpy(buffer, "from client->server");
144
145 len = SSL_write(ssl, buffer, strlen(buffer));
146 if (len < 0) {
147 printf("消息'%s'发送失败!错误代码是%d,错误信息是'%s'\n", buffer, errno, strerror(errno));
148 } else {
149 printf("消息'%s'发送成功,共发送了%d个字节!\n", buffer, len);
150 }
151
152 finish:
153
154 SSL_shutdown(ssl);
155 SSL_free(ssl);
156 close(sockfd);
157 SSL_CTX_free(ctx);
158 return 0;
159 }

服务端代码:

  1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <errno.h>
4 #include <string.h>
5 #include <sys/types.h>
6 #include <netinet/in.h>
7 #include <sys/socket.h>
8 #include <sys/wait.h>
9 #include <unistd.h>
10 #include <arpa/inet.h>
11 #include <openssl/ssl.h>
12 #include <openssl/err.h>
13
14 #define MAXBUF 1024
15
16 #define CA_FILE "/home/waf/keyless/test/cert/CA/cacert.pem"
17 #define SERVER_KEY "/home/waf/keyless/test/cert/server-cert/key.pem"
18 #define SERVER_CERT "/home/waf/keyless/test/cert/server-cert/cert.pem"
19
20 int main(int argc, char **argv)
21 {
22 int sockfd, new_fd;
23 int reuse = 0;
24 socklen_t len;
25 struct sockaddr_in my_addr, their_addr;
26 unsigned int myport, lisnum;
27 char buf[MAXBUF + 1];
28 SSL_CTX *ctx;
29 const SSL_METHOD *method;
30
31 if (argv[1]) {
32 myport = atoi(argv[1]);
33 } else {
34 myport = 7838;
35 }
36
37 if (argv[2]) {
38 lisnum = atoi(argv[2]);
39 } else {
40 lisnum = 2;
41 }
42
43 SSL_library_init();
44 OpenSSL_add_all_algorithms();
45 SSL_load_error_strings();
46
47 method = TLSv1_2_server_method();
48 ctx = SSL_CTX_new(method);
49 if (ctx == NULL) {
50 ERR_print_errors_fp(stdout);
51 exit(1);
52 }
53
54 #if 0
55 const char *cipher_list = "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384";
56 if (SSL_CTX_set_cipher_list(ctx, cipher_list) == 0) {
57 SSL_CTX_free(ctx);
58 printf("Failed to set cipher list %s", cipher_list);
59 }
60 #endif
61
62 SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, 0);
63 /*加载CA FILE*/
64 if (SSL_CTX_load_verify_locations(ctx, CA_FILE, 0) != 1) {
65 SSL_CTX_free(ctx);
66 printf("Failed to load CA file %s", CA_FILE);
67 }
68 /*加载服务端证书*/
69 if (SSL_CTX_use_certificate_file(ctx, SERVER_CERT, SSL_FILETYPE_PEM) <= 0) {
70 ERR_print_errors_fp(stdout);
71 exit(1);
72 }
73 /*加载服务端私钥*/
74 if (SSL_CTX_use_PrivateKey_file(ctx, SERVER_KEY, SSL_FILETYPE_PEM) <= 0) {
75 printf("use private key fail.\n");
76 ERR_print_errors_fp(stdout);
77 exit(1);
78 }
79 /*验证私钥*/
80 if (!SSL_CTX_check_private_key(ctx)) {
81 ERR_print_errors_fp(stdout);
82 exit(1);
83 }
84 //处理握手多次
85 SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
86
87 if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
88 perror("socket");
89 exit(1);
90 } else {
91 printf("socket created\n");
92 }
93
94 if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0){
95 printf("setsockopet error\n");
96 return -1;
97 }
98
99 bzero(&my_addr, sizeof(my_addr));
100 my_addr.sin_family = PF_INET;
101 my_addr.sin_port = htons(myport);
102 my_addr.sin_addr.s_addr = INADDR_ANY;
103
104 if (bind(sockfd, (struct sockaddr *) &my_addr, sizeof(struct sockaddr)) == -1) {
105 perror("bind");
106 exit(1);
107 }
108 printf("Server bind success.\n");
109
110 if (listen(sockfd, lisnum) == -1) {
111 perror("listen");
112 exit(1);
113 }
114 printf("Server begin to listen\n");
115
116 while (1) {
117 SSL *ssl;
118 len = sizeof(struct sockaddr);
119
120 if ((new_fd = accept(sockfd, (struct sockaddr *) &their_addr, &len)) == -1) {
121 perror("accept");
122 exit(errno);
123 }
124
125 printf("Server: receive a connection from %s, port %d, socket %d\n", inet_ntoa(their_addr.sin_addr), ntohs(their_addr.sin_port), new_fd);
126
127 ssl = SSL_new(ctx);
128 if (ssl == NULL) {
129 printf("SSL_new error.\n");
130 }
131
132 SSL_set_fd(ssl, new_fd);
133
134 if (SSL_accept(ssl) == -1) {
135 perror("accept");
136 ERR_print_errors_fp(stderr);
137 close(new_fd);
138 break;
139 }
140 printf("Server with %s encryption\n", SSL_get_cipher(ssl));
141
142 bzero(buf, MAXBUF + 1);
143 strcpy(buf, "server->client");
144 len = SSL_write(ssl, buf, strlen(buf));
145 if (len <= 0) {
146 printf("消息'%s'发送失败!错误代码是%d,错误信息是'%s'\n", buf, errno, strerror(errno));
147 goto finish;
148 } else {
149 printf("消息'%s'发送成功,共发送了%d个字节!\n", buf, len);
150 }
151
152 bzero(buf, MAXBUF + 1);
153 len = SSL_read(ssl, buf, MAXBUF);
154 if (len > 0) {
155 printf("接收消息成功:'%s',共%d个字节的数据\n", buf, len);
156 } else {
157 printf("消息接收失败!错误代码是%d,错误信息是'%s'\n", errno, strerror(errno));
158 }
159 finish:
160 SSL_shutdown(ssl);
161 SSL_free(ssl);
162 close(new_fd);
163 }
164
165 close(sockfd);
166 SSL_CTX_free(ctx);
167 return 0;
168 }

测试结果:

基于openssl的单向和双向认证

基于openssl的单向和双向认证