好记性不如铅笔头

编程

[转]DTLS简单笔记

本文转自

CONTENTS

1. 介绍

DTLS是特意设计成尽可能与TLS相似,这样既能最小化新的安全发明也能最大化重用代码和基础设施。DTLS 1.0 [DTLS1]最初被定义为[TLS11]的一个增量。本文介绍了DTLS的一个新版本,DTLS 1.2,它被定义为TLS 1.2 [TLS12]的一个增量系列。没有DTLS 1.1;这个版本被跳过以便与TLS的版本号相协调。这个版本也会澄清一些与DTLS 1.0的规范相混淆的点。

2. 使用模式

DTLS协议被设计用来保证应用通信数据的安全。它被设计在应用层运行,不需要对内核做任何修改。
数据报传输不要求或提供可靠的或有序的数据传输。DTLS协议为负载数据保留了这特性。诸如流媒体,网络电话和在线游戏这样的应用使用数据报进行通信本质上是由于对传输数据的延迟敏感。当使用DTLS进行安全通信时这类应用的行为不会改变,因为DTLS协议不会补偿丢失或重排序数据流量

3. DTLS概览

设计DTLS的基本思想是构建“数据报传输之上的TLS”。TLS不能直接用于数据报环境的原因只是包可能会丢失或重排序。TLS没有内部机制能处理这种不可靠性;因此,当移植到数据报传输上之后TLS实现就会崩溃。DTLS的目的是对TLS做最小的变更来解决这个问题。最大程度的可能是DTLS与TLS相同。无论何时我们需要发明新的机制时,我们都会试图保留TLS的风格。
不可靠性对TLS产生了两个方面的问题:
1. TLS不运行对单个记录进行独立解密。因为完整性检查依赖于序列号,如果记录N没有收到,对记录N+1的完整性检查会基于错误的序列号进行从而会失败。(需要注意的是对于TLS 1.1之前的版本没有显式IV,而且这样解密也会错误。
2. TLS握手层假定握手消息是可靠投递的,如果消息丢失则会中断。
本节的其余部分描述了DTLS用来解决这些问题的方法。
3.1. 丢失不敏感报文发送
在TLS的流量加密层(被称为TLS记录层),记录并不是独立的。有两种记录间依赖:
1. 密码学上下文(流密码密钥流)在记录间保留。
2. 抗重放和消息乱序保护由一个包含了序列号的MAC来提供,但序列号在记录中是隐藏的。
DTLS通过禁止流密码解决了第一个问题。DTLS通过增加显式序列号解决了第二个问题。
3.2. 为握手提供可靠性
TLS握手是一个古板的密码学握手。消息必须以确定的顺序被传输和接收;任何其它的顺序都是错误的。很明显,这与重排序和消息丢失不兼容。此外,TLS握手消息潜在地比任何给定的数据报大,因此会产生IP分片问题。DTLS必须解决这些问题。
。。。以下内容省略。。。

1.DTLS介绍

1.1 DTLS的作用
互联网先驱们最开始在设计互联网协议时主要考虑的是可用性,安全性是没有考虑在其中的,所以传输层的TCP、UDP协议本身都不具备安全性。SSL/TLS协议是基于TCP socket,在传输层和应用层之间构建了一个端到端的安全通道,保证了传输数据的加密性。
但是SSL/TLS协议并不能用于UDP协议,而UDP也有安全传输的需求,于是产生了DTLS协议(Datagram TLS)。
即DTLS的作用为给UDP提供端到端的安全通道,就像SSL/TLS对TCP的作用一样。并且DTLS尽可能参考了SSL/TLS协议的安全机制,在具体实现上复用了70%的TLS代码。
1.2 DTLS的特点
UDP协议是不面向连接的不可靠协议,且没有对传输的报文段进行加密,不能保证通信双方的身份认证、消息传输过程中的按序接收、不丢失和加密传送。
而DTLS协议在UDP提供的socket之上实现了客户机与服务器双方的握手连接,并且在握手过程中通过使用PSK或ECC实现了加密,并且利用cookie验证机制和证书实现了通信双方的身份认证,并且用在报文段头部加上序号,缓存乱序到达的报文段和重传机制实现了可靠传送。
在握手完成后,通信双方就可以实现应用数据的安全加密和可靠传输。
1.3 DTLS协议层次
DLTS协议分为两层,下层为记录层(记录层),record包的内容分为头部和载荷两部分。记录包的载荷即为上层的内容。DTLS上层的包的类型分为三种,分别是握手消息,警告消息,应用数据;如图一所示。
在整个DTLS协议的通信过程中,通信双方构造报文段的过程都是先产生上层的载荷消息(如握手消息,应用数据,警告消息),然后添加头部,构成完整的上层消息。接着再以此作为记录层的载荷,最后添加记录层的头部,构成完整的记录报文段,最后调用UDP的socket接口,发送给另一方。
加密过程是只对记录层的载荷(即上层消息,此协议中被加密的消息是finished消息和应用数据两种)进行加密,所以接收方在收到记录消息后,首先要做的也是判断记录消息是否被发送方加密,若是,则应先解密才能读取出明文数据以进行后面的处理。
2.DTLS传输阶段
2.1 整个握手阶段的交互过程
DTLS的传输阶段分为两个:握手阶段和握手建立之后的传输应用数据阶段。
DTLS的握手阶段如下图二所示:
客户机向服务器发起连接,服务器可以根据配置选择是否验证客户机的cookie和证书(即是否向客户机发送client_hello_verify和certificate_request报文段)。
2.2 DTLS的cookie验证机制
由于DTLS是基于UDP的,所以可能会遭受两种形式的拒绝服务攻击。一种是类似于对TCP的资源消耗攻击,另一种是放大攻击,即恶意攻击者仿造被攻击者的IP地址发通信初始化报文段给服务器,而服务器会返回一个体积大很多的证书给被攻击者,超大量证书有可能造成被攻击者的瘫痪。
cookie机制要求客户机重复发送服务器之前发送的cookie值来验证通信方的源IP地址确实可以通信,由此可以减少拒绝服务攻击的危害。
cookie验证身份的具体机制为:
协议规定客户机发送的第一个报文段client_hello中含有cookie的值这一项(有可能为空)。服务器检验收到的该报文段中的cookie值,如果cookie为空,则说明之前没建立过连接,服务器根据客户机的源IP地址通过哈希方法随机生成一个cookie,并填入client_hello_verify中发送给客户机。
客户机再在第二次发送的client_hello报文段中填入服务器之前发过来的cookie,服务器第二次收到该报文段之后便检验报文段里面的cookie值和服务器之前发给该主机的cookie值是否完全相同,若是,则通过cookie验证,继续进行握手连接;若不是,则拒绝建立连接。
2.3 client_hello报文段和server_hello报文段的内容
client_hello报文段的内容除cookie外,还有客户机产生的32字节的随机数,其中前4字节为时间戳,后28字节为系统产生的随机数。此外,该报文段的内容还有客户机支持的加密方式(PSK或者ECC)和压缩方式,供服务器进行选择。
在通过cookie校验后,服务器发送server_hello报文段给客户机。该报文段包含有服务器产生的32字节的随机数,和服务器选中的用来进行之后的会话的加密方式和压缩方式。
2.4 certificate报文段的内容
在服务器发给客户机的证书报文段中,包含有服务器证书的公钥;客户机接收到该报文段后,按照协议规定,从报文段的对应位置中读取出服务器证书的公钥存入相关变量中。
2.5 基于ECC加密方式的ECDH秘钥交换协议和ECDSA数字签名算法
若协议所选加密方式为ECC(椭圆曲线加密),则在server_key_exchange报文段的构造过程中会使用ECDH(椭圆曲线秘钥交换协议)和ECDSA(椭圆曲线数字签名算法)。ECDH和ECDSA分别是ECC和DH(diffie-hellman)秘钥交换协议、DSA(数字签名算法)的结合。
在server_key_exchange报文段中,包含有所选用的椭圆曲线E,阶N和基点G的x,y坐标,客户机在收到这个报文段后,进行对应的格式检验,并读取数据,因此服务器和客户机共同获得约定好的用来进行ECDH秘钥协商交换协议的参数,从而可以共同协商出相同的对话秘钥用于加密之后的会话内容。
同时,为了防范中间人攻击,服务器还在server_key_exchange报文段的末尾对整个报文段进行了ECDSA数字签名。具体签名过程为先用client_hello报文段和server_hello报文段中的2个32字节的随机数作为函数参数,利用sha256哈希算法对server_key_exchange报文段本身的载荷产生摘要,然后再用服务器的私钥和sha256哈希算法进行ECDSA数字签名,得到签名结果r和s,并写入server_key_exchange报文段的末尾。
客户机在收到server_key_exchange报文段后,先进行各数值项格式的校验,然后提取出报文段末尾的签名值r和s。之后,用已经读取出的服务器的公钥的x,y坐标值来对server_key_exchange报文段进行ECDSA签名验证,若结果和报文段中的r和s值一致,则报文段通过验证。
2.6 基于PSK加密方式的身份认证过程和会话秘钥产生过程
整个DTLS协议的加密方式可选用ECC或PSK(预共享秘钥,PreSharedKey)两种。若为ECC,则通过ECDH协议来进行通信双方的秘钥协商;若为PSK,则直接以通信双方事先就已经约定好了的秘钥为基础来进行加密通信。
对于PSK加密通信来说,验证对方的通信身份非常关键。所以通信双方会在本地存取对方的psk_id(即身份标志)和psk_id_length(身份标志长度),通过比较收到的报文段中的psk_id,psk_id_length和本地存储的是否完全一致来进行对方身份的验证。
在整个通信过程中,采用PSK与ECC的区别主要体现在server_key_exchange报文段、client_key_exchange报文段的内容不同和双方计算得到预主秘钥方式的不同。
当采用PSK加密时,server_key_exchange报文段和client_key_exchange报文段的内容分别是服务器与客户机各自的psk_id和psk_id_length,由此双方可以互相知道对方的psk_id和psk_id_length。
之后,双方都会对收到的报文段进行检验,只有psk_id和psk_id_length与本地存储的完全一致才会进行后面的通信。
当双方都通过身份验证后,双方再各自用相同的函数产生预主秘钥,而函数的参数包括之前通信阶段中双方各自产生的32字节的随机数,由此可以保证虽然本地存储的psk秘钥不变,但每次临时通信时的会话秘钥还是会一直变化的,从而增强了抗攻击性。
双方产生预主秘钥后,再调用和使用ECC加密的相同方式来产生主秘钥,即用于之后会话通信的对称秘钥,该过程中依然会用到双方产生的32字节的随机数。
由此,通信双方使用PSK加密方式来实现了身份认证和会话秘钥的产生。
2.7 server_hello_done报文段和client_key_exchange报文段的内容
服务器发送的server_hello_done报文段的载荷部分为空,只是发给客户机来作为标志,表示服务器当前阶段的报文段已经发送完毕。客户机在收到server_hello_done报文段后,发送client_key_exchange报文段给服务器,里面包含了用于秘钥协商的基点的x,y坐标,并且不同于server_key_exchange报文段,客户机并没有在报文段的末尾进行ECDSA数字签名。
2.8 客户机产生会话秘钥
之后,客户机再通过ecdh_pre_master_secret函数来产生用于之后会话的预主秘钥。其中函数的参数包括客户机自己的私钥,和服务器共享的用于ECDH秘钥协商算法的基点的x,y坐标。产生预主秘钥后,再根据之前阶段客户机和服务器分别产生的32字节的随机数产生主秘钥master_secret,此时主秘钥为对称秘钥,用于之后会话的加解密。
2.9 change_cipher_spec报文段和finished报文段的内容
客户机计算出会话秘钥后,发送change_cipher_spec报文段给服务器,这个报文段的有效载荷为空,用来作为标志通知服务器,表示客户机已经算出主秘钥,之后发送的报文段会采用主秘钥加密。
握手阶段中客户机发送的最后一个报文段为finished报文段,载荷内容为MAC值(消息验证码),用于给服务器做认证。并且值得注意的是,finished报文段作为记录层的载荷部分在发送时已经用上一步产生的会话秘钥进行加密编码。
2.10 服务器产生会话秘钥
服务器在收到客户机发送过来的finished报文段后,也会和客户机用ECDH秘钥协商算法经过相同的流程,调用相同的函数先产生预主秘钥,再产生主秘钥。
2.11 握手阶段的结束
最后,服务器产生经会话秘钥加密后的finished报文段给客户机,标志整个握手阶段的结束。
客户机收到服务器发过来的finished报文段后,便可发送应用数据。并且应用数据会一直用会话秘钥加密,从而实现了UDP所不具备的安全性。

发表评论

18 + 12 =

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据