基于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.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客户端身份。

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

参考:

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 }

测试结果:

时间: 2024-10-11 12:15:06

基于openssl的单向和双向认证的相关文章

SSL单向、双向认证的过程

在昨天的面试过程中谈单之前开发使用的EJBCA,对于认证这块我不是很了解内部的过程,晚上回来看了下  大致如下: 认证就是发消息的客户端和服务端之间相互认证确认的过程,又分为单向和双向认证:大概是下面这样的过程 一.单向认证: 1.客户端向服务器发送消息,服务器接到消息后,用服务器端的密钥库中的私钥对数据进行加密,然后把加密后的数据和服务器端的公钥一起发送到客户端: 2.客户端用服务器发送来的公钥对数据进行解密,然后在客户端使用服务器发送过来的公钥对数据加密传给服务器端,服务器用私钥对数据进行解

基于mosquitto的MQTT服务器---SSL/TLS 单向认证+双向认证

基于mosquitto的MQTT服务器---SSL/TLS 单向认证+双向认证 摘自:https://blog.csdn.net/ty1121466568/article/details/81118468 2018年07月19日 16:51:57 曾来过 阅读数:1632 本文为参考网上其他博文搭建出服务器后的步骤记录,如有冒犯,请私信!!! 目录... 3 第 1 章 安装Mosquitto. 4 1.1 方法一:手动编译安装... 4 1.2方法二:在Ubuntu下使用apt-get安装..

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

refs: SSL双向认证和SSL单向认证的区别https://www.jianshu.com/p/fb5fe0165ef2 图解 https 单向认证和双向认证!https://cloud.tencent.com/developer/news/233610 SSL/TLS 双向认证(一) -- SSL/TLS工作原理https://blog.csdn.net/wuliganggang/article/details/78428866 双向认证 SSL 协议要求服务器和用户双方都有证书.单向认证

https 单向双向认证说明_数字证书, 数字签名, SSL(TLS) , SASL

转自:https 单向双向认证说明_数字证书, 数字签名, SSL(TLS) , SASL 因为项目中要用到TLS + SASL 来做安全认证层. 所以看了一些网上的资料, 这里做一个总结. 1. 首先推荐几个文章: 数字证书: http://www.cnblogs.com/hyddd/archive/2009/01/07/1371292.html 数字证书和SSL: http://www.2cto.com/Article/201203/121534.html 数字签名: http://www.

【密码学】ssl双向认证和单向认证原理

有朋友在搞一个项目,周末有聊到一些安全性的东西,很自然会想起https,但https究竟如何实施,其原理又是什么? 基于ssl,一般的应用都是单向认证,如果应用场景要求对客户来源做验证也可以实现成双向认证. 网上google一下: 为了便于更好的认识和理解 SSL 协议,这里着重介绍 SSL 协议的握手协议.SSL 协议既用到了公钥加密技术又用到了对称加密技术,对称加密技术虽然比公钥加密技术的速度快,可是公钥加密技术提供了更好的身份认证技术.SSL 的握手协议非常有效的让客户和服务器之间完成相互

https 单向认证和双向认证配置

HTTPS 是我们开发中经常用到的通信加密技术,能有效保护我们网络访问中的安全,本文主要讲解单向 和 双向 https 的配置.关于https 的实现原理在这里我就不赘述了,附上阮一峰老师的关于https介绍几篇博客,有兴趣的童鞋可以看一看:图解SSL/TLS协议   数字签名是什么? 本文目录: 1.单向https配置 2.双向https配置 3.常见名词说明(转载) 1.单向https 配置 生成https证书命令: sudo keytool -genkey -keyalg RSA -dna

https单向认证和双向认证

单向认证: 1.clinet<--server 2.clinet-->server 1.client从server处拿到server的证书,通过公司的CA去验证该证书,以确认server是真实的: 2.从server的证书中取出公钥,对client端产生的一个密钥加密(该密钥即对称密钥).将加密后的密钥发送到server端.server端用其私钥解密出数据,即得到了对称密钥: 3.以后的交易都是http+该对称密钥加密的方式来处理: 双向认证: 与单向认证的区别就是在1.2步骤中产生的是二分之

webservice ssl 3 双向认证【openssl,jax-ws,soapui相关设置开发】

推荐使用openssl,linux基本上都自带了.windows下的openssl折腾3个小时,放弃了,各种dll不全. 直接说主题,webservice ssl双向认证. 一.证书相关生成工作 1.Key Pair Generation[生成私钥,记得密码,保存好此文件] OpenSSL> genrsa -aes256 -out privatekey.pem 2048 2.CSR Generation [生成CSR 证书请求文件] OpenSSL> req -new -sha256 -key

Openssl CA证书生成以及双向认证,及windows系统证书批量导出,android cer转bks

Openssl CA证书生成以及双向认证 首先本文主要参照这篇文章写的 http://h2appy.blog.51cto.com/609721/1181234 只是途中有些问题折腾了一下,比如openssl.cnf如何来的,这个文件在编译完openssl后,应该openssl根目录下/apps/demoCA有个,可以把他拷贝到openssl.exe同一级目录 里面有些目录配置,自己可以修改下,但是我没有修改,所以最后生成的文件路径必须按openssl.cnf里面来,至于如何编译openssl 请