一、前言html
最近工做涉及到https,須要修改nginx的openssl模塊,引入keyless方案。關於keyless能夠參考CloudFlare的官方博客:nginx
在openssl的基礎上修改私鑰校驗過程,所以須要對openssl的認證認證流程須要熟悉一下。SSL中涉及到不少概念,開始都不清楚,例如CA,數字簽名、數字證書等,本文主要是總結SSL認證的基礎知識,openssl的單向和雙向認證流程,並寫代碼測試。算法
二、基礎知識安全
SSL:Secure Socket Layer,安全套接字層,它位於TCP層與Application層之間。提供對Application數據的加密保護(密文),完整性保護(不被篡改)等安全服務,它缺省工做在TCP 443 端口,通常對HTTP加密,即俗稱的HTTPS。服務器
TLS:Transport Layer Secure,更關注的是提供安全的傳輸服務,它很靈活,若是可能,它能夠工做在TCP,也能夠UDP (DTLS),也能夠工做在數據鏈路層,好比802.1x EAP-TLS。less
關於SSL/TSL能夠參考:http://www.ruanyifeng.com/blog/2014/02/ssl_tls.htmlsocket
公鑰:你們公用的,能夠經過電子郵件發佈,經過網站讓別人下載,公鑰其用來加密和驗章。工具
私鑰:就是本身的私有的,必須很是當心保存,最好加上 密碼,私鑰是用來解密和簽章。測試
數字簽名:將報文按雙方約定的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協議的基本思路是採用公鑰加密法,也就是說,客戶端先向服務器端索要公鑰,而後用公鑰加密信息,服務器收到密文後,用本身的私鑰解密。
三、認證流程
單向認證:只須要驗證SSL服務器身份,不須要驗證SSL客戶端身份。
雙向認證:要求服務器和客戶端雙方都有證書,客戶端須要校驗服務端,服務端也須要校驗客戶端。
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
四、測試代碼
證書生成過程:
(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證書出現錯誤處理:
單向認證:
客戶端代碼:不須要配置證書和私鑰
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 }
測試結果: