TLS:總結下ClientHello和ServerHello中的擴展項

目錄

TLS/SSL協議擴展

SNI服務器名稱指示

Max Fragment Length分塊最大數量

Status Request證書狀態請求

Signature Algorithm簽名和摘要算法

ALPN應用層協議協商擴展


以前的我一直很少在意擴展項這部分(除了證書擴展外),但是後來接觸的TLS/SSL協議越多,發現擴展項很多地方都出現,而且挺重要的,如證書鏈結構裏的CRL分發點,用來標識一個URL地址,提供下載證書吊銷列表來做證書吊銷校驗。在CRL結構中也有擴展項,如CRL Number擴展,頒發機構標識符擴展等。同樣是提供證書吊銷狀態校驗的OCSP服務也是提供有可選的擴展項,例如Nonce隨機數擴展,發送OCSP校驗的一方在請求中放置一個隨機數,來標識每一次請求都是唯一的。在LTS握手協議裏面的Client Hello和Server Hello子消息中也有不少可選的擴展項,作用也很重要,客戶端和服務器端之間的擴展項也有一定的聯繫,所以這篇日誌就把Client Hello和Server Hello的擴展項總結一下,擴展項最顯著的一個特點就是可以讓客戶端和服務器端在不更新TLS協議版本的基礎上使用更多的其他功能。

 

TLS/SSL協議擴展

在TLS握手層協議中提供了可選的擴展項,擴展結構由擴展類型的具體的擴展數據兩部分組成:

//擴展項結構
struct {
	ExtensionType extension_type;
	opaque extension_data<0..2^16-1>;
} Extension;

擴展類型ExtensionType是一個枚舉類型:

//擴展類型
enum {
	server_name(0), //服務器名稱
	max_fragment_length(1), //最大fragment長度協商
	client_certificate_url(2), //客戶端證書URL
	trusted_ca_keys(3),
	truncated_hmac(4), //截斷的HMAC
	status_request(5), (65535) //支持的證書狀態請求
	supported_groups(10),
	ec_point_formats(11),
	signature_algorithms(13), //支持的簽名算法和摘要算法
	application_layer_protocol_negotiation(16), //支持的應用層協議
	signed_certificate_timestamp(18), //支持證書透明度機制
	extened_master_secret(23), //擴展的主密鑰
	SessionTicketTLS(35), //支持沒有狀態的會話恢復
	renegotiation_info(65281), //支持安全的重協商
} ExtensionType;

裏面列出了一些TLS握手層協議支持的擴展項,例如擴展支持證書吊銷狀態請求,擴展簽名算法和摘要算法,擴展支持證書透明度機制等,可以說功能十分豐富(且都是前面接觸過的),上圖中括號裏的數字表示的是擴展類型的編號,擴展類型佔用兩個字節的固定空間,擴展數據佔用的空間則是可變的。在TLS握手層協議中,擴展的使用通常是先由客戶端向服務器端發送擴展列表,裏面是客戶端支持的擴展項,擴展列表包含在Client Hello子消息中,服務器接收到自消息後,逐一解析匹配其中的擴展項,並在Server Hello子消息中返回自己能匹配的擴展項。要注意,Server Hello子消息中響應的擴展項必須是Client Hello中存在的,可以響應多個,但不能出現響應客戶端請求擴展中不存在的擴展項,否則就會產生錯誤。

      如果Client Hello請求擴展項中出現服務器不支持的擴展項,那麼服務器可以選擇忽略處理這些不支持的擴展項,而不是產生錯誤,中斷握手過程。這一點必須記住,擴展項這一部分就不是客戶端去“兼容”服務器了,而是服務器向下“兼容”客戶端,如果客戶端發來的擴展項服務器支持,那麼響應,如果不支持,服務器可以選擇不處理。

 

SNI服務器名稱指示

SNI擴展是用來解決一臺服務器綁定多個域名,申請了多張證書,在建立連接的身份驗證階段服務器因爲不知道客戶端瀏覽器訪問的是哪個域名,所以無法判斷該發送哪個證書的問題。即服務器使用到了“虛擬主機”的場景。

虛擬主機

虛擬主機即把一個物理服務器劃分出多個虛擬的服務器,讓其可以提供多個網站服務。一個服務器IP可以綁定多個域名,假設一臺服務器綁定了www.zzzjustin1.comwww.zzzjustin2.com兩個域名,某一用戶訪問www.zzzjustin1.com域名時,通過DNS域名解析服務查出了服務器的IP地址,接着客戶端向服務器端發送TLS請求連接,由於在完成握手階段前,客戶端不會發送應用層的數據,所以服務器並不知道客戶端訪問了哪個域名。

所以在TLS/SSL協議中增加了SNI服務器名稱指示擴展,在握手協議的Client Hello子消息中,客戶端啓用這個擴展,將要訪問的服務器名(域名)也一起發送,相當於提前告訴服務器我要訪問的域名,服務器拿到域名後,將對應的證書響應給客戶端,完成服務器身份校驗。

Max Fragment Length分塊最大數量

MaxFragmentLength擴展的結構如下,是一個枚舉類型:

enum {

        2^9(1), 2^10(2), 2^11(3), 2^12(4), (255)

} MaxFragmentLength

 

上一篇日誌裏總結到TLS記錄層協議時,說到它會將上層握手層協議的消息進行分塊處理,最大的分塊大小爲2^14字節,有時候因爲帶寬限制的問題或者爲了節省內存,需要協商出一個小的最大分塊長度,所以使用到了該擴展,協商出來的最大長度有效期在一個Session會話期間,包括恢復的session。

Status Request證書狀態請求

證書狀態擴展用來提供證書吊銷查詢功能,當客戶端驗證完服務器證書,確認該證書中的服務器主機,公鑰等信息後,身份驗證過程其實還沒有完成,還記得證書吊銷狀態吧,有可能你校驗的證書已經過期了,並且處於吊銷狀態,那麼你前面校驗的信息都是無效的。證書吊銷狀態查詢方式有兩種,還記得吧,CRL和OCSP,通常會選擇使用OCSP在線證書狀態協議,因爲使用CRL證書吊銷列表來校驗的話,第一個問題是,CRL必須下載完整的CRLs文件,隨着一個CA機構簽發的證書越來越多,因過期或其他原因而被吊銷的證書也會越來越多,導致CRLs文件跟着越來越大,影響下載的速度,最終降低了握手效率。第二個問題是CRL吊銷列表非實時更新的,有的瀏覽器會去緩存CRLs文件(爲了解決CRLs文件太大影響握手效率問題),如果某一證書剛剛被吊銷後,因沒有及時更新而導致證書校驗出問題,被吊銷的證書還被校驗爲有效的,會出現安全風險。還有一個比較重要的問題是CRL證書吊銷列表校驗是同步操作,也就是說,在完成CRLs文件下載,校驗過程後,握手過程才能繼續,否則會被一直阻塞。

現在通常使用的是OCSP在線證書狀態協議方式來校驗證書的吊銷狀態,TLS/SSL協議也爲此定義了status_request擴展,OCSP比CRL簡單得多,只需要客戶端向OCSP服務提供方發送校驗請求(如果使用OCSP套封的話,則是由服務器來發送OCSP請求),然後OCSP服務提供方根據查詢請求裏的查詢條件,返回該證書的吊銷狀態。

在status_request擴展中包含有證書狀態請求結構(CertificateStatusRequest)和服務器相應的證書狀態結構(CertificateStatus)。首先開看請求結構:

//請求結構
enum { ocsp(1), (255) } CertificateStatusType;

struct {
	ResponderID responder_id_list<0..2^16-1>;
	Extensions request_extensions;
} OCSPStatusRequest;

struct {
	CertificateStatusType status_type;
	select (status_type) {
		case ocsp: OCSPStatusRequest;
	} request;
} CertificateStatusRequest;

可以看到,在請求結構中定義的是OCSPStatusRequest,表明status_reuqest擴展提供的是OCSP服務。客戶端向服務器發送該擴展,之後服務器響應一個CertificateStatus結構:

//響應結構
opaque OCSPResonse<1..2^24-1>;

struct {
	CertificateStatusType status_type;
	select (status_type) {
		case ocsp: OCSPResponse;
	} response
} CertificateStatus;

opaque OCSPResponse<1..2^24-1>;

響應結構中包含的是OCSPResponse,即OCSP響應結構。

Signature Algorithm簽名和摘要算法

該擴展包含簽名算法和摘要算法兩部分,簽名算法大家很熟悉,摘要算法應用場景之一是數字簽名,消息發送者先對自己的消息使用摘要算法計算出摘要值,再使用私鑰對摘要值進行簽名,接收者收到消息後,拆分出消息和簽名值,然後使用發送者的公鑰對消息進行摘要算法計算出摘要值,再和拆分出的摘要值進行比較,如果一樣,則表示消息沒有被篡改,消息發送者也不能抵賴該消息不是他發送的。還有服務器部署時想申請證書,需要向CA機構提交CSR證書請求文件,CSR文件裏面包含了服務器的公鑰,域名等信息,服務器提交CSR文件時需要用自己的私鑰進行簽名,防止抵賴,CA機構也要對該CSR文件進行簽名。

struct {
	HashAlgorithm hash;
	SignatureAlgorithm signature;
} SignatureAndHashAlgorithm;

//摘要算法
enum {
	none(0), md5(1), shal(2), sha224(3), sha256(4), 
	sha384(5), sha521(6), (255)
} HashAlgorithm;

//簽名算法
enum {
	anonymous(0), rsa(1), dsa(2), ecdsa(3), (255)
} SignatureAlgorithm;

可以看到,簽名算法擴展有兩部分,HashAlgorithm是摘要算法,SignatureAlgorithm是簽名算法,兩者都是枚舉類型,裏面列舉了擴展項所支持的算法,該擴展的功能就是讓客戶端將自己支持的算法發送給服務器。如果沒有此擴展,服務器端也是有辦法獲取客戶端所支持的簽名和摘要算法的,還記得簽名說到雙方建立連接握手階段時要協商出密碼套件嗎,密碼套件中就包含有客戶端支持的簽名算法,消息驗證碼(消息摘要)算法等。

ALPN應用層協議協商擴展

ALPN(Application Layer Protocol Negotiation)應用層協議協商擴展,由客戶端在Client Hello子消息中發送該擴展,詢問服務器所支持的,雙方都能運行在TLS之上的應用層協議。例如HTTP協議版本,通常443端口上能支持TLS的服務默認會支持1.0版本的HTTP協議,如果客戶端瀏覽器想要協商出其他版本的HTTP協議(1.1或者2.0),則需要使用ALPN擴展。瀏覽器訪問一個域名時,不知道該服務器是否支持2.0版本的HTTP協議,所以在Client Hello中發送該擴展,提交其所支持的應用層協議列表,服務器從中選擇,如果支持HTTP/2.0,則在Server Hello中響應,之後雙方就共同協商了一起使用HTTP/2.0。

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