TLS:接近上層應用層的握手層協議

上一篇日誌總結了TLS協議中,在握手層之下接近TCP傳輸層的記錄層協議,其主要工作是將上層握手層的消息進行分塊,封裝,添加消息頭處理。那麼,握手層發來的消息裏面都有些什麼呢?我們都知道客戶端和服務器端握手時會進行密鑰協商,協商得出一個密碼套件(或者叫預備主密鑰),密碼套件指定了客戶端和服務器端連接使用的密鑰協商算法,加密算法等,密碼套件通過密碼衍生算法轉換爲主密鑰(或者說會話密鑰),主密鑰再用同樣的密碼衍生算法轉換爲各個密鑰塊,每一塊密鑰虧對應的是參數,如初始化向量IV,AES對稱加密密鑰等。由此可見TLS協議握手層是多麼的重要。

 

四個子協議

握手層協議由四個子協議組成:握手協議、警告協議,應用層協議和密碼切換協議。其中密碼切換協議在上一篇裏簡單提到過,客戶端和服務器端在一開始建立連接時,各自都處於可讀狀態和可寫狀態,當雙方的密鑰塊準備好後,就可以向對方發送密碼切換協議消息,提示對方切換連接狀態爲可讀和可寫狀態,最後進行數據的加密操作。

握手協議消息頭

從握手層消息頭格式可以看到,由一個字節長度的子消息類型,加上三個字節長度的消息長度標識,可變長度的消息內容組成,和記錄層的消息類型一樣,不同的類型有不同的十六進制編號,上圖的記錄層消息頭中,消息類型是0x16,標識的是握手協議。

密碼切換

TLS記錄層協議在處理握手,警告和密碼切換子協議時,都沒有進行加密保護,因爲此時客戶端和服務器端還沒有完成密鑰協商,協商出一個雙方都支持的密碼套件,因此,TLS記錄層協議在處理這三個子協議時都是明文傳輸的,爲其添加上消息頭,封裝。當客戶端和服務器端協商出密碼套件後,由密碼切換子協議用來告訴TLS記錄層協議,密碼套件已經準備好了,當客戶端向服務器端發送了密碼切換協議,那麼TLS記錄層協議就可以使用密碼套件裏的算法對應用層協議消息進行保護。

警告協議

警告協議顧名思義就是告知錯誤信息,既然是握手層的子協議,當然就是在通信雙方握手失敗時進行錯誤告知,客戶端和服務器端在初次建立連鍵時,會先協商出雙方都支持的密碼套件,協商過程中可能會出現問題,如服務器端出於安全性考慮,通常會使用較高版本的TLS,而一些操作系統版本較舊的客戶端可能並不支持,那麼雙方建立握手後,就會出現TLS版本不一致,無法建立握手的問題。還有的場景就是,在雙方建立握手,會從對方的cipher suites中匹配一個密碼套件,同理服務器出於安全性問題的,都會選擇版本較高的cipher,如果客戶端版本較舊,無法匹配,那麼雙方就協商不出一個大家都支持的密碼套件,握手失敗。第三種可能大家會經常看見的,就是客戶端在握手階段還會對服務器端證書進行驗證,如果服務器證書已過期,被吊銷,都會由警告協議處理。

警告協議具體由兩部分組成,錯誤級別和錯誤信息。

應用層協議

應用層協議就是FTP,SMTP等來自TLS上層的協議,TLS可以直接對應用層協議進行保護,任何應用層的協議自身無需做什麼改變就可以引入TLS協議,來保證客戶端和服務器端傳輸的數據是安全的,沒被篡改的。

從應用層協議的消息格式可以看到,除了可變長度的消息內容外,還包含了一個消息驗證碼MAC值用來校驗消息是否被篡改,在TLS協議處理時會做MAC驗證。

子消息

TLS的握手層協議有四個子協議構成,其中的握手子協議又由多個子消息構成,這些子消息包含了通信方支持的密碼套件列表,密碼交換消息和證書籤名等,十分重要,客戶端和服務器端握手時都需要用到這些消息參數。

//握手協議子消息
enum {
	hello_request(0), client_hello(1), server_hello(2),
	certificate(11), server_key_exchange(12),
	certificate_request(13), server_hello_done(14),
	certificate_verify(15), client_key_exchange(16),
} HandshakeType

struct {
	HandshakeType msg_type;
	unit24 length;
	select (HandshakeType) {
		case hello_request:		HelloRequest;
		case client_hello:		ClientHello;
		case server_hello:		ServerHello;
		case certificate:		Certificate;
		case server_key_exchange:	ServerKeyExchange;
		case certificate_request:	CertificateReuqest;
		case server_hello_done:		ServerHelloDone;
		case certificate_verify:	CertificateVerify;
		case finished:		Finished;
	} body;
} Handshake;

握手協議的過程大致如下:

  1. 首先客戶端和服務器端互相發送Client Hello或Server Hello消息,消息中包含有各自支持的密碼套件列表,隨機數等參數,以此協商出一個雙方都支持的密碼套件。
  2. 客戶端和服務器端互相發送證書信息供對方校驗,
  3. 身份校驗完成後,雙方將協商得到的密碼套件,用密碼衍生算法+客戶端/服務器端的隨機值得到主密鑰。
  4. 握手完成,握手協議將加密參數(隨機值,主密鑰等)傳遞給記錄層協議,最後客戶端和服務器端互相發送Finished子消息。

Client Hello

首先來看Client Hello子消息,當客戶端和服務器端建立連接後,首先由客戶端發送Client Hello子消息,如前面所說,消息內包含有客戶端隨機值,支持的密碼套件列表等:

//Client Hello
struct {
	ProtocolVersion client_version; //客戶端支持的TLS/SSL版本號
	Random random; //客戶端隨機數,生成密鑰用到
	SessionID session_id; //會話ID,恢復會話用到
	CipherSuite cipher_suites<2..2^16-2>; //客戶端支持的密碼套件列表
	CompressionMethod compression_methods<1..2^8-1>; //客戶端支持的壓縮方法
	//擴展
	select (extension_present) {
		case false:
			struct { };
		case true:
			Extension extensions<0..2^16-1>;
	};
} ClientHello;

ProtocolVersion標識客戶端支持的TLS/SSL版本號,從TLS1.0到TLS1.3四個版本;Random隨機數前面提到,是生成主密鑰時用到的;SessionID標識本次客戶端和服務器端連接的會話ID,由服務器發送給客戶端,作用是用來作會話恢復用,如果下一次客戶端請求連接服務器端時,會把會話ID也一同發送過去,當服務器發現該會話ID存在與自己的服務器中時,就會恢復上一次的連接,不需要重新握手,加快了連接速度;CipherSuite標識的就是客戶端支持的密碼套件列表了。CompressionMethod標識的時客戶端支持的壓縮算法,上一篇日誌裏說到,記錄層協議裏壓縮算法基本不會使用,因爲安全問題,壓縮操作在TLS1.3版本中還被移除掉了。最後一個是可選的擴展類型Extension。

Server Hello

客戶端發送了Client Hello子消息後,會等待服務器端發送Server Hello子消息迴應,從子消息給出的參數中選擇一些匹配的項,如TLS/SSL版本號,雙方都要選擇統一支持的版本號,密碼套件,如果無法完成匹配,那麼錯誤消息會交由警告協議處理。

//Server Hello
struct {
	ProtocolVersion server_version; //服務器端支持的TLS/SSL版本號
	Random random; //服務器端隨機數,生成密鑰用到
	SessionID session_id; //會話ID,恢復會話用到
	CipherSuite cipher_suite; //服務器端支持的密碼套件列表
	CompressionMethod compression_method; //服務器端支持的壓縮方法
	//擴展
	select (extension_present) {
		case false:
			struct { };
		case true:
			Extension extensions<0..2^16-1>;
	};
} ServerHello;

可以看到,Server Hello子消息和Client Hello子消息基本相同,Session ID當服務器發現自己的緩存中不存在客戶端發來的會話ID時,表示第一次建立連接,會進行一次完整的握手過程,發送新的會話ID給客戶端。CipherSuite中匹配雙方都支持的密碼套件,通常以服務器的爲主,如果客戶端無法匹配服務器端的密碼套件,那麼握手失敗。

Certificate

服務器發送完Server Hello子消息後,接着發送Certificate子消息,顧名思義,證書,服務器發送自己的證書消息給客戶端進行身份驗證,裏面還會包含服務器公鑰,這也是證書驗證需要用到的。服務器發送的Certificate子消息是證書鏈,從服務器證書到中間證書順序構成的證書鏈,根證書一般已經集成到了客戶端瀏覽器中。

Server Key Exchange

ServerKeyExchange子消息包含了密鑰協商過程中服務器的一些參數,如DH參數(如果使用DH密鑰協商的話),DH公鑰,大質數p等,該子消息並不是一定要發送的,取決於本次通訊使用的密碼套件,例如使用RSA密碼套件的話,也就是RSA密鑰協商,過程是客戶端生成一個隨機值,即會話密鑰,用服務器公鑰加密後發送給服務器,服務器再使用自己的私鑰解密出會話密鑰,完成密鑰協商,這個過程中,並不需要服務器發送ServerKeyExchange子消息。

Server Hello Done

最後的最後,服務器發送Server Hello Done子消息給客戶端,表示服務器已經將握手階段密鑰協商,證書校驗等所需的信息基本發送完畢了,等待客戶端進行響應,客戶端接收到子消息後就可以繼續完成接下來的密鑰協商,服務器身份校驗等過程。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章