TLS握手及其报文详细分析,服务器视角

服务器 0

1、客户端的Client Hello开始

发送此消息的时间:

当客户端首次连接到服务器时,它必须发送ClientHello作为其第一条消息。客户端还可以响应HelloRequest消息或主动发送ClientHello消息以重新协商现有连接中的安全参数。

记录层1字节2字节3字节4字节5字节
Content Type: HandshakeVersion: TLS 1.2Length
0x220x0303---
握手层Handshake Type: Client Hello LengthVersion: TLS 1.2 
0x01 0x0303
Version: TLS 1.2Random: (GMT Unix Time: Jun 26, 2024 11:04:47.000000000 中国标准时间)
0x0303 
Random: (Random Bytes)
 
Random: (Random Bytes)
 
Random: (Random Bytes)
 
Random: (Random Bytes)
 
Random: (Random Bytes)
 
Random: (Random Bytes)Session ID Length: 0  
    

接着上面就是密钥,压缩算法

Cipher Suites Length: 208Cipher Suites Length: 208(密钥长度)Cipher Suites (104 suites)(密钥)
Compression Methods Length: 1(压缩算法长度)Compression Methods (1 method)(压缩算法)
Extensions Length: 80(扩展长度)Extensions (扩展)

 

接下来我们用python进行组包

from scapy.all import *from scapy.layers.tls.all import *from scapy.layers.inet import *tls_ClientHello =TLS(type=22,version=0x0303,msg=TLSClientHello(version="TLS 1.2"))tls_ClientHello.show()sip = Ether() / IP(src=ip, dst=ip) / TCP(sport=port,                                                           dport=port)/tls_ClientHellosendp(sip)print(sip.build())

具体可以看以下抓包

9d0a1455010649af83ea7616190176f5.png

在发送ClientHello消息后,客户端等待ServerHello消息。服务器返回的任何握手消息,除了HelloRequest,都将被视为致命错误。

2、Server Hello

发送此消息的时间:

服务器在能够找到一组可接受的算法后,将响应ClientHello消息并发送此消息。如果找不到匹配的算法,服务器将以握手失败警报作为回应。

记录层1字节2字节3字节4字节
Content Type: HandshakeVersion: TLS 1.2Length
0x220x0303---
握手层Handshake Type: servert Hello Length
0x02 
Version: TLS 1.2Random: (GMT Unix Time: Jun 26, 2024 11:04:47.000000000 中国标准时间)
0x0303 
Random: (Random Bytes)
 
Random: (Random Bytes)
 
Random: (Random Bytes)
 
Random: (Random Bytes)
 
Random: (Random Bytes)
 
Random: (Random Bytes)   
    
    
    

 

Session ID LengthSession ID
Cipher Suites (两个字节)Compression Methods 

 

同样打开mbedtls客户端,应用scapy组包发送,抓包如下。

6d336d005411429da49c8b10c18b82bc.png

发包的时候注意,压缩算法和密钥必须是cllienthello里面,不然就会错误。

18453279d440415eb23b9bd88c584824.png

 

3、Server Certificate

发送时机:

当约定的密钥交换方法使用证书进行身份验证时(本文件定义的所有密钥交换方法除DH_anon外),服务器必须发送证书消息。此消息总是紧跟在ServerHello消息之后。

消息意义:

此消息将服务器的证书链传递给客户端。证书必须适合协商的密码套件的密钥交换算法和任何协商的扩展。

客户端响应服务器的证书请求消息时将使用相同的消息类型和结构。注意,如果客户端没有合适的证书来响应服务器的身份验证请求,它可能不发送任何证书。

服务器发送的证书的规则:

  • 证书类型必须是X.509v3,除非明确协商了其他类型(例如,TLSPGP)。
  • 终端实体证书的公钥(及相关限制)必须与所选密钥交换算法兼容。
  • da1abd9e92604d8681474d8c8cfe7c72.png
  • 如果客户端提供了signature_algorithms扩展,则服务器提供的所有证书必须由该扩展中出现的哈希/签名算法对签名。这意味着一个包含某个签名算法密钥的证书可以由不同签名算法签名(例如,使用DSA密钥签名的RSA密钥)。这与TLS 1.1要求算法相同的规定有所不同。

    如果服务器有多个证书,它会根据上述标准(以及其他标准,例如传输层端点、本地配置和偏好等)选择一个。如果服务器只有一个证书,它应尝试验证该证书是否符合这些标准。

    注意,有些证书使用的算法和/或算法组合目前不能用于TLS。例如,带有RSASSA-PSS签名密钥的证书(在SubjectPublicKeyInfo中为id-RSASSA-PSS OID)不能使用,因为TLS没有定义相应的签名算法。

    随着为TLS协议指定新密钥交换方法的密码套件的引入,它们将暗示证书格式和所需的编码密钥信息。

  • 记录层1字节2字节3字节4字节
    Content Type: HandshakeVersion: TLS 1.2Length
    0x220x0303---
    握手层Handshake TypeLength
      
    Certificate LengthCertificate Length
     
  • 证书先在openssl上进行生成然后进行导入,同样打开mbedtls客户端,我们发送证书。

  •  

  • 5ba87fc448a44ffd8cfeced3792b35de.jpg

     

  • 4、Server Key Exchange Message

  • 发送此消息的时间: 当服务器证书消息(如果发送)或ServerHello消息(如果这是匿名协商)中不包含足够的数据,使得客户端无法交换预主密钥时,服务器将立即发送此消息。

    消息的含义: 此消息传递加密信息,以便客户端能够生成预主密钥:包括一个Diffie-Hellman公钥,客户端可以用它完成密钥交换(生成预主密钥),或者其他算法的公钥。

  • enum {
        dhe_dss, dhe_rsa, dh_anon, rsa, dh_dss, dh_rsa
        /* 可能会扩展,例如对于ECDH,请参阅[TLSECC] */
    } KeyExchangeAlgorithm;

    struct {
        opaque dh_p<1..2^16-1>;
        opaque dh_g<1..2^16-1>;
        opaque dh_Ys<1..2^16-1>;
    } ServerDHParams; /* 临时DH参数 */

    dh_p:
    用于Diffie-Hellman操作的素数模数。

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

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

    struct {
        select (KeyExchangeAlgorithm) {
            case dh_anon:
                ServerDHParams params;
            case dhe_dss:
            case dhe_rsa:
                ServerDHParams params;
                digitally-signed struct {
                    opaque client_random[32];
                    opaque server_random[32];
                    ServerDHParams params;
                } signed_params;
            case rsa:
            case dh_dss:
            case dh_rsa:
                struct {};
                /* 对于rsa、dh_dss和dh_rsa,消息被省略 */
            /* 可能会扩展,例如对于ECDH,请参阅[TLSECC] */
        };
    } ServerKeyExchange;

  • params: 服务器的密钥交换参数。

    signed_params: 对于非匿名密钥交换,对服务器的密钥交换参数进行签名。

    如果客户端提供了"signature_algorithms"扩展,签名算法和哈希算法必须是该扩展中列出的一对。请注意,这里存在一些可能的不一致性。例如,客户端可能提供了DHE_DSS密钥交换,但在其"signature_algorithms"扩展中省略了任何DSA对。为了正确协商,服务器在选择任何候选密码套件之前,必须根据"signature_algorithms"扩展检查其兼容性。尽管这种方法不够优雅,但它是对原始密码套件设计的一种折衷方案。

    此外,哈希和签名算法必须与服务器端终端实体证书中的密钥兼容。RSA密钥可以使用任何允许的哈希算法,但受证书中的限制(如果有)的限制。

    由于DSA签名不包含任何安全的哈希算法指示,如果使用多个哈希算法与任何密钥一起使用,存在哈希替换的风险。当前,DSA [DSS] 只能与SHA-1一起使用。预计未来的DSS [DSS-3]修订版将允许在DSA中使用其他摘要算法,并指导每个密钥大小应使用哪些摘要算法。此外,未来的[PKIX]修订版可能会指定证书用于指示与DSA一起使用的摘要算法的机制。

    随着为TLS定义包含新的密钥交换算法的其他密码套件,只有当与密钥交换算法相关联的证书类型不提供足够的信息以供客户端交换预主密钥时,才会发送服务器密钥交换消息。

  • 如果hello消息里面使用的是rsa则跳过这一步

  • 4、TLSCertificateRequest

  • ### 7.4.4. 证书请求

    **发送此消息的时间**:
    非匿名服务器可以选择性地要求客户端提供证书,如果对所选密码套件合适的话。如果发送了服务器密钥交换消息,则此消息将紧随其后(否则,此消息将跟随服务器的证书消息)。

    **消息的结构**:
    ```plaintext
    enum {
        rsa_sign(1), dss_sign(2), rsa_fixed_dh(3), dss_fixed_dh(4),
        rsa_ephemeral_dh_RESERVED(5), dss_ephemeral_dh_RESERVED(6),
        fortezza_dms_RESERVED(20), (255)
    } ClientCertificateType;

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

    struct {
        ClientCertificateType certificate_types<1..2^8-1>;
        SignatureAndHashAlgorithm supported_signature_algorithms<2^16-1>;
        DistinguishedName certificate_authorities<0..2^16-1>;
    } CertificateRequest;
    ```

    **certificate_types**:
    客户端可以提供的证书类型列表。

    - rsa_sign:包含RSA密钥的证书。
    - dss_sign:包含DSA密钥的证书。
    - rsa_fixed_dh:包含静态DH密钥的证书。
    - dss_fixed_dh:包含静态DH密钥的证书。

    **supported_signature_algorithms**:
    服务器能够验证的哈希/签名算法对列表,按优先级降序排列。

    **certificate_authorities**:
    可接受的证书颁发机构的专有名单,以DER编码格式表示。这些专有名可以指定根CA或下级CA的期望专有名;因此,此消息可用于描述已知根CA以及所需的授权空间。如果certificate_authorities列表为空,则客户端可以发送任何适当ClientCertificateType的证书,除非有外部安排要求不同。

    证书类型和supported_signature_algorithms字段的交互有些复杂。certificate_types自SSLv3以来一直存在,但规范不足。大部分功能已被supported_signature_algorithms取代。以下规则适用:
    - 客户端提供的任何证书必须使用supported_signature_algorithms中的哈希/签名算法对进行签名。
    - 客户端提供的终端实体证书必须包含与certificate_types兼容的密钥。如果密钥是签名密钥,则必须能够与supported_signature_algorithms中的某个哈希/签名算法对一起使用。
    - 由于历史原因,某些客户端证书类型的名称包括用于签名证书的算法。例如,在TLS较早版本中,rsa_fixed_dh表示使用RSA签名的静态DH密钥的证书。在TLS 1.2中,这种功能已被supported_signature_algorithms淘汰,并且证书类型不再限制用于签名证书的算法。例如,如果服务器发送dss_fixed_dh证书类型和{{sha1, dsa}, {sha1, rsa}}签名类型,客户端可以回复使用RSA-SHA1签名的静态DH密钥的证书。

    新的ClientCertificateType值由IANA分配,详见第12节。

    **注意**:列为保留的值不得使用。它们在SSLv3中使用过。

    **注意**:匿名服务器请求客户端认证是一个致命的握手失败警报。

  • 同样打开模拟客户端,抓包。

  •  

  •  

  •  

  • 46db1a479d5a416d900b3cd99e3bcdb6.png

  • 5、Server Hello Done

  • ### 7.4.5. 服务器完成消息

    **发送此消息的时间**:
    服务器发送ServerHelloDone消息来指示ServerHello及相关消息的结束。发送此消息后,服务器将等待客户端的响应。

    **消息的含义**:
    此消息表示服务器已经完成发送支持密钥交换所需的消息,客户端可以继续其密钥交换阶段。

    收到ServerHelloDone消息后,客户端**应**执行以下操作:
    - 如果需要,验证服务器提供的有效证书。
    - 检查服务器Hello参数是否可接受。

    **消息的结构**:
    ```plaintext
    struct { } ServerHelloDone;
    ```

    这是一个空结构体,表示服务器没有额外的数据需要发送,并且希望客户端继续密钥交换过程。

  • 记录层1字节
    Content Type: Handshakeversion
    0x22 
    握手层Handshake Typeversion
      
    server hello donelenth 
     
  •  
  •  

    64c86bf17fd046958b407c9ae46156cc.png

     

    7、客户端后续

  • 3fac7d6f5ff54bf1a0fec9e052b0c864.png
  •  

  • 8、 Change Cipher Spec

  •  

    发送时机:
    Change Cipher Spec消息由TLS服务器发送,用于指示其已经完成密钥交换,并准备好开始使用新密钥加密通信数据。此消息是TLS协议中的一部分,用于确保在通信过程中的数据保密性和完整性。

    5541f008f0ed4c5b9b5cc8783332a62b.png

  •  

    9、finish

     

    ### Finished 消息

    #### 发送时机:

    Finished 消息总是在变更密码规范消息之后立即发送,以验证密钥交换和认证过程是否成功。在发送 Finished 消息之前,必须接收到其他握手消息和变更密码规范消息。

    #### 意义:

    Finished 消息是使用刚刚协商好的算法、密钥和秘密进行保护的第一个消息。接收者必须验证其内容是否正确。一旦一方发送了自己的 Finished 消息并接收并验证了对等方的 Finished 消息,就可以开始在连接上发送和接收应用程序数据。

    #### 消息结构:

    ```c
    struct {
        opaque verify_data[verify_data_length];
    } Finished;
    ```

    - `verify_data`:验证数据,其长度取决于密码套件的具体定义。
    - `finished_label`:对于客户端发送的 Finished 消息,字符串为 "client finished"。对于服务器发送的 Finished 消息,字符串为 "server finished"。
    - `Hash(handshake_messages)`:握手消息的哈希值,用作 PRF 函数的输入。

    在之前的TLS版本中,`verify_data` 总是12个八位字节长。在当前版本中,它依赖于密码套件的定义。如果密码套件未显式指定 `verify_data` 的长度,则其长度为12个字节。这适用于所有现有的密码套件。未来的密码套件可以指定其他长度,但长度必须至少为12字节。

    #### 握手消息:

    `handshake_messages` 包括握手过程中所有消息的数据(不包括任何 HelloRequest 消息),直到但不包括该 Finished 消息。这是握手层可见的所有数据,不包括记录层头部。这是在握手过程中交换的所有 Handshake 结构的串联。

    如果 Finished 消息在握手过程中没有在适当的时间点之前由 ChangeCipherSpec 消息前导,则会导致致命错误。

    注意:ChangeCipherSpec 消息、警报和任何其他记录类型不是握手消息,因此不包括在哈希计算中。

  •  

    61a28f76484b4c5c9910fa78b8c43cb7.png

     

    好了一套流程下来了,废了我半条命,不想写了

 

 

 

 

 

 

也许您对下面的内容还感兴趣: