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。

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