TLS 1.2 客戶端完成消息包含什麼?
我正在實施 TLS 1.2,但我被困在客戶端完成的消息上。
我的問題是:使用 ECDHE_RSA_AES_128_GCM_SHA256 密碼套件時,TLS 1.2 中客戶端完成消息的大小和結構是什麼。
我搜尋了這個問題,有人說它的大小是 48 字節;進一步來說:
- 12字節驗證數據
- 1字節握手類型
- 3字節校驗數據長度
- 和 32 字節 MAC
這真的正確嗎?
我的意思是:根據RFC 5246完成的消息有
{verify_data[verify_data_length]}
和verify_data = PRF(master_secret, finished_label, hash(handshake_messages)
. 此外,根據 RFC 5246 第 5 節PRF(secret, label, seed) = P_<hash>(secret, label+seed)
和P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed)
. 所以,當我使用 SHA256 計算 HMAC 時,verify_data
它的大小是 32 字節。結果,我對
verify_data
大小和完成的消息結構有點困惑。誰能幫助我理解這一點和/或以某種方式讓我走上正確的軌道?
rfc5246 7.4.9定義
verify_data
為PRF(master_secret, finished_label, Hash(handshake_messages)) [0..verify_data_length-1];
注意第二行;這有效地將 PRF 輸出截斷為
verify_data_length
八位字節。它繼續說 verify_data 大小取決於密碼套件。任何未明確指定 verify_data_length 的密碼套件的 verify_data_length 都等於 12。
ECDHE_RSA_AES_128_GCM_SHA256 在沒有明確指定的 rfc 5289 中定義,因此適用此預設值。
第二,某處有人錯了。GCM 和 CCM 密碼套件在(明文)記錄上沒有 HMAC,儘管流和“塊”(CBC)套件有;相反,AEAD 程序將身份驗證標籤添加到加密記錄中。將 6.2.3.3 與 6.2.3.1 和 6.2.3.2 進行比較。
在Finished Message FOR TLS中,除非在密碼套件中另有說明,否則驗證數據的長度為 12 字節,因此在您的情況下,它的長度為 12 字節。它採用以下握手消息形式:
struct { HandshakeType msg_type; /* handshake type */ uint24 length; /* bytes in message */ select (HandshakeType) { ... case finished: Finished; } body; } Handshake;
但是,由於問題原來是DTLS 而不是 TLS,因此將其修改為
struct { HandshakeType msg_type; uint24 length; uint16 message_seq; // New field uint24 fragment_offset; // New field uint24 fragment_length; // New field select (HandshakeType) { ... case finished: Finished; } body; } Handshake;
使用商定密碼套件的 PRF 創建完成的消息。創建握手消息後,您需要將其轉換為TLSCipherText結構,形式為
struct { ContentType type; ProtocolVersion version; uint16 length; select (SecurityParameters.cipher_type) { case stream: GenericStreamCipher; case block: GenericBlockCipher; case aead: GenericAEADCipher; } fragment; } TLSCiphertext;
但 DTLS 又是不同的
struct { ContentType type; ProtocolVersion version; uint16 epoch; // New field uint48 sequence_number; // New field uint16 length; select (CipherSpec.cipher_type) { case block: GenericBlockCipher; case aead: GenericAEADCipher; // New field [sic] } fragment; } DTLSCiphertext;
在這裡,您使用的是ECDHE_RSA_AES_128_GCM_SHA256,它是一個 AEAD 密碼,因此它採用GenericAEADCipher的形式:
struct { opaque nonce_explicit[SecurityParameters.record_iv_length]; aead-ciphered struct { opaque content[TLSCompressed.length]; }; } GenericAEADCipher;
在這裡,nonce_explicit 包含 8 個字節的 nonce,你將它與來自密鑰派生(4 個字節)的“固定 IV”結合起來,然後你得到 12 個字節的 IV 用於 AES-GCM 模式加密。(請注意,您只發送了 IV 的最後8 個字節)。
在這個結構中,
aead-ciphered
結果包括encryption output || authentication tag
. 因此,您已通過將身份驗證標籤連接到加密消息來發送它。在完成消息的情況下,加密輸出和認證標籤是完成消息的加密輸出。最後,對於 TLS,密碼套件ECDHE_RSA_AES_128_GCM_SHA256來自伺服器端的預期完成消息應該如下所示:
16 --ContentType(hanshake) 03 03 --protocolVersion(tls 1.2) 00 28 -- message length(40) --finished message-- 00 00 00 00 00 00 00 00 --nonce_explicit. (8 byte) (this is write sequence number, for initial handshake this should be all zero) xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx -- encrypted finished message. (16 byte) (Note that finished message is of length 16(1 byte finished message type + 3 byte handshake message length + 12 byte verify_data) ) yy yy yy yy yy yy yy yy yy yy yy yy yy yy yy yy -- authentication tag. (16 byte) (this is also output of the encrption of finished message using AES-GCM)
但這對於 DTLS
16 -- type=handshake fe fd -- version=DTLS1.2 nn nn -- epoch, 1 for the initial negotiation, more if renegotiation 00 00 00 00 00 00 -- seqnum, always zero because Finished is first after CCS 00 30 -- length=48 (8 bytes) -- explicit nonce (24 bytes) -- encryption of Finished handshake message (16 bytes) -- authentication tag