The TLS Protocol V1.0 - RFC 2246 中文版

翻译 kipway@outlook.com

阅读原版TLS协议有助于正确使用openssl开源库,本文力求翻译准确,如有错误,请发邮件指正。本译文在保留译者信息的前提下可任意转载。

内容目录

版权声明 1

概述 1

1. 介绍 1

2. 目标 1

3. 本文档的目标 2

4. 描述语言 2

4.1 基本块大小 2

4.2 其他 2

4.3 向量(Vectors) 3

4.4 数字(Numbers) 3

4.5 枚举(Enumerateds) 4

4.6 结构类型 4

4.6.1. 变体(Variants) 4

4.7 加密属性 5

4.8 常量 6

5.HMAC 和伪随机函数 6

6.TLS 记录协议(TLS Record Protocol) 8

6.1 连接状态(Connection states) 8

6.2 记录层(Record layer) 10

6.2.1 碎片(Fragmentation) 10

6.2.2 记录压缩和解压缩 11

6.2.3 记录有效载荷保护(Record payload protection) 12

6.2.3.1 空或标准流加密(Null or standard stream cipher) 12

6.2.3.2 CBC 块加密 13

6.3 密钥计算(Key calculation) 14

6.3.1 出口(Export)密钥生成示例 15

7.TSL 握手协议(TLS Handshake Protocol) 16

7.1 更改加密规范协议(Change cipher spec protocol) 16

7.2 警报协议(Alert protocol) 17

7.2.1 关闭警报(Closure alerts) 18

7.2.2 错误警报 18

7.3 握手协议概述 20

7.4 握手协议 23

7.4.1Hello 消息 23

7.4.1.1Hello 请求 23

7.4.1.2 客户端hello 24

7.4.1.3 服务器hello 26

7.4.2 服务器证书 27

7.4.3 服务器密钥交换消息 28

7.4.4 证书请求(Certificate request) 30

7.4.5 服务器hello完成 31

7.4.6 客户证书(Client certificate) 32

7.4.7 客户端密钥交换(key exchange)消息 32

7.4.7.1RSA 加密的premaster secret消息 32

7.4.7.2 客户Diffie-Hellman公共值 33

7.4.8 证书验证(Certificate verify) 34

7.4.9 结束(Finished) 34

8. 加密计算(Cryptographic computations) 35

8.1 计算master secret 35

8.1.1RSA 36

8.1.2Diffie-Hellman 36

9. 强制加密组件(Mandatory Cipher Suites) 36

10. 应用程序数据协议(Application data protocol) 36

A. 协议常数(Protocol constant values) 36

A.1Record 层 36

A.2. 更改加密规范消息 37

A.3 报警消息 38

A.4 握手协议 38

A.4.1Hello 消息 39

A.4.2 服务器认证和密钥交换消息 40

A.4.3. 客户端验证和密钥交换消息 41

A.5 加密组件(CipherSuite) 42

A.6 安全参数 43

B. 词汇表 44

C.CipherSuite 定义 47

D. 实施说明 49

D.1 临时RSA密钥 50

D.2 随机数生成和种子 50

D.3 证书和认证(Certificates and authentication) 50

D.4 加密组件(CipherSuites) 51

E. 向后兼容SSL 51

E.1 版本2客户端hello 52

E.2 避免中间版本的回滚 53

F. 安全分析(Security analysis) 53

F.1 握手协议(Handshake protocol) 53

F.1.1 认证和密钥交换(Authentication and key exchange) 53

F.1.1.1 匿名密钥交换 54

F.1.1.2 RSA 密钥交换和认证 54

F.1.1.3 Diffie-Hellman 密钥交换认证 54

F.1.2 版本回滚攻击 55

F.1.3 检测对握手协议的攻击 55

F.1.4 恢复会话 55

F.1.5 MD5 和SHA 55

F.2 保护应用程序数据 56

F.3 最后的注意事项 56

G. 专利声明 56

版权声明

版权所有(C)互联网协会(1999)。 版权所有。

概述

本文档规定了传输层安全Transport Layer Security(TLS)协议的版本1.0。 TLS协议通过Internet提供隐私通信。 该协议允许客户端/服务器应用程序以旨在防止窃听、篡改或消息伪造的方式进行通信。

1.介绍

TLS协议的主要目标是在两个通信应用之间提供隐私和数据完整性。协议由两层组成:TLS记录(Record)协议和TLS握手(Handshake)协议。在最底层,在一些可靠的传输协议(例如,TCP [TCP])之上,是TLS记录协议。TLS记录协议提供了具有两个基本的连接安全性特性:

TLS记录协议用于封装各种较高级协议。 而TLS握手协议允许服务器和客户端彼此认证,并在应用协议发送或接收其第一个数据字节之前协商加密算法和加密密钥。TLS握手协议提供的连接安全性有三个基本属性:

TLS的一个优点是它与应用协议无关。高级协议可以透明地层叠在TLS协议之上。然而,TLS标准没有指定协议如何使用TLS添加安全性; 关于如何启动TLS握手以及如何解释交换的认证证书的决定取决于在TLS之上运行的协议的设计者和实现者的判断。

2.目标

TLS协议的目标是按照优先顺序:

1.加密安全性:TLS应用于建立双方之间的安全连接。

2.互操作性:独立的程序员应该能够开发使用TLS的应用程序,然后能够成功地交换加密参数,而不需要彼此了解代码。

3.可扩展性:TLS旨在提供一个可以根据需要纳入新公钥和批量加密方法的框架。 这也将实现两个次级目标:防止创建新协议(并冒险引入可能的新漏洞),并避免不得不为此实现一整套新的安全库。

4.相对效率:加密操作往往是CPU密集型,特别是公钥操作。因此,TLS协议已经结合了可选的会话高速缓存方案,以减少需要从头开始建立的连接数。另外,已经注意减少网络活动。

3.本文档的目标

本文档和TLS协议本身是基于Netscape发布的SSL 3.0协议规范。此协议与SSL 3.0之间的区别并不明显,但它们足够重要,因为TLS 1.0和SSL 3.0不能互操作(尽管TLS 1.0 确实包含一个机制使一个TLS实现可以降级为 SSL 3.0)。本文档主要面向将要执行协议的读者以及进行加密分析的用户。这个说明书写在这一点上,它的目的是反映这两个组的需要。因此,许多算法依赖的数据结构和规则都包含在文本正文中(与附录相反),可以更容易地访问它们。

本文档不是为了提供服务定义和接口定义的任何细节,尽管它涵盖了保护安全性所需的选择政策领域。

4.描述语言

本文档涉及外部表示中数据的格式化。 将使用以下非常基本和稍微定义的演示语法。 该语法从其结构中的多个来源获取。 虽然它的语法和XDR [XDR]的语法和意图类似于编程语言“C”,但是绘制太多的并行体系将是冒险的。 此演示语言的目的仅在于记录TLS,而不是超出该特定目标的一般应用。

4.1 基本块大小

明确指定所有数据项的表示。 基本数据块大小是一个字节(即8位)。 多字节数据项是从左到右从上到下的字节连接。 从字节流中,通过以下方式形成多字节项(示例中的数字)(使用C表示法):

value = (byte[0] << 8*(n-1)) | (byte[1] << 8*(n-2)) |
... | byte[n-1];

多字节值的字节排序是常见的网络字节顺序或大端(big endian)格式。

4.2其他

注释以“/ *”开头,以“* /”结尾。

可选组件用“[[]]”括号括起来表示。

包含未解释数据的单字节实体的类型不透明。

4.3向量(Vectors)

向量(单尺寸数组)是同种数据元素的流。可以在编写文档规范时指定向量的大小,或者在运行时指定向量的大小。在任一情况下,长度都会声明向量中的字节数,而不是元素的数量。用于指定类型T的固定长度向量的新类型T'的语法是

T T'[n];

这里T'在数据流中占据n个字节,其中n是T的大小的倍数。矢量的长度不包括在编码流中。

在以下示例中,Datum被定义为协议不解释的三个连续字节,而Data是连续三个Datum,共耗用9个字节。

opaque Datum[3]; /* three uninterpreted bytes */
Datum Data[9]; /* 3 consecutive 3 byte vectors */

可变长度向量通过使用符号<floor..ceiling>指定法定长度的子范围来定义。 当编码时,实际长度在字节流中的向量的内容之前。 长度将以数字的形式消耗尽可能多的字节,以保持向量的指定最大(ceiling)长度。 具有实际长度字段为零的可变长度向量被称为空向量。

T T'<floor..ceiling>;

在以下示例中,mandatory是必须包含类型为opaque的300到400字节之间的向量。 它永远不会是空的。实际长度字段消耗两个字节,一个uint16,足以表示值400(参见第4.4节)。 另一方面,longer可以表示多达800字节的数据,或400个uint16元素,它可能为空。 它的编码将包括一个两字节的实际长度字段,前面是向量。编码向量的长度必须是单个元素的长度的偶数倍(例如,uint16的17字节向量将是非法的)。

opaque mandatory<300..400>; /* length field is 2 bytes, cannot be empty */
uint16 longer<0..800>; /* zero to 400 16-bit unsigned integers */

4.4数字(Numbers)

基本数字数据类型是无符号字节(uint8)。所有较大的数字数据类型由固定长度的字节序列组成,如第4.1节所述连接,也是无符号的。以下数字类型是预定义的。

uint8 uint16[2];
uint8 uint24[3];
uint8 uint32[4];
uint8 uint64[8];

说明书中的这里和其他地方的所有值都以“network”或“big-endian”的顺序存储; 由十六进制字节01 02 03 04表示的uint32等价于十进制值16909060。

4.5枚举(Enumerateds)

稀疏数据类型称为枚举。类型枚举的字段只能是定义中声明的值。每个定义是不同的类型。相同类型的枚举才能被赋值和比较。必须为枚举的每个元素分配一个值,如下例所示。由于枚举的元素未被排序,因此可以按任何顺序分配任何唯一的值。

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.blue。如果目标明确指定,则不需要这种限定。

Color color = Color.blue; /* overspecified, legal */
Color color = blue; /* correct, type implicit */

对于从未转换为外部表示的枚举,可以省略数字信息。

enum { low, medium, high } Amount;

4.6结构类型

结构类型可以由原始类型构建。每个规范声明一个新的唯一类型。定义的语法很像C.

struct {
T1 f1;
T2 f2;
...
Tn fn;
} [[T]];

结构中的字段可能使用类似于枚举的语法,使用类型的名称进行去确定。 例如,T.f2指上面声明的第二个字段。 可以嵌套定义结构。

4.6.1. 变体(Variants)

定义的结构可能具有变体。选择器必须是枚举类型指定的可用的结构体变量。在选择中声明的枚举的每个元素都必须有一个case arm。可以给出变体结构体的标号以供引用。运行时选择变体的机制不是由演示语言规定的。

struct {
T1 f1;
T2 f2;
....
Tn fn;
select (E) {
case e1: Te1;
case e2: Te2;
....
case en: Ten;
} [[fv]];
} [[Tv]];

例如:

enum { apple, orange } VariantTag;
struct {
uint16 number;
opaque string<0..10>; /* variable length */
} V1;
struct {
uint32 number;
opaque string[10]; /* fixed length */
} V2;
struct {
select (VariantTag) { /* value of selector is implicit */
case apple: V1; /* VariantBody, tag = apple */
case orange: V2; /* VariantBody, tag = orange */
} variant_body; /* optional label on variant */
} VariantRecord;

可以通过在类型之前指定选择器的值来限定(缩小)变体结构。 例如,a是包含类型V2的variant_body的VariantRecord的缩小类型。

4.7加密属性

四种加密操作:数字签名、流加密、分组加密和公钥加密分别被指定为数字签名、流加密、块加密和公开密钥加密。字段的加密处理通过在字段的类型规范之前提供适当的关键字指定来指定。加密密钥由当前会话状态暗示(见第6.1节)。

在数字签名中,单向散列函数用作签名算法的输入。 数字签名元素被编码为不透明向量<0..2 ^ 16-1>,其长度由签名算法和密钥指定。

在RSA签名中,两个哈希(一个SHA和一个MD5)的36字节结构被签名(用私钥加密)。它使用PKCS#1块类型0或类型1进行编码,如[PKCS1]中所述。

在DSS中,SHA哈希的20个字节直接通过数字签名算法运行,没有额外的散列。 这产生两个值r和s。 DSS签名是一个不透明的向量,如上所述,其内容是DER编码:

Dss-Sig-Value ::= SEQUENCE {
r INTEGER,
s INTEGER
}

在流加密中,明文与由加密安全密钥伪随机数发生器产生的相同数量的输出进行异或运算。

在块加密中,每个明文块加密成一个密文块。 所有块加密在CBC(加密块链)模式下完成,所有被块加密的项目将是加密块长度的精确倍数。

在公共密钥加密中,使用公钥算法对数据进行加密,使得只能使用匹配的私钥进行解密。 公钥加密元素被编码为不透明向量<0..2 ^ 16-1>,其长度由签名算法和密钥指定。

RSA加密值用PKCS#1块类型2编码,如[PKCS1]中所述。

在以下示例中:

stream-ciphered struct {
uint8 field1;
uint8 field2;
digitally-signed opaque hash[20];
} UserType;

哈希的内容被用作签名算法的输入,然后整个结构用流加密。该结构的长度(以字节为单位)将相当于field1和field2的2个字节,加上签名长度的两个字节以及签名算法输出的长度。 这是已知的,因为用于签名的算法和密钥在编码或解码该结构之前是已知的。

4.8常量

可以通过声明所需类型的符号并为其分配值来定义类型化常数。这些类型(不透明,可变长度向量和包含不透明的结构)不能够赋值。 无字段的多元素结构体或向量可以被省略。

例如,

struct {
uint8 f1;
uint8 f2;
} Example1;

Example1 ex1 = {1, 4}; /* assigns f1 = 1, f2 = 4 */

5.HMAC和伪随机函数

TLS记录和握手层中的一些操作需要一个密钥MAC; 这是一个通过机密信息(secret)保护的数据的安全摘要。不知道MAC的secret是无法构造正确的MAC摘要的。我们用于此操作的结构称为HMAC,如[HMAC]中所述。

HMAC可以与各种不同的散列算法一起使用。TLS在握手中使用两种不同的算法:MD5和SHA-1,将其表示为HMAC_MD5(secret,data)和HMAC_SHA(secret,data)。额外的散列算法可以由加密组件定义并用于保护记录数据,但是MD5和SHA-1被硬编码到该版本协议的握手描述中。

此外,为了密钥生成或验证的目的,需要构建将机密信息(secrets)扩展到数据块。该伪随机函数(PRF)将secret、seed和识别label作为输入,并产生任意长度的输出。

首先,我们定义一个数据扩展函数P_hash(secret,data),它使用单个散列函数将secret和seed扩展为任意数量的输出:

P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) +
HMAC_hash(secret, A(2) + seed) +
HMAC_hash(secret, A(3) + seed) + ...
其中+表示连接。

A() 被定义为:
A(0) = seed
A(i) = HMAC_hash(secret, A(i-1))

P_hash可以重复生成所需数量的数据所需的次数。例如,如果使用P_SHA-1来创建64字节的数据,则必须迭代4次(通过A(4)),创建80字节的输出数据; 最终迭代的最后16个字节将被丢弃,留下64个字节的输出数据。

TLS的PRF是通过将secret分割成两半而使用一半来生成带有P_MD5的数据,另一半用P_SHA-1生成数据,然后将这两个扩展功能的输出相互排斥在一起。

S1和S2是secret的两半,每个都是相同的长度。 S1从secret的前半部分采取,S2是从下半部开始的。他们的长度是通过将总secret的长度除以2来创建的; 因此,如果原始secret是奇数个字节长,则S1的最后一个字节将与S2的第一个字节相同。

L_S = length in bytes of secret;
L_S1 = L_S2 = ceil(L_S / 2);

如上所述,secret被分成两半(具有一个共享字节的可能性),S1取第一个L_S1字节,S2取最后一个L_S2字节。

然后将PRF定义为将两个伪随机流混合在一起的结果。

PRF(secret, label, seed) = P_MD5(S1, label + seed) XOR P_SHA-1(S2, label + seed);

标签是ASCII字符串。它应该被包括在给定的没有长度字节或尾随空字符的确切形式。 例如,label “slithy toves” 将通过散列以下字节来处理:

73 6C 69 74 68 79 20 74 6F 76 65 73

请注意,由于MD5产生16字节输出,SHA-1产生20字节输出,因此内部迭代的边界将不对齐; 生成80字节的输出将涉及P_MD5通过A(5)迭代,而P_SHA-1将仅迭代A(4)。

6.TLS 记录协议(TLS Record Protocol)

TLS记录协议是分层协议。在每个层,消息可以包括用于长度、描述和内容的字段。记录协议将消息传送出去,将数据分解成可管理的块,可选压缩数据、应用MAC、加密和传输结果。接收到的数据被解密、验证、解压缩和重新组合,然后传递给更高级别的客户端。

本文档描述了四个记录协议客户端:握手协议(handshake protocol)、警报协议(alert protocol)、更改加密规范协议(change cipher spec protocol)和应用程序数据协议(application data protocol)。为了允许扩展TLS协议,记录协议可以支持附加的记录类型。任何新的记录类型都应该为这里描述的四种记录类型的ContentType值立即分配类型值(见附录A.2)。如果TLS实现接收到它不明白的记录类型,则应该忽略它。任何设计用于TLS的协议都必须仔细设计,以应对所有可能的攻击。请注意,由于记录的类型和长度不受加密保护,因此应注意尽量减少这些值的流量分析值。

6.1连接状态(Connection states)

TLS连接状态是TLS记录协议的操作环境。它规定了压缩算法、加密算法和MAC算法。此外,这些算法的参数是已知的:MAC secret和用于在读取和写入方向上的连接的批量加密密钥和IV。在逻辑上,总是有四个连接状态未完成:当前的读写状态以及待处理的读写状态。所有记录都以当前的读写状态进行处理。挂起状态的安全参数可以通过TLS握手协议来设置,而握手协议可以选择性地使两个待处理状态中的任何一个状态为当前状态,在这种情况下,适当的当前状态被处理并替换为挂起状态;待处理状态然后重新初始化为空状态。这是非法的尚未使用安全参数初始化的状态为当前状态。初始当前状态总是指定不使用加密、压缩、或MAC。

TLS连接读写状态的安全参数通过提供以下值来设置:

连接端(connection end)

实体是否被视为“客户端”或“服务器”。

批量加密算法(bulk encryption algorithm)

用于批量加密的算法。 该规范包括该算法的密钥大小、该secret有多少密钥、加密的块大小(如果适用),以及它是否被认为是可“出口”加密算法。

MAC算法(MAC algorithm)

用于消息认证的算法。 该规范包括由MAC算法返回的散列的大小。

压缩算法(compression algorithm)

用于数据压缩的算法。 该规范必须包括算法需要进行压缩的所有信息。

主机密信息(Master secret)

在连接中的两个对等体之间共享一个48字节的密钥。

客户随机数(client random)

由客户端提供的32字节值。

服务器随机数(server random)

由服务器提供的32字节值。

这些参数以演示语言定义为:

enum { server, client } ConnectionEnd;
enum { null, rc4, rc2, des, 3des, des40 } BulkCipherAlgorithm;
enum { stream, block } CipherType;
enum { true, false } IsExportable;
enum { null, md5, sha } MACAlgorithm;
enum { null(0), (255) } CompressionMethod;

/* The algorithms specified in CompressionMethod,
BulkCipherAlgorithm, and MACAlgorithm may be added to. */

struct {
ConnectionEnd entity;
BulkCipherAlgorithm bulk_cipher_algorithm;
CipherType cipher_type;
uint8 key_size;
uint8 key_material_length;
IsExportable is_exportable;
MACAlgorithm mac_algorithm;
uint8 hash_size;
CompressionMethod compression_algorithm;
opaque master_secret[48];
opaque client_random[32];
opaque server_random[32];
} SecurityParameters;

记录层将使用安全参数来生成以下六个项目:

client write MAC secret
server write MAC secret
client write key
server write key
client write IV (for block ciphers only)
server write IV (for block ciphers only)

服务器在接收和处理记录时使用客户端写入参数,反之亦然。 用于从安全参数生成这些项目的算法在第6.3节中描述。

一旦设置了安全参数并且已经生成密钥,则可以通过使连接状态成为当前状态来实例化连接状态。必须对每个处理的记录更新这些当前状态。 每个连接状态包括以下元素:

压缩状态(compression state)

当前压缩算法的状态。

加密状态(cipher state)

当前状态的加密算法。这将包括该连接的预定密钥。此外,对于以CBC模式运行的块加密(仅为TLS指定的模式),最初将包含该连接状态的IV,并将其更新为包含处理记录时加密或解密的最后一个块的密文。对于流加密,这将包含任何必要的状态信息,以允许流继续加密或解密数据。

MAC secret

此连接的MAC 机密信息如上所述。

序列号(sequence number)

每个连接状态包含一个序列号,该序列号分别用于读取和写入状态。每当连接状态为活动状态,序列号必须设置为零。序列号为uint64,不得超过2 ^ 64-1。序列号在每条记录之后增加:具体来说,在特定连接状态下发送的第一条记录应使用序列号0。

6.2记录层(Record layer)

TLS记录层从任意大小的非空块中的较高层接收未解释的数据。

6.2.1碎片(Fragmentation)

记录层将信息块分割成携带2 ^ 14字节(16K块)或更少块的数据的TLSPlaintext记录。客户端消息边界不保留在记录层中(即,相同ContentType的多个客户端消息可以合并到单个TLSPlaintext记录中,或者单个消息可能跨多个记录分段)。

struct {
uint8 major, minor;
} ProtocolVersion;

enum {
change_cipher_spec(20), alert(21), handshake(22),
application_data(23), (255)
} ContentType;

struct {
ContentType type;
ProtocolVersion version;
uint16 length;
opaque fragment[TLSPlaintext.length];
} TLSPlaintext;

type

用于处理封闭片段的较高级协议。

version

使用的协议版本。 本文档介绍了使用版本{3,1}的TLS版本1.0。 版本值3.1是历史的:TLS版本1.0是SSL 3.0协议的一个小修改,它承载版本值3.0。 (见附录A.1)。

length

以下TLSPlaintext.fragment的长度(以字节为单位)。长度不能超过2 ^ 14。

fragment

应用数据。 该数据是透明的,被视为独立的块,由类型字段指定的较高级协议处理。

注意:不同TLS记录层内容类型的数据可能会交错。与其他内容类型相比,应用程序数据的传输优先级通常较低。

6.2.2记录压缩和解压缩

所有记录都使用当前会话状态中定义的压缩算法进行压缩。总是有一个活动的压缩算法; 然而,最初定义为CompressionMethod.null(null表示不压缩)。压缩算法将TLSPlaintext结构转换为TLSCompressed结构。每当连接状态被激活时,压缩函数都将使用默认状态信息进行初始化。

压缩必须是无损的,不能将内容长度增加超过1024字节。 如果解压缩功能遇到一个TLSCompressed.fragment,它将解压缩到超过2 ^ 14个字节的长度,则应报告致命的解压缩失败错误。

struct {
ContentType type; /* same as TLSPlaintext.type */
ProtocolVersion version;/* same as TLSPlaintext.version */
uint16 length;
opaque fragment[TLSCompressed.length];
} TLSCompressed;

length

以下TLSCompressed.fragment的长度(以字节为单位)。长度不应超过2 ^ 14 + 1024。

fragment

压缩格式的TLSPlaintext.fragment。

注意:CompressionMethod.null操作是一个identity操作; 没有字段被改变。

实施说明:

解压缩功能负责确保消息不会导致内部缓冲区溢出。

6.2.3记录有效载荷保护(Record payload protection)

加密和MAC功能将TLSCompressed结构转换为TLSCiphertext。解密功能使过程相反。记录的MAC还包括序列号,以便可以检测到丢失,额外或重复的消息。

struct {
ContentType type;
ProtocolVersion version;
uint16 length;
select (CipherSpec.cipher_type) {
case stream: GenericStreamCipher;
case block: GenericBlockCipher;
} fragment;
} TLSCiphertext;

type

类型字段与TLSCompressed.type相同。

version

版本字段与TLSCompressed.version相同。

length

以下TLSCiphertext.fragment的长度(以字节为单位)。长度不得超过2 ^ 14 + 2048。

fragment

TLSCompressed.fragment的加密形式,带有MAC。

6.2.3.1空或标准流加密(Null or standard stream cipher)

流加密(包括BulkCipherAlgorithm.null - 见附录A.6)将TLSCompressed.fragment结构转换为流TLSCiphertext.fragment结构。

stream-ciphered struct {
opaque content[TLSCompressed.length];
opaque MAC[CipherSpec.hash_size];
} GenericStreamCipher;

MAC产生如下:

HMAC_hash(MAC_write_secret, seq_num + TLSCompressed.type +
TLSCompressed.version + TLSCompressed.length +
TLSCompressed.fragment));

其中“+”表示连接。

seq_num

这个记录的序列号

hash

由SecurityParameters.mac_algorithm指定的散列算法。

请注意,MAC是在加密之前计算的。流加密加密整个块,包括MAC。对于不使用同步向量(例如RC4)的流加密,从一个记录结尾处的流加密状态仅用于后续数据包。如果CipherSuite是TLS_NULL_WITH_NULL_NULL,则加密由身份操作(即,数据未加密,MAC大小为零,暗示不使用MAC)组成。TLSCiphertext.length是TLSCompressed.length加上CipherSpec.hash_size。

6.2.3.2 CBC块加密

对于块加密(如RC2或DES),加密和MAC功能将TLSCompressed.fragment结构转换为块TLSCiphertext.fragment结构。

block-ciphered struct {
opaque content[TLSCompressed.length];
opaque MAC[CipherSpec.hash_size];
uint8 padding[GenericBlockCipher.padding_length];
uint8 padding_length;
} GenericBlockCipher;

如第6.2.3.1节所述生成MAC。

padding

添加的填充将明文长度强制为块密码块长度的整数倍。填充可以是长达255字节的任何长度,只要它导致TLSCiphertext.length是块长度的整数倍。可能需要长于所需时间的长度来阻止基于对交换的消息的长度的分析对协议的攻击。填充数据向量中的每个uint8必须填充填充长度值。

padding_length

填充长度应该使得GenericBlockCipher结构的总大小是加密块长度的倍数。 合法值范围从零到255(含)。 该长度指定padding_length字段本身排除的填充字段的长度。

加密的数据长度(TLSCiphertext.length)比TLSCompressed.length,CipherSpec.hash_size和padding_length的总和多一个。

示例:

如果块长度为8字节,则内容长度(TLSCompressed.length)为61字节,MAC长度为20字节,填充前的长度为82字节。因此,为了使总长度为8字节的偶数倍(块长度),模8的填充长度必须等于6。通过254,填充长度可以为6,14,22等。如果填充长度是必需的最小值,如图6所示,填充将为6字节,每个包含值6.因此,块加密之前的GenericBlockCipher的最后8个八位字节将为xx 06,06 06 06 06 06,其中xx是MAC的最后一个八位字节。

注意:使用CBC模式(加密块链接)中的块加密,当设置了安全参数时,将生成第一条记录的初始化向量(IV)和其他密钥和秘密。后续记录的IV是上次记录的最后一个密文块。

6.3 密钥计算(Key calculation)

记录协议需要一种算法,从握手协议提供的安全性参数生成密钥、IV和MAC secret。

Master secret被散列成一系列安全字节,分配给当前连接状态所需的MAC secret、密钥和非导出IV(见附录A.6)。CipherSpecs需要client write MAC secret、server write MAC secret、client write key、server write key、client write IV 和server write IV,这是从主Master secret按顺序生成的。未使用的值为空。

当生成密钥和MAC secrets时,Master secret被用作熵源,并且随机值为可出口的加密提供未加密的salt material和IV。

要生成密钥材料,计算

key_block = PRF(SecurityParameters.master_secret,
"key expansion",
SecurityParameters.server_random +
SecurityParameters.client_random);

直到产生足够的输出。然后将key_block分区如下:

client_write_MAC_secret[SecurityParameters.hash_size]
server_write_MAC_secret[SecurityParameters.hash_size]
client_write_key[SecurityParameters.key_material_length]
server_write_key[SecurityParameters.key_material_length]
client_write_IV[SecurityParameters.IV_size]
server_write_IV[SecurityParameters.IV_size]

client_write_IV和server_write_IV仅针对非导出块加密生成。 对于可出口的块加密,稍后生成初始化向量,如下所述。 任何额外的key_block资料都被丢弃。

实施说明:

在本文档中定义的加密规范需要最多的材料是3DES_EDE_CBC_SHA:它需要2 x 24字节的密钥,2 x 20字节的MAC secrets和2 x 8字节的IV,总共104个字节的密钥材料。

可出口的加密算法(CipherSpec.is_exportable为true)需要额外的处理,以获得最终的写入密钥:

final_client_write_key =
PRF(SecurityParameters.client_write_key,
"client write key",
SecurityParameters.client_random +
SecurityParameters.server_random);
final_server_write_key =
PRF(SecurityParameters.server_write_key,
"server write key",
SecurityParameters.client_random +
SecurityParameters.server_random);

可出口的加密算法仅从hello消息的随机值中导出其IV:

iv_block = PRF("", "IV block", SecurityParameters.client_random +
SecurityParameters.server_random);

由于key_block位于上面,所以将iv_block分成两个初始化向量:

client_write_IV[SecurityParameters.IV_size]
server_write_IV[SecurityParameters.IV_size]

请注意,在这种情况下,PRF在无secret下使用:这仅仅意味着secret的长度为零字节,对PRF中的散列没有任何贡献。

6.3.1 出口(Export)密钥生成示例

TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5对于两个加密密钥中的每一个需要五个随机字节,对于每个MAC密钥需要16个字节,总共42个字节的密钥材料。 PRF输出存储在key_block中。 key_block被分区,并且写密钥被伪装的(salted),因为这是可出口(exportable)的加密算法。

key_block = PRF(master_secret,
"key expansion",
server_random +
client_random)[0..41]
client_write_MAC_secret = key_block[0..15]
server_write_MAC_secret = key_block[16..31]
client_write_key = key_block[32..36]
server_write_key = key_block[37..41]

final_client_write_key = PRF(client_write_key,
"client write key",
client_random +
server_random)[0..15]
final_server_write_key = PRF(server_write_key,
"server write key",
client_random +
server_random)[0..15]

iv_block = PRF("", "IV block", client_random +
server_random)[0..15]
client_write_IV = iv_block[0..7]
server_write_IV = iv_block[8..15]

7.TSL握手协议(TLS Handshake Protocol)

TLS握手协议包括一组三个子协议,用于允许对等体同意记录层的安全性参数,对自身进行身份验证,实例化协商的安全参数以及将错误状况报告给彼此。

握手议定负责协商会话,其中包括以下内容:

会话标识符(session identifier)

由服务器选择的用于标识活动或可恢复的会话状态的任意字节序列。

对等证书(peer certificate)

X509v3 [X509]对等证书。 状态的这个元素可能为null。

压缩方式(compression method)

用于在加密之前压缩数据的算法。

加密规范(cipher spec)

指定批量数据加密算法(如null,DES等)和MAC算法(如MD5或SHA)。 它还定义了加密属性,如hash_size。 (关于正式定义见附录A.6)

主机密信息(master secret)

在客户端和服务器之间共享48字节的机密信息。

是否可以恢复

指示会话是否可用于发起新连接的标志。

然后,这些项目用于创建安全参数,以便在保护应用程序数据时由记录层使用。通过TLS握手协议的恢复功能,可以使用相同的会话来实例化许多连接。

7.1更改加密规范协议(Change cipher spec protocol)

改变加密规范协议存在于信号转换的加密策略。 该协议由单个消息组成,它在当前(非阻塞)连接状态下被加密和压缩。 该消息由单个字节的值1组成。

struct {
enum { change_cipher_spec(1), (255) } type;
} ChangeCipherSpec;

更改加密规范消息由客户端和服务器发送,以通知接收方,后续记录将受到新协商的加密算法和密钥的保护。 该消息的接收使得接收器指示记录层立即将读取待处理状态复制到读取当前状态。 在发送此消息后,发送方应立即指示记录层将写入挂起状态设置为写入活动状态。 (见第6.1节)在协商安全参数之后,但在验证完成的消息发送之前,在握手期间发送更改加密规范消息(见7.4.9节)。

7.2 警报协议(Alert protocol)

TLS记录层支持的内容类型之一是警报类型。警报消息传达消息的严重性和警报的描述。警报消息,其中一连串致命的结果立即终止连接。在这种情况下,与会话相对应的其他连接可能会继续,但会话标识符必须无效,从而阻止失败的会话被用于建立新的连接。 像其他消息一样,警报消息被加密和压缩,如当前连接状态所指定。

enum { warning(1), fatal(2), (255) } AlertLevel;

enum {
close_notify(0),
unexpected_message(10),
bad_record_mac(20),
decryption_failed(21),
record_overflow(22),
decompression_failure(30),
handshake_failure(40),
bad_certificate(42),
unsupported_certificate(43),
certificate_revoked(44),
certificate_expired(45),
certificate_unknown(46),
illegal_parameter(47),
unknown_ca(48),
access_denied(49),
decode_error(50),
decrypt_error(51),
export_restriction(60),
protocol_version(70),
insufficient_security(71),
internal_error(80),
user_canceled(90),
no_renegotiation(100),
(255)
} AlertDescription;

struct {
AlertLevel level;
AlertDescription description;
} Alert;

7.2.1关闭警报(Closure alerts)

客户端和服务器必须共享连接正在结束的知识,以避免截断攻击。 任何一方可以启动关闭消息的交换。

close_notify

此消息通知收件人,发件人不会在此连接上发送更多消息。如果任何连接终止而没有正确等于警告级别的close_notify消息,则会话将变为不可解释。

任何一方可以通过发送close_notify警报来启动关闭。关闭警报之后收到的任何数据将被忽略。

在关闭连接的写入端之前,每方都需要发送close_notify警报。要求对方以其自己的close_notify警报进行响应,并立即关闭连接,并丢弃任何挂起的写入。在关闭连接的读取端之前,关闭的发起方不需要等待响应close_notify警报。

如果使用TLS的应用程序协议规定,在TLS连接关闭后,任何数据都可能通过底层传输进行传输,则TLS实现必须在向应用层指示TLS连接已结束之前收到响应的close_notify警报。如果应用协议不会传输任何附加数据,但只会关闭底层传输连接,则执行可能会选择关闭传输,而不必等待响应close_notify。不应采用本标准的任何部分来规定TLS管理其数据传输的使用配置文件的方式,包括何时打开或关闭连接。

注意:假设在销毁传输之前关闭连接可靠地传送挂起的数据。

7.2.2 错误警报

TLS握手协议中的错误处理非常简单。 当检测到错误时,检测方向另一方发送消息。 在发送或接收致命警报消息时,双方立即关闭连接。 服务器和客户端需要忘记与故障连接相关联的任何会话标识符,密钥和秘密。 定义了以下错误警报:

unexpected_message

收到不正确的消息。 这种警报总是致命的,在正确的实现之间的通信中不应该被观察到。

bad_record_mac

如果收到带有错误MAC的记录,则返回该警报。 这个消息总是致命的。

decryption_failed

以无效方式解密的TLSCiphertext:当被检查时,它不是块长度或其填充值的偶数倍,不正确。 这个消息总是致命的。

record_overflow

接收到TLSCiphertext记录,其长度大于2 ^ 14 + 2048字节,或解密到具有超过2 ^ 14 + 1024字节的TLSCompressed记录的记录。 这个消息总是致命的。

decompression_failure

解压缩功能接收到不正确的输入(例如将扩展到过长的数据)。 这个消息总是致命的。

handshake_failure

接收handshake_failure警报消息表明发送方无法协商一个可接受的一组安全参数,给定可用的选项。这是一个致命的错误。

bad_certificate

证书已损坏,包含未正确验证的签名等。

unsupported_certificate

证书是不受支持的类型。

certificate_revoked

证书由签字人撤销。

certificate_expired

证书已过期或目前无效。

certificate_unknown

在处理证书时出现了一些其他(未指定)问题,使其不能接受。

illegal_parameter

握手中的一个字段超出了范围,或与其他字段不一致。这总是致命的。

unknown_ca

收到有效的证书链或部分链,但不能接受证书,因为CA证书无法找到或者不能与已知的可信任CA匹配。这个消息总是致命的。

拒绝访问

收到有效的证书,但是当应用访问控制时,发件人决定不进行协商。这个消息总是致命的。

decode_error

无法解码邮件,因为某些字段超出了指定的范围或邮件的长度不正确。这个消息总是致命的。

decrypt_error

握手加密操作失败,包括无法正确验证签名,解密密钥交换或验证已完成的邮件。

export_restriction

检测到不符合出口限制的谈判;例如,尝试传输用于RSA_EXPORT握手方法的1024位临时RSA密钥。这个消息总是致命的。

protocol_version

客户端尝试协商的协议版本被识别,但不被支持。 (例如,出于安全考虑,可能会避免旧的协议版本)。这个消息总是致命的。

insufficient_security

当协商失败时,返回而不是handshake_failure,因为服务器需要比客户端支持的加密更安全的加密。这个消息总是致命的。

内部错误

与对等体无关的内部错误或协议的正确性使得无法继续(例如内存分配失败)。这个消息总是致命的。

user_canceled

由于与协议失败无关的某种原因,此握手被取消。如果用户在握手完成后取消操作,则只需通过发送close_notify来关闭连接更合适。此警报后面应该有一个close_notify。这个消息通常是一个警告。

no_renegotiation

客户端响应hello请求或由服务器响应初始握手后的客户端发送。这些之一通常会导致重新谈判;当不合适时,收件人应该用这个警报来回应;在这一点上,原请求者可以决定是否继续进行连接。一种适合这种情况的情况是服务器产生了满足请求的过程;该过程可能会在启动时接收安全参数(密钥长度,身份验证等),并且可能难以在此之后传送这些参数的更改。此消息始终是警告。

对于没有明确指定警报级别的所有错误,发送方可以自行决定是否是致命错误; 如果接收到警告级别的警报,接收方可以决定是否将其视为致命错误。 然而,所有以致命级别传输的消息必须被视为致命消息。

7.3 握手协议概述

会话状态的加密参数由TLS握手协议产生,TLS协议在TLS Record层之上运行。当TLS客户端和服务器首先开始通信时,他们先对协议版本达成一致、选择加密算法、可选地进行身份验证、使用公钥加密技术来生成共享密钥。

TLS握手协议包括以下步骤:

请注意,较高的层不应该过分依赖于TLS,它始终协商两个对等体之间最强的连接:中间攻击者中的一个人可以尝试使两个实体下降到他们支持的最不安全的方法。 该协议的设计旨在最大程度地降低这种风险,但仍然有可用的攻击:例如,攻击者可能会阻止对安全服务运行的端口的访问,或尝试让对等体协商未经身份验证的连接。 基本规则是,较高的级别必须认识到他们的安全要求是什么,而不是通过不那么安全的渠道来传递信息。 TLS协议是安全的,因为任何加密组件都提供了其承诺的安全级别:如果您通过与验证证书的主机进行1024位RSA密钥交换来协商3DES,则可以期待安全性。

但是,除非您觉得数据的价值不超过打破加密所需的工作量,否则绝对不要通过加密40位安全性的链接发送数据。

这些目标是通过握手协议实现的,可以总结如下:客户端发送客户端hello消息,服务器必须使用服务器hello消息进行响应,否则将发生致命错误,并且连接将失败。 Client hello和Server hello用于在客户端和服务器之间建立安全增强功能。Client hello和Server hello建立以下属性:协议版本、会话ID、加密组件和压缩方法。 另外,生成和交换两个随机值:ClientHello.random和ServerHello.random。(见Fig. 1 )

Client

Server

ClientHello -------→

ServerHello
Certificate*
ServerKeyExchange*
CertificateRequest*
←------- ServerHelloDone

Certificate*
ClientKeyExchange
CertificateVerify*
[ChangeCipherSpec]

Finished -------→

[ChangeCipherSpec]
←------- Finished

Application Data <-------> Application Data

Fig. 1 - Message flow for a full handshake

实际的密钥交换最多可以使用四个消息:服务器证书、服务器密钥交换、客户端证书和客户端密钥交换。 可以通过指定这些消息的格式并定义消息的使用来允许客户端和服务器同意共享密钥来创建新的密钥交换方法。 这个secret应该很长; 当前定义的密钥交换方法交换的secret范围从48到128字节

如果要进行身份验证,按照hello消息,服务器将发送其证书。另外,如果需要,可以发送服务器密钥交换消息(例如,如果其服务器没有证书,或者其证书仅用于签名)。如果服务器被认证,它可以从客户端请求一个证书,如果这适合所选的加密组件。现在服务器将发送服务器hello完成消息,表示握手的hello-message阶段已经完成。然后服务器将等待客户端的响应。如果服务器发送了证书请求消息,则客户端必须发送证书消息。客户端密钥交换消息现在被发送,该消息的内容将取决于在客户端hello和服务器之间选择的公钥算法。如果客户端已经发送了具有签名能力的证书,则会发送一个经数字签名的证书验证消息来显式验证证书。

此时,客户端发送更改加密规范消息,客户端将待处理的加密规范复制到当前加密规范中。 然后,客户端立即按照新的算法、密钥和secret发送finished消息。作为响应,服务器将发送自己的更改加密规范消息,将待处理传输到当前加密规范,并在新的加密规范下发送其finished消息。此时,握手完成,客户端和服务器可以开始交换应用层数据。(见Fig. 1 )

注意:为了帮助避免流水线停顿,ChangeCipherSpec是独立的TLS协议内容类型,实际上并不是TLS握手消息。

当客户端和服务器决定恢复上一个会话或重复现有会话(而不是协商新的安全参数)时,消息流如下所示:

客户端使用要恢复的会话的会话ID发送ClientHello。 然后,服务器检查其会话缓存以进行匹配。 如果发现匹配,并且服务器愿意在指定的会话状态下重新建立连接,则它将发送具有相同会话ID值的ServerHello。 在这一点上,客户端和服务器都必须发送更改加密规范消息,并直接进行完成的消息。 重新建立完成后,客户端和服务器可以开始交换应用层数据。(Fig. 2)如果找不到会话ID匹配,则服务器生成新的会话ID,TLS客户端和服务器执行完全握手。

Client

Server

ClientHello -------→

ServerHello
[ChangeCipherSpec]
<-------- Finished

[ChangeCipherSpec]
Finished -------->
Application Data <-------> Application Data


Fig. 2 - Message flow for an abbreviated handshake

每条消息的内容和意义将在以下部分中详细介绍。

7.4 握手协议

TLS握手协议是TLS记录协议的定义更高级别的客户端之一。 该协议用于协商会话的安全属性。 握手消息被提供给TLS记录层,它们被封装在一个或多个TLSPlaintext结构内,按照当前活动会话状态的指定进行处理和传输。

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 {
HandshakeType msg_type; /* handshake type */
uint24 length; /* bytes in message */
select (HandshakeType) {
case hello_request: HelloRequest;
case client_hello: ClientHello;
case server_hello: ServerHello;
case certificate: Certificate;
case server_key_exchange: ServerKeyExchange;
case certificate_request: CertificateRequest;
case server_hello_done: ServerHelloDone;
case certificate_verify: CertificateVerify;
case client_key_exchange: ClientKeyExchange;
case finished: Finished;
} body;
} Handshake;

握手协议消息按照它们必须发送的顺序显示; 以意外的顺序发送握手信息会导致致命错误。 然而,不需要的握手信息可以省略。 注意排序的一个例外:证书消息在握手中使用两次(从服务器到客户端,然后从客户端到服务器),但仅在其第一个位置描述。 在Hello请求消息中不受这些排序规则约束的消息,可以在任何时候发送,但如果在握手中到达应该被客户端忽略。

7.4.1Hello消息

hello阶段消息用于交换客户端和服务器之间的安全增强功能。 当新的会话开始时,记录层的连接状态加密、散列和压缩算法被初始化为空。 当前连接状态用于重新协商消息。

7.4.1.1Hello请求

发送此消息时机:

Hello请求消息可以由服务器随时发送。

此消息的含义:

Hello请求是一个简单的通知,客户端应该在方便时发送客户端hello消息重新开始协商过程。 如果客户端正在协商会话,客户端将忽略此消息。 如果客户端不希望重新协商会话,客户端可能会忽略此消息,如果客户端希望通过no_renegotiation警报响应,客户端可能会忽略此消息。 由于握手消息旨在具有优先于应用数据的传输优先权,所以预期协商将在从客户端接收到的记录不超过几个之前开始。 如果服务器发送一个hello请求,但没有收到一个客户端hello作为响应,它可能会关闭一个致命警报的连接。

发送hello请求后,服务器不应重复请求,直到后续的握手协商完成。

此消息的结构:

struct {} HelloRequest;

注意:此消息不应包含在消息散列中,这些消息在整个握手过程中维护,并在完成的消息和证书验证消息中使用。

7.4.1.2 客户端hello

发送此消息时机:

当客户端首先连接到服务器时,需要发送客户端hello作为其第一条消息。 客户端还可以发送一条客户端hello消息响应hello请求,或为了重新协商现有连接中的安全参数。

此消息的结构:

客户端hello消息包括随机结构,该协议在以后的协议中使用。

struct {
uint32 gmt_unix_time;
opaque random_bytes[28];
} Random;

gmt_unix_time

标准UNIX 32位格式的当前时间和日期(从1970年1月1日起,GMT开始的午夜之后的秒数),根据发件人的内部时钟。 基本的TLS协议不需要正确设置时钟; 较高级别或应用协议可以定义附加要求。

random_bytes

由安全随机数生成器生成的28字节。

客户端hello消息包括可变长度会话标识符(session identifier)。 如果不为空,则该值标识客户端希望重用其安全参数的同一客户端和服务器之间的会话。 会话标识符可以来自较早的连接,该连接或另一个当前活动的连接。 如果客户端仅希望更新连接的随机结构和派生值,则第二个选项很有用,而第三个选项可以建立多个独立的安全连接,而不会重复完整的握手协议。 这些独立连接可以顺序或同时进行; 当握手协商完成交换完成的消息并持续存在时,SessionID将变为有效,直到由于老化或由于与会话相关联的连接遇到致命错误而被移除。 SessionID的实际内容由服务器定义。

opaque SessionID<0..32>;

警告:

因为SessionID是在没有加密或即时MAC保护的情况下传输的,所以服务器不得将机密信息放在会话标识符中,或让伪会话标识符的内容导致任何安全漏洞。 (请注意,握手的内容,包括SessionID,由握手结束时交换的完成消息保护。)

在客户机hello消息中从客户端传递到服务器的CipherSuite列表包含客户端按照客户端的偏好(首选的首选项)支持的加密算法的组合。 每个CipherSuite定义密钥交换算法、批量加密算法(包括密钥长度)和MAC算法。 服务器将选择一个加密组件,或者如果不提供可接受的选择,则返回握手失败警报并关闭连接。

uint8 CipherSuite[2]; /* Cryptographic suite selector */

客户端hello包括客户端支持的压缩算法列表,根据客户端的偏好进行排序。

enum { null(0), (255) } CompressionMethod;

struct {
ProtocolVersion client_version;
Random random;
SessionID session_id;
CipherSuite cipher_suites<2..2^16-1>;
CompressionMethod compression_methods<1..2^8-1>;
} ClientHello;

client_version

客户端希望在此会话期间通信的TLS协议版本。这应该是客户端支持的最新(最高价值)版本。对于此版本的规范,版本将为3.1(有关向后兼容性的详细信息,请参阅附录E)。

random

客户端生成的随机结构。

session_id

客户端希望用于此连接的会话的ID。 如果没有session_id可用或客户端希望生成新的安全参数,则该字段应为空。

cipher_suites

这是客户端支持的加密选项的列表,首先是客户端的首选项。 如果session_id字段不为空(意味着会话恢复请求),则此向量必须至少包含该会话的cipher_suite。 值在附录A.5中定义。

compression_methods

这是客户端支持的压缩方法的列表,按客户端偏好排序。 如果session_id字段不为空(意味着会话恢复请求),则它必须包含该会话中的compression_method。 此向量必须包含,并且所有实现必须支持CompressionMethod.null。 因此,客户端和服务器将始终能够就压缩方法达成一致。

发送客户端hello消息后,客户端等待服务器hello消息。 除了hello请求之外,服务器返回的任何其他握手消息被视为致命错误。

向前兼容性说明:

为了向前兼容性,ClientHello消息允许在压缩方法之后包含额外的数据。 这些数据必须包含在握手哈希中,否则将被忽略。 这是唯一的握手信息,这是合法的; 对于所有其他消息,消息中的数据量必须与消息的描述精确匹配。

7.4.1.3 服务器hello

发送此消息时机:

当服务器能够找到可接受的一组算法时,服务器将发送此消息以响应客户端的问候消息。 如果找不到这样的匹配,它会用握手失败警报进行响应。

此消息的结构:

struct {
ProtocolVersion server_version;
Random random;
SessionID session_id;
CipherSuite cipher_suite;
CompressionMethod compression_method;
} ServerHello;

server_version

该字段将包含客户机在客户机中建议的较低者,而服务器支持的最高级别。对于此版本的规范,版本为3.1(有关向后兼容性的详细信息,请参阅附录E)。

random

该结构由服务器生成,并且必须与ClientHello.random不同(并且独立于) ClientHello.random。

session_id

这是与此连接相对应的会话的身份。如果ClientHello.session_id不为空,服务器将在其会话缓存中查找匹配项。如果发现匹配,并且服务器愿意使用指定的会话状态建立新连接,则服务器将以与客户端提供的相同的值进行响应。这表示恢复会议,并且指示双方必须直接执行完成的消息。否则,此字段将包含标识新会话的不同值。服务器可能会返回一个空的session_id,以指示会话不会被缓存,因此无法恢复。如果会话恢复,则必须使用最初协商的相同加密组件来恢复会话。

cipher_suite

服务器从ClientHello.cipher_suites列表中选择的单一加密组件。对于恢复会话,该字段是恢复会话状态的值。

compression_method

服务器从ClientHello.compression_methods列表中选择的单一压缩算法。对于恢复会话,该字段是恢复会话状态的值。

7.4.2 服务器证书

发送此消息时机:

只要协商密钥交换方法不是匿名的,服务器必须发送证书。此消息将始终紧跟服务器的hello消息。

此消息的含义:

证书类型必须适用于所选加密组件的密钥交换算法,通常为X.509v3证书。 它必须包含与密钥交换方法匹配的密钥,如下所示。 除非另有说明,证书的签名算法必须与证书密钥的算法相同。 除非另有说明,否则公钥可以是任何长度的。

密钥交换算法证书密钥类型:

RSA : RSA公钥;证书必须允许密钥用于加密。

RSA_EXPORT: 长度大于512位的RSA_EXPORT RSA公钥,可用于签名,或512位或更短的密钥,可用于加密或签名。

DHE_DSS: DSS公钥。

DHE_DSS_EXPORT: DSS公钥。

DHE_RSA: 可用于签名的RSA公钥。

DHE_RSA_EXPORT: 可用于签名的RSA公钥。

DH_DSS: Diffie-Hellman密钥。用于签署证书的算法应为DSS。

DH_RSA : Diffie-Hellman密钥。用于签署证书的算法应为RSA。

所有证书配置文件,密钥和加密格式由IETF PKIX工作组[PKIX]定义。 当存在密钥使用扩展时,如上所述,必须为密钥设置数字签名比特,如上所述,密钥加密位必须存在以允许加密,如上所述。 keyAgreement位必须在Diffie-Hellman证书上设置。

由于为TLS协议指定了指定新密钥交换方法的CipherSuites,它们将暗示证书格式和所需的编码密钥信息。

此消息的结构为:
opaque ASN.1Cert<1..2^24-1>;

struct {
ASN.1Cert certificate_list<0..2^24-1>;
} Certificate;

certificate_list

这是X.509v3证书的序列(链)。 发件人的证书必须列在列表中。 每个以下证书必须直接证明其前面的证书。 因为证书验证需要独立分发根密钥,所以指定根证书颁发机构的自签名证书可以可选地从链中省略,假设远端必须已经拥有它,以便在任何情况下验证它。

相同的消息类型和结构将用于客户端对证书请求消息的响应。 请注意,如果客户端没有适当的证书发送以响应服务器的身份验证请求,客户端可能不会发送证书。

注意:PKCS#7 [PKCS7]不用作证书向量的格式,因为PKCS#6 [PKCS6]扩展证书不被使用。 另外PKCS#7定义了一个SET而不是一个SEQUENCE,使解析列表的任务更加困难。

7.4.3 服务器密钥交换消息

发送此消息时机:

该消息将在服务器证书消息(或服务器hello消息,如果这是匿名协商)之后立即发送。

服务器密钥交换消息仅在服务器证书消息(如果发送)不包含足够的数据以允许客户端交换预主secret时才由服务器发送。 以下密钥交换方法是正确的:

RSA_EXPORT (如果服务器证书中的公钥长于512位)
DHE_DSS
DHE_DSS_EXPORT
DHE_RSA
DHE_RSA_EXPORT
DH_anon

发送以下密钥交换方法的服务器密钥交换消息是不合法的:

RSA
RSA_EXPORT (当服务器证书中的公钥长度小于或等于512位时)
DH_DSS
DH_RSA

此消息的含义:

该消息传达加密信息,以允许客户端传达预主secret:RSA公钥加密预主secret,或者Diffie-Hellman公钥,客户端可以通过该密钥完成密钥交换(结果是预主secret。)

由于额外的CipherSuites被定义为TLS,包括新的密钥交换算法,当且仅当与密钥交换算法相关联的证书类型没有提供足够的信息以供客户端交换前端秘密时,将发送服务器密钥交换消息。

注:根据目前的美国出口法,RSA模数大于512位可能不会用于从美国出口的软件的密钥交换。 使用此消息,可以使用证书中编码的较大的RSA密钥为RSA_EXPORT密钥交换方法签署临时较短的RSA密钥。

这个消息的结构为:

enum { rsa, diffie_hellman } KeyExchangeAlgorithm;

struct {
opaque rsa_modulus<1..2^16-1>;
opaque rsa_exponent<1..2^16-1>;
} ServerRSAParams;

rsa_modulus
The modulus of the server's temporary RSA key.

rsa_exponent
The public exponent of the server's temporary RSA key.

struct {
opaque dh_p<1..2^16-1>;
opaque dh_g<1..2^16-1>;
opaque dh_Ys<1..2^16-1>;
} ServerDHParams; /* Ephemeral DH parameters */

dh_p

用于Diffie-Hellman操作的质量模数。

dh_g

用于Diffie-Hellman操作的生成器。

dh_Ys

服务器的Diffie-Hellman公共值(g ^ X mod p)。

struct {
select (KeyExchangeAlgorithm) {
case diffie_hellman:
ServerDHParams params;
Signature signed_params;
case rsa:
ServerRSAParams params;
Signature signed_params;
};
} ServerKeyExchange;

PARAMS

服务器的密钥交换参数。

signed_params

对于非匿名密钥交换,对应的params值的散列值与适用于该哈希的签名相对应。

MD5_HASH

MD5(ClientHello.random + ServerHello.random + ServerParams);

sha_hash

SHA(ClientHello.random + ServerHello.random + ServerParams);

enum { anonymous, rsa, dsa } SignatureAlgorithm;

select (SignatureAlgorithm)
{ case anonymous: struct { };
case rsa:
digitally-signed struct {
opaque md5_hash[16];
opaque sha_hash[20];
};
case dsa:
digitally-signed struct {
opaque sha_hash[20];
};
} Signature;


7.4.4 证书请求(Certificate request)

发送此消息时机:

如果适用于所选择的加密组件,非匿名服务器可以选择从客户端请求证书。 此消息(如果发送)将立即遵循服务器密钥交换消息(如果已发送;否则为服务器证书消息)。

此消息的结构如下:

enum {
rsa_sign(1), dss_sign(2), rsa_fixed_dh(3), dss_fixed_dh(4),
(255)
} ClientCertificateType;

opaque DistinguishedName<1..2^16-1>;

struct {
ClientCertificateType certificate_types<1..2^8-1>;
DistinguishedName certificate_authorities<3..2^16-1>;
} CertificateRequest;

certificate_types

此字段是请求的证书类型的列表,按照服务器的首选项的顺序进行排序。

certificate_authorities

可接受的认证机构的可分辨名称的列表。 这些可分辨名称可以为根CA或下级CA指定期望的可分辨名称; 因此,该消息可以用于描述已知的根和期望的授权空间。

注意:DistinguishedName派生自[X509]。

注意:匿名服务器请求客户端的身份识别是一个致命的handshake_failure警报。

7.4.5 服务器hello完成

发送此消息时机:

服务器hello完成消息由服务器发送,以指示服务器的结束hello和关联的消息。 发送此消息后,服务器将等待客户端响应。

此消息的含义:

该消息意味着服务器完成发送消息以支持密钥交换,并且客户端可以继续进行密钥交换的阶段。

在收到服务器hello完成消息后,客户端应该验证服务器是否提供有效证书(如果需要),并检查服务器hello参数是否可以接受。

此消息的结构如下:

struct { } ServerHelloDone;

7.4.6 客户证书(Client certificate)

发送此消息时机:

这是客户端在收到服务器hello完成消息后可以发送的第一条消息。 仅当服务器请求证书时,才会发送此消息。 如果没有合适的证书可用,客户端应发送不包含证书的证书消息。如果服务器需要客户端身份验证才能继续握手,则可能会使用致命的握手失败警报进行响应。使用第7.4.2节中定义的证书结构发送客户端证书。

注意:当使用基于静态Diffie-Hellman的密钥交换方法(DH_DSS或DH_RSA)时,如果客户端认证被请求,客户端证书中编码的Diffie-Hellman组和生成器必须与服务器指定的Diffie-Hellman参数匹配,如果客户端的参数 将用于密钥交换。

7.4.7客户端密钥交换(key exchange)消息

发送此消息时机:

此消息始终由客户端发送。如果发送,它将立即遵循客户端证书消息。否则,它将是客户端收到服务器hello完成消息后发送的第一条消息。

此消息的含义:

有了这个消息,即使是直接传输RSA加密的secret,还是通过传输Diffie-Hellman参数,这将允许每一方同意相同的前置secret,设置了前置secret。当密钥交换方式为DH_RSA或DH_DSS时,客户端已经被请求认证,客户端能够使用包含Diffie-Hellman公钥的证书进行响应,该密钥的参数(组和生成器)与服务器在其证书中指定的参数,此消息将不包含任何数据。

此消息的结构:

消息的选择取决于选择了哪种密钥交换方式。 KeyExchangeAlgorithm定义见7.4.3节。

struct {
select (KeyExchangeAlgorithm) {
case rsa: EncryptedPreMasterSecret;
case diffie_hellman: ClientDiffieHellmanPublic;
} exchange_keys;
} ClientKeyExchange;

7.4.7.1RSA加密的premaster secret消息

此消息的含义:

如果使用RSA进行密钥协商和认证,则客户端将生成一个48字节的premaster secret,使用服务器证书中的公钥或服务器密钥交换消息中提供的临时RSA密钥对其进行加密,并将发送含有加密premaster secret的结果消息。 该结构(PreMasterSecret)是客户端密钥交换消息的变体,而不是消息本身。

此消息的结构定义:

struct {
ProtocolVersion client_version;
opaque random[46];
} PreMasterSecret;
client_version
客户端支持的最新(最新)版本。 这用于检测版本回滚攻击。 在接收到premaster secret后,服务器应该检查该值是否与客户机hello消息中客户端发送的值相匹配。
random
46个安全生成的随机字节。
struct {
public-key-encrypted PreMasterSecret pre_master_secret;
} EncryptedPreMasterSecret;

注意:Daniel Bleichenbacher [BLEI]发现的攻击可用于攻击使用PKCS#1编码的RSA的TLS服务器。 攻击利用了以下事实:通过以不同的方式失败,可以强制TLS服务器来揭示当解密时特定消息是否正确PKCS#1格式化。

避免这种攻击的脆弱性的最佳方法是以不正确格式的RSA块区分的方式处理格式错误的消息。 因此,当它接收到格式不正确的RSA块时,服务器应该生成一个随机的48字节的值,然后继续使用它作为前置机密信息。 因此,无论接收的RSA块是否被正确编码,服务器将相同地起作用。

pre_master_secret

该随机值由客户端生成,用于生成主机密信息,如第8.1节所述。

7.4.7.2 客户Diffie-Hellman公共值

此消息的含义:

如果客户的证书中没有包含客户端的Diffie-Hellman公共值(Yc),则该结构将传达该消息。用于Yc的编码由枚举的PublicValueEncoding确定。该结构是客户端密钥交换消息的变体,而不是消息本身。

此消息的结构如下:

enum { implicit, explicit } PublicValueEncoding;

implicit
如果客户端证书已经包含合适的Diffie-Hellman密钥,则Yc是隐式的,不需要再次发送。 在这种情况下,客户端密钥交换消息将被发送,但将为空。
explicit
Yc needs to be sent.

struct {
select (PublicValueEncoding) {
case implicit: struct { };
case explicit: opaque dh_Yc<1..2^16-1>;
} dh_public;
} ClientDiffieHellmanPublic;

dh_Yc
客户的Diffie-Hellman公共价值(Yc)。

7.4.8证书验证(Certificate verify)

发送此消息时机:

此消息用于提供客户端证书的显式验证。 该消息仅在具有签名功能的客户端证书(即除包含固定Diffie-Hellman参数的证书之外的所有证书)之后发送。 发送后,将立即按照客户端密钥交换消息。

此消息结构为:

struct {
Signature signature;
} CertificateVerify;

签名类型在7.4.3中定义。

CertificateVerify.signature.md5_hash
MD5(handshake_messages);

Certificate.signature.sha_hash
SHA(handshake_messages);

这里的handshake_messages是指从客户端开始发送或接收的所有握手消息,但不包括此消息,包括握手消息的类型和长度字段。 这是到目前为止交换的所有握手结构的连接。

7.4.9结束(Finished)

发送此消息时机:

完成的消息总是在更改加密规范消息之后立即发送,以验证密钥交换和认证过程是否成功。 必须在其他握手消息和完成消息之间接收更改加密规范消息。

此消息的含义:

完成的消息是第一个使用刚刚协商的算法,密钥和秘密进行保护的消息。 完成消息的收件人必须验证内容是否正确。 一旦一方已经发送了其完成的消息并从其对等体接收并验证了完成的消息,则它可以开始通过连接发送和接收应用程序数据。

struct {
opaque verify_data[12];
} Finished;

verify_data

PRF(master_secret,finished_label,MD5(handshake_messages)+

SHA-1(handshake_messages))[0..11];

finished_label

对于客户端发送的完成消息,字符串“客户端已完成”。 对于服务器发送的完成消息,字符串“server finished”。

handshake_messages

来自所有握手消息的所有数据,但不包括此消息。 这只是在握手层可见的数据,不包括记录层标题。这是到目前为止交换的所有握手结构的连接。

如果完成的消息在握手中的适当位置前没有更改加密规范消息,则是致命的错误。

由服务器发送的完成消息中包含的哈希值包含Sender.server;由客户端发送的那些包含Sender.client。值handshake_messages包括从客户端开始,但不包括此完成的消息的所有握手消息。这可能与第7.4.8节中的handshake_messages不同,因为它将包括证书验证消息(如果发送)。此外,客户端发送的完成消息的handshake_messages将与服务器发送的完成消息的handshake_messages不同,因为第二个发送的消息将包括先前的消息。

注意:更改加密规则消息,警报和任何其他记录类型不是握手消息,不包括在散列计算中。此外,在握手哈希中省略了Hello请求消息。

8.加密计算(Cryptographic computations)

为了开始连接保护,TLS Record协议需要规定一套算法,一个master secret以及客户端和服务器的随机值。认证、加密和MAC算法由服务器选择的cipher_suite确定,并显示在服务器hello消息中。压缩算法在hello消息中协商,随机值在hello消息中交换。剩下的一切就是计算master secret。

8.1 计算master secret

对于所有密钥交换方法,使用相同的算法将pre_master_secret转换为master_secret。 一旦计算了master_secret,pre_master_secret应该从内存中删除。

master_secret = PRF(pre_master_secret, "master secret",
ClientHello.random + ServerHello.random)
[0..47];

master_secret长度一般为48字节。 pre_master_secret的长度将根据密钥交换方式而有所不同。

8.1.1RSA

当RSA用于服务器认证和密钥交换时,客户端生成一个48字节的pre_master_secret,并在服务器的公钥下加密,并发送到服务器。服务器使用其私钥来解密pre_master_secret。 双方然后将pre_master_secret转换为master_secret,如上所述。

使用PKCS#1 [PKCS1]块类型1执行RSA数字签名。使用PKCS#1块类型2执行RSA公钥加密。

8.1.2Diffie-Hellman

执行传统的Diffie-Hellman计算。 协商密钥(Z)用作pre_master_secret,并转换为master_secret,如上所述。

注意:Diffie-Hellman参数由服务器指定,可能是短暂的或包含在服务器的证书中。

9.强制加密组件(Mandatory Cipher Suites)

在没有另外指定的应用程序标准配置文件的情况下,TLS兼容应用程序必须实现加密组件TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA。

10.应用程序数据协议(Application data protocol)

应用数据消息由记录层承载,并根据当前的连接状态进行分段,压缩和加密。 消息被视为记录层的透明数据。

A.协议常数(Protocol constant values)

本节介绍协议类型和常量。

A.1Record 层

struct {
uint8 major, minor;
} ProtocolVersion;

ProtocolVersion version = { 3, 1 }; /* TLS v1.0 */

enum {
change_cipher_spec(20), alert(21), handshake(22),
application_data(23), (255)
} ContentType;

struct {
ContentType type;
ProtocolVersion version;
uint16 length;
opaque fragment[TLSPlaintext.length];
} TLSPlaintext;

struct {
ContentType type;
ProtocolVersion version;
uint16 length;
opaque fragment[TLSCompressed.length];
} TLSCompressed;

struct {
ContentType type;
ProtocolVersion version;
uint16 length;
select (CipherSpec.cipher_type) {
case stream: GenericStreamCipher;
case block: GenericBlockCipher;
} fragment;
} TLSCiphertext;

stream-ciphered struct {
opaque content[TLSCompressed.length];
opaque MAC[CipherSpec.hash_size];
} GenericStreamCipher;

block-ciphered struct {
opaque content[TLSCompressed.length];
opaque MAC[CipherSpec.hash_size];
uint8 padding[GenericBlockCipher.padding_length];
uint8 padding_length;
} GenericBlockCipher;

A.2. 更改加密规范消息

struct {
enum { change_cipher_spec(1), (255) } type;
} ChangeCipherSpec;

A.3报警消息

enum { warning(1), fatal(2), (255) } AlertLevel;

enum {
close_notify(0),
unexpected_message(10),
bad_record_mac(20),
decryption_failed(21),
record_overflow(22),
decompression_failure(30),
handshake_failure(40),
bad_certificate(42),
unsupported_certificate(43),
certificate_revoked(44),
certificate_expired(45),
certificate_unknown(46),
illegal_parameter(47),
unknown_ca(48),
access_denied(49),
decode_error(50),
decrypt_error(51),
export_restriction(60),
protocol_version(70),
insufficient_security(71),
internal_error(80),
user_canceled(90),
no_renegotiation(100),
(255)
} AlertDescription;

struct {
AlertLevel level;
AlertDescription description;
} Alert;

A.4握手协议

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 {
HandshakeType msg_type;
uint24 length;
select (HandshakeType) {
case hello_request: HelloRequest;
case client_hello: ClientHello;
case server_hello: ServerHello;
case certificate: Certificate;
case server_key_exchange: ServerKeyExchange;
case certificate_request: CertificateRequest;
case server_hello_done: ServerHelloDone;
case certificate_verify: CertificateVerify;
case client_key_exchange: ClientKeyExchange;
case finished: Finished;
} body;
} Handshake;

A.4.1Hello消息

struct { } HelloRequest;

struct {
uint32 gmt_unix_time;
opaque random_bytes[28];
} Random;

opaque SessionID<0..32>;

uint8 CipherSuite[2];

enum { null(0), (255) } CompressionMethod;

struct {
ProtocolVersion client_version;
Random random;
SessionID session_id;
CipherSuite cipher_suites<2..2^16-1>;
CompressionMethod compression_methods<1..2^8-1>;
} ClientHello;

struct {
ProtocolVersion server_version;
Random random;
SessionID session_id;
CipherSuite cipher_suite;
CompressionMethod compression_method;
} ServerHello;

A.4.2服务器认证和密钥交换消息

opaque ASN.1Cert<2^24-1>;

struct {
ASN.1Cert certificate_list<1..2^24-1>;
} Certificate;

enum { rsa, diffie_hellman } KeyExchangeAlgorithm;

struct {
opaque RSA_modulus<1..2^16-1>;
opaque RSA_exponent<1..2^16-1>;
} ServerRSAParams;

struct {
opaque DH_p<1..2^16-1>;
opaque DH_g<1..2^16-1>;
opaque DH_Ys<1..2^16-1>;
} ServerDHParams;

struct {
select (KeyExchangeAlgorithm) {
case diffie_hellman:
ServerDHParams params;
Signature signed_params;
case rsa:
ServerRSAParams params;
Signature signed_params;
};
} ServerKeyExchange;

enum { anonymous, rsa, dsa } SignatureAlgorithm;

select (SignatureAlgorithm)
{ case anonymous: struct { };
case rsa:
digitally-signed struct {
opaque md5_hash[16];
opaque sha_hash[20];
};
case dsa:
digitally-signed struct {
opaque sha_hash[20];
};
} Signature;

enum {
rsa_sign(1), dss_sign(2), rsa_fixed_dh(3), dss_fixed_dh(4),
(255)
} ClientCertificateType;

opaque DistinguishedName<1..2^16-1>;

struct {
ClientCertificateType certificate_types<1..2^8-1>;
DistinguishedName certificate_authorities<3..2^16-1>;
} CertificateRequest;

struct { } ServerHelloDone;

A.4.3. 客户端验证和密钥交换消息

struct {
select (KeyExchangeAlgorithm) {
case rsa: EncryptedPreMasterSecret;
case diffie_hellman: DiffieHellmanClientPublicValue;
} exchange_keys;
} ClientKeyExchange;

struct {
ProtocolVersion client_version;
opaque random[46];

} PreMasterSecret;

struct {
public-key-encrypted PreMasterSecret pre_master_secret;
} EncryptedPreMasterSecret;

enum { implicit, explicit } PublicValueEncoding;

struct {
select (PublicValueEncoding) {
case implicit: struct {};
case explicit: opaque DH_Yc<1..2^16-1>;
} dh_public;
} ClientDiffieHellmanPublic;

struct {
Signature signature;
} CertificateVerify;

A.4.4握手完成消息

struct {
opaque verify_data[12];
} Finished;

A.5加密组件(CipherSuite)

以下值定义客户机hello和服务器hello消息中使用的CipherSuite代码。

CipherSuite定义了TLS版本1.0中支持的加密规范。

TLS_NULL_WITH_NULL_NULL被指定,并且是在该通道的第一次握手中的TLS连接的初始状态,但不能协商,因为它不提供比不安全连接更多的保护。

CipherSuite TLS_NULL_WITH_NULL_NULL = {0x00,0x00};

以下CipherSuite定义要求服务器提供可用于密钥交换的RSA证书。 服务器可以在证书请求消息中请求具有RSA或DSS签名的证书。

CipherSuite TLS_RSA_WITH_NULL_MD5 = { 0x00,0x01 };
CipherSuite TLS_RSA_WITH_NULL_SHA = { 0x00,0x02 };
CipherSuite TLS_RSA_EXPORT_WITH_RC4_40_MD5 = { 0x00,0x03 };
CipherSuite TLS_RSA_WITH_RC4_128_MD5 = { 0x00,0x04 };
CipherSuite TLS_RSA_WITH_RC4_128_SHA = { 0x00,0x05 };
CipherSuite TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 = { 0x00,0x06 };
CipherSuite TLS_RSA_WITH_IDEA_CBC_SHA = { 0x00,0x07 };
CipherSuite TLS_RSA_EXPORT_WITH_DES40_CBC_SHA = { 0x00,0x08 };
CipherSuite TLS_RSA_WITH_DES_CBC_SHA = { 0x00,0x09 };
CipherSuite TLS_RSA_WITH_3DES_EDE_CBC_SHA = { 0x00,0x0A };

以下CipherSuite定义用于服务器认证(可选的客户端认证)Diffie-Hellman。 DH表示加密组件,其中服务器的证书包含由证书颁发机构(CA)签名的Diffie-Hellman参数。 DHE表示短暂的Diffie-Hellman,其中Diffie-Hellman参数由已经由CA签名的DSS或RSA证书签名。 所使用的签名算法在DH或DHE参数之后指定。 服务器可以从客户端请求具有RSA或DSS签名的证书进行客户端认证,或者可以请求Diffie-Hellman证书。 客户端提供的任何Diffie-Hellman证书必须使用服务器描述的参数(组和生成器)。

CipherSuite TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA = { 0x00,0x0B };
CipherSuite TLS_DH_DSS_WITH_DES_CBC_SHA = { 0x00,0x0C };
CipherSuite TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA = { 0x00,0x0D };
CipherSuite TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA = { 0x00,0x0E };
CipherSuite TLS_DH_RSA_WITH_DES_CBC_SHA = { 0x00,0x0F };
CipherSuite TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA = { 0x00,0x10 };
CipherSuite TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA = { 0x00,0x11 };
CipherSuite TLS_DHE_DSS_WITH_DES_CBC_SHA = { 0x00,0x12 };
CipherSuite TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA = { 0x00,0x13 };
CipherSuite TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA = { 0x00,0x14 };
CipherSuite TLS_DHE_RSA_WITH_DES_CBC_SHA = { 0x00,0x15 };
CipherSuite TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA = { 0x00,0x16 };

以下CipherSuite用于完全匿名的Diffie-Hellman通信,其中双方都不进行身份验证。 请注意,这种模式很容易受到中间人攻击,因此不推荐使用。

CipherSuite TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 = { 0x00,0x17 };
CipherSuite TLS_DH_anon_WITH_RC4_128_MD5 = { 0x00,0x18 };
CipherSuite TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA = { 0x00,0x19 };
CipherSuite TLS_DH_anon_WITH_DES_CBC_SHA = { 0x00,0x1A };
CipherSuite TLS_DH_anon_WITH_3DES_EDE_CBC_SHA = { 0x00,0x1B };

注意:第一个字节为0xFF的所有CipherSuite都被认为是私有的,可用于定义本地/实验算法。 这种类型的互操作性是本地事务。

注意:可以通过发布指定CipherSuite的RFC来注册其他CipherSuite,包括必要的TLS协议信息,包括消息编码,pre_master_secret推导,对称加密和MAC计算以及所涉及的算法的适当参考信息。 RFC编辑办公室可以自行决定发布不完全描述的CipherSuite的规范(例如,对于分类算法),如果该规范发现该技术规范具有技术上的意义并被完全指定。

注意:保留CipherSuite值{0x00,0x1C}和{0x00,0x1D},以避免与SSL 3中基于Fortezza的CipherSuite冲突。

A.6安全参数

这些安全参数由TLS握手协议确定,并作为参数提供给TLS记录层,以初始化连接状态。 SecurityParameters包括:

enum { null(0), (255) } CompressionMethod;

enum { server, client } ConnectionEnd;

enum { null, rc4, rc2, des, 3des, des40, idea }
BulkCipherAlgorithm;

enum { stream, block } CipherType;

enum { true, false } IsExportable;

enum { null, md5, sha } MACAlgorithm;

/* The algorithms specified in CompressionMethod,
BulkCipherAlgorithm, and MACAlgorithm may be added to. */

struct {
ConnectionEnd entity;
BulkCipherAlgorithm bulk_cipher_algorithm;
CipherType cipher_type;
uint8 key_size;
uint8 key_material_length;
IsExportable is_exportable;
MACAlgorithm mac_algorithm;
uint8 hash_size;
CompressionMethod compression_algorithm;
opaque master_secret[48];
opaque client_random[32];
opaque server_random[32];
} SecurityParameters;

B.词汇表

应用程序协议(application protocol)

应用协议是通常直接在传输层之上(例如TCP / IP)层级的协议。 示例包括HTTP,TELNET,FTP和SMTP。

不对称加密(asymmetric cipher)

请参阅公钥加密。

认证(authentication)

认证是一个实体确定另一个实体身份的能力。

块加密(block cipher)

块加密是在被称为块的比特组中以明文操作的算法。 64位是一个通用的块大小。

批量加密(bulk cipher)

一种用于加密大量数据的对称加密算法。

加密块链接(CBC)

CBC是使用块加密的每个明文块首先与先前的密文块(或者在第一个块的情况下,与初始化向量)进行异或运算的模式。对于解密,首先对每个块进行解密,然后与先前的密文块(或IV)进行异或。

证书(certificate)

作为X.509协议(a.k.a. ISO认证框架)的一部分,证书由受信任的证书颁发机构分配,并在一方的身份或某些其他属性及其公钥之间提供强大的绑定。

客户(client)

启动与服务器的TLS连接的应用程序实体。这可能意味着客户端启动了底层传输连接。服务器和客户端之间的主要操作差异在于服务器通常被认证,而客户端只可以被认证。

客户端写密钥(client write key)

用于加密客户端写入数据的密钥。

客户端写MAC secret (client write MAC secret)

用于验证客户端写入数据的机密信息。

连接(connection)

连接是提供合适类型服务的传输(在OSI分层模型定义中)。对于TLS,这种连接是对等关系。连接是短暂的。每个连接与一个会话相关联。

数据加密标准(Data Encryption Standard)

DES是一种非常广泛使用的对称加密算法。 DES是具有56位密钥和8字节块大小的块加密。请注意,在TLS中,对于密钥生成目的,DES被视为具有8字节密钥长度(64位),但它仍然只提供56位保护。 (假设每个关键字节的低位被设置为在该关键字节中产生奇校验)。DES也可以以对于每个数据块使用三个独立的键和三个加密的模式来操作。这使用168位密钥(TLS密钥生成方法中的24个字节),并提供相当于112位的安全性。 [DES],[3DES]

数字签名标准(DSS)(Digital Signature Standard)

由美国国家标准技术研究所批准的数字签名标准,由美国商务部1994年5月出版的NIST FIPS PUB 186“数字签名标准”中定义。[DSS]

数字签名(digital signatures)

数字签名利用公钥加密和单向哈希函数来产生可以被认证的数据的签名,并且难以伪造或拒绝。

握手(handshake)

客户端和服务器之间的初步协商,建立其交易参数。

初始化向量(IV)(Initialization Vector)

当在CBC模式中使用块加密时,初始化向量在加密之前与第一个明文块进行异或运算。

IDEA

Xuejia Lai和James Massey设计的64位块加密。 [IDEA]

消息认证码(MAC)Message Authentication Code

消息认证码是从消息和一些secret计算的单向散列。在不知道secret的情况下难以伪造。其目的是检测消息是否已被更改。

主机密信息(master secret)

用于生成加密密钥,MAC secret和IV的安全secret数据。

MD5

MD5是将任意长的数据流转换为固定大小(16字节)的摘要的安全散列函数。

公共密钥加密(public key cryptography) : 一类使用双加密密码的加密技术。使用公钥加密的消息只能使用关联的私钥进行解密。相反,使用私钥签名的邮件可以通过公钥进行验证。

单向散列函数(one-way hash function) : 将任意数量的数据转换为固定长度散列的单向转换。在计算上很难扭转转型或发现碰撞。 MD5和SHA是单向哈希函数的例子。

RC2

由Ron Rivest在RSA Data Security,Inc. [RSADSI]开发的块加密在[RC2]中描述。

RC4

由RSA Data Security [RSADSI]授权的流加密。兼容加密在[RC4]中有描述。

RSA

一种非常广泛使用的公共密钥算法,可用于加密或数字签名。 [RSA]

salt

用于导出加密密钥的非秘密随机数据可抵抗预计算攻击。

服务器(server)

服务器是响应来自客户端的连接请求的应用程序实体。另见客户端。

会话(session)

TLS会话是客户端和服务器之间的关联。会话由握手协议创建。会话定义了一组加密安全参数,可以在多个连接之间共享。会话用于避免每个连接的新安全参数的昂贵协商。

会话标识符(session identifier)

会话标识符是由标识特定会话的服务器生成的值。

服务器写入密钥(server write key)

用于加密由服务器写入的数据的密钥。

服务器写MAC secret(server write MAC secret)

用于认证由服务器写入的数据的机密数据。

SHA

安全散列算法在FIPS PUB 180-1中定义。它产生一个20字节的输出。注意,所有对SHA的引用实际上都使用修改后的SHA-1算法。 [SHA]

SSL

Netscape的安全套接层协议[SSL3]。 TLS基于SSL版本3.0

流加密(stream cipher)

将密钥转换为加密较强的密钥流的加密算法,然后将其与纯文本进行异或运算。

对称加密(symmetric cipher)

请参阅批量加密。

传输层安全(TLS)(Transport Layer Security)

这个协议还有互联网工程任务组(IETF)的传输层安全工作组。请参阅本文档末尾的“注释”。

C.CipherSuite 定义

CipherSuite

Is Exportable

Key Exchange

Cipher

Hash

TLS_NULL_WITH_NULL_NULL

*

NULL

NULL

NULL

TLS_RSA_WITH_NULL_MD5

*

RSA

NULL

MD5

TLS_RSA_WITH_NULL_SHA

*

RSA

NULL

SHA

TLS_RSA_EXPORT_WITH_RC4_40_MD5

*

RSA_EXPORT

RC4_40

MD5

TLS_RSA_WITH_RC4_128_MD5

RSA

RC4_128

MD5

TLS_RSA_WITH_RC4_128_SHA

RSA

RC4_128

SHA

TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5

*

RSA_EXPORT

RC2_CBC_40

MD5

TLS_RSA_WITH_IDEA_CBC_SHA

RSA

IDEA_CBC

SHA

TLS_RSA_EXPORT_WITH_DES40_CBC_SHA

*

RSA_EXPORT

DES40_CBC

SHA

TLS_RSA_WITH_DES_CBC_SHA

RSA

DES_CBC

SHA

TLS_RSA_WITH_3DES_EDE_CBC_SHA

RSA

3DES_EDE_CBC

SHA

TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA

*

DH_DSS_EXPORT

DES40_CBC

SHA

TLS_DH_DSS_WITH_DES_CBC_SHA

DH_DSS

DES_CBC

SHA

TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA

DH_DSS

3DES_EDE_CBC

SHA

TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA

*

DH_RSA_EXPORT

DES40_CBC

SHA

TLS_DH_RSA_WITH_DES_CBC_SHA

DH_RSA

DES_CBC

SHA

TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA

DH_RSA

3DES_EDE_CBC

SHA

TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA

*

DHE_DSS_EXPORT

DES40_CBC

SHA

TLS_DHE_DSS_WITH_DES_CBC_SHA

DHE_DSS

DES_CBC

SHA

TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA

DHE_DSS

3DES_EDE_CBC

SHA

TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA

*

DHE_RSA_EXPORT

DES40_CBC

SHA

TLS_DHE_RSA_WITH_DES_CBC_SHA

DHE_RSA

DES_CBC

SHA

TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA

DHE_RSA

3DES_EDE_CBC

SHA

TLS_DH_anon_EXPORT_WITH_RC4_40_MD5

*

DH_anon_EXPORT

RC4_40

MD5

TLS_DH_anon_WITH_RC4_128_MD5

DH_anon

RC4_128

MD5

TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA

DH_anon

DES40_CBC

SHA

TLS_DH_anon_WITH_DES_CBC_SHA

DH_anon

DES_CBC

SHA

TLS_DH_anon_WITH_3DES_EDE_CBC_SHA

DH_anon

3DES_EDE_CBC

SHA

* Indicates IsExportable is True


Key Exchange Algorithm

Description

Key size limit

DHE_DSS

Ephemeral DH with DSS signatures

None

DHE_DSS_EXPORT

Ephemeral DH with DSS signatures

DH = 512 bits

DHE_RSA

Ephemeral DH with RSA signatures

None

DHE_RSA_EXPORT

Ephemeral DH with RSA signatures

DH = 512 bits, RSA = none

DH_anon

Anonymous DH, no signatures

None

DH_anon_EXPORT

Anonymous DH, no signatures

DH = 512 bits

DH_DSS

DH with DSS-based certificates

None

DH_DSS_EXPORT

DH with DSS-based certificates

DH = 512 bits

DH_RSA

DH with RSA-based certificates

None

DH_RSA_EXPORT

DH with RSA-based certificates

DH = 512 bits,RSA = none

NULL

No key exchange

N/A

RSA

RSA key exchange

None

RSA_EXPORT

RSA key exchange

RSA = 512 bits


密钥大小限制

密钥大小限制给出了在可出口的加密组件中可以合法用于加密的最大公钥的大小。

Cipher

Type

Key

Material

Expanded

Key

Material

Effective

Key Bits

IV

Size

Block

Size

NULL *

Stream

0

0

0

0

N/A

IDEA_CBC

Block

16

16

128

8

8

RC2_CBC_40 *

Block

5

16

40

8

8

RC4_40 *

Stream

5

16

40

0

N/A

RC4_128

Stream

16

16

128

0

N/A

DES40_CBC *

Block

5

8

40

8

8

DES_CBC

Block

8

8

56

8

8

3DES_EDE_CBC

Block

24

24

168

8

8

* Indicates IsExportable is true.

Type

指示这是否是以CBC模式运行的流加密或块加密。

Key Material

用于生成写入密钥的key_block的字节数。

Expanded Key Material

实际馈入加密算法的字节数

Effective Key Bits

在加密程序中输入的关键材料中有多少熵材料。

IV Size

需要为初始化向量生成多少数据。 零为流加密; 其余为块加密的块大小。

Block Size

块加密在一个块中加密的数据量; 以CBC模式运行的块加密只能加密其块大小的偶数倍。

Hash function

Hash Size

Padding Size

NULL

0

0

MD5

16

16

SHA

20

20

D.实施说明

TLS协议不能防止许多常见的安全错误。 本节提供了几个建议来协助实现者。

D.1临时RSA密钥

美国出口限制将用于加密的RSA密钥限制为512位,但不要对用于签名操作的RSA密钥的长度设置任何限制。证书通常需要大于512位,因为512位RSA密钥对于高价值交易或需要长期安全性的应用来说不够安全。一些证书也被指定为仅签名,在这种情况下,它们不能用于密钥交换。

当证书中的公钥不能用于加密时,服务器签署一个临时的RSA密钥,然后进行交换。在可出口应用中,临时RSA密钥应为最大允许长度(即512位)。因为512位RSA密钥相对不安全,应该经常更改。对于典型的电子商务应用,建议每天或每500个交易更改密钥,如果可能,更频繁地更改密钥。请注意,虽然对于多个事务使用相同的临时密钥是可以接受的,但它必须在每次使用时都进行签名。

RSA密钥生成是一个耗时的过程。在许多情况下,可以将低优先级进程分配给密钥生成任务。

无论何时完成新密钥,现有的临时密钥都可以用新的密钥替代。

D.2 随机数生成和种子

TLS需要一个加密安全的伪随机数生成器(PRNG)。 必须注意设计和做种PRNG。 基于安全散列操作的PRNG(最值得注意的是MD5和/或SHA)是可接受的,但不能提供比随机数发生器状态的大小更多的安全性。 (例如,基于MD5的PRNG通常提供128位的状态。)

要估计正在产生的种子材料的数量,请在每个种子字节中添加不可预测信息的位数。 例如,即使计数器值的总大小为16位或更多,从PC兼容的18.2 Hz定时器获取的击键定时值也分别提供1个或2个安全位。 为了播种128位PRNG,因此需要大约100个这样的定时器值。

警告:

RSAREF中的种子功能和3.0之前的BSAFE版本与订单无关。 例如,如果提供1000个种子比特,则在种子功能的1000次单独调用中一次一个,则PRNG将结束于仅依赖于种子数据中的0或1种子比特数的状态(即, ,有1001个可能的最终状态)。 使用BSAFE或RSAREF的应用必须特别注意确保正确播种。 这可以通过将种子位累加到缓冲器中并且一次处理它们或通过用每个种子位处理递增计数器来实现; 任何一种方法将重新引入依赖于种子过程的顺序。

D.3 证书和认证(Certificates and authentication)

实施负责验证证书的完整性,通常应支持证书撤销消息。 应始终验证证书,以确保受信任的证书颁发机构(CA)正确签名。 信任CA的选择和添加应该非常仔细地进行。 用户应该能够查看有关证书和根CA的信息。

D.4加密组件(CipherSuites)

TLS支持一系列密钥大小和安全级别,包括一些不提供或最小安全性的密钥。 正确的实现可能不会支持许多加密组件。 例如,40位加密很容易被破解,所以需要强大安全性的实现不应该允许40位密钥。 同样地,匿名的Diffie-Hellman是非常不鼓励的,因为它不能防止中间人的袭击。 应用程序还应执行最小和最大密钥大小。 例如,包含512位RSA密钥或签名的证书链不适用于高安全性应用程序。

E.向后兼容SSL

由于历史原因,为了避免浪费预留端口号码,由TLS 1.0,SSL 3.0和SSL 2.0保护的应用协议都经常共享相同的连接端口:例如https协议(由SSL保护的HTTP或TLS)使用端口443,无论使用哪种安全协议。因此,必须确定一些机制来区分和协商各种协议。

TLS版本1.0和SSL 3.0非常相似;因此,两者都很容易。希望与SSL 3.0服务器进行协商的TLS客户端应使用SSL 3.0记录格式和客户机端口结构发送客户端hello消息,为版本字段发送{3,1}以注意它们支持TLS 1.0。如果服务器仅支持SSL 3.0,则会使用SSL 3.0服务器进行响应;如果它支持TLS,使用TLS服务器hello。然后协商进行协商的协议。

类似地,希望与SSL 3.0客户端互操作的TLS服务器应该接受SSL 3.0客户端hello消息,并且如果接收到版本字段为{3,0}的SSL 3.0客户端hello,则响应SSL 3.0服务器hello,表示该此客户端不支持TLS。

每当客户端已经知道服务器已知的最高协议(例如,恢复会话时),它应该启动该本地协议的连接。

支持SSL 2.0服务器的TLS 1.0客户端必须发送SSL版本2.0客户端问候消息[SSL2]。如果TLS服务器希望在同一连接端口上支持SSL 2.0客户端,那么TLS服务器应该接受客户端hello格式。与版本2.0规范的唯一偏差是能够指定值为3的版本,并支持CipherSpec中更多的加密类型。

警告:发送版本2.0客户端hello消息的能力将逐渐被淘汰。 实施者应尽全力推进。 3.0版提供了更好的机制来移动到较新的版本。

以下加密规范是SSL版本2.0的转储。 假设使用RSA进行密钥交换和认证。

V2CipherSpec TLS_RC4_128_WITH_MD5 = { 0x01,0x00,0x80 };
V2CipherSpec TLS_RC4_128_EXPORT40_WITH_MD5 = { 0x02,0x00,0x80 };
V2CipherSpec TLS_RC2_CBC_128_CBC_WITH_MD5 = { 0x03,0x00,0x80 };
V2CipherSpec TLS_RC2_CBC_128_CBC_EXPORT40_WITH_MD5 = { 0x04,0x00,0x80 };
V2CipherSpec TLS_IDEA_128_CBC_WITH_MD5 = { 0x05,0x00,0x80 };
V2CipherSpec TLS_DES_64_CBC_WITH_MD5 = { 0x06,0x00,0x40 };
V2CipherSpec TLS_DES_192_EDE3_CBC_WITH_MD5 = { 0x07,0x00,0xC0 };

使用以下语法可以将TLS原生的加密规范包含在V2.0客户端hello消息中。 其第一个字节等于零的任何V2CipherSpec元素将被2.0版服务器忽略。 发送任何上述V2CipherSpecs的客户端还应包含TLS等效项(见附录A.5):

V2CipherSpec (see TLS name) = { 0x00, CipherSuite };

E.1版本2客户端hello

以下使用本文档的演示模型介绍2.0版客户端的hello消息。 真正的定义仍然被认为是SSL版本2.0规范。

uint8 V2CipherSpec[3];
struct {
uint8 msg_type;
Version version;
uint16 cipher_spec_length;
uint16 session_id_length;
uint16 challenge_length;
V2CipherSpec cipher_specs[V2ClientHello.cipher_spec_length];
opaque session_id[V2ClientHello.session_id_length];
Random challenge;
} V2ClientHello;

MSG_TYPE

此字段与版本字段一起标识版本2客户端hello消息。 值应为1(1)。

version

客户端支持的协议的最高版本(等于ProtocolVersion.version,请参阅附录A.1)。

cipher_spec_length

该字段是字段cipher_specs的总长度。 它不能为零,必须是V2CipherSpec长度(3)的倍数。

session_id_length

该字段的值必须为零或16.如果为零,客户端将创建一个新的会话。如果16,session_id字段将包含16个字节的会话标识。

challenge_length

客户端对服务器进行身份验证的挑战的长度(以字节为单位)此值必须为32。

cipher_specs

这是客户端愿意并能够使用的所有CipherSpecs的列表。服务器必须至少有一个CipherSpec可以接受。

session_id

如果该字段的长度不为零,它将包含客户端希望恢复的会话的标识。

challenge

客户端对服务器的挑战,使服务器识别自身是一个(几乎)任意长度的随机数。 TLS服务器将正确地证明挑战数据成为ClientHello.random数据(如果需要,填充前导零),如本协议规范中所述。如果挑战的长度大于32字节,则仅使用最后的32个字节。 V3服务器拒绝具有少于16个字节的挑战数据的V2 ClientHello是合法的(但不是必需的)。

注意:恢复TLS会话的请求应该使用TLS客户端hello。

E.2 避免中间版本的回滚

当TLS客户端回到版本2.0兼容模式时,他们应该使用特殊的PKCS#1块格式化。 这样做是为了使TLS服务器能够拒绝具有TLS功能的客户端的2.0版本会话。

当TLS客户端处于版本2.0兼容模式时,它们为加密密钥数据字段的RSA加密设置了PKCS填充(不包括填充的终端null)的右侧(最低有效)8个随机字节 的CLIENT-MASTER-KEY到0x03(其他填充字节是随机的)。 解密ENCRYPTED-KEY-DATA字段后,如果这8个填充字节为0x03,则支持TLS的服务器应该发出错误。 接收以这种方式填充的块的2.0版服务器将正常进行。

F.安全分析(Security analysis)

TLS协议旨在建立客户端和通过不安全通道进行通信的服务器之间的安全连接。本文件提出了几个传统的假设,包括攻击者拥有大量的计算资源,无法从协议之外的来源获取秘密信息。假设攻击者具有捕获,修改,删除,重放和以其他方式篡改通过通信通道发送的消息的能力。本附录概述了TLS如何设计来抵御各种攻击。

F.1握手协议(Handshake protocol)

握手协议负责选择CipherSpec并生成一个Master Secret,它们一起构成与安全会话关联的主加密参数。握手协议还可以可选地验证具有由受信任的证书颁发机构签名的证书的各方。

F.1.1认证和密钥交换(Authentication and key exchange)

TLS支持三种认证方式:双方认证,未认证客户端进行服务器认证,全匿名。每当服务器进行身份验证时,该通道对于中间人的攻击是安全的,但完全匿名的会话本身就容易受到这种攻击。匿名服务器无法验证客户端。如果服务器进行身份验证,其证书消息必须提供一个有效的证书链,从而导致可接受的证书颁发机构。同样,经过身份验证的客户端必须向服务器提供可接受的证书。各方负责核实对方的证书是否有效,还没有过期或被吊销。

密钥交换过程的总体目标是创建一个通信方知道而攻击方不知道的pre_master_secret,这个参数将用于生成master_secret(参见第8.1节)。 master_secret需要生成证书验证和完成的消息、加密密钥和MAC secrets(参见7.4.8,7.4.9和6.3节)。通过发送正确的完成消息,各方因此证明他们知道正确的pre_master_secret。

F.1.1.1 匿名密钥交换

使用RSA或Diffie-Hellman进行密钥交换可以建立完全匿名的会话。 使用匿名RSA,客户端将从服务器密钥交换消息中提取的服务器未经认证的公钥,加密pre_master_secret后结果放在客户端密钥交换消息中发送给服务端。 由于窃听者不知道服务器的私有密钥,因此他们对pre_master_secret进行解码是不可行的。 (请注意,本文档中未定义匿名RSA加密组件)。

使用Diffie-Hellman,服务器的公共参数包含在服务器密钥交换消息中,客户端的公共参数在客户端密钥交换消息中发送。 不知道私钥的窃听者不能找到Diffie-Hellman的结果(即pre_master_secret)。

警告:完全匿名连接仅提供防范被动窃听的保护。 除非使用独立的防篡改信道来验证已完成的消息未被攻击者替代,否则在需要主动中间人攻击的环境中需要进行服务器认证。

F.1.1.2 RSA密钥交换和认证

使用RSA,合并了密钥交换和服务器认证。公钥可以包含在服务器的证书中,也可以是在服务器密钥交换消息中发送的临时RSA密钥。当使用临时RSA密钥时,它们由服务器的RSA或DSS证书签名。签名包括当前的ClientHello.random,所以老签名和临时密钥不能被重播。服务器可以使用单个临时RSA密钥进行多个协商会话。

注意:如果服务器需要大型证书但必须符合用于密钥交换的密钥的政府规定的大小限制,则临时RSA密钥选项很有用。

验证服务器的证书后,客户端使用服务器的公钥加密pre_master_secret。通过成功地解码pre_master_secret并产生正确的完成的消息,服务器证明它知道与服务器证书相对应的私钥。

当RSA用于密钥交换时,客户端将使用证书验证消息进行身份验证(请参见第7.4.8节)。客户端签署从master_secret派生值和所有先前握手消息。这些握手消息包括将签名绑定到服务器的服务器证书以及将签名绑定到当前握手过程的ServerHello.random。

F.1.1.3 Diffie-Hellman密钥交换认证

当使用Diffie-Hellman密钥交换时,服务器可以提供包含固定Diffie-Hellman参数的证书,或者可以使用服务器密钥交换消息发送一组使用DSS或RSA证书签名的临时Diffie-Hellman参数。临时参数在签名前使用hello.random值进行散列,以确保攻击者不会重播旧参数。在任一情况下,客户端都可以验证证书或签名,以确保参数属于服务器。

如果客户端具有包含固定Diffie-Hellman参数的证书,则其证书包含完成密钥交换所需的信息。请注意,在这种情况下,客户端和服务器将在每次通信时生成相同的Diffie-Hellman结果(即pre_master_secret)。为了防止pre_master_secret不再需要在内存中,应尽快将其转换为master_secret。客户端Diffie-Hellman参数必须与由服务器提供的密钥交换工作的那些参数兼容。

如果客户端具有标准的DSS或RSA证书或未经身份验证,则会在客户端密钥交换消息中向服务器发送一组临时参数,然后可选地使用证书验证消息进行身份验证。

F.1.2版本回滚攻击

由于TLS包括对SSL 2.0版本的实质性改进,因此攻击者可能会尝试使具有TLS功能的客户端和服务器可以退回到2.0版本。如果(且只有)两个支持TLS的方使用SSL 2.0握手,则可能会发生此攻击。

虽然使用非随机PKCS#1块类型2消息填充的解决方案是不合适的,但它为3.0版服务器提供了一种合理的安全方式来检测攻击。在应用程序指定的等待阈值已过期之前,此解决方案不会对攻击者施加强制,并替换包含相同密钥(但具有正常填充)的新的ENCRYPTED-KEY-DATA消息。关注这种规模的攻击的各方不应该使用40位加密密钥。更改PKCS填充的最低有效8字节的填充不会影响协议中使用的带符号散列和RSA密钥长度的大小的安全性,因为这基本上等同于将输入块大小增加8个字节。

F.1.3 检测对握手协议的攻击

攻击者可能会尝试影响握手交换,使各方选择不同于通常选择的加密算法。 因为许多实现将支持40位可出口加密,有些甚至可以支持空加密或MAC算法,这种攻击是特别关注的。

对于这种攻击,攻击者必须主动更改一个或多个握手信息。 如果发生这种情况,客户端和服务器将为握手消息散列计算不同的值。 结果,双方不会接受彼此的完成信息。 没有master_secret,攻击者无法修复完成的消息,所以攻击将被发现。

F.1.4恢复会话

当通过恢复会话建立连接时,新的ClientHello.random和ServerHello.random值将与会话的master_secret进行散列。如果master_secret没有被泄露,并且用于产生加密密钥和MAC secrets的安全哈希操作是安全的,则连接应该是安全的并且有效地独立于先前的连接。攻击者无法使用已知的加密密钥或MAC secret来破坏master_secret,而不会破坏安全的哈希操作(使用SHA和MD5)。

会话无法恢复,除非客户端和服务器同意。如果任何一方怀疑会话可能已被泄密,或者证书可能已经过期或被撤销,则应强制进行完全握手。建议会话ID生存期限为24小时的上限,因为获取master_secret的攻击者可能会模仿受感染方,直到相应的会话ID退出。可能在相对不安全的环境中运行的应用程序不应将会话ID写入稳定的存储。

F.1.5 MD5和SHA

TLS非常保守地使用散列函数。 在可能的情况下,MD5和SHA一起使用,以确保一个算法中的非灾难性缺陷不会破坏整体协议。

F.2 保护应用程序数据

master_secret与ClientHello.random和ServerHello.random进行散列,为每个连接生成唯一的数据加密密钥和MAC secret。

传输数据在发送前用MAC保护。 为了防止消息重放或修改攻击,MAC从MAC secret、序列号、消息长度、消息内容和两个固定字符串计算。 消息类型字段是必需的,以确保一个TLS记录层客户端的消息不被重定向到另一个。 序列号确保检测到删除或重新排序消息的尝试。 由于序列号是64位长,它们不应该溢出。 来自一方的消息无法插入对方的输出,因为它们使用独立的MAC secret。 类似地,服务器写入和客户端写入密钥是独立的,因此流加密密钥仅使用一次。

如果攻击者确实破解加密密钥,则可以读取该密钥加密的所有消息。 类似地,MAC密钥的妥协可以使消息修改攻击成为可能。 由于MAC也被加密,消息改变攻击通常需要打破加密算法以及MAC。

注意:MAC secrets可能大于加密密钥,因此即使加密密钥被破坏,消息也可以保持防篡改。

F.3 最后的注意事项

为了能够提供安全连接的TLS,客户端和服务器系统,密钥和应用程序都必须是安全的。 此外,实现必须没有安全错误。

该系统对最弱和最强的密钥交换和认证一样支持,只能使用可靠的加密功能。 使用短公钥、40位批量加密密钥和匿名服务器必须特别谨慎。 在决定哪些证书和认证机构可以接受时,实施和使用者必须小心; 不诚实的认证机构可以造成巨大的损失。

G.专利声明

提出用于本协议的一些加密算法具有专利权利要求。 此外,Netscape Communications Corporation在本标准基于的安全套接字层(SSL)工作方面拥有专利权。 RFC 2026中定义的互联网标准流程要求从专利持有人那里获得一份声明,表明许可证将在合理的条件和条件下提供给申请人。

马萨诸塞理工学院已授予RSA Data Security公司对美国发行的以下专利的独家次级许可权:

加密通信系统和方法(“RSA”),第4,405,829号

Netscape Communications Corporation已在美国发行以下专利:

安全套接字层应用程序设备和方法(“SSL”),第5,657,390号

Netscape Communications发布了以下声明:

知识产权

安全链路层

美国专利商标局(“PTO”)最近向Netscape发布了美国专利号5,657,390(“SSL专利”),用于发明,称为安全套接字层(“SSL”)。 IETF正在考虑采用SSL作为具有安全特性的传输协议。 Netscape在以下条款和条件下鼓励免版税的采用和使用SSL协议:

*如果您今天已经有一个有效的SSL Ref许可证,其中包括Netscape的源代码,则不需要SSL专利下的附加专利许可。

*如果您没有SSL Ref许可证,您可以拥有免版税许可证,以构建SSL专利权利要求或IETF TLS规范所涵盖的实施,只要您不为Netscape或其他公司声明任何专利权实施SSL或IETF TLS建议。

什么是“专利权利要求书”:

专利权利要求书是在已发行的外国或国内专利中提出的:

1)为了实施IETF TLS规范的方法或构建产品,必须被侵害; 要么

2)要求SSL专利权利要求的要素和/或其等同物被侵害的专利权利要求。

互联网协会,互联网建筑委员会,互联网工程指导小组和国家研究计划公司对专利和专利申请的有效性或范围,以及保证条款的适用性均不承担任何责任。 上述互联网协会和其他团体对于可能适用于本标准实践的任何其他知识产权没有作出任何决定。 进一步考虑这些事项是用户自己的责任。

安全注意事项

在本备忘录中讨论安全问题。

参考

[3DES] W.Tuchman,“Hellman Presents No Shortcut Solutions To DES”,IEEE Spectrum,v.16,n。 7,1979年7月,第40-41页。

[BLEI] Bleichenbacher D.,“Select the Ciphertext Attacks against Protocols Based on RSA Encryption Standard PKCS#1”in Advances in Cryptology - CRYPTO'98,LNCS vol。 1462,pages:1--12,1998。

[DES] ANSI X3.106,“美国国家标准信息系统 - 数据链路加密”,美国国家标准协会1983年。

[DH1] W.D diffie和M.E.Hellman,“New Directions in Cryptography”,IEEE Transactions on Information Theory,V.IT-22,n。 6,1977年6月,第74-84页。

[DSS] NIST FIPS PUB 186,“数字签名标准”,国家标准与技术研究所,美国商务部,1994年5月18日。

[FTP] Postel J.和J.Reynolds,“File Transfer Protocol”,STD 9,RFC 959,1985年10月。

[HTTP] Berners-Lee,T.,Fielding,R.,and H. Frystyk,“Hypertext Transfer Protocol-HTTP / 1.0”,RFC 1945,May 1996。

[HMAC] Krawczyk,H.,Bellare,M.和R. Canetti,“HMAC:Keyed-Hashing for Message Authentication”,RFC 2104,February 1997。

[IDEA] X.Lai,“On the Design and Security of Block Ciphers”,ETH Series in Information Processing,v.1,Konstanz:Hartung-Gorre Verlag,1992。

[MD2] Kaliski,B.,“MD2消息摘要算法”,RFC 1319,1992年4月。

[MD5] Rivest,R.,“MD5 Message Digest Algorithm”,RFC 1321,1992年4月。

[PKCS1] RSA实验室,“PKCS#1:RSA加密标准”,1.5版,1993年11月。

[PKCS6] RSA实验室,“PKCS#6:RSA扩展证书语法标准”,1.5版,1993年11月。

[PKCS7] RSA实验室,“PKCS#7:RSA加密消息语法标准”,1.5版,1993年11月。

[PKIX] Housley,R.,Ford,W.,Polk,W.and D.Sony,“Internet Public Key Infrastructure:Part I:X.509 Certificate and CRL Profile”,RFC 2459,January 1999。

[RC2] Rivest,R.,“A Description of the RC2(r)Encryption Algorithm”,RFC 2268,1998年1月。

[RC4] Thayer,R.和K. Kaukonen,A Stream Cipher Encryption Algorithm,Work in Progress。

[RSA] R. Rivest,A.Shamir和L.M.Adleman,“A Method for Obtaining Digital Signatures and Public-Key Cryptosystems”,Communications of the ACM,v.21,n。 2,1978年2月,第120-126页。

[RSADSI]联系RSA Data Security,Inc.,电话:415-595-8782

[SCH] B.施奈尔。 Applied Cryptography:Protocols,Algorithms,and Source Code in C,John Wiley&Sons,Inc.出版1994。

[SHA]美国商务部美国国家标准与技术研究所,1994年5月31日,美国商务部NIS FIPS PUB 180-1“安全哈希标准”。

[SSL2] Hickman,Kipp,“The SSL Protocol”,Netscape Communications Corp.,1995年2月9日。

[SSL3] A.Frier,P.Karton和P.Kocher,“The SSL 3.0 Protocol”,Netscape Communications Corp.,1996年11月18日。

[TCP] Postel,J.,“Transmission Control Protocol”,STD 7,RFC 793,1981年9月。

[TEL] Postel J.和J.Reynolds,“Telnet Protocol Specifications”,STD 8,RFC 854,1993年5月。

[TEL] Postel J.和J.Reynolds,“Telnet Option Specifications”,STD 8,RFC 855,May 1993。

[X509] CCITT。 建议X.509:“目录 - 认证框架”。1988年。

[XDR] R. Srinivansan,Sun Microsystems,RFC-1832:XDR:External Data Representation Standard,August 1995。

完整版权声明

版权所有(C)互联网协会(1999)。版权所有。

本文件及其翻译可能会复制和提供给他人,对其作出任何评论或解释或协助实施的衍生作品,可以全部或部分内容,不受任何形式的限制,制作,复制,发布和分发条件是上述版权声明和本段都包含在所有这些副本和衍生作品中。但是,本文档本身不得以任何方式进行修改,例如删除版权声明或引用互联网协会或其他互联网组织,除非为制定互联网标准而需要,否则版权定义在必须遵循互联网标准过程,或按照要求将其翻译成英语以外的语言。

上述授予的有限权限是永久性的,不会被互联网协会或其继承人或受让人撤销。

本文档和本文档所包含的信息以“按原样”提供,互联网协会和互联网工程任务组织不承担任何明示或默示的担保,包括但不限于使用本文信息的任何担保侵犯任何权利或任何暗示的适销性或适用于特定用途的担保。

点击此处下载Transport Layer Security(TSL)协议 RFC2246中文版的PDF文件。