2.3 密钥交换
2.3.1 RSA密钥交换
RSA密钥交换的过程十分直截了当。客户端生成预主密钥(46字节随机数),使用服务器公钥对其加密,将其包含在ClientKeyExchange消息中,最后发送出去。服务器只需要解密这条消息就能取出预主密钥。TLS使用的是RFC 3447定义的RSAES-PKCS-v1_5加密方案。
注意 因为RSA算法可以同时用于加密和数字签名,所以RSA密钥交换可以按照这种方式工作。其他流行的密钥类型,比如DSA(DSS)和ECDSA,只能用于签名。
RSA密钥交换的简单性也是它最大的弱点。用于加密主密钥的服务器公钥,一般会保持多年不变。任何能够接触到对应私钥的人都可以恢复主密钥,并构建相同的主密钥,从而危害到会哈安全性。
对目标的攻击并不需要实时进行,强大的对手可以制定长期行动。攻击者会揭露所有加密的流量,耐心等待有朝一日可以得到密钥。比如,计算机能力的进步使暴力破解成为可能;也可以通过法律强制力、政治高压、贿赂或强行进入使用该密钥的服务器取得密钥。只要密钥泄漏,就可以解密之前记录的所有流量了。
TLS中其他常见的密钥交换方式都不受这个问题的影响,被称为支持前向保密。使用那些密钥交换时,每个连接使用的主密钥相互独立。泄漏的服务器密钥可以用于冒充服务器,但不能用于追溯解密任何流量。
2.3.2 Diffie-Hellman密钥交换
Diffie-Hellman(DH)密钥交换是一种密钥协定的协议,它使两个团体在不安全的信道上生成共享密钥成为可能。
注意
以这种方式协商共享密钥时不会收到被动攻击的威胁,但主动攻击者却可以劫持通信信道,冒充对端。这就是DH交换通常与身份验证联合使用的原因。
抛开算法的细节,DH的诀窍是使用了一种正向计算简单、逆向计算困难的熟悉函数,即使交换中某些因子已被知晓,情况也是一样。最恰当的类比示例是混色:如果有两种颜色,那么何容易将其混在一起得到第三种颜色;但是如果只有第三种颜色的话,就很难确定它究竟是由那两种颜色混合而成的。
DH密钥交换需要6个参数;其中两个(dh_p和dh_g)称为域参数,有服务器选取。协商过程中国,客户端和服务器各自生成另外两个参数,相互发送其中一个参数(dh_YS和dh_Yc)到对端,再经过计算,最终得到共享密钥。
临时Diffie-Hellman(ephemeral Diffie-Hellman,DHE)密钥交换中没有任何参数被重复使用。与之相对,在一些DH密钥交换方式中,某些参数是静态的,并被嵌入到服务器和客户端中。这样的话,密钥交换的结果是一直不变的共享密钥,就无法具备前向保密的能力。
TLS支持静态DH密钥交换,但无人只用。在协商DHE套件时,服务器将其所有参数填入ServerDHParams块并发送:
struct{
opaque dp_p;
opaque dp_g;
opaque dp_Ys;
}ServerDHParams;
客户端响应并发送其公开参数(dh_Yc);
struct{
select(PublicValueEncoding){
case implicit:
/空的,当客户端公共参数嵌入其客户端时/
case explicit:
opaque dh_Yc;
}dh_public;
}ClientDiffieHellmanPublic;
当前使用的DH交换存在一下这些现实问题。
- DH参数的安全性
DH密钥交换的安全性取决于域参数的质量。服务器发送弱的或者不安全的参数,将对会话的安全性造成损害。这个问题在一篇论文“Triple Handshake Attack”中进行过重点论述,弱DH参数被用作一种攻击向量。 - DH参数协商
TLS并没有为客户端提供期望使用的DH参数的强度的设施。比如,客户端可能希望避免使用弱参数,抑或可能不支持强参数。因此,选择DHE套件的服务器实际上只能期待DH参数可以被客户端接受。 - 参数强度不够
以历史角度来说,DH参数很大程度上被忽略了,其安全性也被忽视了。许多库和服务器默认使用弱DH参数而且经常不提供配置DH参数强度的方法。因此,服务器使用1024位弱参数,768位非安全参数,更有甚者使用512位参数,这些情况都很常见。直到最近,一些平台才开始使用2048位或者更高位数的强参数。
2015年5月Logjam攻击表明,512位的DH参数在使用合适资源的情况下可以被攻击者在很短的世界内成功利用,同时可以估计厉害的攻击者甚至可能利用768位的参数。同样的研究害强调非常厉害的攻击者甚至有可能可以攻破那些被广泛使用的、长度为1024位的标准参数组,从而以被动攻击方式入侵数以百万计的互联网服务器。在6.5节中可以找到有关此问题的更多信息。
这些问题可以通过对不同强度的域参数定义来进行标准化,或者扩展TLS客户端告知其偏好的方法来解决。
2.3.3 椭圆曲线Diffe-Hellman密钥交换
临时椭圆曲线Diffie-Hellman(elliptic curve Diffie-Hellman,ECDH)密钥交换原理与DH相似,但它的核心使用来不同的数学基础。正如名称所示,ECDHE基于椭圆曲线(elliptic curve,EC)加密。
ECDH密钥交换发生在一条由服务器定义的特定的椭圆曲线上。这条曲线代替了DH中域参数的角色。理论上,ECDH支持静态的密钥交换,但实际使用时,只使用了这种临时的变种(ECDH)。
密钥交换由服务器发起,它选择一条椭圆曲线和公开参数(EC point)并提交:
struct{
ECParameters curve_params;
ECPoint public;
}ServerECDHParams;
服务器可以为密钥交换明确指定任意一条曲线,但TLS并未使用这个功能。作为替代,在TLS中,服务器通过指定某个名称引用一条可能预先定义好参数的曲线(EC point):
struct{
ECCurveType curve_type;
select(curve_type){
case explicit_prime:
case explicit_char2:
case named_curve:
NamedCurve namedcurve;
};
}EcParameters;
然后客户端提交自己的公开参数。在那以后,就可以计算主密钥:
struct{
select(PublicValueEncoding){
case implicit:
case explicit:
ECPoint ecdh_Yc;
}ecdh_public;
}ClientECDiffieHellmanPublic;
使用预定义参数,以及ellipic_curve扩展(客户端可以提交支持的曲线),可以使用服务器选择一条双方都支持的曲线。你可以在2.12.3节中找到更多有关命名曲线的可用信息。
2.4 身份验证
在TLS中,为了避免重复执行密码操作造成巨大的开销,身份验证与密钥交换紧紧捆绑在一起,大多数场景中,身份验证的基础是证书支持的公钥密钥(最常见的是RSA,有时也用ECDSA)。一旦证书验证通过,客户端就知道了使用的公钥。在此之后,客户端将公钥交给指定的密钥交换算法,并由它负责以某种方式使用公钥验证另一端。
在RSA密钥交换的过程中,客户端生成一个随机值作为预主密钥,并以服务器公钥加密后发送出去。拥有对应私钥的服务器解码消息得到预主密钥。身份验证原理很清楚:只有拥有对应私钥的服务器才能取得预主密钥,构造正确的会话密钥,并生成正确的Finished消息。
在DHE和ECDHE的交换过程中,服务器为密钥交换提供自己的参数,并使用自己的私钥签名。客户端持有对应的公钥(从已验证的证书中获得),可以验证参数是否真正出自期望的服务器。
注意
服务器参数是与客户端和服务器随机值连在一起进行签名的,而客户端和服务器随机值对于握手来说是唯一的。因而,即使签名是以明文方式发送的,它也只对当前握手有效,这意味者攻击者无法重用签名。Logjam攻击显示了这种将签名绑定在握手过程上面的弊端;主动网络攻击者可以同步产生这个随机值,并且在某些情况下再次利用服务器签名。