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 *filename: ssl-server.c 17 *purpose: 演示利用 OpenSSL 庫進行基於 IP層的 SSL 加密通訊的方法,這是服務器端例子 18 *wrote by: zhoulifa([email protected]) 周立發(http://zhoulifa.bokee.com) 19 Linux愛好者 Linux知識傳播者 SOHO族 開發者 最擅長C語言 20 *date time:2007-02-02 19:40 21 *Note: 任何人可以任意復制代碼並運用這些文檔,當然包括你的商業用途 22 * 但請遵循GPL 23 *Thanks to:Google 24 *Hope:希望越來越多的人貢獻自己的力量,為科學技術發展出力 25 * 科技站在巨人的肩膀上進步更快!感謝有開源前輩的貢獻! 26 *********************************************************************/ 27 int main(int argc, char **argv) 28 { 29 int sockfd, new_fd; 30 socklen_t len; 31 struct sockaddr_in my_addr, their_addr; 32 unsigned int myport, lisnum; 33 char buf[MAXBUF + 1]; 34 SSL_CTX *ctx; 35 36 if (argv[1]) 37 myport = atoi(argv[1]); 38 else 39 myport = 7838; 40 41 if (argv[2]) 42 lisnum = atoi(argv[2]); 43 else 44 lisnum = 2; 45 46 /* SSL 庫初始化 */ 47 SSL_library_init(); 48 /* 載入所有 SSL 算法 */ 49 OpenSSL_add_all_algorithms(); 50 /* 載入所有 SSL 錯誤消息 */ 51 SSL_load_error_strings(); 52 /* 以 SSL V2 和 V3 標准兼容方式產生一個 SSL_CTX ,即 SSL Content Text */ 53 ctx = SSL_CTX_new(SSLv23_server_method()); 54 /* 也可以用 SSLv2_server_method() 或 SSLv3_server_method() 單獨表示 V2 或 V3標准 */ 55 if (ctx == NULL) { 56 ERR_print_errors_fp(stdout); 57 exit(1); 58 } 59 /* 載入用戶的數字證書, 此證書用來發送給客戶端。 證書裡包含有公鑰 */ 60 if (SSL_CTX_use_certificate_file(ctx, argv[4], SSL_FILETYPE_PEM) <= 0) { 61 ERR_print_errors_fp(stdout); 62 exit(1); 63 } 64 /* 載入用戶私鑰 */ 65 if (SSL_CTX_use_PrivateKey_file(ctx, argv[5], SSL_FILETYPE_PEM) <= 0) { 66 ERR_print_errors_fp(stdout); 67 exit(1); 68 } 69 /* 檢查用戶私鑰是否正確 */ 70 if (!SSL_CTX_check_private_key(ctx)) { 71 ERR_print_errors_fp(stdout); 72 exit(1); 73 } 74 75 /* 開啟一個 socket 監聽 */ 76 if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) { 77 perror("socket"); 78 exit(1); 79 } else 80 printf("socket created\n"); 81 82 bzero(&my_addr, sizeof(my_addr)); 83 my_addr.sin_family = PF_INET; 84 my_addr.sin_port = htons(myport); 85 if (argv[3]) 86 my_addr.sin_addr.s_addr = inet_addr(argv[3]); 87 else 88 my_addr.sin_addr.s_addr = INADDR_ANY; 89 90 if (bind(sockfd, (struct sockaddr *) &my_addr, sizeof(struct sockaddr)) 91 == -1) { 92 perror("bind"); 93 exit(1); 94 } else 95 printf("binded\n"); 96 97 if (listen(sockfd, lisnum) == -1) { 98 perror("listen"); 99 exit(1); 100 } else 101 printf("begin listen\n"); 102 103 while (1) { 104 SSL *ssl; 105 len = sizeof(struct sockaddr); 106 /* 等待客戶端連上來 */ 107 if ((new_fd = 108 accept(sockfd, (struct sockaddr *) &their_addr, 109 &len)) == -1) { 110 perror("accept"); 111 exit(errno); 112 } else 113 printf("server: got connection from %s, port %d, socket %d\n", 114 inet_ntoa(their_addr.sin_addr), 115 ntohs(their_addr.sin_port), new_fd); 116 117 /* 基於 ctx 產生一個新的 SSL */ 118 ssl = SSL_new(ctx); 119 /* 將連接用戶的 socket 加入到 SSL */ 120 SSL_set_fd(ssl, new_fd); 121 /* 建立 SSL 連接 */ 122 if (SSL_accept(ssl) == -1) { 123 perror("accept"); 124 close(new_fd); 125 break; 126 } 127 128 /* 開始處理每個新連接上的數據收發 */ 129 bzero(buf, MAXBUF + 1); 130 strcpy(buf, "server->client"); 131 /* 發消息給客戶端 */ 132 len = SSL_write(ssl, buf, strlen(buf)); 133 134 if (len <= 0) { 135 printf 136 ("消息'%s'發送失敗!錯誤代碼是%d,錯誤信息是'%s'\n", 137 buf, errno, strerror(errno)); 138 goto finish; 139 } else 140 printf("消息'%s'發送成功,共發送了%d個字節!\n", 141 buf, len); 142 143 bzero(buf, MAXBUF + 1); 144 /* 接收客戶端的消息 */ 145 len = SSL_read(ssl, buf, MAXBUF); 146 if (len > 0) 147 printf("接收消息成功:'%s',共%d個字節的數據\n", 148 buf, len); 149 else 150 printf 151 ("消息接收失敗!錯誤代碼是%d,錯誤信息是'%s'\n", 152 errno, strerror(errno)); 153 /* 處理每個新連接上的數據收發結束 */ 154 finish: 155 /* 關閉 SSL 連接 */ 156 SSL_shutdown(ssl); 157 /* 釋放 SSL */ 158 SSL_free(ssl); 159 /* 關閉 socket */ 160 close(new_fd); 161 } 162 163 /* 關閉監聽的 socket */ 164 close(sockfd); 165 /* 釋放 CTX */ 166 SSL_CTX_free(ctx); 167 return 0; 168 }
1 #include <string.h> 2 #include <errno.h> 3 #include <sys/socket.h> 4 #include <resolv.h> 5 #include <stdlib.h> 6 #include <netinet/in.h> 7 #include <arpa/inet.h> 8 #include <unistd.h> 9 #include <openssl/ssl.h> 10 #include <openssl/err.h> 11 12 #define MAXBUF 1024 13 14 void ShowCerts(SSL * ssl) 15 { 16 X509 *cert; 17 char *line; 18 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 *filename: ssl-client.c 34 *purpose: 演示利用 OpenSSL 庫進行基於 IP層的 SSL 加密通訊的方法,這是客戶端例子 35 *wrote by: zhoulifa([email protected]) 周立發(http://zhoulifa.bokee.com) 36 Linux愛好者 Linux知識傳播者 SOHO族 開發者 最擅長C語言 37 *date time:2007-02-02 20:10 38 *Note: 任何人可以任意復制代碼並運用這些文檔,當然包括你的商業用途 39 * 但請遵循GPL 40 *Thanks to:Google 41 *Hope:希望越來越多的人貢獻自己的力量,為科學技術發展出力 42 * 科技站在巨人的肩膀上進步更快!感謝有開源前輩的貢獻! 43 *********************************************************************/ 44 int main(int argc, char **argv) 45 { 46 int sockfd, len; 47 struct sockaddr_in dest; 48 char buffer[MAXBUF + 1]; 49 SSL_CTX *ctx; 50 SSL *ssl; 51 52 if (argc != 3) { 53 printf 54 ("參數格式錯誤!正確用法如下:\n\t\t%s IP地址 端口\n\t比如:\t%s 127.0.0.1 80 55 \n此程序用來從某個 IP 地址的服務器某個端口接收最多 MAXBUF 個字節的消息", 56 argv[0], argv[0]); 57 exit(0); 58 } 59 60 /* SSL 庫初始化,參看 ssl-server.c 代碼 */ 61 SSL_library_init(); 62 OpenSSL_add_all_algorithms(); 63 SSL_load_error_strings(); 64 ctx = SSL_CTX_new(SSLv23_client_method()); 65 if (ctx == NULL) { 66 ERR_print_errors_fp(stdout); 67 exit(1); 68 } 69 70 /* 創建一個 socket 用於 tcp 通信 */ 71 if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 72 perror("Socket"); 73 exit(errno); 74 } 75 printf("socket created\n"); 76 77 /* 初始化服務器端(對方)的地址和端口信息 */ 78 bzero(&dest, sizeof(dest)); 79 dest.sin_family = AF_INET; 80 dest.sin_port = htons(atoi(argv[2])); 81 if (inet_aton(argv[1], (struct in_addr *) &dest.sin_addr.s_addr) == 0) { 82 perror(argv[1]); 83 exit(errno); 84 } 85 printf("address created\n"); 86 87 /* 連接服務器 */ 88 if (connect(sockfd, (struct sockaddr *) &dest, sizeof(dest)) != 0) { 89 perror("Connect "); 90 exit(errno); 91 } 92 printf("server connected\n"); 93 94 /* 基於 ctx 產生一個新的 SSL */ 95 ssl = SSL_new(ctx); 96 SSL_set_fd(ssl, sockfd); 97 /* 建立 SSL 連接 */ 98 if (SSL_connect(ssl) == -1) 99 ERR_print_errors_fp(stderr); 100 else { 101 printf("Connected with %s encryption\n", SSL_get_cipher(ssl)); 102 ShowCerts(ssl); 103 } 104 105 /* 接收對方發過來的消息,最多接收 MAXBUF 個字節 */ 106 bzero(buffer, MAXBUF + 1); 107 /* 接收服務器來的消息 */ 108 len = SSL_read(ssl, buffer, MAXBUF); 109 if (len > 0) 110 printf("接收消息成功:'%s',共%d個字節的數據\n", 111 buffer, len); 112 else { 113 printf 114 ("消息接收失敗!錯誤代碼是%d,錯誤信息是'%s'\n", 115 errno, strerror(errno)); 116 goto finish; 117 } 118 bzero(buffer, MAXBUF + 1); 119 strcpy(buffer, "from client->server"); 120 /* 發消息給服務器 */ 121 len = SSL_write(ssl, buffer, strlen(buffer)); 122 if (len < 0) 123 printf 124 ("消息'%s'發送失敗!錯誤代碼是%d,錯誤信息是'%s'\n", 125 buffer, errno, strerror(errno)); 126 else 127 printf("消息'%s'發送成功,共發送了%d個字節!\n", 128 buffer, len); 129 130 finish: 131 /* 關閉連接 */ 132 SSL_shutdown(ssl); 133 SSL_free(ssl); 134 close(sockfd); 135 SSL_CTX_free(ctx); 136 return 0; 137 }
編譯程序用如下命令:
gcc -Wall ssl-client.c -o client -lssl -lcrypto gcc -Wall ssl-server.c -o server -lssl -lcrypto
證書 privkey.pem 和 cacert.pem 生成使用如下命令(具體請參考 “OpenSSL體系下使用密鑰數字證書等”):
openssl genrsa -out privkey.pem 2048 openssl req -new -x509 -key privkey.pem -out cacert.pem -days 1095
運行程序使用如下命令:
./server 7838 1 127.0.0.1 cacert.pem privkey.pem ./client 127.0.0.1 7838
運行截圖如下:
服務端:
客戶端:
參考資料:
1、http://blog.csdn.net/thq0201/article/details/6766449#
2、http://blog.chinaunix.net/uid-20682147-id-76392.html
3、http://zhoulifa.bokee.com