安全生产 SSL 安全协议中文版
SSL 协议
翻译—隋立颖
一本文件的地位
本文件是一个 Internet草案。Internet草案是 Internet工程特遣组(ITEF)及其领域和工
作组的工作文件。请注意,其他团体也可以发布 Internet草案。
Internet草案自公布之日起至多六个月内有效。它可以随时被修改、被替换,或被其他文件
所覆盖。把 Internet 草案作为文献来引用,除说明是“正在进展中的工作”以外,是不合
适的。
要了解任何一个 Internet的当前地位,请查阅如下网址:(美国东海岸),
(欧洲),(美国东海岸)以及 (环太平洋地区)。
其中 InternetDraftsShadowDirectories 目录下的 列表可提供这方面的
信息。
二摘要
本文制定了安全套接层协议第 版()规范。SSL是一个提供 Internet上的通信隐
私性的安全协议。该协议允许客户端/服务器应用之间进行防窃听、消息篡改及消息伪造的
安全的通讯。
三简介
制定 SSL协议的初衷是为通讯双方提供安全可靠的通讯服务,协议包含两个层次:其较低的
SSL 记录层协议位于某一可靠的传输协议(例如 TCP[TCP]协议)之上;SSL 记录层协议用来
对其上层的协议进行封装。握手协议就在这些被封装的上层协议之中,它允许客户端和服务
器彼此认证对方;并且在应用协议发出或收到第一个数据之前协商加密算法和加密密钥。这
样作的原因是保证了应用协议的独立性,使低级协议对高级协议是透明的。
SSL协议提供的连接安全性具有以下三条属性
连接是安全的。在初始化握手协议协商加密密钥之后传输的消息均为加密的消息。
加密的算法为单钥加密算法(例如 DES[DES],RC4[RC4]等)。
对方的身份是可以通过非对称加密算法-即公钥加密算法(例如 RSA[RSA],DSS[DSS]
等)来验证。
连接是可靠的。所传输的消息均包含一利用签名私钥加密的消息文摘(MAC),以保
证消息的完整性。安全杂凑(hash)函数(例如 SHA,MD5等)被用来产生消息文摘(MAC)。
四目标
按它们的优先级,SSL协议 的目标是
在通讯双方之间利用加密的 SSL消息建立安全的连接。
互操作性。通讯双方的程序是独立的,即一方可以在不知道对方程序编码的情况下利用
成功的交换加密参数。
注意:并不是所有的 SSL的实例(甚至在同一应用程序内)都可以成功的连接。例如,如果
服务器支持一特定的硬件令牌(token),而客户端不能访问此令牌,则连接不会成功。
可扩展性。SSL 寻求提供一种框架结构,在此框架结构中,在不对协议进行大的修改的
情况下,新的公钥算法和单钥算法可以在必要时被加入。这样做还可以实现两个子目标
1. 避免产生新协议的需要,因而进一步避免了产生新的不足的可能性。
2. 避免了实现一完整的安全协议的需要。
相对的有效性。加密操作,尤其是公钥加密,对 CPU来说是一种很耗时的事,因此 SSL协议
引入一可选的对话缓存(CACHE)来减少从头开始的连接的数目。同时,它还注意减少网络的
活动。
五此文档的目的
SSL 协议版本 详细说明书的主要读者是要实现此协议的人和进行加密分析的人。此详细
说明书主要是为这两类人而写的,所以它时刻注意反映这两类人的需要。因此在本详细说明
书中(而不是写在附录中)以文本方式包含了许多与算法相关的数据结构和规则,使它们易
于被访问。虽然本详细说明书包含了维护物理安全性所必须的策略,本详细说明书并不想提
供关于服务和界面的定义。
六描述语言(Presentationlanguage)
本文档主要是描述外部表示(externalrepresentation)的数据的格式,所以用到了下列简
单、基础而有点随意的定义的表示语法,这些语法在结构上来自不同的出处。虽然这些语法
在结构上有点象程序设计语言 C、在语法和目标上象 XDR[XDR],但过分的强调这种类似是有
害的。本描述语言的目的仅仅是描述 SSL。
基本块长(Basicblocksize)
所有的数据项的表示均是显式说明的,基本数据块的长度为一字节(也就是说 8比特)多字
节的数据项是由从上至下、从左至右的多个字节连接组成。从字节流的角度来看,一多字节
的数据项(在本例中是一数字)是通过下述公式形成的:
value=(byte[0]<<8*(n-1))|(byte[1]<<8*(n-2))|...|byte[n-1];
这种字节的顺序关系是网络中常用的顺序关系即大 endian格式。
杂项
注释以“/*”开始,以“*/”结束。
可选的部分是由将其包含进斜体的括号“[]”中而指定的。
单字节的包含不可解释的数据的实体的类型为 opaque
向量(Vectors)
向量(一维数组)是一同类型的数据元素的流,向量的规模可以在编写文档时说明,也可以留
至运行时才指明;不管在哪一种情况下,向量的规模(即大小)是由向量中字节的个数而不
是向量中元素的个数决定的。
说明一新类型 T’是一固定长度的类型 T的向量的语法为:
TT'[n];
在这里,T’在数据流中占 n 比特,其中 n 是 T 的所占字节数的倍数。向量中包含数据元素
的个数没有包含在数据流之中。在下例中,Datum 被定义为三个连续的协议无法解释的字节
的向量;而 Data被定义为三个连续的 Datum,一共包含 9个字节
opaqueDatum[3];/*三个协议无法解释的字节*/
DatumData[9];/*三个连续的包含三个字节的向量*/
可变长向量可以通过指明合法长度的范围,即形如<最小长度..最大长度>的形式来定义,在
编码时,在字节流中实际长度应在向量的内容之前,此实际长度是以数字的形式存储的,此
数字应能表示此向量的最大长度(ceilinglength)。空向量指的是一实际长度为零的向量。
TT'<floor..ceiling>;
在下例中,mandatory是一必须包含 300到 400字节的 opaque类型数据的向量,它不能是空
向量,其实际长度域占有两个字节,即 uint16,足以表示 400(见 节),而 longer最多
能表示 800 个字节,即 400 个 uint16 的数据元素,且<请合法使用软件>可以是空向量。它
的编码包含一两字节的实际长度域。
opaquemandatory<300..400>;/*长度域为两个字节,不能为空向量*/
uint16longer<0..800>;/*零至 400个 16比特的无符号整数*/
数字(Numbers)
基本的数字的数据类型是无符号字节(uint8)。其他所有的大的数字均是由 节中描述的
固定长度的字节流连接而成,且它们均是无符号的。下列数字类型是预定义的:
uint8uint16[2];
uint8uint24[3];
uint8uint32[4];
uint8uint64[8];
枚举(Enumerate)
另一类稀疏的数据类型是枚举(enum),枚举类型的数据的取值范围只能是在其定义是声明
的值。每一次定义均定义了一不同的类型。只有相同类型的枚举数据才可以相互赋值和比较,
枚举类型的每个枚举元素均必须象下例中所示的那样,被赋一个值。由于枚举类型这的元素
是没有顺序的,所以它们可以取任意顺序的不同的值。
enum{e1(v1),e2(v2),...,en(vn),[(n)]}Te;
枚举类型的值在字节流中占据的空间的大小是其定义的取值范围中最大的可能值所占的空
间大小。下列定义会使类型 Color占有一个字节。
enum{red(3),blue(5),white(7)}Color;
你还可以通过指定一个无标签的值来强制枚举类型所占的字节数,这样就不需定义一冗余元
素了。在下例中,类型 Taste在字节流中占两个字节但只能在 1,2或 4中取值。
enum{sweet(1),sour(2),bitter(4),(32000)}Taste;
枚举类型的元素的名字只在定义的类型中是有效的。在第一个例子中,对类型 Color中的第
二个元素的完全限定引用为 。这样的限定当赋值的目标是被说明的时候时是可以
忽略的。
Colorcolor=;/*重复说明,但是合法的*/
Colorcolor=blue;/*正确,类型是隐含的*/
对于元素的值不会转化为外部表示的枚举类型,元素的取值信息是可以省略的。
enum{low,medium,high}Amount;
结构(Constructedtype)
结构类型可以由基本的数据类型方便的建成,每一次说明均声明了一新的、唯一的类型,定
义的语法类似于 C语言中结构的定义。
struct{
T1f1;
T2f2;
...
Tnfn;
}[T];
在一结构中的各域可以象枚举中引用元素时的语法一样用类型名加域名引用,例如 引用
的是上例中的第二个域,结构的定义可以嵌套。
变体结构(Variant)
定义结构时可能根据环境的不同而有不同的变体,选择器必须为枚举类型的数据,以定义结
构中可能的变体,且必须用 case语句将 select中声明的每个枚举元素不会起来。变体结构
的结构体可以有一供其引用的标签。在运行时如何决定变体的机制并没有在描述语言中规定。
struct{
T1f1;
T2f2;
...
Tnfn;
select(E){
casee1:Te1;
casee2:Te2;
....
caseen:Ten;
}[fv];
}[Tv];
例如:
enum{apple,orange}VariantTag;
struct{
uint16number;
opaquestring<0..10>;/*可变的长度*/
}V1;
struct{
uint32number;
opaquestring[10];/*固定的长度*/
}V2;
struct{
select(VariantTag){/*变体的选择器是隐含的*/
caseapple:V1;/*VariantBody的定义,标签=apple*/
caseorange:V2;/*VariantBody的定义,标签=orange*/
}variant_body;/*可选的变体标签*/
}VariantRecord;
变体结构可以通过在类型前指定选择器的值来限定(narrowed),例如:
orangeVariantRecord
是类型 VariantRecord的一限定,它包含类型为 V2的 variant_body。
加密属性(Cryptographicattribute)
数字签名、流加密、块加密和公钥加密这四项加密操作的加密属性分别为
digitally-signed,stream-ciphered,block-ciphered和 public-key-encrypted。对一个
域进行何种加密操作是由在此域的类型说明前的合适的加密属性(关键字)决定的,加密的
密钥是由当前对话状态字隐含给出的(见 节)。
在数字签名中,输入为一单向哈希函数(one-wayhashfunction)。当用 RSA算法进行签名时,
用签名私钥对一 36字节的结构进行签名,此 36字节的结构是由两个哈希函数生成的,一个
为 SHA,另一个是 MD5。当用 DSS算法进行签名时,可以直接对由 SHA哈希函数生成的 20字
节的结构进行签名。
在流加密中,明文的长度与由密钥产生的密文的长度是相同的。此密钥是由伪随机数发生器
生成的安全的密钥,是根据时间的变化而变化的。
在块加密中,密文的每一块均被加密成一块密文。由于明文的长度并不是固定的,所以有可
能在对明文(发出的数据)分块时产生一不满的块(块的长度通常为 64比特),此时就需要
将此不满的块的剩余部分填充数据,一般来说是填零。
在公钥加密中,单向限门函数被用来加密要发出的数据,用一给定公钥加密的数据仅能由相
应的私钥解出,同样用一给定私钥加密的数据仅能由相应的公钥解出。
在下例中:
stream-cipheredstruct{
uint8field1;
uint8field2;
digitally-signedopaquehash[20];
}UserType;
哈希函数的结果做为签名算法的输入,整个结构 UserType用流加密进行加密。
常量(Constant)
有类型的常量可以通过在常量名前加上所希望的类型,并在常量名后给其赋上所期待的值来
定义。未限定的类型(opaque,可变长向量,变体结构及带有 opaque的结构)不能被赋值。
多元素的结构和向量的所有域均应被赋值。
例如:
struct{
uint8f1;
uint8f2;
}Example1;
Example1ex1={1,4};/*令 f1=1,f2=4*/
七、SSL协议
SSL是一层次化协议。在每一层,消息均可以包含描述长度、消息的描述及消息的内容的域。
SSL 在传输消息时,首先将消息分为其可处理的数据块,可以进行压缩,将其封装为一带消
息验证(MAC)的包,随之进行加密并传输所得到的加密后的消息。在收到消息时,首先解
密,然后验证、解压缩并重新组合得到原有的消息,将此消息发向较高的层次。
对话及连接状态
SSL 的对话是有状态的,是由 SSL 的握手协议来同步客户端和服务器的状态的,因而允许它
们一致的操作而不管它们的协议状态是否是并行的。从逻辑上讲,状态被提到了两次,一次
是当前的操作状态,而另一次是在握手协议中的未决状态。而且,还维持单独的读状态和写
状态。当客户端或服务器收到 changecipherspec 消息时,它将未决读状态复制到当前读状
态。当客户端或服务器发出 changecipherspec消息时,它将未决写状态复制到当前写状态。
当握手协商完毕时,客户端或服务器将彼此交换 changecipherspec消息(见 节),这样
它们就可以用新同意的 cipherspec来进行通信了。
SSL对话可以包含若干次安全连接,而且每一方均可以同时有多个对话。
对话状态包含下列元素:
对话标识一由服务器为标识当前活跃的对话或重新开始的对话而随机
选取的字节流。
对等证书对等方的 [X509]证书,状态的此元素可以为空。
压缩方法在加密之前压缩数据所采用的算法。
加密说明指出所采用的数据加密算法(如没有采用加密算法,采用 DES
等)和作消息文摘的算法(如 MD5,SHA等),它还定义象
hash_size一类的加密的属性(见附录 )
主共享的秘密客户端和服务器所共享的 48比特的共享的秘密。
是否可以重开始一标识此对话是否可以用来初始化新的连接的标志。
连接状态包含下列元素:
客户端和服务器的随机数由客户端和服务器为建立一次连接而随机选取的一字
节流。
服务器的 MAC写共享秘密服务器在对数据进行消息验证(MAC)操作时所使用的
共享的秘密。
客户端的 MAC写共享秘密客户端在对数据进行消息验证(MAC)操作时所使用的
共享的秘密。
服务器的写密钥服务器在对数据进行加密时所使用的加密密钥,此密
钥也是客户端进行解密时的解密密钥。
客户端的写密钥客户端在对数据进行加密时所使用的加密密钥,此密
钥也是服务器进行解密时的解密密钥。
初始化向量当用 CBC方式进行块加密时,对于每一密钥系统都将维
护一初始化向量(IV)。此域的值是由 SSL握手协议进行
初始化的,为以后使用的方便此后的每一记录的最终的
密文块被保存在记录的后面。
序列号参与连接的每一方都为其发出的和收到的消息维护一独
立的序列号。当一方发出或收到 ChangeCipherspec
消息时,其序列号置为零。序列号的类型为 Unit64,所
以序列号不能超过 264-1。
记录层
SSL记录层由更高的层次那里接收未加解释的任意长度的非空块。
打包
记录层将信息块分裂为小于或等于 214字节的 SSLPlainText记录。客户端消息的界限并不反
映至记录层中(也就是说,具有同样 ContentType 的多个客户消息可能会合并为一
SSLPlaintext记录)。
struct{
uint8major,minor;
}ProtocolVersion;
enum{
change_cipher_spec(20),alert(21),handshake(22),
application_data(23),(255)
}ContentType;
struct{
ContentTypetype;
ProtocolVersionversion;
uint16length;
opaquefragment[];
}SSLPlaintext;
其中
type指出采用打包的更高层次的协议。
version协议的版本号。此文档所描述的是 SSL版本 (见附录 ).
lengthSSLPlaintext的字节长度,此长度不应超过 214
fragment应用数据。此数据对由 Type域中所指出的更高层次的协议是透明的,并被
视为一独立的块。
注意:不同的 SSL记录层的 CententType数据可以交叉存取,应用数据一般要比其他的
ContentType数据要求更低级的传输过程。
记录的压缩和解压缩
所有的记录均应用在当前的对话状态中定义的压缩算法进行压缩。一般地,此算法为当前活
跃的压缩算法,但在初始化时它被定义成 。压缩算法将
SSLPlaintext 结构转换为 SSLCompressed 结构,当 CipherSpec 变换后,压缩函数将删除其
状态信息。
注意:CipherSpec是在 节中所描述的对话状态的一部分,对 CipherSpec中各域的引
用在本文档中是用表示语法来表达的。关于 CipherSpec的更加详细的描述见附录
.
压缩必须是无损压缩且对原文的长度的增加不超过 1024 比特。如果解压缩函数遇到一待解
的超过 214比特的 ,它将产生一终止的 decompression_failure 报
警(见 节)。
struct{
ContentTypetype;/**/
ProtocolVersionversion;/**/
uint16length;
opaquefragment[];
}SSLCompressed;
的长度(单位:字节)。长度不应超过 214+1024。
的压缩格式。
注意:操作 是一标识性操作,没有任何一个域的值被改变
(见附录 )。
实现时请注意:解压缩函数的责任是保证消息不会造成内部的缓冲区溢出。
记录的有效负荷保护和加密说明(CipherSpec)
所有的记录均用在当前的加密说明(CipherSpec)中定义的加密算法和消息验证(MAC)算
法所保护,一般地,在 SSL 内部有一活跃的 CipherSpec,但在初始化时,它的值为
SSL_NULL_WITH_NULL_NULL,从值并不提供任何安全性。只有当握手结束后,参与双方共享一
用于加密记录和计算消息验证码(MACs)的公共秘密。进行加密和消息验证(MAC)操作的
技术有 CipherSpec 定义,并受 _type 的限制。加密和消息验证(MAC)
函数将一 SSLCompressed结构转换为一 SSLCiphertext结构,解密函数作相反的过程。传输
时将包含一序列号,这样当包丢失、被改变或包被重复收到时可以及时的发现。
struct{
ContentTypetype;
ProtocolVersionversion;
uint16length;
select(_type){
casestream:GenericStreamCipher;
caseblock:GenericBlockCipher;
}fragment;
}SSLCiphertext;
type类型域被指定为 。
version版本域被指定为 。
length指明随后的 的长度(单位:字节)。长度不应
超过 214+2048。
fragment包含消息验证码(MAC)的 加密后的形式。
或标准的流加密
流加密(包含 –见附录 )将 结构
转换为 流结构,或者反之,将 结构转换
为 流结构。
stream-cipheredstruct{
opaquecontent[];
opaqueMAC[_size];
}GenericStreamCipher;
产生的消息验证码(MAC)形式为:
hash(MAC_write_secret+pad_2+
hash(MAC_write_secret+pad_1+seq_num+length+content));
其中“+”表示将前后连接起来。
pad_1字符 0x36在 MD5算法中重复 48次或在 SHA算法中重复 40次。
pad_2字符 0x5c,与 pad_1一样的重复。
seq_num从消息的序列号。
hash由 cipher组合所决定的杂凑算法。
请注意,消息验证码(MAC)在加密之前就计算出来了。流加密加密的是包含消息验证码
(MAC)在内的整个块。对于不用同步向量的流加密方法(如 RC4),在记录后边的流加密方
法的状态被简单的用在随后的包中,若 CipherSuite 是 SSL_NULL_WITH_NULL_NULL,且加密
包含指定的操作(也就是说,数据还未被加密且消息验证码(MAC)的长度为零,标志着不
使用消息验证码( MAC)),则 SSLCiphertext 的长度是 SSLCompressed 的长度与
_size的和。
密码分组链接(CBC)块加密
对于块加密(象 RC2或 DES),加密和消息验证(MAC)函数将 结构
转换成 块结构。
block-cipheredstruct{
opaquecontent[];
opaqueMAC[_size];
uint8padding[_length];
uint8padding_length;
}GenericBlockCipher;
消息验证(MAC)与 节中描述的一样。
padding为了使明文的长度成为加密块长度的倍数而添加的随机字节。
padding_length填料的长度必须比加密块的长度小且可以为零,填料的长度应使结构
GenericBlockCipher的总长度是加密块长度的倍数
被 加 密 的 数 据 长 度 () 应 比 SSLCompressed 的 长
度,_size和填料的长度的总和多一。
注意:对于 CBC块加密来说,其第一个记录的 CBC块链的初始化向量(IV)是由握手协议提
供的,随后记录的 IV是前一记录的最后一密文块。
更改加密说明 cipherspec的协议
更改加密说明(cipherspec)的协议在加密策略中被用来通知参与各方这一改变。协议只包
含一个在当前(不是未决的)CipherSpec下加密并压缩过的消息。此消息包含一个字节,其
值为 1。
struct{
enum{change_cipher_spec(1),(255)}type;
}ChangeCipherSpec;
更改 cipherspec 的消息可以由客户端或服务器发出来通知对方随后的记录将由刚协商好的
CipherSpec和密钥来保护。收方收到此消息后,将读未决状态复制到当前读状态中。客户端
在密钥交换握手和证书验证消息(如果有的话)之后发出更改 cipherspec 的消息,服务器
则在成功的处理了客户端发来的密钥交换消息之后发出一更改 cipherspec 的消息。一意外
的更改 cipherspec消息应产生一 unexpected_message报警(见 节)。当重新开始一原
有的对话时,更改 cipherspec消息应在问候消息(hellomessages)之后发出。
报警协议
由 SSL记录层所支持的一种媒体类型为报警类型,报警消息带有此消息的严重程度的编码和
对此报警的描述。最严重一级的报警消息将立即终止连接,在这种情况下,本次对话的其他
连接还可以继续进行,但对话标识符必须无效以防止此失败的对话重新建立新的连接。象其
他的消息一样,报警消息是利用由当前连接状态所指出的算法加密和压缩的。
enum{warning(1),fatal(2),(255)}AlertLevel;
enum{
close_notify(0),
unexpected_message(10),
bad_record_mac(20),
decompression_failure(30),
handshake_failure(40),no_certificate(41),bad_certificate(42),
unsupported_certificate(43),certificate_revoked(44),
certificate_expired(45),certificate_unknown(46),
illegal_parameter(47)
(255)
}AlertDescription;
struct{
AlertLevellevel;
AlertDescriptiondescription;
}Alert;
关闭报警
客户端和服务器为避免截断攻击必须共享连接已关闭这一信息,它们中的任一方均可以初始
化关闭信息的交换。
close_notify此消息通知收方发出者不会在此连接内再发任何消息,当一次对话中
的所有连接都没有恰当的 close_notify消息而终止时,此次对话是
不能重新开始的。close_notify消息的严重程度是警告级的
错误报警
在 SSL握手协议中的错误处理是很简单的,当发现一个错误后,发现方将向对方发一消息。
当传输或收到最严重一级的的报警消息时,连接双方均立即终止此连接。服务器和客户端均
应忘记前一次对话的标识符、密钥及有关失败的连接的共享信息。SSL 中定义了下列错误报
警:
unexpected_message收到一意外的消息,此报警通常是致命性错误的报警且不应在正
常的连接中被观察到。
bad_record_mac当收到一带有不正确的 MAC的记录时,将返回此报警。此报警通
常是致命性错误的报警。
decompression_failure解密函数收到不合法的输入(如数据太长等),此报警通是致命
性错误的报警。
handshake_failure收到一 handshake_failure报警消息表明发出者不能接受现有的
选项所提供的安全参数的集合,此报警通常是致命性错误的报
警。
no_certificate当被要求给出证书而没有合法的证书时,将发出一
no_certificate报警消息。
bad_certificate当一证书被讹用、或者证书中不会的签名不能被正确的认证等
时,发出此报警。
unsupported_certificate 一有不被支持的类型的证书(如包含了用户自定义的扩展)。
certificate_revoked一被其发出者取消的证书。
certificate_expired一过期了的或不合法证书。
certificate_unknown由一些不明的发出者发出的证书所引起的证书的不可接受性。
illegal_parameter在握手中的一个域的值溢出或与其他域的值不一致,此报警是致
命性错误的报警。
握手协议总揽
对话状态的加密的参数是由 SSL握手协议产生的,握手协议是在 SSL记录层的顶部操作的。
当一 SSL客户和服务器首次开始通讯时,它们就协议版本、加密算法的选择、是否验证对方
及公钥加密技术的应用进行协商以产生共享的秘密,这一处理是由握手协议完成的,可以总
结如下:
其中*表示不是必须发出的可选的或依赖于环境的消息
客户端首先发出客户问候消息(clienthellomessage),服务器收到之后或者发出服务器问
候消息(serverhellomessage),或者发生一终止性的错误然后此次连接将无法建立客户和
服务器问候消息(clienthellomessage)被用来在客户端和服务器之间建立安全的性能的协
商,客户和服务器的问候消息(clienthellomessage)将产生了下列属性:协议版本号、对
话标识符、加密套接字及压缩方法,而且产生了两个随机数 和
并且相互交换。
在问候消息之后,若要求验证身份,服务器将发出其证书,另外,如果需要的话(例如,如
果他们的服务器没有证书,或者其证书仅用来进行签名),将发出一个 serverkeyexchange
消息。如果这个服务器已经被认证,而且被所选的密码组(cipherSUITE)所允许的话,它将
向客户端请求证书。
现在这个服务器将发出服务器问候结束消息(serverhellodonemessage),表明握手过程中
的问候消息阶段已经结束。这个服务器接着将等候客户端的回答。
如 果 服 务 器 发 出 一 个 certificaterequest 消 息 , 客 户 端 必 须 发 出 证 书 消 息
(certificatemessang),或者一个 nocertificate 报警。现在,客户端密钥交换消息
(clientkeyexchangemessage)准备发送,而且消息的内容将取决于在客户端问候消息
(clienthellomessage)和服务器问候消息(serverhellomessage)之间所选择的公钥算法。
如果客户端已经发出了一个具备签名能力的证书,一个数字签名后的证书验证消息
(certificateverifymessage)将被发送以确认此证书的合法性。
就这一点而言,一个改变加密说明(changecipherspec)消息是被客户端发送的,而且客户
端将未决的 CipherSpec 复制到当前 CipherSpec。然后,客户端立即用协商的新的算法、密
钥、和共享信息发出结束消息。服务器将发出其自己的改变 cipherspec 消息
( changecipherspecmessage)作为回应,将未决 (pending)cipherspec 复制到当前
CipherSpec,并用新的 cipherspec 发出其结束消息。此时,握手过程结束,客户端和服务
器可以开始交换应用层数据了(见上图)。
注意:为了避免通道延迟,changeCipherspec是一独立的 SSL协议的媒体类型,而并非
一 SSL握手消息。
当客户端和服务器决定重新开始一以前的对话或复制一已存在的对话(并不协商新的安全参
数)时,其消息流如下:
客 户 端 首 先 利 用 需 要 重 新 开 始 的 对 话 的 对 话 标 识 符 发 出 客 户 端 问 候 消 息
(ClientHellomessage),服务器检查对话缓存来寻找匹配的对话,若找到匹配的对话,服
务器将在指定的对话状态下重新建立连接,它将发出带有对话标识符的服务器问候消息
( ServerHello )。 此 时 , 客 户 端 和 服 务 器 均 必 须 发 出 改 变 cipherspec 消 息
(changecipherspecmessage)和结束消息(finishedmessage),只要此重新建立连接一完
毕,客户端和服务器将交换应用层数据(见上图)。若没找到找到的对话标识符,服务器将
产生新的对话标识符,然后 SSL客户和服务器将进行正常的握手过程。
每一消息的内容和重要性将在以下各节中详细的描述。
握手协议
SSL 握手协议是 SSL 记录协议(recordProtocol)的一个高级的客户。此协议用来协商一对话
的安全参数,握手消息被传给 SSL 记录层,在那里这些消息被封装在一个或多个
SSLPlaintext 结构之中,这些 SSLPlaintext 结构由当前活跃的对话状态中所指定的参数进
行处理和传输。
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),
finished(20),(255)
}HandshakeType;
struct{
HandshakeTypemsg_type;/*握手消息的类型*/
uint24length;/*握手消息体的字节数*/
select(HandshakeType){
casehello_request:HelloRequest;
caseclient_hello:ClientHello;
caseserver_hello:ServerHello;
casecertificate:Certificate;
caseserver_key_exchange:ServerKeyExchange;
casecertificate_request:CertificateRequest;
caseserver_hello_done:ServerHelloDone;
casecertificate_verify:CertificateVerify;
caseclient_key_exchange:ClientKeyExchange;
casefinished:Finished;
}body;
}Handshake;
握手协议的消息必须按指定的顺序发出(此顺序如上所示),若不按此顺序发出,则会重新
终止性错误。
问候消息(Hellomessage)
问候消息用来在客户端和服务器之间交换彼此安全系统的性能。当一个对话刚开始时,
CipherSpec 中的加密、杂凑(hash)和压缩算法均初始化为 Null,当前的 CipherSpec 被用来
协商这些参数。
要求问候消息(hellorequestmessage)可以由服务器在任何时间发出,但若客户端正在进
行握手过程的话,此消息将会被客户端所忽略。它只是一个简单的通知,通知客户端可以在
方便的时候发出一客户问候消息(clienthellomessage)来开始一协商的过程。
注意:由于握手消息是比应用层数据的传输优先级高,所以协商的时间不应超过最大长度的
应用层数据消息的传输时间的一到两倍。
在发出要求问候消息之后,在握手协商未完成之前服务器不应再重复发出此消息。一处于协
商状态中的客户可以简单的忽略其收到随后要求问候消息。
要求问候消息的结构如下:
struct{}HelloRequest;
客户问候消息(Clienthello)
当一客户第一次与服务器进行连接时,它必须发客户问候消息(Clienthello)作为它的第
一个消息。客户也可以将此消息作为对服务器发来的要求问候消息的回应,还可以作为它自
己想重新协商一已存在的对话的安全参数的标志发出此消息。
客户问候消息(Clienthello)包含一以后会在协议中用到的随机结构
struct{
uint32gmt_unix_time;
opaquerandom_bytes[28];
}Random;
gmt_unix_time以标准的 UNIX的 32位形式表示的发出者的内部时钟的当前时间和日期。
SSL协议中并不要求时钟必须是准确的,更高级的协议或应用层协议可能
会对时钟有更高的要求。
random_bytes一由安全随机数发生器产生的 28字节的随机数。
客户问候消息(Clienthello)包含一可变长度的对话标识符,如果此域的值非空,则此值
标识了在同一客户和同一服务器之间的一次对话,此次对话的安全参数是客户端想重新使用
的。这个对话的标识符也许是来自一个早期的连接,此次连接,或另一个当前活动的连接。
如果客户端仅仅要更新这个随机结构及一次连接的导出值的话,第二种选择是有用的,而第
三种选择使得不必完全重复握手协议而同时建立几种同步且独立的安全连接成为可能。对话
标识符的实际内容由服务器定义。
opaqueSessionID<0..32>;
注意:服务器不能在对话标识符中放置机密信息,不能使假的对话标识符中的内容导致任何
泄密。
这个包含在由客户端传向服务器的客户问候消息(clienthello)中的加密套接字
(CipherSuite)列表包含了加密算法的组合,此列表是客户端所支持的的加密算法的列表,
且此列表的顺序是由客户端按其自身的偏爱而选定的(列表的第一项是其最喜爱的)。每一
CipherSuite 同时定义了一个密钥交换算法和一个 CipherSpec。服务器将或者选择一个
CipherSuite,或者,如果未给出可接受的选择,将返回一个 handshakefailure报警并关闭
连接。
uint8CipherSuite[2];/*加密组选择器*/
此客户问候消息(clienthello)包含了一个由客户端支持的压缩算法的列表,且根据客户
端的偏好排序。如果服务器不支持客户端所定义的任何一种压缩算法,则此次对话失败。
enum{null(0),(255)}CompressionMethod;
问题:需要支持哪一种要压缩算法正处于调查之中。
客户问候消息(clienthello)的结构如下:
struct{
ProtocolVersionclient_version;
Randomrandom;
SessionIDsession_id;
CipherSuitecipher_suites<2..216-1>;
CompressionMethodcompression_methods<1..28-1>;
}ClientHello;
client_version客户端希望在此次对话中使用的 SSL协议的版本。这应该是被客户
端所支持的最新的版本(最高值)。对于本文所描述的 SSL协议,版
本号应该是 。(关于背景兼容信息请见附录 E)。
random一个客户端生成的随机结构。
session_id客户端在此次连接中想使用的对话标识符(ID)。如果没有可用的
session—ID或者客户端想要生成新的加密参数,这个值应该为空。
cipher_suites这是一个由客户端支持的,由客户端按其自身的偏爱而选定的加密套
接字的列表(列表的第一项是其最喜爱的),如果 session_id域非
空(暗示重新开始一已有的对话),则此向量必须至少包含来自已有
对话的 cipher_suite。加密套接字的值的定义见附录 。
compression_methods这是一个由客户端支持的压缩算法的列表,他根据客户端自身的偏
爱而选定的(列表的第一项是其最喜爱的),如果 session_id域非
空(暗示重新开始一已有的对话),则此向量必须至少包含一个来自
已有对话的 compression_methods的参数。所有实现均必须支持
。
继发送 clienthello 消息之后,客户端等候一个服务器问候消息(serverhellomessage)。
除了 hello消息外,由服务器返回的任何其他握手消息,均被视为致命错误(fatalerror)。
实现时注意:只有当结束消息(finishedmessage)发送之后,应用程序的数据才能被发送。
在一个合法的结束(finished)消息被收到之前,就传输应用程序的数据被认为是不安全的。
如果此次连接有一个当前的,非空的加密,则此绝对的限制将被放宽。
服务器问候消息(Serverhello)
服务器处理客户端问候消息(clienthello)并且对客户端问候消息作出握手失败
(handshake_failure)警告或者发出服务器问候消息(serverhello)作为响应。
struct{
ProtocolVersionserver_version;
Randomrandom;
SessionIDsession_id;
CipherSuitecipher_suite;
CompressionMethodcompression_method;
}ServerHello;
server_version这个域将包含客户端在客户端问候消息(clienthello)中建
议使用的最低版本和被服务器所支持的最高版本。对于使用本
详细说明书的版本来说,版本号应为 (关于背景兼容性的详
细信息请见附录 E)
random这个结构由服务器产生,且必须与客户问候消息中的
不同,并且独立于 。
session_id这是对应于此次连接的对话标识。若客户问候消息中的
_id非空,服务器将在对话缓存器中寻找
匹配的对话。如果匹配被找到并且服务器希望利用给定的对话
对话状态码建立一个新的连接,服务器将用与客户问候消息中
给定的相同的值响应,这确认了一个重新开始的对话,且对话
双方将在收到对方的直到 finished消息之前将继续执行下去。
否则,这个域将包含一个与客户问候消息中的 session_id不同
的值以标志一个新的对话。服务器可以返回一个空对话标识
(session_id)用来表示这个对话将不会被缓存,而且因此不能
被重新开始。
Cipher_suite由服务器从客户端问候消息中的 _suites
列表中选择一个加密套接字而得到的。对于重新开始的对话,
此域的值是从重新开始的对话状态字中得到的。
compression_method由服务器从客户端问候消息中的 compress_method列表中选择的
一压缩算法。对于重新开始的对话此域的值是从重新开始的对话
状态字中得到的。
服务器的证书(Servercertificate)
如果服务器要求被认证(通常都是这么要求的),则服务器在发出服务器问候消息
(serverhellomessage)之后接着发出服务器证书。证书的类型必须是由被选择的加密套接
字中密钥交换算法所支持的,通常是 .版本 3的证书(或是一在 Fortezza[FOR]下的修
改过的 证书。客户端的证书的类型与服务器的证书类型相同。
<1..224-1>;
struct{
_list<1..224-1>;
}Certificate;
certificate_list 证书链中包含一序列 .版本 3 的证书,这些证书的顺序是首先是要
验证的一方的证书,然后是发出前一个证书的一方的证书…最后是根的证书。
注意:由于没有使用 PKCS#6[PKCS6]扩充证书,所以 PKCS#7[PKCS7]也不能做为证书向量的
格式来使用。且 PKCS#7 定义了一个集合而不是一个序列,从而使解析证书列表的任务更为
复杂。
服务器密钥交换消息(Serverkeyexchangemessage)
若服务器没有证书,或只有供其签名用的公钥证书(例如 DSS[DSS]证书,只供签名的 RSA[RSA]
证书),或使用了 Fortezza/DMS 密钥交换,则服务器发出服务器密钥交换消息
(serverkeyexchangemessage)。当服务器的证书中包含 Diffie-Hellman[DH1](即公钥加密)
参数时,则不发出此消息。
注意:根据当前的美国出口法律,在软件中用于密钥交换的超过 512比特的 RSA模块是不允
许出口的。对于此消息,长的 RSA密钥可以做为只用作签名的证书来签用作密钥交换的临时
的短的 RSA密钥。
enum{rsa,diffie_hellman,fortezza_dms}KeyExchangeAlgorithm;
struct{
opaquersa_modulus<1..216-1>;
opaquersa_exponent<1..216-1>;
}ServerRSAParams;
其中:
rsa_modulus服务器的临时的 RSA密钥的模数。
rsa_exponent服务器的临时的 RSA密钥的公开指数。
struct{
opaquedh_p<1..216-1>;
opaquedh_g<1..216-1>;
opaquedh_Ys<1..216-1>;
}ServerDHParams;/*短期的 DH参数*/
其中:
dh_pDiffie-Hellman操作中用到的质模数。
dh_gDiffie-Hellman操作中用到的发生器。
dh_Y服务器的 Diffie-Hellman公开值(gXmodp)。
struct{
opaquer_s[128];
}ServerFortezzaParams;
其中:
r_s服务器为密钥交换算法而生成的随机数。
digitally-signedstruct{
select(SignatureAlgorithm){
caseanonymous:struct{};
casersa:opaquemd5_hash[16];
opaquesha_hash[20];
casedsa:opaquesha_hash[20];
};
}Signature;
struct{
select(KeyExchangeAlgorithm){
casediffie_hellman:ServerDHParamsparams;
Signaturesigned_params;
casersa:ServerRSAParamsparams;
Signaturesigned_params;
casefortezza_dms:ServerFortezzaParamsparams;
};
}ServerKeyExchange;
其中:
params服务器的密钥交换参数。
signed_params相应的参数值的哈希值,及对此哈希值的签名。
md5_hashMD5(++ServerParams);
sha_hashSHA(++ServerParams);
enum{anonymous,rsa,dsa}SignatureAlgorithm;
证书请求(Certificaterequest)
如果选择的加密套接字允许的话,一非匿名的服务器可以向客户端要求客户端的证书。
enum{
rsa_sign(1),dss_sign(2),rsa_fixed_dh(3),dss_fixed_dh(4),
rsa_ephemeral_dh(5),dss_ephemeral_dh(6),fortezza_dms(20),(255)
}ClientCertificateType;
opaqueDistinguishedName<3..216-1>;
struct{
ClientCertificateTypecertificate_types<1..28-1>;
DistinguishedNamecertificate_authorities<3..216-1>;
}CertificateRequest;
certificate_types此域的值是一被请求的证书的类型的列表,此列表是按服务器
的偏好的先后顺序排序的。
certificate_authorities是可接受的证书授权当局的唯一的辨别名的列表。
注意:唯一的辨别名是由[X509]中导出的。
注意:对于一匿名的服务器来说,请求客户端发出客户端的证书是一致命的握手失败报警。
服务器问候结束(Serverhellodone)
由服务器发出的服务器问候结束消息(serverhellodonemessage)是表明服务器问候和其相
关的消息的结束。当服务器发出此消息后,它将等待客户端的回应。
struct{}ServerHelloDone;
当客户端收到服务器问候结束消息(serverhellodonemessage)后,若它要求的话,它将验
证服务器的证书是否合法,并且检查在服务器问候消息中的参数是否是可接受的。
客户端的证书(Clientcertificate)
客户端证书是客户端收到服务器问候结束消息(serverhellodonemessage)后所能发出的第
一个消息。只有当服务器要求客户端的证书时客户端才发出此消息。如果客户端没有合适的
证书,则它发出没有证书报警(nocertificatealert),此报警仅仅是一个警告,若服务器
要求客户端认证,则服务器回应一握手失败的致命性的报警。
客户端的证书的格式的定义件 节。
注意:客户端的 Diffie-Hellman证书必须与服务器指定的 Diffie-Hellman参数相匹配。
客户端密钥交换消息(Clientkeyexchangemessage)
是否选择发出此消息依赖于在密钥交换算法定义中选择的公钥算法(见 节)
struct{
select(KeyExchangeAlgorithm){
casersa:EncryptedPreMasterSecret;
casediffie_hellman:ClientDiffieHellmanPublic;
casefortezza_dms:FortezzaKeys;
}exchange_keys;
}ClientKeyExchange;
选择合适的记录结构的信息在未决的对话状态字中(见 节)
。
加密的预主秘密消息(RSAencryptedpremastersecretmessage)
若在密钥一致性及认证时使用的是 RSA 算法,则客户端产生一 48 比特的预主秘密
(pre-mastersecret),并用服务器证书中的公钥或一由服务器密钥交换消息中得到的临时
RSA密钥对其进行加密,然后将加密的结果用一加密的预主秘密(encryptedpremastersecret)
消息发给服务器。
struct{
ProtocolVersionclient_version;
opaquerandom[46];
}PreMasterSecret;
client_version客户端所支持的最新的 SSL版本,此域用来发现版本重算攻击
(versionroll-backattacks)。
random46比特安全产生的随机数。
struct{
public-key-encryptedPreMasterSecretpre_master_secret;
}EncryptedPreMasterSecret;
pre_master_secret由客户端产生的此随机数是用来产生 节中说明的主秘密
(mastersecret)的。
密钥交换消息(Fortezzakeyexchangemessage)
在 FortezzaDMS 下,客户端利用 Fortezza 密钥交换算法 (KEA)得到一标记加密密钥
(TokenEncryptionKey(TEK))。客户端利用服务器证书中的服务器公钥和其自身的标记参
数来计算 KEA,并且利用其自身的参数发出供服务器产生 TEK 的公开参数。客户端产生对话
密钥,用 TEK 封装后发给服务器;客户端还产生对话密钥的初始向量(IV)和 TEK,并将它们
发给服务器;它还初始一 48比特的随机的预主秘密,用 TEK加密后发给服务器。
struct{
opaquey_c<0..128>;
opaquer_c[128];
opaquey_signature[20];
opaquewrapped_client_write_key[12];
opaquewrapped_server_write_key[12];
opaqueclient_write_IV[24];
opaqueserver_write_IV[24];
opaquemaster_secret_IV[24];
block-cipheredopaqueencrypted_pre_master_secret[48];
}FortezzaKeys;
y_signaturey_signature是 KEA公钥的签名,是用客户端的 DSS私钥签的
名。
y_c在 KEA计算中用到的客户端的 Yc值(公钥)。若客户端已发
出其证书且 KEA公钥是合适的,则由于证书中已有此值,此
域可以为空。当客户端发出一密钥合适的公钥的证书的时候,
就要有 y_c,且 y_signature是用客户端 DSS私钥签署的 KEA
公钥的签名。它必须在 64至 128比特之间。
r_c客户端为计算 KEA的 Rc值。
wrapped_client_write_key这是客户端的写密钥,是由 TEK封装的。
wrapped_server_write_key这是服务器的写密钥,是由 TEK封装的。
client_write_IV这是客户端的写密钥的初始化向量。
server_write_IV这是服务器的写密钥的初始化向量。
master_secret_IV这是用来加密预主秘密的 TEK的初始化向量。
pre_master_secret这是一个由客户端产生的随机数,用来产生 节中所描述
的主秘密。在上述结构中,它是用 TEK加密过的。
客户端 Diffie-Hellman公开值(ClientDiffie-Hellmanpublicvalue)
若客户端的 Diffie-Hellman公开值(Yc)未包含在客户端的证书中的话,此结构将传送它。
Yc使用的编码方式是由枚举类型 PublicValueEncoding.所决定的。
enum{implicit,explicit}PublicValueEncoding;
其中:
implicit若客户端的证书中已包含此公开值,则它是隐含的,所以 Yc不需再传了。
ExplicitYc需要被传送。
struct{
select(PublicValueEncoding){
caseimplicit:struct{};
caseexplicit:opaquedh_Yc<1..216-1>;
}dh_public;
}ClientDiffieHellmanPublic;
其中:
dh_Yc客户端的 Diffie-Hellman公开值(Yc)。
证书验证(Certificateverify)
此消息被用来对客户端的证书提供明显的验证。此消息仅在有签名能力的客户端证书(即没
有包含固定的 Diffie-Hellman参数的所有证书)发出之后才被发出。
struct{
Signaturesignature;
}CertificateVerify;
_hash
MD5(master_secret+pad2+
MD5(handshake_messages+master_secret+pad1));
_hash
SHA(master_secret+pad2+
SHA(handshake_messages+master_secret+pad1));
在这里,握手消息(handshake_messages)指的是从客户端问候(clienthello)消息开始
的,不包含此消息在内的到目前为止的所有握手消息。
结束消息(Finished)
在 发 出 旨 在 验 证 密 钥 交 换 和 认 证 过 程 是 否 成 功 的 更 改 加 密 说 明 消 息
(changecipherspecsmessage)之后,发出此结束消息,此结束消息是第一个由刚刚协商的
算法、密钥及秘密保护的消息,且此消息不要求回应。通信各方在发出结束消息之后便可发
出加密过的应用数据。此结束消息的接收者必须验证消息内容是正确的。
enum{client(0x434C4E54),server(0x53525652)}Sender;
struct{
opaquemd5_hash[16];
opaquesha_hash[20];
}Finished;
其中:
md5_hashMD5(master_secret+pad2+MD5(handshake_messages+
Sender+master_secret+pad1));
sha_hashSHA(master_secret+pad2+SHA(handshake_messages+
Sender+master_secret+pad1));
由服务器发出的结束消息中包含的哈希值与 中的值是一致的,而由客户端发
出 的 结 束 消 息 中 的 哈 希 值 与 中 的 值 相 一 致 。 握 手 消 息
(handshake_messages)中的值包含由客户端问候消息开始的,不包含结束消息在内的所有
握手消息。由于它包含证书验证消息(若它发出的话),所以这与 节中定义的握手消
息(handshake_messages)不同。
注意:更改加密说明消息(Changecipherspecmessages)不是握手消息,所以它并没有包含
在哈希值的计算中。.
应用数据传输协议(Applicationdataprotocol)
应用数据消息是由记录层传输的,它根据当前的连接状态被打包、压缩和加密。这些消息被
记录层认为是透明的数据。
八加密计算(Cryptographiccomputations)
密钥交换。认证、加密和消息文摘( MAC)的算法是由服务器选择的加密套接字
(cipher_suite)并且在服务器问候中被反映出来。
非对称的加密算法
非对称的加密算法用于在握手协议中认证各方并且产生共享的密钥和秘密。
对 于 Diffie-Hellman , RSA 和 Fortezza 来 说 , 相 同 的 算 法 被 用 来 将 预 主 秘 密
(pre_master_secret)转化为主秘密(master_secret)。当主秘密(master_secret)被计
算出来之后,预主秘密(pre_master_secret)应从内存中删除。
master_secret=
MD5(pre_master_secret+SHA(`A'+pre_master_secret+
+))+
MD5(pre_master_secret+SHA(`BB'+pre_master_secret+
+))+
MD5(pre_master_secret+SHA(`CCC'+pre_master_secret+
+));
当服务器认证和密钥交换是使用的是 RSA 算法时,客户端将产生一 48 比特的预主秘密,并
用服务器的公钥加密后发给服务器。服务器利用它的私钥解出此预主秘密,然后通信双方均
按如上方法将预主秘密转化为主秘密。
RSA 数字签名是利用 PKCS#1[PKCS1]的 blocktype1 进行的,RSA 公钥加密是利用 PKCS#1 的
blocktype2进行的。
-Hellman
这里进行的是一传统的 Diffie-Hellman 加密计算。协商的密钥(Z)用作预主秘密
(pre_master_secret),并按上述方法被转化成主秘密(master_secret)。
注意:Diffie-Hellman参数由服务器指定,且可以是临时的,也可以被包含在服务器的证书
中。
客户端产生一随机的 48比特的预主秘密(pre_master_secret)被 TEK和其初始化向量 IV加
密后发出,服务器解出此预主秘密(pre_master_secret)并用上述方法将其转化为主秘密
(master_secret)。Bulk 加密密钥和初始化向量是由客户端标识(token)产生的并在密钥交
换消息中被交换。主秘密只在产生消息文摘(MAC)时才用到。
对称加密算法和加密说明(CipherSpec)
加密的验证 SSL记录完整性的技术是由当前活跃的加密说明(CipherSpec)所指定的。一个
典型的例子是用 DES进行数据加密、用 MD5产生认证码。在 SSL握手协议开始时,加密算法
和消息验证(MAC)算法被设为 SSL_NULL_WITH_NULL_NULL,表明消息未被加密且不需认证。
握手协议被用来协商一个更为安全的加密说明(CipherSpec)并产生加密的密钥。
主秘密(mastersecret)
在安全加密和完整性验证可以被用在记录之前,客户端和服务器需要产生一只有它们采知道
的共享秘密。此值是一 48 比特的称为主秘密的字节流,主秘密被用来产生加密和消息验证
码(MAC)的密钥和秘密。有一些象 Fortezza那样的算法,有其自身的产生加密密钥的过程,
所以主秘密仅被用在产生消息验证码(MAC)。
将主秘密转化为密钥和消息验证码(MAC)的秘密
主秘密被哈希函数杂凑成一系列安全的字节流,它按当前的加密说明(CipherSpec)中的要
求被赋给消息验证码(MAC)秘密、密钥和初始化向量(见附录 )。
加密说明(CipherSpecs)由一客户端写 MAC秘密(clientwriteMACsecret),一服务器写 MAC
秘密(serverwriteMACsecret),一客户端写密钥(clientwritekey),一服务器写密钥
(aserverwritekey),一客户端写初始化向量(clientwriteIV)和一服务器写初始化向量
(aserverwriteIV)组成,它们是按此顺序由主秘密产生的。象 Fortezza 算法中那样利用
密钥交换消息交换的数据加密密钥,而在加密说明(CipherSpecs)中未用到的值置为空。
下列是定义密钥过程的输入:
opaqueMasterSecret[48]
当产生密钥和消息验证码秘密时,主秘密被用作熵,而随机数提供了未加密随机原材料
(saltmaterial)。初始化向量提供了适合输出的密码(exportableciphers)。
为产生密钥,计算:
key_block=
MD5(master_secret+SHA(`A'+master_secret+
+))+
MD5(master_secret+SHA(`BB'+master_secret+
+))+
MD5(master_secret+SHA(`CCC'+master_secret+
+))+[...];
直至产生了足够的输出,这样密钥块(key_block)被如下分配:
client_write_MAC_secret[_size]
server_write_MAC_secret[_size]
client_write_key[_material]
server_write_key[_material]
client_write_IV[_size]/*非输出性密码*/
server_write_IV[_size]/*非输出性密码*/
其他密钥块均被抛弃。
可输出的加密算法(即 _exportable 的值为真)要求如下附加的过程来得到
最终的写密钥:
final_client_write_key=MD5(client_write_key+
+);
final_server_write_key=MD5(server_write_key+
+);
可输出的加密算法由消息中的随机数得到它们的初始化向量:
client_write_IV=MD5(+);
server_write_IV=MD5(+);
通过删除最不重要的字节,MD5的输出被修剪至合适的大小。
输出的密钥(Exportkey)的产生的例子
SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5要求每一(共两个)加密密钥有 5个随机的字节、每
一消息验证码(MAC)密钥(共两个)有 16 个随机的字节,所以共需要 42 个随机的字节。
每一次调用 MD5都将产生 16字节的输出,所以共需调用 3次 MD5,MD5的输出连接起来形成
一 48字节的密钥块,其中第一次调用 MD5产生第 0至 15字节,第二次调用提供第 16至 31
字节等,密钥块被分割了且由于用到了可输出的加密算法,写密钥是 salted。
client_write_MAC_secret=key_block0..15
server_write_MAC_secret=key_block16..31
client_write_key=key_block32..36
server_write_key=key_block37..41
final_client_write_key=MD5(client_write_key+
+)0..15;
final_server_write_key=MD5(server_write_key+
+)0..15;
client_write_IV=MD5(+)0..7;
server_write_IV=MD5(+)0..7;
附录 A
A.协议常量值(Protocolconstantvalue)
本节主要描述协议的类型和常量
保留的端口值
目前 SSL是利用 TCP/IP做为其基本网络技术实现的。IANA为 SSL连接保留下列 Internet协
议(IP)端口:
443为带有 SSL的超文本传输协议(HTTP)而保留的端口。
465 为带有 SSL的简易邮件传输协议(ssmtp)而保留(未决的)的端口。
563为带有 SSL的网络新闻组传输协议(snntp)而保留(未决的)的端口。
记录层(Recordlayer)
struct{
uint8major,minor;
}ProtocolVersion;
ProtocolVersionversion={3,0};/*定义 SSL版本号为 */
enum{
change_cipher_spec(20),alert(21),handshake(22),
application_data(23),(255)
}ContentType;
struct{
ContentTypetype;
ProtocolVersionversion;
uint16length;
opaquefragment[];
}SSLPlaintext;
struct{
ContentTypetype;/*与 相同*/
ProtocolVersionversion;/*与 相同*/
uint16length;
opaquefragment[];
}SSLCompressed;
struct{
ContentTypetype;
ProtocolVersionversion;
uint16length;
select(_type){
casestream:GenericStreamCipher;
caseblock:GenericBlockCipher;
}fragment;
}SSLCiphertext;
stream-cipheredstruct{
opaquecontent[];
opaqueMAC[_size];
}GenericStreamCipher;
block-cipheredstruct{
opaquecontent[];
opaqueMAC[_size];
uint8padding[_length];
uint8padding_length;
}GenericBlockCipher;
更改加密说明消息(Changecipherspecsmessage)
struct{
enum{change_cipher_spec(1),(255)}type;
}ChangeCipherSpec;
报警消息(Alertmessage)
enum{warning(1),fatal(2),(255)}AlertLevel;
enum{
close_notify(0),
unexpected_message(10),
bad_record_mac(20),
decompression_failure(30),
handshake_failure(40),no_certificate(41),bad_certificate(42),
unsupported_certificate(43),certificate_revoked(44),
certificate_expired(45),certificate_unknown(46),
illegal_parameter(47),
(255)
}AlertDescription;
struct{
AlertLevellevel;
AlertDescriptiondescription;
}Alert;
握手协议(Handshakeprotocol)
enum{
hello_request(0),client_hello(1),server_hello(2),
certificate(11),server_key_exchange(12),certificate_request(13),
server_done(14),certificate_verify(15),client_key_exchange(16),
finished(20),(255)
}HandshakeType;
struct{
HandshakeTypemsg_type;/*握手消的类型*/
uint24length;/*握手消息体的长度(以字节计算)*/
select(HandshakeType){
casehello_request:HelloRequest;
caseclient_hello:ClientHello;
caseserver_hello:ServerHello;
casecertificate:Certificate;
caseserver_key_exchange:ServerKeyExchange;
casecertificate_request:CertificateRequest;
caseserver_done:ServerHelloDone;
casecertificate_verify:CertificateVerify;
caseclient_key_exchange:ClientKeyExchange;
casefinished:Finished;
}body;
}Handshake;
struct{}HelloRequest;
struct{
uint32gmt_unix_time;
opaquerandom_bytes[28];
}Random;
opaqueSessionID<0..32>;
uint8CipherSuite[2];
enum{null(0),(255)}CompressionMethod;
struct{
ProtocolVersionclient_version;
Randomrandom;
SessionIDsession_id;
CipherSuitecipher_suites<0..216-1>;
CompressionMethodcompression_methods<0..28-1>;
}ClientHello;
struct{
ProtocolVersionserver_version;
Randomrandom;
SessionIDsession_id;
CipherSuitecipher_suite;
CompressionMethodcompression_method;
}ServerHello;
服 务 器 认 证 和 密 钥 交 换 消 息
(Serverauthenticationandkeyexchangemessage)
<224-1>;
struct{
_list<1..224-1>;
}Certificate;
enum{rsa,diffie_hellman,fortezza_dms}KeyExchangeAlgorithm;
struct{
opaqueRSA_modulus<1..216-1>;
opaqueRSA_exponent<1..216-1>;
}ServerRSAParams;
struct{
opaqueDH_p<1..216-1>;
opaqueDH_g<1..216-1>;
opaqueDH_Ys<1..216-1>;
}ServerDHParams;
struct{
opaquer_s[128]
}ServerFortezzaParams
struct{
select(KeyExchangeAlgorithm){
casediffie_hellman:
ServerDHParamsparams;
Signaturesigned_params;
casersa:
ServerRSAParamsparams;
Signaturesigned_params;
casefortezza_dms:
ServerFortezzaParamsparams;
};
}ServerKeyExchange;
enum{anonymous,rsa,dsa}SignatureAlgorithm;
digitally-signedstruct{
select(SignatureAlgorithm){
caseanonymous:struct{};
casersa:
opaquemd5_hash[16];
opaquesha_hash[20];
casedsa:
opaquesha_hash[20];
};
}Signature;
enum{
RSA_sign(1),DSS_sign(2),RSA_fixed_DH(3),DSS_fixed_DH(4),
RSA_ephemeral_DH(5),DSS_ephemeral_DH(6),Fortezza_dms(20),(255)
}CertificateType;
opaqueDistinguishedName<3..216-1>;
struct{
CertificateTypecertificate_types<1..28-1>;
DistinguishedNamecertificate_authorities<3..216-1>;
}CertificateRequest;
struct{}ServerHelloDone;
客 户 端 认 证 和 密 钥 交 换 消 息
(Clientauthenticationandkeyexchangemessage)
struct{
select(KeyExchangeAlgorithm){
casersa:EncryptedPreMasterSecret;
casediffie_hellman:DiffieHellmanClientPublicValue;
casefortezza_dms:FortezzaKeys;
}exchange_keys;
}ClientKeyExchange;
struct{
ProtocolVersionclient_version;
opaquerandom[46];
}PreMasterSecret;
struct{
public-key-encryptedPreMasterSecretpre_master_secret;
}EncryptedPreMasterSecret;
struct{
opaquey_c<0..128>;
opaquer_c[128];
opaquey_signature[20];
opaquewrapped_client_write_key[12];
opaquewrapped_server_write_key[12];
opaqueclient_write_iv[24];
opaqueserver_write_iv[24];
opaquemaster_secret_iv[24];
opaqueencrypted_preMasterSecret[48];
}FortezzaKeys;
enum{implicit,explicit}PublicValueEncoding;
struct{
select(PublicValueEncoding){
caseimplicit:struct{};
caseexplicit:opaqueDH_Yc<1..216-1>;
}dh_public;
}ClientDiffieHellmanPublic;
struct{
Signaturesignature;
}CertificateVerify;
握手结束消息(Handshakefinalizationmessage)
struct{
opaquemd5_hash[16];
opaquesha_hash[20];
}Finished;
加密套接字(CipherSuite)
在加密套接字(CipherSuite)中定义的下列值在客户端问候消息和服务器问候消息中被用
到。
一加密套接字(CipherSuite)定义了一由 SSL版本 所支持的加密说明。
CipherSuiteSSL_NULL_WITH_NULL_NULL={0x00,0x00};
下列加密套接字(CipherSuite)的定义要求服务器提供一可以用来作密钥交换的 RSA证书。
服务器可以在证书请求消息中请求一能进行 RSA或 DSS签名的证书。
CipherSuiteSSL_RSA_WITH_NULL_MD5={0x00,0x01};
CipherSuiteSSL_RSA_WITH_NULL_SHA={0x00,0x02};
CipherSuiteSSL_RSA_EXPORT_WITH_RC4_40_MD5={0x00,0x03};
CipherSuiteSSL_RSA_WITH_RC4_128_MD5={0x00,0x04};
CipherSuiteSSL_RSA_WITH_RC4_128_SHA={0x00,0x05};
CipherSuiteSSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5={0x00,0x06};
CipherSuiteSSL_RSA_WITH_IDEA_CBC_SHA={0x00,0x07};
CipherSuiteSSL_RSA_EXPORT_WITH_DES40_CBC_SHA={0x00,0x08};
CipherSuiteSSL_RSA_WITH_DES_CBC_SHA={0x00,0x09};
CipherSuiteSSL_RSA_WITH_3DES_EDE_CBC_SHA={0x00,0x0A};
下列加密套接字(CipherSuite)的定义被用来进行服务器的 Diffie-Hellman认证(当然也
可以做客户端认证)。其中 DH 指定了一由证书授权当局(CA)签署的包含 Diffie-Hellman 参
数的服务器证书的加密套接字(ciphersuite);DHE指定一临时的 Diffie-Hellman参数,这
些参数是由证书授权当局(CA)签署的 DSS 或 RSA 证书中的公钥签署过的。在 DH 或 DHE 之后
的是所使用的签名算法。在所有的情况下,客户端的证书类型都要和服务器的证书类型相一
致,且必须利用由服务器所选择的 Diffie-Hellman参数。
CipherSuiteSSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA={0x00,0x0B};
CipherSuiteSSL_DH_DSS_WITH_DES_CBC_SHA={0x00,0x0C};
CipherSuiteSSL_DH_DSS_WITH_3DES_EDE_CBC_SHA={0x00,0x0D};
CipherSuiteSSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA={0x00,0x0E};
CipherSuiteSSL_DH_RSA_WITH_DES_CBC_SHA={0x00,0x0F};
CipherSuiteSSL_DH_RSA_WITH_3DES_EDE_CBC_SHA={0x00,0x10};
CipherSuiteSSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA={0x00,0x11};
CipherSuiteSSL_DHE_DSS_WITH_DES_CBC_SHA={0x00,0x12};
CipherSuiteSSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA={0x00,0x13};
CipherSuiteSSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA={0x00,0x14};
CipherSuiteSSL_DHE_RSA_WITH_DES_CBC_SHA={0x00,0x15};
CipherSuiteSSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA={0x00,0x16};
下列加密套接字被用来在通信双方均没有认证的情况下进行完全匿名的 Diffie-Hellman 通
讯,值得注意的是,这种方式是很容易受到中间人的攻击,所以这里不推荐使用这种方式。
CipherSuiteSSL_DH_anon_EXPORT_WITH_RC4_40_MD5={0x00,0x17};
CipherSuiteSSL_DH_anon_WITH_RC4_128_MD5={0x00,0x18};
CipherSuiteSSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA={0x00,0x19};
CipherSuiteSSL_DH_anon_WITH_DES_CBC_SHA={0x00,0x1A};
CipherSuiteSSL_DH_anon_WITH_3DES_EDE_CBC_SHA={0x00,0x1B};
最后是 Fortezza标识(token)的加密套接字。
CipherSuiteSSL_FORTEZZA_DMS_WITH_NULL_SHA={0X00,0X1C};
CipherSuiteSSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA={0x00,0x1D};
注意:以 0xFF 作为第一个字节的所有加密套接字都被认为是私有的,所以可以被用来定义
局部/临时的算法。这种类型的互操作性是一个局部的问题。
注意:只有当独立的通信双方均递交了公证信后,附加的加密套接字才会被考虑实现。在公
开的控制 SSL的标准被承认之前,NetscapeCommunications公司会充当中间的注册机构。
加密说明(CipherSpec)
一加密套接字标识了一加密说明(CipherSpec)。这些结构是 SSL 对话状态字的一部分。加
密说明(CipherSpec)包括:
enum{stream,block}CipherType;
enum{true,false}IsExportable;
enum{null,rc4,rc2,des,3des,des40,fortezza}BulkCipherAlgorithm;
enum{null,md5,sha}MACAlgorithm;
struct{
BulkCipherAlgorithmbulk_cipher_algorithm;
MACAlgorithmmac_algorithm;
CipherTypecipher_type;
IsExportableis_exportable
uint8hash_size;
uint8key_material;
uint8IV_size;
}CipherSpec;
AppendixB
B.词汇表
应用协议(applicationprotocol)
应用协议是通常位于传输协议(例如 TCP/IP)之上的协议,常见的应用协议有:HTTP,
TELNET,FTP和 SMTP。
非对称加密(asymmetriccipher)
见公钥加密(publickeycryptography)。
认证(authentication)
认证是参与连接的一方决定另一方是否是它所要连接的对象的能力。
块加密(blockcipher)
块加密是一将明文首先分为大小相等的块,然后再对这些块进行加密的算法。典型的块的大
小为 64比特。
bulkcipher
用来对大量的数据进行加密的对称的加密算法。
CipherBlockChainingMode(CBC)
CBC 是一种加密方式,其中,每一明文块在加密之前首先与上一个明文块的加密所得的密文
相异或(当所加密的密文块是第一个密文块时,它与初始化向量相异或),然后再进行加密。
证书(certificate)
证书作为 协议()的一部分,是由可信的证书授权
当局发放的。是用来对一方进行身份验证和提供被授予方的公钥的
客户端(client)
与服务器端初始化一连接的应用实体。
客户端写密钥(clientwritekey)
用来对客户端所写的数据进行加密的密钥。
客户端写 MAC秘密(clientwriteMACsecret)
用来对客户端所写的数据进行完整性验证的秘密数据。
连接(connection)
一连接是一提供合适类型服务的传送器(根据 OSI 七层协议的定义)。对于 SSL 来说,这种
连接是一点对点的关系,连接是临时的且每一连接均与一对话相对应。
数据加密标准(DataEncryptionStandard(DES))
DES是一被广泛使用的对称加密算法,它属于块加密。
数字签名标准(DigitalSignatureStandard(DSS))
DSS 是 数 字 签 名 的 标 准 , 其 中 包 含 由 NISTFIPSPUB186 所 定 义 的 、 由
NationalInstituteofStandardsandTechnology所支持的、由美国商业部在 1994年五月出版
的数字签名算法。
数字签名(digitalsignatures)
数字签名利用公钥加密算法和单向哈希函数产生一可以被验证的数据的签名。且此签名
asignatureofthedatathat很难被伪造和复制。
Fortezza
一同时提供加密和数字签名的 PCMCIA卡。
握手(handshake)
在客户端和服务器之间初始化协商它们之间的连接参数的过程。
初始化向量(InitializationVector(IV))
当使用 CBC方式的块加密时,初始化向量与明文的第一块进行异或后再进行加密。
IDEA
由 XuejiaLai和 JamesMassey所设计的 64比特的对称加密算法。
消息验证码(MessageAuthenticationCode(MAC))
消息验证码是一消息及相关的秘密数据的单向哈希值。它的目的是防止消息在传输过程中被
篡改。
主秘密(mastersecret)
被用来产生加密用的密钥、MAC秘密和初始化向量的安全的秘密数据。
MD5
MD5[7]是一将任意长的数据转化为固定长度的数据流的安全哈希算法。
公钥加密算法(publickeycryptography)
一由两个密钥组成的加密技术,由公钥加密的消息仅能由相应的私钥解出;同样的,由私钥
签署的消息仅能由相应的公钥进行验证。
单向哈希函数(one-wayhashfunction)
是一将一任意长度的数据转化为一固定长度的哈希值的单向转换过程。它的逆过程和找到冲
突的可能性必须是计算上不可行的。MD5和 SHA是单向哈希函数。
RC2,RC4
由 RSADataSecurity,Inc 所专有的 bulk 加密算法(由于他们没有出版他们的工作成果,所
以有参考很少,只能见[RSADSI])。RC2是一块加密算法而 RC4是一流加密算法。
RSA
可以用来加密也可以用来签名的被广泛使用的公钥加密算法.
salt
用来使可输出的加密密钥对预计算攻击(precomputationattack)有一定的防卫能力的非加
密的随机数。
服务器(server)
服务器是对客户端的连接请求进行应答的应用实体。服务器被动的等待客户端的请求。
session
一 SSL对话是客户端和服务器之间进行的一次联系。对话是由握手协议产生的。对话定义了
一系列可以由多个连接所共享的加密参数。利用对话可以避免为每一连接协商新的加密参数。
sessionidentifier
是由服务器产生的用来标识一特定的对话的一标识值。
服务器写密钥(serverwritekey)
是用来对服务器所写的数据进行加密的密钥。
服务器写 MAC秘密(serverwriteMACsecret)
是用来验证服务器所写的数据的完整性的密码数据。
SHA 安全哈希算法(SecureHashAlgorithm)是在 IPSPUB180-1 中定义的,它将产生一 20 比
特的输出。
流加密 streamcipher
是一加密算法,此算法先将密钥转化为一与加密相关的密钥流,然后将此密钥流于明文进行
异或(Ored)。
对称加密(symmetriccipher)
见 bulkcipher。