首页 > 代码库 > 基于openssl的单向和双向认证

基于openssl的单向和双向认证

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.html 和 http://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客户端身份。

技术分享

 

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

技术分享

参考:

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  

单向认证:

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

  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 }

测试结果:

技术分享

技术分享

双向认证:

客户端代码:需要设置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的单向和双向认证