# transcript.rs - source
Source of the Rust file `crates/core/src/fixtures/transcript.rs`.

Skip to main content

#
tlsn_core/fixtures/
transcript.rs

    1//! Transcript fixtures for testing.
    2
    3use aead::Payload as AeadPayload;
    4use aes_gcm::{aead::Aead, Aes128Gcm, NewAead};
    5#[allow(deprecated)]
    6use generic_array::GenericArray;
    7use rand::{rngs::StdRng, Rng, SeedableRng};
    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, VerifyData},
    18    fixtures::ConnectionFixture,
    19    transcript::{ContentType, Record, TlsTranscript},
    20};
    21
    22/// The key used for encryption of the sent and received transcript.
    23pub const KEY: [u8; 16] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
    24
    25/// The iv used for encryption of the sent and received transcript.
    26pub const IV: [u8; 4] = [1, 3, 3, 7];
    27
    28/// The record size in bytes.
    29pub const RECORD_SIZE: usize = 512;
    30
    31/// Creates a transript fixture for testing.
    32pub 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        let server_cert_chain = tlsn.server_cert_data.certs;
    58        let server_signature = tlsn.server_cert_data.sig;
    59        let cert_binding = tlsn.server_cert_data.binding;
    60
    61        let cf_vd: [u8; 12] = rng.random();
    62        let sf_vd: [u8; 12] = rng.random();
    63
    64        let verify_data = VerifyData {
    65            client_finished: cf_vd.to_vec(),
    66            server_finished: sf_vd.to_vec(),
    67        };
    68
    69        let sent = self.gen_records(cf_vd, sent);
    70        let recv = self.gen_records(sf_vd, recv);
    71
    72        TlsTranscript::new(
    73            time,
    74            version,
    75            Some(server_cert_chain),
    76            Some(server_signature),
    77            cert_binding,
    78            verify_data,
    79            sent,
    80            recv,
    81        )
    82        .unwrap()
    83    }
    84
    85    fn gen_records(&self, vd: [u8; 12], plaintext: &[u8]) -> Vec<Record> {
    86        let mut records = Vec::new();
    87
    88        let handshake = self.gen_handshake(vd);
    89        records.push(handshake);
    90
    91        for (seq, msg) in (1_u64..).zip(plaintext.chunks(RECORD_SIZE)) {
    92            let record = self.gen_app_data(seq, msg);
    93            records.push(record);
    94        }
    95
    96        records
    97    }
    98
    99    fn gen_app_data(&self, seq: u64, plaintext: &[u8]) -> Record {
    100        assert!(
    101            plaintext.len() <= 1 << 14,
    102            "plaintext len per record must be smaller than 2^14 bytes"
    103        );
    104
    105        let explicit_nonce: [u8; 8] = seq.to_be_bytes();
    106        let msg = PlainMessage {
    107            typ: ContentType::ApplicationData.into(),
    108            version: ProtocolVersion::TLSv1_2,
    109            payload: Payload::new(plaintext),
    110        };
    111        let opaque = aes_gcm_encrypt(self.key, self.iv, seq, explicit_nonce, &msg);
    112
    113        let mut payload = opaque.payload.0;
    114        let mut ciphertext = payload.split_off(8);
    115        let tag = ciphertext.split_off(ciphertext.len() - 16);
    116
    117        Record {
    118            seq,
    119            typ: ContentType::ApplicationData,
    120            plaintext: Some(plaintext.to_vec()),
    121            explicit_nonce: explicit_nonce.to_vec(),
    122            ciphertext,
    123            tag: Some(tag),
    124        }
    125    }
    126
    127    fn gen_handshake(&self, vd: [u8; 12]) -> Record {
    128        let seq = 0_u64;
    129        let explicit_nonce = seq.to_be_bytes();
    130
    131        let mut plaintext = Vec::new();
    132
    133        let payload = Payload(vd.to_vec());
    134        let hs_payload = HandshakePayload::Finished(payload);
    135        let handshake_message = HandshakeMessagePayload {
    136            typ: HandshakeType::Finished,
    137            payload: hs_payload,
    138        };
    139        handshake_message.encode(&mut plaintext);
    140
    141        let msg = PlainMessage {
    142            typ: ContentType::Handshake.into(),
    143            version: ProtocolVersion::TLSv1_2,
    144            payload: Payload::new(plaintext.clone()),
    145        };
    146
    147        let opaque = aes_gcm_encrypt(self.key, self.iv, seq, explicit_nonce, &msg);
    148        let mut payload = opaque.payload.0;
    149        let mut ciphertext = payload.split_off(8);
    150        let tag = ciphertext.split_off(ciphertext.len() - 16);
    151
    152        Record {
    153            seq,
    154            typ: ContentType::Handshake,
    155            plaintext: Some(plaintext),
    156            explicit_nonce: explicit_nonce.to_vec(),
    157            ciphertext,
    158            tag: Some(tag),
    159        }
    160    }
    161}
    162
    163fn aes_gcm_encrypt(
    164    key: [u8; 16],
    165    iv: [u8; 4],
    166    seq: u64,
    167    explicit_nonce: [u8; 8],
    168    msg: &PlainMessage,
    169) -> OpaqueMessage {
    170    let mut aad = [0u8; 13];
    171
    172    aad[..8].copy_from_slice(&seq.to_be_bytes());
    173    aad[8] = msg.typ.get_u8();
    174    aad[9..11].copy_from_slice(&msg.version.get_u16().to_be_bytes());
    175    aad[11..13].copy_from_slice(&(msg.payload.0.len() as u16).to_be_bytes());
    176    let payload = AeadPayload {
    177        msg: &msg.payload.0,
    178        aad: &aad,
    179    };
    180
    181    let mut nonce = [0u8; 12];
    182    nonce[..4].copy_from_slice(&iv);
    183    nonce[4..].copy_from_slice(&explicit_nonce);
    184    #[allow(deprecated)]
    185    let nonce = GenericArray::from_slice(&nonce);
    186    let cipher = Aes128Gcm::new_from_slice(&key).unwrap();
    187
    188    // ciphertext will have the MAC appended
    189    let ciphertext = cipher.encrypt(nonce, payload).unwrap();
    190
    191    // prepend the explicit nonce
    192    let mut nonce_ct_mac = vec![0u8; 0];
    193    nonce_ct_mac.extend(explicit_nonce.iter());
    194    nonce_ct_mac.extend(ciphertext.iter());
    195
    196    OpaqueMessage {
    197        typ: msg.typ,
    198        version: msg.version,
    199        payload: Payload::new(nonce_ct_mac),
    200    }
    201}