1use aead::Payload as AeadPayload;
4use aes_gcm::{Aes128Gcm, NewAead, aead::Aead};
5#[allow(deprecated)]
6use generic_array::GenericArray;
7use rand::{Rng, SeedableRng, rngs::StdRng};
8use tls_core::msgs::{
9 base::Payload,
10 codec::Codec,
11 enums::{HandshakeType, ProtocolVersion},
12 handshake::{HandshakeMessagePayload, HandshakePayload},
13 message::{OpaqueMessage, PlainMessage},
14};
15
16use crate::{
17 connection::TranscriptLength,
18 fixtures::ConnectionFixture,
19 transcript::{ContentType, Record, TlsTranscript},
20};
21
22pub const KEY: [u8; 16] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
24
25pub const IV: [u8; 4] = [1, 3, 3, 7];
27
28pub const RECORD_SIZE: usize = 512;
30
31pub fn transcript_fixture(sent: &[u8], recv: &[u8]) -> TlsTranscript {
33 TranscriptGenerator::new(KEY, IV).generate(sent, recv)
34}
35
36struct TranscriptGenerator {
37 key: [u8; 16],
38 iv: [u8; 4],
39}
40
41impl TranscriptGenerator {
42 fn new(key: [u8; 16], iv: [u8; 4]) -> Self {
43 Self { key, iv }
44 }
45
46 fn generate(&self, sent: &[u8], recv: &[u8]) -> TlsTranscript {
47 let mut rng = StdRng::from_seed([1; 32]);
48
49 let transcript_len = TranscriptLength {
50 sent: sent.len() as u32,
51 received: recv.len() as u32,
52 };
53 let tlsn = ConnectionFixture::tlsnotary(transcript_len);
54
55 let time = tlsn.connection_info.time;
56 let version = tlsn.connection_info.version;
57
58 let cf_vd: [u8; 12] = rng.random();
59 let sf_vd: [u8; 12] = rng.random();
60
61 let client_finished = self.gen_finished_record(cf_vd);
62 let server_finished = self.gen_finished_record(sf_vd);
63
64 let mut sent = self.gen_app_records(sent);
65 let mut recv = self.gen_app_records(recv);
66
67 sent.insert(0, client_finished);
68 recv.insert(0, server_finished);
69
70 TlsTranscript {
71 time,
72 version,
73 server_signature: Some(tlsn.server_cert_data.sig),
74 server_cert_chain: Some(tlsn.server_cert_data.certs),
75 certificate_binding: tlsn.server_cert_data.binding,
76 cf_hash: None,
77 session_hash: None,
78 sf_hash: None,
79 sent,
80 recv,
81 }
82 }
83
84 fn gen_app_records(&self, plaintext: &[u8]) -> Vec<Record> {
85 (1_u64..)
86 .zip(plaintext.chunks(RECORD_SIZE))
87 .map(|(seq, msg)| self.gen_app_data(seq, msg))
88 .collect()
89 }
90
91 fn gen_app_data(&self, seq: u64, plaintext: &[u8]) -> Record {
92 assert!(
93 plaintext.len() <= 1 << 14,
94 "plaintext len per record must be smaller than 2^14 bytes"
95 );
96
97 let explicit_nonce: [u8; 8] = seq.to_be_bytes();
98 let msg = PlainMessage {
99 typ: ContentType::ApplicationData.into(),
100 version: ProtocolVersion::TLSv1_2,
101 payload: Payload::new(plaintext),
102 };
103 let opaque = aes_gcm_encrypt(self.key, self.iv, seq, explicit_nonce, &msg);
104
105 let mut payload = opaque.payload.0;
106 let mut ciphertext = payload.split_off(8);
107 let tag = ciphertext.split_off(ciphertext.len() - 16);
108
109 Record {
110 seq,
111 typ: ContentType::ApplicationData,
112 plaintext: Some(plaintext.to_vec()),
113 explicit_nonce: explicit_nonce.to_vec(),
114 ciphertext,
115 tag: Some(tag),
116 }
117 }
118
119 fn gen_finished_record(&self, vd: [u8; 12]) -> Record {
120 let seq = 0_u64;
121 let explicit_nonce = seq.to_be_bytes();
122
123 let mut plaintext = Vec::new();
124
125 let payload = Payload(vd.to_vec());
126 let hs_payload = HandshakePayload::Finished(payload);
127 let handshake_message = HandshakeMessagePayload {
128 typ: HandshakeType::Finished,
129 payload: hs_payload,
130 };
131 handshake_message.encode(&mut plaintext);
132
133 let msg = PlainMessage {
134 typ: ContentType::Handshake.into(),
135 version: ProtocolVersion::TLSv1_2,
136 payload: Payload::new(plaintext.clone()),
137 };
138
139 let opaque = aes_gcm_encrypt(self.key, self.iv, seq, explicit_nonce, &msg);
140 let mut payload = opaque.payload.0;
141 let mut ciphertext = payload.split_off(8);
142 let tag = ciphertext.split_off(ciphertext.len() - 16);
143
144 Record {
145 seq: 0,
146 typ: ContentType::Handshake,
147 plaintext: Some(plaintext),
148 explicit_nonce: explicit_nonce.to_vec(),
149 ciphertext,
150 tag: Some(tag),
151 }
152 }
153}
154
155fn aes_gcm_encrypt(
156 key: [u8; 16],
157 iv: [u8; 4],
158 seq: u64,
159 explicit_nonce: [u8; 8],
160 msg: &PlainMessage,
161) -> OpaqueMessage {
162 let mut aad = [0u8; 13];
163
164 aad[..8].copy_from_slice(&seq.to_be_bytes());
165 aad[8] = msg.typ.get_u8();
166 aad[9..11].copy_from_slice(&msg.version.get_u16().to_be_bytes());
167 aad[11..13].copy_from_slice(&(msg.payload.0.len() as u16).to_be_bytes());
168 let payload = AeadPayload {
169 msg: &msg.payload.0,
170 aad: &aad,
171 };
172
173 let mut nonce = [0u8; 12];
174 nonce[..4].copy_from_slice(&iv);
175 nonce[4..].copy_from_slice(&explicit_nonce);
176 #[allow(deprecated)]
177 let nonce = GenericArray::from_slice(&nonce);
178 let cipher = Aes128Gcm::new_from_slice(&key).unwrap();
179
180 let ciphertext = cipher.encrypt(nonce, payload).unwrap();
182
183 let mut nonce_ct_mac = vec![0u8; 0];
185 nonce_ct_mac.extend(explicit_nonce.iter());
186 nonce_ct_mac.extend(ciphertext.iter());
187
188 OpaqueMessage {
189 typ: msg.typ,
190 version: msg.version,
191 payload: Payload::new(nonce_ct_mac),
192 }
193}