首页 > 其他分享 >Transport Layer Security for UDP&TCP(TLS/DTLS1.2)

Transport Layer Security for UDP&TCP(TLS/DTLS1.2)

时间:2024-07-31 22:55:01浏览次数:10  
标签:TLS case UDP 握手 DTLS1.2 消息 hello 客户端

参考文章:https://blog.csdn.net/alwaysrun/article/details/89076492

  https://www.jianshu.com/p/fd0a624d0912

  https://cloud.tencent.com/developer/article/1928677

文档:https://www.rfc-editor.org/rfc/rfc6347

   https://www.rfc-editor.org/rfc/rfc5246

1.SSL/TLS 协议

1.1背景

首先从我们比较熟悉的 SSL/TLS 开始讲起。SSL(Secure Socket Layer) 和 TLS(Transport Layer Security) 简单理解就是同一件东西的两个演进阶段,同样都是在应用层和传输层之间加入的安全层,最早的时候这个安全层叫做 SSL,由 Netscape 公司推出,后来被 IETF 组织标准化并称之为 TLS。

TLS的动机从HTTPS讲起。HTTP 本身不具备加密的功能,所以也无法做到对通信整体(使用 HTTP 协议通信的请求和响应的内容)进行加密。按传输层 TCP/IP 协议族的工作机制,通信内容在所有的通信线路上都有可能遭到窥视。而HTTP 在传输数据的过程中,所有的数据都是明文传输,非常奔放,自然没有安全性可言。数据在公网上传输,容易被第三方获取,尤其特别是一些敏感数据,比如用户密码和信用卡信息等,一旦被第三方获取后果不堪设想。HTTPS 主要用于解决数据安全传输的问题,通过加密套件,让数据在网络传输过程中对第三方“不可见”(看见的是无意义的乱码信息)。在 HTTPS 中,原有的 HTTP 协议会得到 TLS (安全传输层协议) 或其前辈 SSL (安全套接层) 的加密。因此 HTTPS 也常指 HTTP over TLS 或 HTTP over SSL,即HTTPS = HTTP + SSL / TLS。

 

SSL/TLS 的作用是为了解决互联网通信中存在的三种风险:

  1. 窃听风险:第三方可以获知通信内容;
  2. 篡改风险:第三方可以修改通信内容;
  3. 冒充风险:第三方可以冒充他人身份参与通信。

SSL/TLS 协议能够做到以下这几点,从而解决上述的三种风险:

  1. 所有信息通过加密传播,第三方无法窃听;
  2. 具有数据签名及校验机制,一旦被篡改,通信双方立刻可以发现;
  3. 具有身份证书,防止其他人冒充。

1.2协议细则

(1)架构

SSL/TLS协议有一个高度模块化的架构,分为很多子协议,如下图所示。也可以简单地理解为,TLS协议分为两层,一层是记录层,一层是握手层。

  • TLS记录层负责从更高层接收数据并对其进行处理。具体来说,记录层接收要传输的消息,将数据分成可管理的块,可选地压缩数据,应用MAC(消息认证码),加密,然后传输结果。接收到的数据被解密、验证、解压缩、重新组装,然后传递给更高层的客户端。 另外,为了允许TLS协议的扩展,记录层可以支持额外的记录内容类型。
  • 在TLST握手层,中有三个子协议使用到了记录: handshake protocol、alert protocol、changecipher spec protocol。

SSL握手协议:包括协商安全参数和密码套件、服务器身份认证(客户端身份认证可选)、密钥交换;
SSL握手密钥参数更换协议:一条消息表明握手协议已经完成;
SSL告警协议:对握手协议中一些异常的错误提醒,分为fatal和warning两个级别,fatal类型的错误会直接中断SSL链接,而warning级别的错误SSL链接仍可继续,只是会给出错误警告;

(2)流程

SSL/TLS协议的执行过程被设计为两阶段:握手阶段和应用阶段。

  • 握手阶段也称协商阶段,在这一阶段,客户端和服务器端会认证对方身份(依赖于PKI体系,利用数字证书进行身份认证),并协商通信中使用的安全参数、密码套件以及MasterSecret。后续通信使用的所有密钥都是通过MasterSecret生成。
  • 在握手阶段完成后,进入应用阶段。在应用阶段通信双方使用握手阶段协商好的密钥进行安全通信。

随机数

生成方

生成报文

含义

A

Client

ClientHello

C = pre-master-key

master-key = function(A,B,pre-master-key)

B

Server

ServerHello

C

Client

——

1.3协议实现

(1)记录层

记录层将接收到的数据分片成大小不超过2^14字节的TLSPlaintext记录。这个分片过程是为了使数据块更易于管理和传输。重要的一点是,客户端的消息边界在记录层中并不保留,这意味着:

多个相同类型的客户端消息可以合并成一个TLSPlaintext记录。

一个消息可以被分片成多个记录。

struct {
    uint8 major;
    uint8 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;

 (2)握手层

ChangeCipherSpec

更改密码规范协议(Change Cipher Spec Protocol)用于标志加密策略的转换。它通过一个单字节的消息来通知对方,后续的通信将使用新协商的加密算法和密钥。

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

Alert

警报消息传达消息的严重性(警告或致命)和警报的描述。严重性为致命的警报消息会立即终止连接。

enum { warning(1), fatal(2), (255) } AlertLevel;
//warning:警告级别的警报,表示可能存在问题,但不需要立即终止连接。
//fatal:致命级别的警报,表示严重问题,必须立即终止连接。
enum {
    close_notify(0),
    unexpected_message(10),
    bad_record_mac(20),
    decryption_failed_RESERVED(21),
    record_overflow(22),
    decompression_failure(30),
    handshake_failure(40),
    no_certificate_RESERVED(41),
    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_RESERVED(60),
    protocol_version(70),
    insufficient_security(71),
    internal_error(80),
    user_canceled(90),
    no_renegotiation(100),
    unsupported_extension(110),
    (255)
} AlertDescription;

struct {
    AlertLevel level;
    AlertDescription description;
} Alert;

Handshake

TLS握手协议的任务是生成会话状态的加密参数,该协议在TLS记录层之上运行。当TLS客户端和服务器首次开始通信时,它们会协商协议版本,选择加密算法,可选地相互认证,并使用公钥加密技术生成共享的秘密。

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;

 ①HelloRequest

HelloRequest消息是由服务器发送给客户端的一个简单通知,指示客户端应该重新开始协商过程。

服务器可以在任何时间发送HelloRequest消息,但不应在客户端初次连接时立即发送。

HelloRequest消息结构非常简单,仅包含一个空的结构体。

struct { } HelloRequest;

②ClientHello

当客户端首次连接到服务器时,必须发送ClientHello作为其第一条消息。客户端还可以在收到HelloRequest后或出于自身需要重新协商现有连接的安全参数时发送ClientHello。

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

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

uint8 CipherSuite[2]; /* 加密套件选择器 */

struct {
    ProtocolVersion client_version;
    Random random;
    SessionID session_id;
    CipherSuite cipher_suites<2..2^16-2>;
    CompressionMethod compression_methods<1..2^8-1>;
    select (extensions_present) {
        case false:
            struct {};
        case true:
            Extension extensions<0..2^16-1>;
    };
} ClientHello;

ClientHello消息包含以下主要部分:

  • Random:一个包含当前时间和28字节随机数的结构,用于生成后续的加密参数。
  • SessionID:一个可变长度的会话标识符,用于指示客户端希望重用的会话。
  • CipherSuite:一个加密套件列表,按客户端的偏好顺序排列。
  • CompressionMethod:一个压缩方法列表,按客户端的偏好顺序排列。
  • Extensions:一个可选的扩展字段,用于请求服务器提供扩展功能。

加密套件列表包含客户端支持的加密算法组合,每个加密套件定义一个密钥交换算法、一个批量加密算法(包括密钥长度)、一个MAC算法和一个PRF算法。

③ClientKeyExchange

此消息总是由客户端发送。如果发送了客户端证书消息,它必须紧跟在客户端证书消息之后。否则,它必须是客户端在接收到ServerHelloDone消息后发送的第一条消息。

通过此消息,设置预主密钥,方法是直接传输RSA加密的秘密或传输Diffie-Hellman参数,使双方能够达成相同的预主密钥。

struct {
    select (KeyExchangeAlgorithm) {
        case rsa:
            EncryptedPreMasterSecret;// RSA加密的预主密钥
        case dhe_dss:
        case dhe_rsa:
        case dh_dss:
        case dh_rsa:
        case dh_anon:
            ClientDiffieHellmanPublic;// 客户端的Diffie-Hellman公钥值
    } exchange_keys;
} ClientKeyExchange;
  • 计算主密钥

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

master_secret = PRF(pre_master_secret, "master secret",
                    ClientHello.random + ServerHello.random)//伪随机函数
                    [0..47];
  • RSA

当使用RSA进行服务器认证和密钥交换时,客户端生成一个48字节的pre_master_secret,使用服务器的证书中的公钥加密,并发送给服务器。服务器使用其私钥解密得到pre_master_secret。然后双方按照上述规定将pre_master_secret转换为master_secret。此结构是ClientKeyExchange消息的变体,不是独立消息。

PreMasterSecret中的版本号是客户端在ClientHello.client_version中提供的版本,而不是为连接协商的版本。此功能设计用于防止回滚攻击。

struct {
    ProtocolVersion client_version;
    opaque random[46];
} PreMasterSecret;

struct {
    public-key-encrypted PreMasterSecret pre_master_secret;//由客户端生成的随机值,用于生成主密钥
} EncryptedPreMasterSecret;
  • Diffle-Herman

如果客户端使用了Diffie-Hellman密钥交换方法,客户端需要向服务器传递其Diffie-Hellman公钥值(Yc)。根据情况不同,Yc的传递可以是显式的或隐式的。

enum { implicit, explicit } PublicValueEncoding;
//implicit:客户端已经发送了包含Diffie-Hellman密钥的证书,因此不需要再次发送Yc。客户端密钥交换消息将被发送,但内容为空。
//explicit:需要发送Yc。
struct {
    select (PublicValueEncoding) {
        case implicit: struct { };
        case explicit: opaque dh_Yc<1..2^16-1>;
    } dh_public;//客户端的Diffie-Hellman公钥值(Yc)
} ClientDiffieHellmanPublic;

④CertificateVerify

此消息用于对客户端证书进行显式验证。此消息仅在客户端证书具有签名能力(即,除包含固定Diffie-Hellman参数的证书外的所有证书)后发送。发送时,它必须紧跟在客户端密钥交换消息之后。

struct {
    digitally-signed struct {
        opaque handshake_messages[handshake_messages_length];
    }
} CertificateVerify;

 这里的handshake_messages指的是从客户端hello开始到(但不包括)此消息为止发送或接收的所有握手消息,包括握手消息的类型和长度字段。这是迄今为止交换的所有握手结构(如第7.4节所定义)的连接。注意,这要求双方要么缓存消息,要么为所有潜在的哈希算法计算运行哈希,直到CertificateVerify计算时。服务器可以通过在CertificateRequest消息中提供有限的摘要算法集合来最小化此计算成本。

⑤Finished

完成消息(Finished)是TLS握手过程中的最后一个握手消息,用于确认整个握手过程的完整性和正确性。它是第一个使用刚协商的加密算法、密钥和秘密进行保护的消息。

完成消息总是在更改密码规范消息(ChangeCipherSpec)之后立即发送。这个顺序是必须的,因为完成消息是用新协商的加密算法和密钥保护的。

struct {
    opaque verify_data[verify_data_length];
} Finished;
//verify_data是一个通过伪随机函数(PRF)计算的验证数据
PRF(master_secret, finished_label, Hash(handshake_messages))[0..verify_data_length-1];
/*
finished_label:
    客户端发送的完成消息使用字符串:"client finished"。
    服务器发送的完成消息使用字符串:"server finished"。
*/
/*
handshake_messages:
    这是到目前为止交换的所有握手消息的哈希值,不包括HelloRequest消息和记录层头。
*/

2.DTLS(1.2)

2.1背景

DTLS 的全称为 Datagram Transport Layer Security,从名字上就可以看出它和 TLS 的区别就在于多了一个“Datagram”,因为我们把使用 UDP 传输的报文叫做 “Datagram”,所以这个名字也就意味着 DTLS 是适用于 UDP 传输过程的加密协议。 TLS 1.2 及之前都没有尝试解决 DoS 攻击的问题,直到 TLS 1.3 才通过加入了 HelloRetryRequest 和 Cookie 来解决 DoS 攻击的问题。而相对 TCP 来说,UDP对 DoS 攻击更加敏感,因此 DTLS 在 1.0 版本就加入了 HelloVerifyRequest 和 Cookie,用于服务端对客户端的二次校验。
单对比 TLS 1.2,DTLS 1.2 大部分步骤都是一样的,只是在服务端多了一步 HelloVerifyRequest,客户端因此也多了第二次的 ClientHello

2.2协议细则

(1)架构

(2)流程

DTLS使用与TLS相同的所有握手消息和流程,但有三个主要变化:

  1. 添加了无状态的cookie交换,以防止拒绝服务攻击。
  2. 修改了握手头部以处理消息丢失、重新排序和DTLS消息分片(为了避免IP分片)。
  3. 为了处理消息丢失而设置了重传定时器。

 

服务端在首次收到客户端发送的 Client Hello 之后,只会生成一个 Cookie,不进行任何其他的操作,并给客户端发送 HelloVerifyRequest 消息,带上这个 Cookie。只有当客户端重新发送一次 Client Hello,并带上服务端发送的这个 Cookie 后,服务端才会继续握手过程。

2.3协议实现

(1)记录层

(2)握手层

为了支持消息丢失、重新排序和消息分片,DTLS修改了TLS 1.2的握手头部结构:

enum {
  hello_request(0), client_hello(1), server_hello(2),
  hello_verify_request(3),                          // 新字段
  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;
  uint16 message_seq;                               // 新字段
  uint24 fragment_offset;                           // 新字段
  uint24 fragment_length;                           // 新字段
  select (HandshakeType) {
    case hello_request: HelloRequest;
    case client_hello:  ClientHello;
    case server_hello:  ServerHello;
    case hello_verify_request: HelloVerifyRequest;  // 新字段
    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;
  • 消息序列号(message_seq:每条握手消息都有一个序列号,以确保消息的完整性和顺序。序列号从0开始,每发送一条消息递增。这有助于在消息重传时维持顺序。

  在每次握手中,每方传输的第一条消息的message_seq总是为0。每当生成新消息时,message_seq的值增加1。

  • 片段偏移(fragment_offset)和片段长度(fragment_length:这两个新字段允许将较大的握手消息分成多个片段进行传输。这是因为UDP等数据报协议不保证单一消息的完整性,所以需要手动处理消息的分片和重组。

  • 新的握手类型(hello_verify_request:这是DTLS特有的消息类型,用于验证客户端,作为防止DoS攻击的一部分。

 ①ClientHello

struct {
  ProtocolVersion client_version;
  Random random;
  SessionID session_id;
  opaque cookie<0..2^8-1>;                             // 新字段
  CipherSuite cipher_suites<2..2^16-1>;
  CompressionMethod compression_methods<1..2^8-1>;
} ClientHello;

②Certificate

 

随机数

生成方

生成报文

A

Client

ClientHello

B

Server

ServerHello

C

Client

——

标签:TLS,case,UDP,握手,DTLS1.2,消息,hello,客户端
From: https://www.cnblogs.com/elegantcloud/p/18334711

相关文章

  • 协议-TLS协议-客户端TLS解密的实现原理
    参考来源:练习实践-TLS协议01-Wireshark对https数据的解密练习实践-TLS协议01-客户端curl配合sslkey文件实现解密极客时间:网络排查案例课-实战二:应用层真实案例揭秘篇-20丨TLS加解密:如何解密HTTPS流量?客户端如何做TLS解密?这里说的客户端,包括了Chrome、Firefox等浏览......
  • SSL/TLS 深入浅出
    SSL,https(HTTPoverSSL),X.509,SSL证书,证书申请/导入/签发,等名词,想必有一定工作经验的小伙伴,一定都会略有耳闻,或者至少也听神边大神念叨过。虽然司空见惯,但是能够比较系统理清其中关系,能够从整体到局部深入浅出讲解下的人,估计至少也是十里挑一。反正没人给我讲,我只好......
  • 网络协议 TCP、UDP 和 HTTP
    TCP与UDPTCP(TransmissionControlProtocol)和UDP(UserDatagramProtocol)是两个广泛使用的传输层协议,它们在数据传输的方式、可靠性和应用场景方面有显著的区别。TCP特点:面向连接:TCP是面向连接的协议,传输数据前需建立连接(三次握手)。可靠传输:TCP通过确认(ACK)、序列号、重传......
  • .NET TCP、UDP、Socket、WebSocket
    做.NET应用开发肯定会用到网络通信,而进程间通信是客户端开发使用频率较高的场景。进程间通信方式主要有命名管道、消息队列、共享内存、Socket通信,个人使用最多的是Sokcet相关。而Socket也有很多使用方式,Socket、WebSocket、TcpClient、UdpClient,是不是很多?HttpClient与TcpClien......
  • UDP使用Epoll 实现
       #include<sys/socket.h>#include<sys/epoll.h>#include<netinet/in.h>#include<arpa/inet.h>#include<fcntl.h>#include<unistd.h>#include<stdio.h>#include<errno.h>#include<stdlib.h>#......
  • 使用 FFpyplayer 帧和 QPixmap 以及 MPEG-TS 格式的 UDP 流时出现追赶延时缓冲和滞后
    我正在尝试根据此帖子中找到的代码来构建我的用例。但是,我在使用pythonFFpyPlayer时遇到了麻烦;对于传统的ffplay,我没有这些问题。运行我的应用程序时,我注意到一种追赶延时缓冲效果,视频播放速度显着加快,然后恢复到正常速度。在某些视频中,我发......
  • socket 收发TCP/UDP
    一、c++个人测试记录,有问题还请指出,谢谢参考:C++开发基础之网络编程WinSock库使用详解TCP/UDPSocket开发_c++udp使用什么库-CSDN博客代码中Logger测试见文章: c++中spdlog的使用/python中logger的使用-CSDN博客1、main.cpp收发TCP信号:#include<iostream>#include<thr......
  • udp 广播通信
    基于全网段广播的代码示例,要点主要有两个:(1)设置socket属性SO_BROADCAST(2)发送方添加广播255.255.255.255的路由,不然会产生“Networkisunreachable”错误iprouteadd255.255.255.255deveth0示例代码:#include<stdio.h>#include<string.h>#include<stdlib.h>#includ......
  • 《UDP---FTP网络编程》
    UDP网络编程服务端(1)使用DatagramSocket创建socket,监听6666端口(2)使用DatagramPacket创建数据包(3)调用.receive()接收数据包(4)从数据包中读取数据**注意:使用String构造方法,将字节转换为原始的字符串(5)向客户端发送响应消息客户端(1)使用DatagramSo......
  • 【计算机网络中的TCP/IP】TCP/IP协议中的tcp与udp
    目录简单介绍一些TCP/IP协议TCP/IP协议的组成TCP/IP协议中tcp与udp的区别1.简单介绍一下TCP/IP协议         TCP/IP(TransmissionControlProtocol/InternetProtocol,传输控制协议/网际协议)是指能够在多个不同网络间实现信息传输的协议簇。TCP/IP协议不仅仅指......