概述
- SSL/TLS是世界上應用最廣泛的密碼通信方法。比如,在網(wǎng)上商城輸入信用卡卡號時,Web瀏覽器就會使用SSL/TLS進行密碼通信。使用SSL/TLS可以對通信對象進行認證,還可以確保通信內(nèi)容的機密性。TLS相當于SSL的后續(xù)版本。
- SSL (Secure Sockets Layer)安全套接層協(xié)議 :由Netscape公司開發(fā)。協(xié)議的第一個版本從未發(fā)布過,第二個版于1994年11月發(fā)布,但是存在嚴重漏洞,最終退出歷史舞臺。1995年年底,第三個版本SSL 3.0發(fā)布,此版本是完全重新設(shè)計的協(xié)議,因此該設(shè)計一直沿用到今天。
- TLS(Transport Layer Security)安全傳輸層協(xié)議:1996年5月,TLS工作組成立,開始將SSL從Netscape遷移至IETF。最終,TLS 1.0于1999年1月問世,與SSL 3.0版本相比修改并不大,但還是改名為TLS。2006年4月,TLS 1.1發(fā)布,修復了一些關(guān)鍵的安全性問題。2008年8月,TLS 1.2發(fā)布,該版本添加了對已驗證加密的支持,并且基本上刪除了協(xié)議說明中所有硬編碼的安全基元,使協(xié)議完全彈性化。
SSL/TLS、HTTP、HTTPS關(guān)系
- HTTPS是安全版本的HTTP,簡單理解 HTTPS = HTTP + SSL/TLS,即HTTPS就是使用SSL/TLS協(xié)議對HTTP報文進行了加密處理。
SSL/TLS單向認證和雙向認證
- 單向認證指的是通信雙方只校驗一方發(fā)送過來的數(shù)字證書,另一方不校驗。通常是客戶端根據(jù)服務器傳過來的證書信息校驗服務器的合法性。
- 雙向認證指的是在通信雙方都要校驗對方發(fā)送過來的數(shù)字證書,一般應用于對安全性要求更高的領(lǐng)域。
SSL/TLS握手過程
- 這里先重點介紹下SSL/TLS雙向認證的握手過程,SSL/TLS單向認證后面也會提到,并進行比對。
- TLS握手涉及到加密算法和數(shù)字證書的知識。不了解的可參考我的另外兩篇文章。加密算法簡介 數(shù)字證書簡介
- 握手圖示 圖中虛線部分是雙向認證時需要額外發(fā)送的消息。
- 備注:不同的密鑰協(xié)商算法計算預備主密鑰的方法不一樣,這里展示的是RSA密鑰協(xié)商算法計算預備主密鑰的方法。
-
握手詳解
-
[1] Client Hello
- 客戶端發(fā)送TLS版本,支持的加密套件列表給服務端,并生成客戶端隨機數(shù)發(fā)送給服務端。
- Version : 表示客戶端支持的SSL/TLS協(xié)議版本
- Random : 客戶端隨機數(shù)
- Session ID : 和會話恢復有關(guān)
- Cipher Suites : 客戶端支持的密碼套件列表
- Compression Methods : 客戶端支持的壓縮方法
- Extension : 擴展項
-
[2] Server Hello
- 服務端確認TLS版本,選擇使用的加密套件,生成服務端隨機數(shù)發(fā)送給客戶端。
- Version : 服務端根據(jù)客戶端傳遞的版本號,選擇一個雙方都支持的版本
- Random : 服務端隨機數(shù)
- Session ID : 和會話恢復有關(guān)
- Cipher Suite : 根據(jù)客戶端傳遞過來的密碼套件列表,選擇一個雙方都支持的密碼套件
- Compression Method : 壓縮算法
- Extension : 擴展項
-
[3] Server Certificate
- 該消息是可選的。根據(jù)協(xié)商出來的密碼套件,服務端選擇是否發(fā)送證書消息。在HTTPS網(wǎng)站中一般服務器會發(fā)送證書,如果協(xié)商出的密碼套件是DH_anon或者ECDH_anon,則服務器不發(fā)送該消息,可能會遇到中間人攻擊。
- 服務器發(fā)送證書一般有兩個目的:一是進行身份驗證,二是證書中包含服務器的公鑰,該公鑰結(jié)合密碼套件的密鑰協(xié)商算法協(xié)商出預備主密鑰。
-
[4] Server Key Exchange
- 該消息是有條件才發(fā)送的。如果證書包含的信息不足以進行密鑰交換,那么必須發(fā)送該消息。
- 下列的密碼套件,服務端會發(fā)送Server Key Exchange消息
- DHE DSS、DHE RSA 、ECDHE ECDSA 、ECDHE RSA
- 上述密碼套件都是使用臨時DH/ECDH密碼協(xié)商算法,客戶端每次連接服務器的時候,服務器會發(fā)送動態(tài)DH信息,這些信息不存在服務端證書中,需要通過Server Key Exchange消息傳遞,傳遞的DH信息需要使用服務器的私鑰進行簽名,該私鑰和證書中包含的服務器公鑰是一對。
- 下列的密鑰套件,服務端也會發(fā)送Server Key Exchange消息
- DH_anon、ECDH_anon
- 使用的是靜態(tài)DH/ECDH協(xié)商算法,但由于沒有證書,所以需要Server Key Exchange消息傳遞相關(guān)DH信息,傳遞的DH消息需要使用服務器的私鑰進行簽名
- 下列的密碼套件不允許服務器發(fā)送Server Key Exchange消息
- RSA、DH_DSS、DH_RSA
- 對于RSA密碼套件,客戶端計算出預備主密鑰,然后使用服務器RSA公鑰加密發(fā)送給服務端,服務端反解出預備主密鑰即可,沒有Server Key Exchange子消息也能完成密鑰協(xié)商。
- 對于DH_DSS/DH_RSA密鑰套件,證書中已經(jīng)包含靜態(tài)DH信息,無須服務端額外發(fā)送Server Key Exchange子消息,客戶端和服務端各協(xié)商出預備主密鑰的一半密鑰,結(jié)合起來就是預備主密鑰。目前已經(jīng)很少看到這樣的密碼套件,CA機構(gòu)也不會在簽發(fā)證書時包含靜態(tài)DH信息。
-
[5] Certificate Request
- 該消息表示想要收到客戶端的證書,一般是雙向認證時有該消息。
-
[6] Server Hello Done
- 表示服務端發(fā)送了足夠的消息,接下來等待和客戶端協(xié)商出預備主密鑰。
-
[7] Client Certificate
- 發(fā)送客戶端證書,一般是雙向認證時會發(fā)送。
-
[8] Client Key Exchange
- 消息結(jié)構(gòu)
-
struct { select(KeyExchangeAlgorithm){ case rsa: EncryptedPreMasterSecret; case dhe_dss: case dhe_rsa: case df_dss: case dh_rsa: case dh_anon: ClientDiffieHellmanPublic; case ec_diffie)hellman: ClientECHiffieHellmanPublic; }exchange_keys; } ClientKeyExchange;
- 針對不同的密碼套件,該消息一般有三種處理邏輯
-
EncryptedPreMasterSecret
- 如果 RSA算法用于身份驗證和密鑰交換,客戶端會生成一個48字節(jié)的預備主密鑰,然后用服務器證書中的公鑰加密并發(fā)送給服務器端。最終發(fā)送的消息就是Encrypted PreMaster。
-
ClientDiffieHellmanPublic
- 如果密碼套件中密鑰協(xié)商算法是 DH算法,客戶端必須發(fā)送 DH公鑰給服務器端。
-
ClientECDiffieHellmanPublic
- 如果協(xié)商出的密碼套件密鑰協(xié)商算法是 ECDHE,客戶端需要發(fā)送 ECDH公鑰。
-
[9] 計算主密鑰和密鑰塊
- 計算預備主密鑰,不同的密鑰協(xié)商算法,計算方法不同。
- RSA密鑰協(xié)商算法
- RSA密鑰協(xié)商算法,生成預備主密鑰比較簡單,直接生成預備主密鑰。
- 然后使用服務端證書中的公鑰加密預備主密鑰,將加密后的預備主密鑰發(fā)送給服務端。
- 服務端接收到加密后的預備主密鑰后,使用私鑰解密,得到預備主密鑰。
- DH密鑰協(xié)商算法
- 服務器端生成DH參數(shù)和服務器DH密鑰對,用RSA私鑰簽名DH參數(shù)和服務器DH公鑰,最后將簽名值、DH參數(shù)、服務器DH公鑰發(fā)送給客戶端。
- 客戶端通過服務器發(fā)送的證書中的RSA的公鑰驗證簽名,獲取到DH參數(shù)和服務器DH公鑰。
- 客戶端通過DH參數(shù)生成客戶端的DH密鑰對,并將客戶端DH公鑰發(fā)送給服務器端。
- 客戶端通過客戶端DH私鑰和服務器端DH公鑰計算出預備主密鑰。
- 服務器端接收到客戶端的DH公鑰,結(jié)合服務器的DH私鑰計算出預備主密鑰。
- 最終客戶端和服務器端計算出的預備主密鑰能夠保持一致。
- 雙方都拿到預備主密鑰后,就可以根據(jù)以下公式計算出主密鑰
- master_secret = PRF(pre_master_secret, “master secret”, ClientHello.random + ServerHello.random)
- 主密鑰的長度固定是48字節(jié)。而預備主密鑰的長度取決于密碼套件算法,如果 RSA算法用來協(xié)商密鑰,預備主密鑰的長度是 48字節(jié);如果 DH/ECDH算法用來協(xié)商密鑰,長度取決于 DH /ECDH算法的公鑰。
- 計算出主密鑰后,還需要根據(jù)主密鑰計算出密鑰塊。密鑰塊主要有六個
- Client MAC Key
- Server MAC Key
- Client Key
- Server Key
- Client IV
- Server IV
- MAC Key主要用于數(shù)據(jù)的完整性校驗,Key用于加密數(shù)據(jù)。IV作為加密算法的初始化向量。
-
[10] Certificate verify
- 證書驗證。雙向認證時有該消息,這個時候客戶端已經(jīng)把證書發(fā)送給服務端了,但客戶端還要向服務器證明證書中對應的私鑰的正確和自己是會話持有者。
-
[11] Change Cipher Spec
- 通知對方,可以用協(xié)商好的密鑰進行通信了。
-
[12] Finished [Encrypted Handshake Message]
- 確認所有握手消息沒有被篡改。
-
[1] Client Hello
Nginx搭建HTTPS網(wǎng)站
-
接下來用Nginx搭建一個HTTPS網(wǎng)站,實現(xiàn)SSL/TLS的雙向認證。
-
打開Nginx的配置文件/usr/local/nginx/conf/nginx.conf,HTTPS服務默認是注釋的,去掉注釋,并且需要再添加兩個字段ssl_verify_client 和 ssl_client_certificate
-
# HTTPS server server { listen 10088 ssl; server_name localhost; # 服務端證書 ssl_certificate server.crt; # 服務端證書密鑰 ssl_certificate_key server.key; ssl_session_cache shared:SSL:1m; ssl_session_timeout 5m; # 表示開啟客戶端證書校驗 ssl_verify_client on; # 放置CA證書 ssl_client_certificate ca.crt; ssl_ciphers HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers on; location / { root html; index index.html index.htm; } }
-
這里需要用到三張證書,CA證書,服務端證書和客戶端證書,可以通過OpenSSL命令行工具來生成。
-
CA證書
- 生成RSA私鑰
- openssl genrsa -out ca.key 2048
- 生成CA證書
- openssl req -new -x509 -key ca.key -out ca.crt -days 365
-
服務端證書
- 生成服務端密鑰
- openssl genrsa -out server.key 2048
- 生成證書請求文件
- openssl req -new -key server.key -out server.csr
- 使用CA證書簽發(fā)服務端證書
- openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out server.crt -days 365
-
客戶端證書
- 生成客戶端密鑰
- openssl genrsa -out client.key 2048
- 生成證書請求文件
- openssl req -new -key client.key -out client.csr
- 使用CA證書簽發(fā)客戶端證書
- openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out client.crt -days 365
- 將客戶端證書和私鑰合并成pfx證書
- openssl pkcs12 -export -in client.crt -inkey client.key -out client.pfx
-
服務端證書以及私鑰和CA證書生成后,放到Nginx配置文件所在目錄下,然后將客戶端的pfx證書拷貝到windows平臺下,打開Edge瀏覽器的設(shè)置界面,在隱私、搜索和服務欄找到管理證書,然后把剛才的client.pfx證書導入即可。這里注意下,導入后要關(guān)掉瀏覽器重新打開。
-
然后去訪問對應https網(wǎng)站,瀏覽器會彈出對話框,讓我們選擇對應的客戶端證書。只有選擇證書并確認后,才可以成功訪問到對應的https網(wǎng)站。沒有客戶端證書或者未成功選擇證書,都是無法訪問的。如果是單向認證的話,就不需要客戶端證書了。
WireShark抓包分析SSL/TLS握手過程
-
接下來就用WireShark抓包工具詳細分析SSL/TLS雙向認證的握手過程。
-
先看下整體流程,抓包可以看到,在進行SSL/TLS握手前,先要進行TCP的三次握手,建立連接。關(guān)于TCP的握手過程,這里就不介紹了,可參考我的這一篇文章 抓包分析TCP協(xié)議
-
接下來對SSL/TLS握手的每條信息,詳細看一下
-
Client Hello
- Client Hello消息中有TLS版本號,客戶端生成的隨機數(shù),以及客戶端支持的密碼套件等信息。
- Client Hello消息中有TLS版本號,客戶端生成的隨機數(shù),以及客戶端支持的密碼套件等信息。
-
Server Hello
- Client Hello消息中有TLS版本號,服務端生成的隨機數(shù),以及服務端最終確認要使用的密碼套件等信息。
- Client Hello消息中有TLS版本號,服務端生成的隨機數(shù),以及服務端最終確認要使用的密碼套件等信息。
-
Server Certificate
- 服務端發(fā)送自己的證書
- 服務端發(fā)送自己的證書
-
Server Key Exchange
-
Certificate Request
- 表示服務端想要收到客戶端的證書
- 表示服務端想要收到客戶端的證書
-
Server Hello Done
- 服務端請求結(jié)束
- 服務端請求結(jié)束
-
Client Certificate
- 客戶端發(fā)送自己的證書
- 客戶端發(fā)送自己的證書
-
Client Key ExChange
- 上面選擇的加密套件是 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,密鑰協(xié)商算法是ECDHE,因此這里發(fā)送的消息是ClientECDiffieHellmanPublic
- 如果選擇的加密套件密鑰協(xié)商算法為RSA,比如 TLS_RSA_WITH_AES_128_GCM_SHA256 加密套件,則對應發(fā)送的消息就為 EncryptedPreMasterSecret。
- 上面選擇的加密套件是 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,密鑰協(xié)商算法是ECDHE,因此這里發(fā)送的消息是ClientECDiffieHellmanPublic
-
Certificate Verify
- 客戶端證書驗證
- 客戶端證書驗證
-
Change Cipher Spec
- 通知對方,可以用協(xié)商好的密鑰進行通信了。
- 通知對方,可以用協(xié)商好的密鑰進行通信了。
-
Finished [Encrypted Handshake Message]
- 密鑰協(xié)商完成
- 密鑰協(xié)商完成
-
Application Data
- 用協(xié)商好的密鑰進行加密通信
- 用協(xié)商好的密鑰進行加密通信
-
這就是整個SSL/TLS協(xié)議握手的過程。
-
上面展示的是SSL/TLS雙向認證的過程,可以關(guān)掉Nginx對客戶端的證書校驗,實現(xiàn)單向認證。
文章來源:http://www.zghlxwxcb.cn/news/detail-452570.html
-
這是單向認證時抓的包,可以與上面的雙向認證比對下,主要少了服務端請求客戶端發(fā)送證書的消息Certificate Request,客戶端發(fā)送證書消息Client Certificate,客戶端證書校驗消息Certificate verify。其他流程和雙向認證是一樣的。文章來源地址http://www.zghlxwxcb.cn/news/detail-452570.html
C/C++代碼實現(xiàn)SSL/TLS通信
- 我們還可以使用C/C++代碼來實現(xiàn)SSL/TLS的通信
-
服務端代碼
-
#include <stdio.h> #include <stdlib.h> #include <memory.h> #include <errno.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #include <openssl/rsa.h> #include <openssl/crypto.h> #include <openssl/x509.h> #include <openssl/pem.h> #include <openssl/ssl.h> #include <openssl/err.h> #include <openssl/rand.h> #define CERTF "server.crt" /*服務端的證書(需經(jīng)CA簽名)*/ #define KEYF "server.key" /*服務端的私鑰(建議加密存儲)*/ #define CACERT "ca.crt" /*CA 的證書*/ #define PORT 10088 /*準備綁定的端口*/ int main (){ SSL_load_error_strings(); /*為打印調(diào)試信息作準備*/ OpenSSL_add_ssl_algorithms(); /*初始化*/ SSL_CTX* ctx = SSL_CTX_new(TLSv1_server_method()); if(ctx == NULL) { printf("SSL_CTX_new failed.\n"); return -1; } SSL_CTX_set_verify(ctx,SSL_VERIFY_PEER,NULL); /*是否驗證客戶端證書,雙向認證時開啟*/ SSL_CTX_load_verify_locations(ctx,CACERT,NULL); /*若驗證,則放置CA證書*/ if (SSL_CTX_use_certificate_file(ctx, CERTF, SSL_FILETYPE_PEM) <= 0) { ERR_print_errors_fp(stderr); return -1; } if (SSL_CTX_use_PrivateKey_file(ctx, KEYF, SSL_FILETYPE_PEM) <= 0) { ERR_print_errors_fp(stderr); return -1; } if (!SSL_CTX_check_private_key(ctx)) { printf("Private key does not match the certificate public key\n"); return -1; } SSL_CTX_set_cipher_list(ctx,"RC4-MD5"); /*開始正常的TCP socket過程.*/ printf("Begin TCP socket...\n"); int listenSock = socket(AF_INET, SOCK_STREAM, 0); if(listenSock == -1){ perror("socket"); return -1; } struct sockaddr_in sa_serv; memset (&sa_serv, 0, sizeof(sa_serv)); sa_serv.sin_family = AF_INET; sa_serv.sin_addr.s_addr = INADDR_ANY; sa_serv.sin_port = htons(PORT); if(bind(listenSock, (struct sockaddr*) &sa_serv, sizeof (sa_serv)) == -1){ perror("bind"); return -1; } /*接受TCP鏈接*/ if(listen (listenSock, 5) == -1){ perror("listen"); return -1; } struct sockaddr_in sa_cli; socklen_t client_len = sizeof(sa_cli); int connfd = accept (listenSock, (struct sockaddr*) &sa_cli, &client_len); if(connfd == -1){ perror("accept"); close (listenSock); return -1; } printf ("[%s:%d] connected...\n", inet_ntoa(sa_cli.sin_addr), sa_cli.sin_port); /*TCP連接已建立,進行服務端的SSL過程. */ printf("Begin server side SSL\n"); SSL* ssl = SSL_new (ctx); if(ssl == NULL){ printf("SSL_new failed.\n"); return -1; } SSL_set_fd (ssl, connfd); int sslSock = SSL_accept (ssl); if(sslSock == -1){ ERR_print_errors_fp(stderr); return -1; } printf("SSL_accept finished\n"); /*打印所有加密算法的信息(可選)*/ printf ("SSL connection using %s\n", SSL_get_cipher(ssl)); /*得到客戶端的證書并打印些信息(可選) */ X509* client_cert = SSL_get_peer_certificate (ssl); if (client_cert != NULL) { printf ("Client certificate:\n"); char* subStr = X509_NAME_oneline(X509_get_subject_name (client_cert), 0, 0); if(subStr == NULL){ printf("X509_NAME_oneline subject failed.\n"); return -1; } printf ("subject: %s\n", subStr); //Free (subStr); char* issStr = X509_NAME_oneline(X509_get_issuer_name (client_cert), 0, 0); if(issStr == NULL){ printf("X509_NAME_oneline subject failed.\n"); return -1; } printf ("issuer: %s\n", issStr); //Free (issStr); X509_free (client_cert);/*如不再需要,需將證書釋放 */ }else{ printf ("Client does not have certificate\n"); } char buf[4096] = {0}; /* 數(shù)據(jù)交換開始,用SSL_write,SSL_read代替write,read */ int readSize = SSL_read(ssl, buf, sizeof(buf) - 1); if(readSize == -1){ ERR_print_errors_fp(stderr); return -1; } printf ("SSL_read buf[%d] = {%s}\n", readSize, buf); if(SSL_write (ssl, "Welcome to Connect to Server!", strlen("Welcome to Connect to Server!")) == -1){ ERR_print_errors_fp(stderr); return -1; } shutdown (connfd, 2); SSL_free (ssl); SSL_CTX_free (ctx); return 0; }
-
-
客戶端代碼
-
#include <stdio.h> #include <stdlib.h> #include <memory.h> #include <errno.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #include <openssl/rsa.h> #include <openssl/crypto.h> #include <openssl/x509.h> #include <openssl/pem.h> #include <openssl/ssl.h> #include <openssl/err.h> #include <openssl/rand.h> /*所有需要的參數(shù)信息都在此處以#define的形式提供*/ #define CERTF "client.crt" /*客戶端的證書(需經(jīng)CA簽名)*/ #define KEYF "client.key" /*客戶端的私鑰(建議加密存儲)*/ #define CACERT "ca.crt" /*CA 的證書*/ #define PORT 10088 /*服務端的端口*/ #define SERVER_ADDR "127.0.0.1" /*服務段的IP地址*/ int main () { /*初始化*/ OpenSSL_add_ssl_algorithms(); //載入所有SSL錯誤消息 SSL_load_error_strings(); /*采用什么協(xié)議(SSLv2/SSLv3/TLSv1)在此指定*/ /*申請SSL會話環(huán)境*/ SSL_CTX *ctx = SSL_CTX_new(TLSv1_client_method()); if(ctx == NULL){ printf("SSL_CTX_new failed!\n"); return -1; } /*是否驗證服務端證書*/ SSL_CTX_set_verify(ctx,SSL_VERIFY_PEER,NULL); /*若驗證對方,則放置CA證書*/ SSL_CTX_load_verify_locations(ctx,CACERT,NULL); /*加載自己的證書*/ if (SSL_CTX_use_certificate_file(ctx, CERTF, SSL_FILETYPE_PEM) <= 0) { ERR_print_errors_fp(stderr); return -1; } /*加載自己的私鑰,以用于簽名*/ if (SSL_CTX_use_PrivateKey_file(ctx, KEYF, SSL_FILETYPE_PEM) <= 0) { ERR_print_errors_fp(stderr); return -1; } /*調(diào)用了以上兩個函數(shù)后,檢驗一下自己的證書與私鑰是否配對*/ if (!SSL_CTX_check_private_key(ctx)) { printf("Private key does not match the certificate public key\n"); return -1; } /*以下是正常的TCP socket建立過程*/ printf("Begin tcp socket...\n"); int sock = socket(AF_INET, SOCK_STREAM, 0); if(sock == -1){ perror("socket"); return -1; } struct sockaddr_in sa; memset (&sa, 0, sizeof(sa)); sa.sin_family = AF_INET; sa.sin_addr.s_addr = inet_addr(SERVER_ADDR); /* Server IP */ sa.sin_port = htons(PORT); /* Server Port number */ if(connect(sock, (struct sockaddr*) &sa, sizeof(sa)) == -1){ perror("connect"); return -1; } /* TCP 鏈接已建立.開始 SSL 握手過程 */ printf("Begin SSL negotiation \n"); /*申請一個SSL套接字*/ SSL* ssl = SSL_new (ctx); if(ssl == NULL){ printf("SSL_new failed.\n"); return -1; } /*綁定讀寫套接字*/ SSL_set_fd(ssl, sock); if(SSL_connect(ssl) == -1){ ERR_print_errors_fp(stderr); return -1; } /*打印所有加密算法的信息(可選)*/ printf ("SSL connection using %s\n", SSL_get_cipher(ssl)); /*得到服務端的證書并打印些信息(可選) */ X509* server_cert = SSL_get_peer_certificate (ssl); if(server_cert == NULL){ printf("SSL_get_peer_certificate failed.\n"); return -1; } printf ("Server certificate:\n"); char* subStr = X509_NAME_oneline(X509_get_subject_name (server_cert),0,0); if(subStr == NULL){ printf("X509_NAME_oneline subject failed.\n"); return -1; } printf("subject: %s\n", subStr); // Free(subStr); char* issStr = X509_NAME_oneline (X509_get_issuer_name(server_cert),0,0); if(issStr == NULL){ printf("X509_NAME_oneline issuer failed.\n"); return -1; } printf ("issuer: %s\n", issStr); // Free (issStr); X509_free(server_cert); /*如不再需要,需將證書釋放 */ /* 數(shù)據(jù)交換開始,用SSL_write,SSL_read代替write,read */ printf("Begin SSL data exchange\n"); if(SSL_write(ssl, "Hello, I am client!", strlen("Hello, I am client!")) == -1){ ERR_print_errors_fp(stderr); return -1; } char buf[4096] = {0}; int readSize = SSL_read(ssl, buf, sizeof(buf) - 1); if(readSize == -1){ ERR_print_errors_fp(stderr); return -1; } printf ("SSL_read buf[%d] = {%s}\n", readSize, buf); SSL_shutdown (ssl); /* send SSL/TLS close_notify */ shutdown (sock, 2); SSL_free (ssl); SSL_CTX_free (ctx); return 0; }
-
-
Makefile
-
all: server client server: server.cpp g++ -o server server.cpp -lssl -lcrypto client: client.cpp g++ -o client client.cpp -lssl -lcrypto clean: rm server client
-
參考資料
- 《HTTPS權(quán)威指南》
- 《深入淺出HTTPS從原理到實戰(zhàn)》
- 《圖解密碼技術(shù)》
到了這里,關(guān)于SSL/TLS協(xié)議詳解 - https為什么比http更安全的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!